mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
User content usages & quotas - initial check-in
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@7453 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1482,8 +1482,15 @@ public class NTProtocolHandler extends CoreProtocolHandler
|
||||
m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
|
||||
return;
|
||||
}
|
||||
catch (DiskFullException ex)
|
||||
{
|
||||
m_sess.sendErrorResponseSMB(SMBStatus.NTDiskFull, SMBStatus.HRDWriteFault, SMBStatus.ErrHrd);
|
||||
return;
|
||||
}
|
||||
catch (java.io.IOException ex)
|
||||
{
|
||||
if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
|
||||
logger.debug("IOException ignore: "+ex);
|
||||
}
|
||||
|
||||
// Remove the file from the connections list of open files
|
||||
|
@@ -35,6 +35,7 @@ import java.nio.charset.Charset;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.filesys.server.filesys.AccessDeniedException;
|
||||
import org.alfresco.filesys.server.filesys.DiskFullException;
|
||||
import org.alfresco.filesys.server.filesys.FileAttribute;
|
||||
import org.alfresco.filesys.server.filesys.FileInfo;
|
||||
import org.alfresco.filesys.server.filesys.FileOpenParams;
|
||||
@@ -52,6 +53,7 @@ import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.MimetypeService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.usage.ContentQuotaException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -382,7 +384,14 @@ public class ContentNetworkFile extends NodeRefNetworkFile
|
||||
// Update node properties
|
||||
|
||||
ContentData contentData = content.getContentData();
|
||||
nodeService.setProperty( getNodeRef(), ContentModel.PROP_CONTENT, contentData);
|
||||
try
|
||||
{
|
||||
nodeService.setProperty( getNodeRef(), ContentModel.PROP_CONTENT, contentData);
|
||||
}
|
||||
catch (ContentQuotaException qe)
|
||||
{
|
||||
throw new DiskFullException(qe.getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -168,6 +168,9 @@ public interface ContentModel
|
||||
static final QName PROP_PRESENCEPROVIDER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "presenceProvider");
|
||||
static final QName PROP_PRESENCEUSERNAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "presenceUsername");
|
||||
|
||||
static final QName PROP_SIZE_CURRENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "sizeCurrent");
|
||||
static final QName PROP_SIZE_QUOTA = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "sizeQuota");
|
||||
|
||||
// Ownable aspect
|
||||
static final QName ASPECT_OWNABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "ownable");
|
||||
static final QName PROP_OWNER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "owner");
|
||||
|
@@ -59,6 +59,7 @@ import org.alfresco.service.cmr.repository.NoTransformerException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.usage.ContentQuotaException;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
@@ -567,6 +568,10 @@ public class RoutingContentService implements ContentService
|
||||
" value: " + contentData);
|
||||
}
|
||||
}
|
||||
catch (ContentQuotaException qe)
|
||||
{
|
||||
throw qe;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new ContentIOException("Failed to set content property on stream closure: \n" +
|
||||
|
@@ -500,6 +500,19 @@
|
||||
where
|
||||
node.store.key.protocol = :protocol and
|
||||
node.store.key.identifier = :identifier
|
||||
</query>
|
||||
</query>
|
||||
|
||||
<query name="node.GetNodesWithPropertyStringValueForStore">
|
||||
select
|
||||
node
|
||||
from
|
||||
org.alfresco.repo.domain.hibernate.NodeImpl as node
|
||||
join node.properties prop
|
||||
where
|
||||
index(prop) = :propQName and
|
||||
prop.stringValue = :propStringValue and
|
||||
node.store.key.protocol = :protocol and
|
||||
node.store.key.identifier = :identifier
|
||||
</query>
|
||||
|
||||
</hibernate-mapping>
|
||||
|
@@ -0,0 +1,79 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
'-//Hibernate/Hibernate Mapping DTD 3.0//EN'
|
||||
'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
|
||||
|
||||
<!-- Hibernate mapping for storing usage delta information -->
|
||||
<!-- -->
|
||||
<!-- This generates a schema for content usage deltas -->
|
||||
<!-- which can be used to keep track of current usages until a -->
|
||||
<!-- background job has rolled up and stored against -->
|
||||
<!-- the actual entity (e.g. person, folder). -->
|
||||
<!-- -->
|
||||
|
||||
<hibernate-mapping>
|
||||
|
||||
<!-- The Usage Delta -->
|
||||
|
||||
<class name="org.alfresco.repo.usage.hibernate.UsageDeltaImpl"
|
||||
proxy="org.alfresco.repo.usage.UsageDelta"
|
||||
table="alf_usage_delta"
|
||||
dynamic-update="false"
|
||||
dynamic-insert="false"
|
||||
select-before-update="false"
|
||||
lazy="true"
|
||||
optimistic-lock="version">
|
||||
|
||||
<!-- An auto-generated id -->
|
||||
<id name="id" column="id" type="long">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
|
||||
<!-- Optimistic locking -->
|
||||
<version column="version" name="version" type="long" />
|
||||
|
||||
<!-- forward assoc to node -->
|
||||
<many-to-one
|
||||
name="node"
|
||||
not-null="true"
|
||||
lazy="proxy"
|
||||
class="org.alfresco.repo.domain.hibernate.NodeImpl"
|
||||
fetch="select" >
|
||||
<column name="node_id" />
|
||||
</many-to-one>
|
||||
|
||||
<property name="deltaSize" column="delta_size" type="long" not-null="true"/>
|
||||
|
||||
</class>
|
||||
|
||||
<!-- Get total usage delta for a node -->
|
||||
<query name="usage.GetTotalDeltaSize">
|
||||
select
|
||||
sum(deltaSize)
|
||||
from
|
||||
org.alfresco.repo.usage.hibernate.UsageDeltaImpl as usage_delta
|
||||
where
|
||||
usage_delta.node = :node
|
||||
</query>
|
||||
|
||||
|
||||
<!-- Get nodes with usage deltas -->
|
||||
<query name="usage.GetUsageDeltaNodes">
|
||||
select
|
||||
distinct usage_delta.node
|
||||
from
|
||||
org.alfresco.repo.usage.hibernate.UsageDeltaImpl as usage_delta
|
||||
</query>
|
||||
|
||||
<!-- Get usage deltas for a node -->
|
||||
<query name="usage.GetDeltas">
|
||||
select
|
||||
usage_delta
|
||||
from
|
||||
org.alfresco.repo.usage.hibernate.UsageDeltaImpl as usage_delta
|
||||
where
|
||||
usage_delta.node = :node
|
||||
</query>
|
||||
|
||||
</hibernate-mapping>
|
@@ -293,6 +293,8 @@ public interface NodeDaoService
|
||||
*/
|
||||
public int getNodeCount(final StoreRef storeRef);
|
||||
|
||||
public Collection<Node> getNodesWithPropertyStringValueForStore(final StoreRef storeRef, final QName propQName, final String propStringValue);
|
||||
|
||||
public Transaction getTxnById(long txnId);
|
||||
/**
|
||||
* Get all transactions in a given time range. Since time-based retrieval doesn't guarantee uniqueness
|
||||
|
@@ -60,6 +60,7 @@ import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.TransactionAwareSingleton;
|
||||
import org.alfresco.repo.transaction.TransactionalDao;
|
||||
import org.alfresco.repo.usage.UsageDeltaDAO;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
|
||||
import org.alfresco.service.cmr.repository.AssociationExistsException;
|
||||
@@ -113,6 +114,8 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
||||
private static final String QUERY_GET_CHILD_ASSOCS_FOR_STORE = "node.GetChildAssocsForStore";
|
||||
private static final String QUERY_GET_NODES_EXCEPT_ROOT_FOR_STORE = "node.GetNodesExceptRootForStore";
|
||||
|
||||
private static final String QUERY_NODES_WITH_PROPERTY_STRING_VALUE_FOR_STORE = "node.GetNodesWithPropertyStringValueForStore";
|
||||
|
||||
private static Log logger = LogFactory.getLog(HibernateNodeDaoServiceImpl.class);
|
||||
/** Log to trace parent association caching: <b>classname + .ParentAssocsCache</b> */
|
||||
private static Log loggerParentAssocsCache = LogFactory.getLog(HibernateNodeDaoServiceImpl.class.getName() + ".ParentAssocsCache");
|
||||
@@ -131,7 +134,14 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
||||
/** used for debugging */
|
||||
private Set<String> changeTxnIdSet;
|
||||
|
||||
TenantService tenantService;
|
||||
private UsageDeltaDAO usageDeltaDao;
|
||||
private TenantService tenantService;
|
||||
|
||||
|
||||
public void setUsageDeltaDao(UsageDeltaDAO usageDeltaDao)
|
||||
{
|
||||
this.usageDeltaDao = usageDeltaDao;
|
||||
}
|
||||
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
@@ -616,6 +626,13 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
||||
{
|
||||
getHibernateTemplate().delete(assoc);
|
||||
}
|
||||
|
||||
if (isDebugEnabled)
|
||||
{
|
||||
logger.debug("Deleting usage deltas of node (if any)" + node.getId());
|
||||
}
|
||||
usageDeltaDao.deleteDeltas(node);
|
||||
|
||||
// update the node status
|
||||
NodeRef nodeRef = node.getNodeRef();
|
||||
NodeStatus nodeStatus = getNodeStatus(nodeRef, true);
|
||||
@@ -1427,6 +1444,29 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
||||
// done
|
||||
return count.intValue();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<Node> getNodesWithPropertyStringValueForStore(final StoreRef storeRef, final QName propQName, final String propStringValue)
|
||||
{
|
||||
HibernateCallback callback = new HibernateCallback()
|
||||
{
|
||||
public Object doInHibernate(Session session)
|
||||
{
|
||||
Query query = session.getNamedQuery(QUERY_NODES_WITH_PROPERTY_STRING_VALUE_FOR_STORE);
|
||||
query.setString("protocol", storeRef.getProtocol())
|
||||
.setString("identifier", storeRef.getIdentifier())
|
||||
.setParameter("propQName", propQName)
|
||||
.setString("propStringValue", propStringValue)
|
||||
.setReadOnly(true);
|
||||
return query.list();
|
||||
}
|
||||
};
|
||||
|
||||
List<Node> queryResults = (List<Node>) getHibernateTemplate().execute(callback);
|
||||
return queryResults;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Queries for transactions
|
||||
|
@@ -607,6 +607,10 @@ public class PersonServiceImpl implements PersonService,
|
||||
properties.put(ContentModel.PROP_EMAIL, "");
|
||||
properties.put(ContentModel.PROP_ORGID, "");
|
||||
properties.put(ContentModel.PROP_HOME_FOLDER_PROVIDER, defaultHomeFolderProvider);
|
||||
|
||||
properties.put(ContentModel.PROP_SIZE_CURRENT, 0L);
|
||||
properties.put(ContentModel.PROP_SIZE_QUOTA, -1L); // no quota
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
@@ -615,6 +619,9 @@ public class PersonServiceImpl implements PersonService,
|
||||
String userName = DefaultTypeConverter.INSTANCE.convert(String.class, properties
|
||||
.get(ContentModel.PROP_USERNAME));
|
||||
properties.put(ContentModel.PROP_USERNAME, userName);
|
||||
|
||||
properties.put(ContentModel.PROP_SIZE_CURRENT, 0L);
|
||||
|
||||
return nodeService.createNode(getPeopleContainer(), ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_PERSON,
|
||||
ContentModel.TYPE_PERSON, properties).getChildRef();
|
||||
}
|
||||
|
412
source/java/org/alfresco/repo/usage/ContentUsageImpl.java
Normal file
412
source/java/org/alfresco/repo/usage/ContentUsageImpl.java
Normal file
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.usage;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.node.NodeServicePolicies;
|
||||
import org.alfresco.repo.policy.JavaBehaviour;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.usage.ContentUsageService;
|
||||
import org.alfresco.service.cmr.usage.UsageService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Implements Content Usage service and policies/behaviour.
|
||||
*
|
||||
*/
|
||||
public class ContentUsageImpl implements ContentUsageService,
|
||||
NodeServicePolicies.OnCreateNodePolicy,
|
||||
NodeServicePolicies.OnUpdatePropertiesPolicy,
|
||||
NodeServicePolicies.BeforeDeleteNodePolicy
|
||||
{
|
||||
// Logger
|
||||
private static Log logger = LogFactory.getLog(ContentUsageImpl.class);
|
||||
|
||||
private NodeService nodeService;
|
||||
private PersonService personService;
|
||||
private PolicyComponent policyComponent;
|
||||
private UsageService usageService;
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
public static final StoreRef SPACES_STOREREF = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
|
||||
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setPersonService(PersonService personService)
|
||||
{
|
||||
this.personService = personService;
|
||||
}
|
||||
|
||||
public void setUsageService(UsageService usageService)
|
||||
{
|
||||
this.usageService = usageService;
|
||||
}
|
||||
|
||||
public void setPolicyComponent(PolicyComponent policyComponent)
|
||||
{
|
||||
this.policyComponent = policyComponent;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The initialise method
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
// Register interest in the onCreateNode policy
|
||||
policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"),
|
||||
ContentModel.TYPE_CONTENT,
|
||||
new JavaBehaviour(this, "onCreateNode"));
|
||||
|
||||
// Register interest in the onUpdateProperties policy
|
||||
policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
|
||||
ContentModel.TYPE_CONTENT,
|
||||
new JavaBehaviour(this, "onUpdateProperties"));
|
||||
|
||||
// Register interest in the beforeDeleteNode policy
|
||||
policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
|
||||
ContentModel.TYPE_CONTENT,
|
||||
new JavaBehaviour(this, "beforeDeleteNode"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when a new node has been created.
|
||||
*
|
||||
* @param childAssocRef the created child association reference
|
||||
*/
|
||||
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
NodeRef nodeRef = childAssocRef.getChildRef();
|
||||
if (nodeRef.getStoreRef().equals(SPACES_STOREREF))
|
||||
{
|
||||
// Get content size
|
||||
|
||||
// TODO use data dictionary to get content property
|
||||
ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
|
||||
Long contentSize = (contentData == null ? null : contentData.getSize());
|
||||
|
||||
// Get owner/creator
|
||||
String owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER);
|
||||
if (owner == null)
|
||||
{
|
||||
owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATOR);
|
||||
}
|
||||
|
||||
if (contentSize != null && contentSize != 0 && owner != null)
|
||||
{
|
||||
// new node with non-empty content size
|
||||
if (logger.isDebugEnabled()) logger.debug("onCreateNode: contentSize="+contentSize+", nodeRef="+nodeRef+", ownerAfter="+owner);
|
||||
incrementUserUsage(owner, contentSize, nodeRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after a node's properties have been changed.
|
||||
*
|
||||
* @param nodeRef reference to the updated node
|
||||
* @param before the node's properties before the change
|
||||
* @param after the node's properties after the change
|
||||
*/
|
||||
public void onUpdateProperties(
|
||||
NodeRef nodeRef,
|
||||
Map<QName, Serializable> before,
|
||||
Map<QName, Serializable> after)
|
||||
{
|
||||
if (nodeRef.getStoreRef().equals(SPACES_STOREREF))
|
||||
{
|
||||
// Check for change in content size
|
||||
|
||||
// TODO use data dictionary to get content property
|
||||
ContentData contentDataBefore = (ContentData)before.get(ContentModel.PROP_CONTENT);
|
||||
Long contentSizeBefore = (contentDataBefore == null ? null : contentDataBefore.getSize());
|
||||
ContentData contentDataAfter = (ContentData)after.get(ContentModel.PROP_CONTENT);
|
||||
Long contentSizeAfter = (contentDataAfter == null ? null : contentDataAfter.getSize());
|
||||
|
||||
// Check for change in owner/creator
|
||||
String ownerBefore = (String)before.get(ContentModel.PROP_OWNER);
|
||||
if (ownerBefore == null)
|
||||
{
|
||||
ownerBefore = (String)before.get(ContentModel.PROP_CREATOR);
|
||||
}
|
||||
String ownerAfter = (String)after.get(ContentModel.PROP_OWNER);
|
||||
if (ownerAfter == null)
|
||||
{
|
||||
ownerAfter = (String)after.get(ContentModel.PROP_CREATOR);
|
||||
}
|
||||
|
||||
// check change in size (and possibly owner)
|
||||
if (contentSizeBefore == null && contentSizeAfter != null && contentSizeAfter != 0 && ownerAfter != null)
|
||||
{
|
||||
// new size has been added - note: ownerBefore does not matter since the contentSizeBefore is null
|
||||
if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateSize (null -> "+contentSizeAfter+"): nodeRef="+nodeRef+", ownerAfter="+ownerAfter);
|
||||
incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef);
|
||||
|
||||
}
|
||||
else if (contentSizeAfter == null && contentSizeBefore != null && contentSizeBefore != 0 && ownerBefore != null)
|
||||
{
|
||||
// old size has been removed - note: ownerAfter does not matter since contentSizeAfter is null
|
||||
if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateSize ("+contentSizeBefore+" -> null): nodeRef="+nodeRef+", ownerBefore="+ownerBefore);
|
||||
decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef);
|
||||
}
|
||||
else if (contentSizeBefore != null && contentSizeAfter != null)
|
||||
{
|
||||
if (contentSizeBefore.equals(contentSizeAfter) == false)
|
||||
{
|
||||
// size has changed (and possibly owner)
|
||||
if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateSize ("+contentSizeBefore+" -> "+contentSizeAfter+"): nodeRef="+nodeRef+", ownerBefore="+ownerBefore+", ownerAfter="+ownerAfter);
|
||||
|
||||
if (contentSizeBefore != 0 && ownerBefore != null)
|
||||
{
|
||||
decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef);
|
||||
}
|
||||
if (contentSizeAfter != 0 && ownerAfter != null)
|
||||
{
|
||||
incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// same size - check change in owner only
|
||||
if (ownerBefore == null && ownerAfter != null && contentSizeAfter != 0 && ownerAfter != null)
|
||||
{
|
||||
// new owner has been added
|
||||
if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateOwner (null -> "+ownerAfter+"): nodeRef="+nodeRef+", contentSize="+contentSizeAfter);
|
||||
incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef);
|
||||
}
|
||||
else if (ownerAfter == null && ownerBefore != null && contentSizeBefore != 0)
|
||||
{
|
||||
// old owner has been removed
|
||||
if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateOwner ("+ownerBefore+" -> null): nodeRef="+nodeRef+", contentSize="+contentSizeBefore);
|
||||
decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef);
|
||||
}
|
||||
else if (ownerBefore != null && ownerAfter != null && ownerBefore.equals(ownerAfter) == false)
|
||||
{
|
||||
// owner has changed (size has not)
|
||||
if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateOwner ("+ownerBefore+" -> "+ownerAfter+"): nodeRef="+nodeRef+", contentSize="+contentSizeBefore);
|
||||
|
||||
if (contentSizeBefore != 0)
|
||||
{
|
||||
decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef);
|
||||
}
|
||||
if (contentSizeAfter != 0)
|
||||
{
|
||||
incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before a node is deleted.
|
||||
*
|
||||
* @param nodeRef the node reference
|
||||
*/
|
||||
public void beforeDeleteNode(NodeRef nodeRef)
|
||||
{
|
||||
if (nodeRef.getStoreRef().equals(SPACES_STOREREF))
|
||||
{
|
||||
// TODO use data dictionary to get content property
|
||||
ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
|
||||
|
||||
if (contentData != null)
|
||||
{
|
||||
long contentSize = contentData.getSize();
|
||||
String owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER);
|
||||
|
||||
if (contentSize != 0 && owner != null)
|
||||
{
|
||||
// decrement usage if node is being deleted
|
||||
if (logger.isDebugEnabled()) logger.debug("beforeDeleteNode: nodeRef="+nodeRef+", owner="+owner+", contentSize="+contentSize);
|
||||
decrementUserUsage(owner, contentSize, nodeRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void incrementUserUsage(String userName, long contentSize, NodeRef contentNodeRef)
|
||||
{
|
||||
// increment usage - add positive delta
|
||||
if (logger.isDebugEnabled()) logger.debug("incrementUserUsage: username="+userName+", contentSize="+contentSize+", contentNodeRef="+contentNodeRef);
|
||||
|
||||
long currentSize = getUserUsage(userName);
|
||||
long quotaSize = getUserQuota(userName);
|
||||
|
||||
long newSize = currentSize + contentSize;
|
||||
|
||||
// check whether user's quota exceeded
|
||||
if ((quotaSize != -1) && (newSize > quotaSize))
|
||||
{
|
||||
if (logger.isWarnEnabled())
|
||||
{
|
||||
logger.warn("User (" + userName + ") quota exceeded: content=" + contentSize +
|
||||
", usage=" + currentSize +
|
||||
", quota=" + quotaSize);
|
||||
}
|
||||
}
|
||||
|
||||
NodeRef personNodeRef = personService.getPerson(userName);
|
||||
usageService.insertDelta(personNodeRef, contentSize);
|
||||
}
|
||||
|
||||
private void decrementUserUsage(String userName, long contentSize, NodeRef contentNodeRef)
|
||||
{
|
||||
// decrement usage - add negative delta
|
||||
if (logger.isDebugEnabled()) logger.debug("decrementUserUsage: username="+userName+", contentSize="+contentSize+", contentNodeRef="+contentNodeRef);
|
||||
|
||||
long currentSize = getUserUsage(userName);
|
||||
|
||||
long newSize = currentSize + contentSize;
|
||||
|
||||
if (newSize < 0)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("User (" + userName + ") has negative usage (" + newSize + ") - reset to 0");
|
||||
}
|
||||
}
|
||||
|
||||
NodeRef personNodeRef = personService.getPerson(userName);
|
||||
usageService.insertDelta(personNodeRef, (-contentSize));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user's usage. Should only be called by background (collapse) job !
|
||||
*
|
||||
* @param userName
|
||||
* @param currentUsage
|
||||
*/
|
||||
public void setUserStoredUsage(NodeRef personNodeRef, long currentUsage)
|
||||
{
|
||||
if (personNodeRef != null)
|
||||
{
|
||||
nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, new Long(currentUsage));
|
||||
}
|
||||
}
|
||||
|
||||
public long getUserStoredUsage(NodeRef personNodeRef)
|
||||
{
|
||||
Long currentUsage = null;
|
||||
if (personNodeRef != null)
|
||||
{
|
||||
currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT);
|
||||
}
|
||||
|
||||
return (currentUsage == null ? -1 : currentUsage);
|
||||
}
|
||||
|
||||
public long getUserUsage(String userName)
|
||||
{
|
||||
long currentUsage = -1;
|
||||
|
||||
NodeRef personNodeRef = personService.getPerson(userName);
|
||||
if (personNodeRef != null)
|
||||
{
|
||||
currentUsage = getUserStoredUsage(personNodeRef);
|
||||
}
|
||||
|
||||
if (currentUsage != -1)
|
||||
{
|
||||
// add any deltas
|
||||
currentUsage = currentUsage + usageService.getTotalDeltaSize(personNodeRef);
|
||||
|
||||
if (currentUsage < 0)
|
||||
{
|
||||
if (logger.isWarnEnabled())
|
||||
{
|
||||
logger.warn("User usage ("+ userName+") is negative ("+currentUsage+") overriding to 0");
|
||||
}
|
||||
currentUsage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return currentUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user's current quota.
|
||||
* Usually called by Web Client (Admin Console) if admin is changing/setting a user's quota.
|
||||
*
|
||||
* @param userName
|
||||
* @param currentQuota
|
||||
*/
|
||||
public void setUserQuota(String userName, long currentQuota)
|
||||
{
|
||||
NodeRef personNodeRef = personService.getPerson(userName);
|
||||
if (personNodeRef != null)
|
||||
{
|
||||
nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_QUOTA, new Long(currentQuota));
|
||||
}
|
||||
}
|
||||
|
||||
public long getUserQuota(String userName)
|
||||
{
|
||||
Long currentQuota = null;
|
||||
|
||||
NodeRef personNodeRef = personService.getPerson(userName);
|
||||
if (personNodeRef != null)
|
||||
{
|
||||
currentQuota = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_QUOTA);
|
||||
}
|
||||
|
||||
return (currentQuota == null ? -1 : currentQuota);
|
||||
}
|
||||
|
||||
public boolean getEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
}
|
42
source/java/org/alfresco/repo/usage/UsageDelta.java
Normal file
42
source/java/org/alfresco/repo/usage/UsageDelta.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.usage;
|
||||
|
||||
import org.alfresco.repo.domain.Node;
|
||||
|
||||
/**
|
||||
* Interface for persistent <b>usage delta</b> objects.
|
||||
*
|
||||
*/
|
||||
public interface UsageDelta
|
||||
{
|
||||
public Node getNode();
|
||||
|
||||
public void setNode(Node node);
|
||||
|
||||
public long getDeltaSize();
|
||||
|
||||
public void setDeltaSize(long usageDeltaSize);
|
||||
}
|
56
source/java/org/alfresco/repo/usage/UsageDeltaDAO.java
Normal file
56
source/java/org/alfresco/repo/usage/UsageDeltaDAO.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.usage;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.domain.Node;
|
||||
|
||||
/**
|
||||
* The interface to persist usage delta information.
|
||||
*
|
||||
*/
|
||||
public interface UsageDeltaDAO
|
||||
{
|
||||
/**
|
||||
* Create a usage delta entry.
|
||||
*
|
||||
* @param deltaInfo
|
||||
*/
|
||||
public void insertDelta(UsageDelta deltaInfo);
|
||||
|
||||
/**
|
||||
* Get the total delta size for a node.
|
||||
*
|
||||
* @param node
|
||||
* @return sum of delta sizes (in bytes) - can be +ve or -ve
|
||||
*/
|
||||
public long getTotalDeltaSize(Node node);
|
||||
|
||||
|
||||
public Set<Node> getUsageDeltaNodes();
|
||||
|
||||
public int deleteDeltas(Node node);
|
||||
}
|
113
source/java/org/alfresco/repo/usage/UsageServiceImpl.java
Normal file
113
source/java/org/alfresco/repo/usage/UsageServiceImpl.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.usage;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.domain.Node;
|
||||
import org.alfresco.repo.node.db.NodeDaoService;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.repo.usage.hibernate.UsageDeltaImpl;
|
||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.usage.UsageService;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* The implementation of the UsageService for tracking usages.
|
||||
*
|
||||
*/
|
||||
public class UsageServiceImpl implements UsageService
|
||||
{
|
||||
private UsageDeltaDAO usageDeltaDao;
|
||||
private NodeDaoService nodeDaoService;
|
||||
private TenantService tenantService;
|
||||
|
||||
//private static Log logger = LogFactory.getLog(UsageServiceImpl.class);
|
||||
|
||||
|
||||
public void setUsageDeltaDao(UsageDeltaDAO usageDeltaDao)
|
||||
{
|
||||
this.usageDeltaDao = usageDeltaDao;
|
||||
}
|
||||
|
||||
public void setNodeDaoService(NodeDaoService nodeDaoService)
|
||||
{
|
||||
this.nodeDaoService = nodeDaoService;
|
||||
}
|
||||
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
}
|
||||
|
||||
|
||||
public void insertDelta(NodeRef usageNodeRef, long deltaSize)
|
||||
{
|
||||
UsageDelta delta = new UsageDeltaImpl();
|
||||
|
||||
// delta properties
|
||||
delta.setNode(getNodeNotNull(usageNodeRef));
|
||||
delta.setDeltaSize(deltaSize);
|
||||
|
||||
usageDeltaDao.insertDelta(delta);
|
||||
}
|
||||
|
||||
public long getTotalDeltaSize(NodeRef usageNodeRef)
|
||||
{
|
||||
return usageDeltaDao.getTotalDeltaSize(getNodeNotNull(usageNodeRef));
|
||||
}
|
||||
|
||||
public Set<NodeRef> getUsageDeltaNodes()
|
||||
{
|
||||
Set<Node> nodes = usageDeltaDao.getUsageDeltaNodes();
|
||||
|
||||
// convert nodes to nodeRefs
|
||||
Set<NodeRef> results = new HashSet<NodeRef>(nodes.size());
|
||||
for (Node node : nodes)
|
||||
{
|
||||
results.add(tenantService.getBaseName(node.getNodeRef()));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public int deleteDeltas(NodeRef usageNodeRef)
|
||||
{
|
||||
return usageDeltaDao.deleteDeltas(getNodeNotNull(usageNodeRef));
|
||||
}
|
||||
|
||||
private Node getNodeNotNull(NodeRef nodeRef) throws InvalidNodeRefException
|
||||
{
|
||||
ParameterCheck.mandatory("nodeRef", nodeRef);
|
||||
|
||||
Node unchecked = nodeDaoService.getNode(tenantService.getName(nodeRef));
|
||||
if (unchecked == null)
|
||||
{
|
||||
throw new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef);
|
||||
}
|
||||
return unchecked;
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.usage;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
/**
|
||||
* Bootstraps user's content usage. This job is performed once at startup.
|
||||
*
|
||||
* If usages are enabled (as specified by 'system.usages.enabled=true' repository property) then will calculate
|
||||
* usages for all users that have no current usage.
|
||||
*
|
||||
* If usages are disabled (as specified by 'system.usages.enabled=false' repository property) then will clear
|
||||
* current usages for all users.
|
||||
*/
|
||||
public class UserUsageBootstrapJob implements Job
|
||||
{
|
||||
private static final String KEY_COMPONENT = "userUsageBootstrapComponent";
|
||||
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException
|
||||
{
|
||||
JobDataMap jobData = context.getJobDetail().getJobDataMap();
|
||||
UserUsageTrackingComponent usageComponent = (UserUsageTrackingComponent) jobData.get(KEY_COMPONENT);
|
||||
if (usageComponent == null)
|
||||
{
|
||||
throw new JobExecutionException("Missing job data: " + KEY_COMPONENT);
|
||||
}
|
||||
// perform the content usage calculations
|
||||
usageComponent.execute();
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.usage;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
/**
|
||||
* Collapses user's content usage delta. This is performed as a regular background job.
|
||||
*/
|
||||
public class UserUsageCollapseJob implements Job
|
||||
{
|
||||
private static final String KEY_COMPONENT = "userUsageCollapseComponent";
|
||||
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException
|
||||
{
|
||||
JobDataMap jobData = context.getJobDetail().getJobDataMap();
|
||||
UserUsageTrackingComponent usageComponent = (UserUsageTrackingComponent) jobData.get(KEY_COMPONENT);
|
||||
if (usageComponent == null)
|
||||
{
|
||||
throw new JobExecutionException("Missing job data: " + KEY_COMPONENT);
|
||||
}
|
||||
// perform the content usage calculations
|
||||
usageComponent.execute();
|
||||
}
|
||||
}
|
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.usage;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.domain.Node;
|
||||
import org.alfresco.repo.node.db.NodeDaoService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.TransactionServiceImpl;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.usage.UsageService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* User Usage Tracking Component - to allow user usages to be collapsed or re-calculated
|
||||
*
|
||||
* - used by UserUsageCollapseJob to collapse usage deltas.
|
||||
* - used by UserUsageBootstrapJob to either clear all usages or (re-)calculate all missing usages.
|
||||
*/
|
||||
public class UserUsageTrackingComponent
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(UserUsageTrackingComponent.class);
|
||||
|
||||
private static boolean busy = false;
|
||||
|
||||
private boolean bootstrap = false;
|
||||
|
||||
private NodeDaoService nodeDaoService;
|
||||
private TransactionServiceImpl transactionService;
|
||||
private ContentUsageImpl contentUsageImpl;
|
||||
|
||||
private PersonService personService;
|
||||
private NodeService nodeService;
|
||||
private UsageService usageService;
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
|
||||
public void setNodeDaoService(NodeDaoService nodeDaoService)
|
||||
{
|
||||
this.nodeDaoService = nodeDaoService;
|
||||
}
|
||||
|
||||
public void setTransactionService(TransactionServiceImpl transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
public void setContentUsageImpl(ContentUsageImpl contentUsageImpl)
|
||||
{
|
||||
this.contentUsageImpl = contentUsageImpl;
|
||||
}
|
||||
|
||||
public void setBootstrap(boolean bootstrap)
|
||||
{
|
||||
this.bootstrap = bootstrap;
|
||||
}
|
||||
|
||||
public void setPersonService(PersonService personService)
|
||||
{
|
||||
this.personService = personService;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setUsageService(UsageService usageService)
|
||||
{
|
||||
this.usageService = usageService;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
|
||||
public void execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (! busy && ! enabled)
|
||||
{
|
||||
busy = true;
|
||||
|
||||
// disabled - remove all usages
|
||||
if (bootstrap == true)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Disabled - clear usages for all users ...");
|
||||
}
|
||||
|
||||
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
|
||||
|
||||
// wrap to make the request in a transaction
|
||||
RetryingTransactionCallback<Integer> clearAllUsages = new RetryingTransactionCallback<Integer>()
|
||||
{
|
||||
public Integer execute() throws Throwable
|
||||
{
|
||||
Set<NodeRef> allPeople = personService.getAllPeople();
|
||||
|
||||
for (NodeRef personNodeRef : allPeople)
|
||||
{
|
||||
nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null);
|
||||
usageService.deleteDeltas(personNodeRef);
|
||||
}
|
||||
return allPeople.size();
|
||||
}
|
||||
};
|
||||
// execute in txn
|
||||
int count = txnHelper.doInTransaction(clearAllUsages, false);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("... cleared usage for " + count + " users");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (! busy && enabled)
|
||||
{
|
||||
busy = true;
|
||||
|
||||
if (bootstrap == true)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Enabled - calculate usages for all users (without usage) ...");
|
||||
}
|
||||
|
||||
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
|
||||
|
||||
// wrap to make the request in a transaction
|
||||
RetryingTransactionCallback<Set<String>> getAllPeople = new RetryingTransactionCallback<Set<String>>()
|
||||
{
|
||||
public Set<String> execute() throws Throwable
|
||||
{
|
||||
Set<NodeRef> allPeople = personService.getAllPeople();
|
||||
Set<String> userNames = new HashSet<String>();
|
||||
|
||||
for (NodeRef personNodeRef : allPeople)
|
||||
{
|
||||
Long currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT);
|
||||
if (currentUsage == null)
|
||||
{
|
||||
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
|
||||
userNames.add(userName);
|
||||
}
|
||||
}
|
||||
return userNames;
|
||||
}
|
||||
};
|
||||
// execute in READ-ONLY txn
|
||||
final Set<String> userNames = txnHelper.doInTransaction(getAllPeople, true);
|
||||
|
||||
for (String userName : userNames)
|
||||
{
|
||||
recalculateUsage(userName);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("... calculated usage for " + userNames.size() + " users");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Collapse usage deltas (if a person has initial usage set)
|
||||
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
|
||||
|
||||
// wrap to make the request in a transaction
|
||||
RetryingTransactionCallback<Object> collapseUsages = new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
// Get distinct candidates
|
||||
Set<NodeRef> usageNodeRefs = usageService.getUsageDeltaNodes();
|
||||
|
||||
for(NodeRef usageNodeRef : usageNodeRefs)
|
||||
{
|
||||
QName nodeType = nodeService.getType(usageNodeRef);
|
||||
|
||||
if (nodeType.equals(ContentModel.TYPE_PERSON))
|
||||
{
|
||||
NodeRef personNodeRef = usageNodeRef;
|
||||
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
|
||||
|
||||
long currentUsage = contentUsageImpl.getUserStoredUsage(personNodeRef);
|
||||
if (currentUsage != -1)
|
||||
{
|
||||
// collapse the usage deltas
|
||||
currentUsage = contentUsageImpl.getUserUsage(userName);
|
||||
usageService.deleteDeltas(personNodeRef);
|
||||
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Collapsed usage: username=" + userName + ", usage=" + currentUsage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isWarnEnabled())
|
||||
{
|
||||
logger.warn("Initial usage for user has not yet been calculated: " + userName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
txnHelper.doInTransaction(collapseUsages, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
busy = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate content usage for given user. Required if upgrading an existing Alfresco, for users that
|
||||
* have not had their initial usage calculated. In a future release, could also be called explicitly by
|
||||
* a SysAdmin, eg. via a JMX operation.
|
||||
*
|
||||
* @param userName
|
||||
*/
|
||||
public void recalculateUsage(final String userName)
|
||||
{
|
||||
final StoreRef storeRef = ContentUsageImpl.SPACES_STOREREF;
|
||||
|
||||
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
|
||||
|
||||
// wrap to make the request in a transaction
|
||||
RetryingTransactionCallback<Long> calculatePersonCurrentUsage = new RetryingTransactionCallback<Long>()
|
||||
{
|
||||
public Long execute() throws Throwable
|
||||
{
|
||||
// get nodes for which user is owner
|
||||
Collection<Node> ownerNodes = nodeDaoService.getNodesWithPropertyStringValueForStore(storeRef, ContentModel.PROP_OWNER, userName);
|
||||
|
||||
long totalUsage = 0;
|
||||
for (Node ownerNode : ownerNodes)
|
||||
{
|
||||
if (ownerNode.getTypeQName().equals(ContentModel.TYPE_CONTENT))
|
||||
{
|
||||
ContentData contentData = ContentData.createContentProperty(ownerNode.getProperties().get(ContentModel.PROP_CONTENT).getStringValue());
|
||||
totalUsage = totalUsage + contentData.getSize();
|
||||
}
|
||||
}
|
||||
|
||||
// get nodes for which user is creator, and then filter out those that have an owner
|
||||
Collection<Node> creatorNodes = nodeDaoService.getNodesWithPropertyStringValueForStore(storeRef, ContentModel.PROP_CREATOR, userName);
|
||||
|
||||
for (Node creatorNode : creatorNodes)
|
||||
{
|
||||
if (creatorNode.getTypeQName().equals(ContentModel.TYPE_CONTENT) &&
|
||||
creatorNode.getProperties().get(ContentModel.PROP_OWNER) == null)
|
||||
{
|
||||
ContentData contentData = ContentData.createContentProperty(creatorNode.getProperties().get(ContentModel.PROP_CONTENT).getStringValue());
|
||||
totalUsage = totalUsage + contentData.getSize();
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
long quotaSize = contentUsageImpl.getUserQuota(userName);
|
||||
logger.debug("Recalc usage ("+ userName+") totalUsage="+totalUsage+", quota="+quotaSize);
|
||||
}
|
||||
|
||||
return totalUsage;
|
||||
}
|
||||
};
|
||||
// execute in READ-ONLY txn
|
||||
final Long currentUsage = txnHelper.doInTransaction(calculatePersonCurrentUsage, true);
|
||||
|
||||
// wrap to make the request in a transaction
|
||||
RetryingTransactionCallback<Object> setUserCurrentUsage = new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
NodeRef personNodeRef = personService.getPerson(userName);
|
||||
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
|
||||
usageService.deleteDeltas(personNodeRef);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
txnHelper.doInTransaction(setUserCurrentUsage, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.usage.hibernate;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.domain.Node;
|
||||
import org.alfresco.repo.transaction.TransactionalDao;
|
||||
import org.alfresco.repo.usage.UsageDelta;
|
||||
import org.alfresco.repo.usage.UsageDeltaDAO;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.springframework.orm.hibernate3.HibernateCallback;
|
||||
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
|
||||
|
||||
/**
|
||||
* Hibernate-specific implementation of the persistence-independent <b>Usage Delta</b> DAO interface
|
||||
*
|
||||
*/
|
||||
public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements UsageDeltaDAO, TransactionalDao
|
||||
{
|
||||
private static final String QUERY_GET_DELTAS = "usage.GetDeltas";
|
||||
private static final String QUERY_GET_TOTAL_DELTA_SIZE = "usage.GetTotalDeltaSize";
|
||||
private static final String QUERY_GET_USAGE_DELTA_NODES = "usage.GetUsageDeltaNodes";
|
||||
|
||||
/** a uuid identifying this unique instance */
|
||||
private final String uuid;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public HibernateUsageDeltaDAO()
|
||||
{
|
||||
this.uuid = GUID.generate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks equality by type and uuid
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!(obj instanceof HibernateUsageDeltaDAO))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
HibernateUsageDeltaDAO that = (HibernateUsageDeltaDAO) obj;
|
||||
return this.uuid.equals(that.uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #uuid
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return uuid.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* NO-OP
|
||||
*/
|
||||
public void beforeCommit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this <tt>Session</tt> contain any changes which must be
|
||||
* synchronized with the store?
|
||||
*
|
||||
* @return true => changes are pending
|
||||
*/
|
||||
public boolean isDirty()
|
||||
{
|
||||
// create a callback for the task
|
||||
HibernateCallback callback = new HibernateCallback()
|
||||
{
|
||||
public Object doInHibernate(Session session)
|
||||
{
|
||||
return session.isDirty();
|
||||
}
|
||||
};
|
||||
// execute the callback
|
||||
return ((Boolean)getHibernateTemplate().execute(callback)).booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Just flushes the session
|
||||
*/
|
||||
public void flush()
|
||||
{
|
||||
getSession().flush();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public int deleteDeltas(final Node node)
|
||||
{
|
||||
HibernateCallback callback = new HibernateCallback()
|
||||
{
|
||||
public Object doInHibernate(Session session)
|
||||
{
|
||||
Query query = session.getNamedQuery(QUERY_GET_DELTAS);
|
||||
query.setParameter("node", node);
|
||||
return query.list();
|
||||
}
|
||||
};
|
||||
|
||||
// execute
|
||||
List<UsageDelta> queryResults = (List<UsageDelta>)getHibernateTemplate().execute(callback);
|
||||
|
||||
for (UsageDelta usageDelta : queryResults)
|
||||
{
|
||||
getHibernateTemplate().delete(usageDelta);
|
||||
}
|
||||
|
||||
return queryResults.size();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public long getTotalDeltaSize(final Node node)
|
||||
{
|
||||
HibernateCallback callback = new HibernateCallback()
|
||||
{
|
||||
public Object doInHibernate(Session session)
|
||||
{
|
||||
Query query = session.getNamedQuery(QUERY_GET_TOTAL_DELTA_SIZE);
|
||||
query.setParameter("node", node);
|
||||
query.setReadOnly(true);
|
||||
return query.uniqueResult();
|
||||
}
|
||||
};
|
||||
// execute read-only tx
|
||||
Long queryResult = (Long)getHibernateTemplate().execute(callback);
|
||||
|
||||
return (queryResult == null ? 0 : queryResult);
|
||||
}
|
||||
|
||||
public void insertDelta(UsageDelta deltaInfo)
|
||||
{
|
||||
// Save
|
||||
getSession().save(deltaInfo);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<Node> getUsageDeltaNodes()
|
||||
{
|
||||
HibernateCallback callback = new HibernateCallback()
|
||||
{
|
||||
public Object doInHibernate(Session session)
|
||||
{
|
||||
Query query = session.getNamedQuery(QUERY_GET_USAGE_DELTA_NODES);
|
||||
query.setReadOnly(true);
|
||||
return query.list();
|
||||
}
|
||||
};
|
||||
// execute read-only tx
|
||||
List<Node> queryResults = (List<Node>)getHibernateTemplate().execute(callback);
|
||||
Set<Node> results = new HashSet<Node>(queryResults.size());
|
||||
for (Node node : queryResults)
|
||||
{
|
||||
results.add(node);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.usage.hibernate;
|
||||
|
||||
import org.alfresco.repo.domain.Node;
|
||||
import org.alfresco.repo.usage.UsageDelta;
|
||||
|
||||
/**
|
||||
* Usage Delta Implementation
|
||||
*
|
||||
*/
|
||||
public class UsageDeltaImpl implements UsageDelta
|
||||
{
|
||||
private Long id;
|
||||
private Long version;
|
||||
|
||||
private Node node;
|
||||
private long deltaSize; // +ve or -ve or 0 (in bytes)
|
||||
|
||||
|
||||
public Long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* For Hibernate use
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setId(Long id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* For Hibernate use
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setVersion(Long version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
|
||||
public Node getNode()
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
public void setNode(Node node)
|
||||
{
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public long getDeltaSize()
|
||||
{
|
||||
return deltaSize;
|
||||
}
|
||||
|
||||
public void setDeltaSize(long deltaSize)
|
||||
{
|
||||
this.deltaSize = deltaSize;
|
||||
}
|
||||
}
|
@@ -116,7 +116,7 @@ public class WorkflowInterpreter extends BaseInterpreter
|
||||
|
||||
if (!transactionService.isReadOnly())
|
||||
{
|
||||
interpretCommand("var bpm:package package 1");
|
||||
//interpretCommand("var bpm:package package 1"); // only used for testing workflows, causes increment usage/delta
|
||||
interpretCommand("var bpm:assignee person admin");
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.service.cmr.usage;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ContentQuotaException extends AlfrescoRuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1346806021547860709L;
|
||||
|
||||
public ContentQuotaException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public ContentQuotaException(String msg, Throwable cause)
|
||||
{
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.service.cmr.usage;
|
||||
|
||||
import org.alfresco.service.Auditable;
|
||||
import org.alfresco.service.PublicService;
|
||||
|
||||
@PublicService
|
||||
public interface ContentUsageService
|
||||
{
|
||||
/**
|
||||
* Gets user usage
|
||||
*
|
||||
* @return Return user's current calculated usage (in bytes)
|
||||
*/
|
||||
@Auditable
|
||||
public long getUserUsage(String userName);
|
||||
|
||||
/**
|
||||
* Gets user quota
|
||||
*
|
||||
* Note: -1 means no quota limit set
|
||||
*
|
||||
* @return Return user's quota (in bytes).
|
||||
*/
|
||||
@Auditable
|
||||
public long getUserQuota(String userName);
|
||||
|
||||
/**
|
||||
* Set user quota.
|
||||
*
|
||||
* Note: It is possible to set a quota that is below the current usage. At this point
|
||||
* the user will be over quota until their usage is decreased.
|
||||
*
|
||||
* Note: -1 means no quota limit set
|
||||
*
|
||||
* @param User's new quota (in bytes)
|
||||
*/
|
||||
@Auditable
|
||||
public void setUserQuota(String userName, long newQuota);
|
||||
|
||||
/**
|
||||
* Are ContentUsages enabled (refer to 'system.usages.enabled' repository property) ?
|
||||
*
|
||||
* @return true if ContentUsages are enabled, otherwise false
|
||||
*/
|
||||
@Auditable
|
||||
public boolean getEnabled();
|
||||
}
|
63
source/java/org/alfresco/service/cmr/usage/UsageService.java
Normal file
63
source/java/org/alfresco/service/cmr/usage/UsageService.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.service.cmr.usage;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.NotAuditable;
|
||||
import org.alfresco.service.PublicService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* The public API by which applications can create usage delta entries.
|
||||
*
|
||||
*/
|
||||
@PublicService
|
||||
public interface UsageService
|
||||
{
|
||||
/**
|
||||
* Add a usage delta entry.
|
||||
*/
|
||||
@NotAuditable
|
||||
public void insertDelta(NodeRef usageNodeRef, long deltaSize);
|
||||
|
||||
/**
|
||||
* Get sum of usage delta sizes.
|
||||
*/
|
||||
@NotAuditable
|
||||
public long getTotalDeltaSize(NodeRef usageNodeRef);
|
||||
|
||||
/**
|
||||
* Get distinct set of usage delta nodes
|
||||
*/
|
||||
@NotAuditable
|
||||
public Set<NodeRef> getUsageDeltaNodes();
|
||||
|
||||
/**
|
||||
* Delete the usage delta nodes
|
||||
*/
|
||||
@NotAuditable
|
||||
public int deleteDeltas(NodeRef usageNodeRef);
|
||||
}
|
Reference in New Issue
Block a user