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:
@@ -47,6 +47,7 @@
|
|||||||
<value>org/alfresco/repo/domain/hibernate/Permission.hbm.xml</value>
|
<value>org/alfresco/repo/domain/hibernate/Permission.hbm.xml</value>
|
||||||
<value>org/alfresco/repo/avm/hibernate/AVM.hbm.xml</value>
|
<value>org/alfresco/repo/avm/hibernate/AVM.hbm.xml</value>
|
||||||
<value>org/alfresco/repo/attributes/hibernate/Attributes.hbm.xml</value>
|
<value>org/alfresco/repo/attributes/hibernate/Attributes.hbm.xml</value>
|
||||||
|
<value>org/alfresco/repo/domain/hibernate/UsageDelta.hbm.xml</value>
|
||||||
|
|
||||||
<!-- Audit config -->
|
<!-- Audit config -->
|
||||||
<!-- TODO: Move into org/alfresco/repo/domain/hibernate/ -->
|
<!-- TODO: Move into org/alfresco/repo/domain/hibernate/ -->
|
||||||
@@ -229,6 +230,12 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="usageDeltaDao" class="org.alfresco.repo.usage.hibernate.HibernateUsageDeltaDAO">
|
||||||
|
<property name="sessionFactory">
|
||||||
|
<ref bean="sessionFactory"/>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean id="nodeDaoServiceImpl" class="org.alfresco.repo.node.db.hibernate.HibernateNodeDaoServiceImpl">
|
<bean id="nodeDaoServiceImpl" class="org.alfresco.repo.node.db.hibernate.HibernateNodeDaoServiceImpl">
|
||||||
<property name="sessionFactory">
|
<property name="sessionFactory">
|
||||||
<ref bean="sessionFactory" />
|
<ref bean="sessionFactory" />
|
||||||
@@ -239,6 +246,9 @@
|
|||||||
<property name="tenantService">
|
<property name="tenantService">
|
||||||
<ref bean="tenantService"/>
|
<ref bean="tenantService"/>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="usageDeltaDao">
|
||||||
|
<ref bean="usageDeltaDao"/>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="dbNodeDaoServiceTxnRegistration" class="org.alfresco.repo.transaction.TransactionalDaoInterceptor" >
|
<bean id="dbNodeDaoServiceTxnRegistration" class="org.alfresco.repo.transaction.TransactionalDaoInterceptor" >
|
||||||
|
@@ -185,6 +185,14 @@
|
|||||||
<property name="cm:presenceUsername">
|
<property name="cm:presenceUsername">
|
||||||
<type>d:text</type>
|
<type>d:text</type>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
<property name="cm:sizeCurrent">
|
||||||
|
<type>d:long</type>
|
||||||
|
</property>
|
||||||
|
<property name="cm:sizeQuota">
|
||||||
|
<type>d:long</type>
|
||||||
|
</property>
|
||||||
|
|
||||||
</properties>
|
</properties>
|
||||||
</type>
|
</type>
|
||||||
|
|
||||||
|
@@ -197,4 +197,26 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="usageService" class="org.alfresco.repo.usage.UsageServiceImpl">
|
||||||
|
<property name="usageDeltaDao">
|
||||||
|
<ref bean="usageDeltaDao"/>
|
||||||
|
</property>
|
||||||
|
<property name="nodeDaoService">
|
||||||
|
<ref bean="nodeDaoService" />
|
||||||
|
</property>
|
||||||
|
<property name="tenantService">
|
||||||
|
<ref bean="tenantService"/>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="contentUsageImpl" class="org.alfresco.repo.usage.ContentUsageImpl" init-method="init">
|
||||||
|
<property name="personService" ref="personService"/>
|
||||||
|
<property name="nodeService" ref="nodeService"/>
|
||||||
|
<property name="policyComponent" ref="policyComponent"/>
|
||||||
|
<property name="usageService" ref="usageService"/>
|
||||||
|
<property name="enabled">
|
||||||
|
<value>${system.usages.enabled}</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
@@ -565,6 +565,36 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<!-- Content Usage Service -->
|
||||||
|
|
||||||
|
<bean id="ContentUsageService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||||
|
<property name="proxyInterfaces">
|
||||||
|
<value>org.alfresco.service.cmr.usage.ContentUsageService</value>
|
||||||
|
</property>
|
||||||
|
<property name="target">
|
||||||
|
<ref bean="contentUsageImpl"/>
|
||||||
|
</property>
|
||||||
|
<property name="interceptorNames">
|
||||||
|
<list>
|
||||||
|
<idref local="ContenUsageService_transaction"/>
|
||||||
|
<idref local="AuditMethodInterceptor"/>
|
||||||
|
<idref local="exceptionTranslator"/>
|
||||||
|
<idref bean="ContentUsageService_security"/>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="ContenUsageService_transaction" class="org.springframework.transaction.interceptor.TransactionInterceptor">
|
||||||
|
<property name="transactionManager">
|
||||||
|
<ref bean="transactionManager"/>
|
||||||
|
</property>
|
||||||
|
<property name="transactionAttributes">
|
||||||
|
<props>
|
||||||
|
<prop key="*">${server.transaction.mode.default}</prop>
|
||||||
|
</props>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<!-- Authentication Service -->
|
<!-- Authentication Service -->
|
||||||
|
|
||||||
<bean id="AuthenticationService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
<bean id="AuthenticationService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||||
|
@@ -806,4 +806,11 @@
|
|||||||
|
|
||||||
<bean id="RepoAdminService_security" class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
|
<bean id="RepoAdminService_security" class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
|
||||||
|
|
||||||
|
<!-- ===================== -->
|
||||||
|
<!-- Content Usage Service -->
|
||||||
|
<!-- ===================== -->
|
||||||
|
|
||||||
|
<!-- TODO: Add content usage security -->
|
||||||
|
<bean id="ContentUsageService_security" class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
|
||||||
|
|
||||||
</beans>
|
</beans>
|
@@ -172,3 +172,6 @@ user.name.caseSensitive=false
|
|||||||
|
|
||||||
# AVM Specific properties.
|
# AVM Specific properties.
|
||||||
avm.remote.idlestream.timeout=30000
|
avm.remote.idlestream.timeout=30000
|
||||||
|
|
||||||
|
# ECM content usages/quotas
|
||||||
|
system.usages.enabled=true
|
||||||
|
@@ -231,4 +231,123 @@
|
|||||||
<value>0 30 3 * * ?</value>
|
<value>0 30 3 * * ?</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
<bean id="userUsageCollapseComponent" class="org.alfresco.repo.usage.UserUsageTrackingComponent">
|
||||||
|
<property name="nodeDaoService">
|
||||||
|
<ref bean="nodeDaoService"/>
|
||||||
|
</property>
|
||||||
|
<property name="transactionService">
|
||||||
|
<ref bean="transactionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="contentUsageImpl">
|
||||||
|
<ref bean="contentUsageImpl"/>
|
||||||
|
</property>
|
||||||
|
<property name="personService">
|
||||||
|
<ref bean="personService"/>
|
||||||
|
</property>
|
||||||
|
<property name="nodeService">
|
||||||
|
<ref bean="nodeService"/>
|
||||||
|
</property>
|
||||||
|
<property name="usageService">
|
||||||
|
<ref bean="usageService"/>
|
||||||
|
</property>
|
||||||
|
<property name="enabled">
|
||||||
|
<value>${system.usages.enabled}</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="userUsageBootstrapComponent" class="org.alfresco.repo.usage.UserUsageTrackingComponent">
|
||||||
|
<property name="nodeDaoService">
|
||||||
|
<ref bean="nodeDaoService"/>
|
||||||
|
</property>
|
||||||
|
<property name="transactionService">
|
||||||
|
<ref bean="transactionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="contentUsageImpl">
|
||||||
|
<ref bean="contentUsageImpl"/>
|
||||||
|
</property>
|
||||||
|
<property name="personService">
|
||||||
|
<ref bean="personService"/>
|
||||||
|
</property>
|
||||||
|
<property name="nodeService">
|
||||||
|
<ref bean="nodeService"/>
|
||||||
|
</property>
|
||||||
|
<property name="usageService">
|
||||||
|
<ref bean="usageService"/>
|
||||||
|
</property>
|
||||||
|
<property name="enabled">
|
||||||
|
<value>${system.usages.enabled}</value>
|
||||||
|
</property>
|
||||||
|
<property name="bootstrap">
|
||||||
|
<value>true</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- enable scheduler property to activate -->
|
||||||
|
<bean id="userUsageCollapseJob" class="org.alfresco.util.TriggerBean">
|
||||||
|
<property name="jobDetail">
|
||||||
|
<bean id="userUsageTrackingJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||||
|
<property name="jobClass">
|
||||||
|
<value>org.alfresco.repo.usage.UserUsageCollapseJob</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobDataAsMap">
|
||||||
|
<map>
|
||||||
|
<entry key="userUsageCollapseComponent">
|
||||||
|
<ref bean="userUsageCollapseComponent" />
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<!-- enable this to activate bean -->
|
||||||
|
|
||||||
|
<property name="scheduler">
|
||||||
|
<ref bean="schedulerFactory" />
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<!-- start after 5 minutes and repeat every 5 minutes -->
|
||||||
|
<property name="startDelayMinutes">
|
||||||
|
<value>5</value>
|
||||||
|
</property>
|
||||||
|
<property name="repeatIntervalMinutes">
|
||||||
|
<value>5</value>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- enable scheduler property to activate -->
|
||||||
|
<bean id="userUsageBootstrapJob" class="org.alfresco.util.TriggerBean">
|
||||||
|
<property name="jobDetail">
|
||||||
|
<bean id="userUsageBootstrapDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||||
|
<property name="jobClass">
|
||||||
|
<value>org.alfresco.repo.usage.UserUsageBootstrapJob</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobDataAsMap">
|
||||||
|
<map>
|
||||||
|
<entry key="userUsageBootstrapComponent">
|
||||||
|
<ref bean="userUsageBootstrapComponent" />
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<!-- enable this to activate bean -->
|
||||||
|
|
||||||
|
<property name="scheduler">
|
||||||
|
<ref bean="schedulerFactory" />
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<!-- start after bootstrap (0 minutes) and run once -->
|
||||||
|
<property name="startDelayMinutes">
|
||||||
|
<value>0</value>
|
||||||
|
</property>
|
||||||
|
<property name="repeatCount">
|
||||||
|
<value>0</value>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
@@ -19,4 +19,4 @@ version.build=@build-number@
|
|||||||
|
|
||||||
# Schema number
|
# Schema number
|
||||||
|
|
||||||
version.schema=113
|
version.schema=114
|
||||||
|
@@ -1482,8 +1482,15 @@ public class NTProtocolHandler extends CoreProtocolHandler
|
|||||||
m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
|
m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
catch (DiskFullException ex)
|
||||||
|
{
|
||||||
|
m_sess.sendErrorResponseSMB(SMBStatus.NTDiskFull, SMBStatus.HRDWriteFault, SMBStatus.ErrHrd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
catch (java.io.IOException ex)
|
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
|
// 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.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.filesys.server.filesys.AccessDeniedException;
|
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.FileAttribute;
|
||||||
import org.alfresco.filesys.server.filesys.FileInfo;
|
import org.alfresco.filesys.server.filesys.FileInfo;
|
||||||
import org.alfresco.filesys.server.filesys.FileOpenParams;
|
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.MimetypeService;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
@@ -382,7 +384,14 @@ public class ContentNetworkFile extends NodeRefNetworkFile
|
|||||||
// Update node properties
|
// Update node properties
|
||||||
|
|
||||||
ContentData contentData = content.getContentData();
|
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
|
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_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_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
|
// Ownable aspect
|
||||||
static final QName ASPECT_OWNABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "ownable");
|
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");
|
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.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
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.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
@@ -567,6 +568,10 @@ public class RoutingContentService implements ContentService
|
|||||||
" value: " + contentData);
|
" value: " + contentData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (ContentQuotaException qe)
|
||||||
|
{
|
||||||
|
throw qe;
|
||||||
|
}
|
||||||
catch (Throwable e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
throw new ContentIOException("Failed to set content property on stream closure: \n" +
|
throw new ContentIOException("Failed to set content property on stream closure: \n" +
|
||||||
|
@@ -502,4 +502,17 @@
|
|||||||
node.store.key.identifier = :identifier
|
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>
|
</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 int getNodeCount(final StoreRef storeRef);
|
||||||
|
|
||||||
|
public Collection<Node> getNodesWithPropertyStringValueForStore(final StoreRef storeRef, final QName propQName, final String propStringValue);
|
||||||
|
|
||||||
public Transaction getTxnById(long txnId);
|
public Transaction getTxnById(long txnId);
|
||||||
/**
|
/**
|
||||||
* Get all transactions in a given time range. Since time-based retrieval doesn't guarantee uniqueness
|
* 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.AlfrescoTransactionSupport;
|
||||||
import org.alfresco.repo.transaction.TransactionAwareSingleton;
|
import org.alfresco.repo.transaction.TransactionAwareSingleton;
|
||||||
import org.alfresco.repo.transaction.TransactionalDao;
|
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.DataTypeDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
|
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
|
||||||
import org.alfresco.service.cmr.repository.AssociationExistsException;
|
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_CHILD_ASSOCS_FOR_STORE = "node.GetChildAssocsForStore";
|
||||||
private static final String QUERY_GET_NODES_EXCEPT_ROOT_FOR_STORE = "node.GetNodesExceptRootForStore";
|
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);
|
private static Log logger = LogFactory.getLog(HibernateNodeDaoServiceImpl.class);
|
||||||
/** Log to trace parent association caching: <b>classname + .ParentAssocsCache</b> */
|
/** Log to trace parent association caching: <b>classname + .ParentAssocsCache</b> */
|
||||||
private static Log loggerParentAssocsCache = LogFactory.getLog(HibernateNodeDaoServiceImpl.class.getName() + ".ParentAssocsCache");
|
private static Log loggerParentAssocsCache = LogFactory.getLog(HibernateNodeDaoServiceImpl.class.getName() + ".ParentAssocsCache");
|
||||||
@@ -131,7 +134,14 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
/** used for debugging */
|
/** used for debugging */
|
||||||
private Set<String> changeTxnIdSet;
|
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)
|
public void setTenantService(TenantService tenantService)
|
||||||
{
|
{
|
||||||
@@ -616,6 +626,13 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
{
|
{
|
||||||
getHibernateTemplate().delete(assoc);
|
getHibernateTemplate().delete(assoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isDebugEnabled)
|
||||||
|
{
|
||||||
|
logger.debug("Deleting usage deltas of node (if any)" + node.getId());
|
||||||
|
}
|
||||||
|
usageDeltaDao.deleteDeltas(node);
|
||||||
|
|
||||||
// update the node status
|
// update the node status
|
||||||
NodeRef nodeRef = node.getNodeRef();
|
NodeRef nodeRef = node.getNodeRef();
|
||||||
NodeStatus nodeStatus = getNodeStatus(nodeRef, true);
|
NodeStatus nodeStatus = getNodeStatus(nodeRef, true);
|
||||||
@@ -1428,6 +1445,29 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
return count.intValue();
|
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
|
* Queries for transactions
|
||||||
*/
|
*/
|
||||||
|
@@ -607,6 +607,10 @@ public class PersonServiceImpl implements PersonService,
|
|||||||
properties.put(ContentModel.PROP_EMAIL, "");
|
properties.put(ContentModel.PROP_EMAIL, "");
|
||||||
properties.put(ContentModel.PROP_ORGID, "");
|
properties.put(ContentModel.PROP_ORGID, "");
|
||||||
properties.put(ContentModel.PROP_HOME_FOLDER_PROVIDER, defaultHomeFolderProvider);
|
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;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,6 +619,9 @@ public class PersonServiceImpl implements PersonService,
|
|||||||
String userName = DefaultTypeConverter.INSTANCE.convert(String.class, properties
|
String userName = DefaultTypeConverter.INSTANCE.convert(String.class, properties
|
||||||
.get(ContentModel.PROP_USERNAME));
|
.get(ContentModel.PROP_USERNAME));
|
||||||
properties.put(ContentModel.PROP_USERNAME, userName);
|
properties.put(ContentModel.PROP_USERNAME, userName);
|
||||||
|
|
||||||
|
properties.put(ContentModel.PROP_SIZE_CURRENT, 0L);
|
||||||
|
|
||||||
return nodeService.createNode(getPeopleContainer(), ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_PERSON,
|
return nodeService.createNode(getPeopleContainer(), ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_PERSON,
|
||||||
ContentModel.TYPE_PERSON, properties).getChildRef();
|
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())
|
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");
|
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