mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
RM-273 - RM: PublishUpdatesJob allows concurrent execution
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/BRANCHES/V2.0@36435 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -10,27 +10,25 @@
|
||||
-->
|
||||
<bean id="scheduledNotifyOfRecordsDueForReviewJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||
<property name="jobClass">
|
||||
<value>org.alfresco.module.org_alfresco_module_rm.job.NotifyOfRecordsDueForReviewJob</value>
|
||||
<value>org.alfresco.module.org_alfresco_module_rm.job.RecordsManagementJob</value>
|
||||
</property>
|
||||
<property name="jobDataAsMap">
|
||||
<map>
|
||||
<entry key="recordsManagementService">
|
||||
<ref bean="recordsManagementService"/>
|
||||
<map>
|
||||
<entry key="jobName" value="scheduledNotifyOfRecordsDueForReview"/>
|
||||
<entry key="jobLockService">
|
||||
<ref bean="jobLockService" />
|
||||
</entry>
|
||||
<entry key="recordsManagementNotificationHelper">
|
||||
<ref bean="recordsManagementNotificationHelper"/>
|
||||
</entry>
|
||||
<entry key="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
<entry key="jobExecuter">
|
||||
<ref bean="scheduledNotifyOfRecordsDueForReviewJobExecuter" />
|
||||
</entry>
|
||||
<entry key="searchService">
|
||||
<ref bean="searchService" />
|
||||
</entry>
|
||||
<entry key="transactionService">
|
||||
<ref bean="transactionService" />
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="scheduledNotifyOfRecordsDueForReviewJobExecuter" class="org.alfresco.module.org_alfresco_module_rm.job.NotifyOfRecordsDueForReviewJobExecuter">
|
||||
<property name="nodeService" ref="nodeService" />
|
||||
<property name="searchService" ref="searchService" />
|
||||
<property name="recordsManagementNotificationHelper" ref="recordsManagementNotificationHelper" />
|
||||
</bean>
|
||||
|
||||
<bean id="scheduledNotifyOfRecordsDueForReviewJobTrigger" class="org.alfresco.util.CronTriggerBean">
|
||||
@@ -49,25 +47,27 @@
|
||||
<!-- Disposition Lifecycle Job -->
|
||||
<bean id="scheduledDispositionLifecyceleJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||
<property name="jobClass">
|
||||
<value>org.alfresco.module.org_alfresco_module_rm.job.DispositionLifecycleJob</value>
|
||||
<value>org.alfresco.module.org_alfresco_module_rm.job.RecordsManagementJob</value>
|
||||
</property>
|
||||
<property name="jobDataAsMap">
|
||||
<map>
|
||||
<entry key="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
</entry>
|
||||
<entry key="searchService">
|
||||
<ref bean="searchService" />
|
||||
</entry>
|
||||
<entry key="recordsManagementActionService">
|
||||
<ref bean="recordsManagementActionService" />
|
||||
</entry>
|
||||
<entry key="transactionService">
|
||||
<ref bean="transactionService" />
|
||||
<map>
|
||||
<entry key="jobName" value="dispositionLifecycle"/>
|
||||
<entry key="jobLockService">
|
||||
<ref bean="jobLockService" />
|
||||
</entry>
|
||||
<entry key="jobExecuter">
|
||||
<ref bean="dispositionLifecycleJobExecuter" />
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="dispositionLifecycleJobExecuter" class="org.alfresco.module.org_alfresco_module_rm.job.DispositionLifecycleJobExecuter">
|
||||
<property name="nodeService" ref="nodeService" />
|
||||
<property name="searchService" ref="searchService" />
|
||||
<property name="retryingTransactionHelper" ref="retryingTransactionHelper" />
|
||||
<property name="recordsManagementActionService" ref="recordsManagementActionService" />
|
||||
</bean>
|
||||
|
||||
<bean id="scheduledDispositionLifecyceleJobTrigger" class="org.alfresco.util.CronTriggerBean">
|
||||
<property name="jobDetail">
|
||||
@@ -84,42 +84,38 @@
|
||||
|
||||
<bean id="scheduledPublishUpdatesJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||
<property name="jobClass">
|
||||
<value>org.alfresco.module.org_alfresco_module_rm.job.PublishUpdatesJob</value>
|
||||
<value>org.alfresco.module.org_alfresco_module_rm.job.RecordsManagementJob</value>
|
||||
</property>
|
||||
<property name="jobDataAsMap">
|
||||
<map>
|
||||
<entry key="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
</entry>
|
||||
<entry key="searchService">
|
||||
<ref bean="searchService" />
|
||||
</entry>
|
||||
<entry key="retryingTransactionHelper">
|
||||
<ref bean="retryingTransactionHelper" />
|
||||
</entry>
|
||||
<entry key="publishExecutorRegistry">
|
||||
<ref bean="publishExecutorRegistry" />
|
||||
</entry>
|
||||
<entry key="behaviourFilter">
|
||||
<ref bean="policyBehaviourFilter" />
|
||||
<map>
|
||||
<entry key="jobName" value="publishUpdates"/>
|
||||
<entry key="jobLockService">
|
||||
<ref bean="jobLockService" />
|
||||
</entry>
|
||||
<entry key="jobExecuter">
|
||||
<ref bean="publishUpdatesJobExecuter" />
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="scheduledPublishUpdatesJobTrigger" class="org.alfresco.util.CronTriggerBean">
|
||||
<property name="jobDetail">
|
||||
<ref bean="scheduledPublishUpdatesJobDetail" />
|
||||
</property>
|
||||
<property name="scheduler">
|
||||
<ref bean="schedulerFactory" />
|
||||
</property>
|
||||
<property name="jobDetail" ref="scheduledPublishUpdatesJobDetail" />
|
||||
<property name="scheduler" ref="schedulerFactory" />
|
||||
<property name="cronExpression">
|
||||
<!-- <value>0 30 3 * * ?</value> -->
|
||||
<value>0/30 * * * * ?</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="publishUpdatesJobExecuter" class="org.alfresco.module.org_alfresco_module_rm.job.PublishUpdatesJobExecuter">
|
||||
<property name="nodeService" ref="nodeService" />
|
||||
<property name="searchService" ref="searchService" />
|
||||
<property name="retryingTransactionHelper" ref="retryingTransactionHelper" />
|
||||
<property name="publishExecutorRegistry" ref="publishExecutorRegistry" />
|
||||
<property name="behaviourFilter" ref="policyBehaviourFilter" />
|
||||
</bean>
|
||||
|
||||
<bean id="publishExecutorRegistry" class="org.alfresco.module.org_alfresco_module_rm.job.publish.PublishExecutorRegistry"/>
|
||||
|
||||
<bean id="dispositionActionDefintionPublishExecutor"
|
||||
|
@@ -87,12 +87,16 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="rmEntryVoter" class="org.alfresco.module.org_alfresco_module_rm.capability.RMEntryVoter" lazy-init="false" parent="RMSecurityCommon">
|
||||
<bean id="rmEntryVoter"
|
||||
class="org.alfresco.module.org_alfresco_module_rm.capability.RMEntryVoter"
|
||||
lazy-init="false"
|
||||
parent="RMSecurityCommon"
|
||||
depends-on="CapabilityService">
|
||||
<!-- Services -->
|
||||
<property name="namespacePrefixResolver" ref="namespaceService"/>
|
||||
<property name="dictionaryService" ref="dictionaryService"/>
|
||||
<property name="dispositionService" ref="dispositionService"/>
|
||||
<property name="capabilityService" ref="CapabilityService"/>
|
||||
<property name="capabilityService" ref="capabilityService"/>
|
||||
|
||||
</bean>
|
||||
|
||||
|
@@ -229,10 +229,9 @@
|
||||
|
||||
<!-- Capability Service -->
|
||||
|
||||
<bean id="CapabilityService" class="org.alfresco.module.org_alfresco_module_rm.capability.CapabilityServiceImpl">
|
||||
<bean id="capabilityService" class="org.alfresco.module.org_alfresco_module_rm.capability.CapabilityServiceImpl">
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
<bean id="CapabilityService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces">
|
||||
<value>org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService</value>
|
||||
@@ -244,7 +243,7 @@
|
||||
<list>
|
||||
<idref local="CapabilityService_transaction"/>
|
||||
<idref bean="exceptionTranslator"/>
|
||||
<idref local="CapabilityService_security"/>
|
||||
<!-- <idref local="CapabilityService_security"/> -->
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
@@ -273,15 +272,11 @@
|
||||
<property name="objectDefinitionSource">
|
||||
<value>
|
||||
<![CDATA[
|
||||
org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService.registerCapability=RM_ALLOW
|
||||
org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService.getCapability=RM_ALLOW
|
||||
org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService.getCapabilities=RM_ALLOW
|
||||
org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService.getCapabilitiesAccessState=RM_ALLOW
|
||||
org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService.*=RM_DENY
|
||||
org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService.*=RM_ALLOW
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
</bean> -->
|
||||
</bean>
|
||||
|
||||
<!-- Records Management Search Service -->
|
||||
|
||||
|
@@ -49,21 +49,24 @@ public interface CapabilityService
|
||||
Capability getCapability(String name);
|
||||
|
||||
/**
|
||||
* Get a list of all the assignable capabilities.
|
||||
*
|
||||
* @return
|
||||
* @return {@link Set}<{@link Capability}> set of all the assignable capabilities
|
||||
*/
|
||||
Set<Capability> getCapabilities();
|
||||
|
||||
/**
|
||||
* Get a list of all the capabilities, optionally including those that are non-assignable.
|
||||
*
|
||||
* @param includePrivate
|
||||
* @return
|
||||
* @param includePrivate indicates that the private, or non-assignable capabilities are included in the result
|
||||
* @return {@link Set}<{@link Capability}> set of capabilities
|
||||
*/
|
||||
Set<Capability> getCapabilities(boolean includePrivate);
|
||||
|
||||
/**
|
||||
* Get all the capabilities access state based on the current user.
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param nodeRef node reference
|
||||
* @return
|
||||
*/
|
||||
Map<Capability, AccessStatus> getCapabilitiesAccessState(NodeRef nodeRef);
|
||||
|
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.module.org_alfresco_module_rm.job;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementAction;
|
||||
import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
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.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
/**
|
||||
* The Disposition Lifecycle Job Finds all disposition action nodes which are
|
||||
* for "retain" or "cutOff" actions Where asOf > now OR
|
||||
* dispositionEventsEligible = true;
|
||||
*
|
||||
* Runs the cut off or retain action for
|
||||
* elligible records.
|
||||
*
|
||||
* @author mrogers
|
||||
*/
|
||||
public class DispositionLifecycleJob implements Job
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(DispositionLifecycleJob.class);
|
||||
|
||||
/**
|
||||
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
|
||||
*/
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException
|
||||
{
|
||||
final RecordsManagementActionService rmActionService = (RecordsManagementActionService) context
|
||||
.getJobDetail().getJobDataMap().get("recordsManagementActionService");
|
||||
final NodeService nodeService = (NodeService) context.getJobDetail().getJobDataMap().get(
|
||||
"nodeService");
|
||||
final SearchService search = (SearchService) context.getJobDetail().getJobDataMap().get(
|
||||
"searchService");
|
||||
final TransactionService trxService = (TransactionService) context.getJobDetail()
|
||||
.getJobDataMap().get("transactionService");
|
||||
|
||||
logger.debug("Job Starting");
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||
{
|
||||
public Object doWork() throws Exception
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("+TYPE:\"rma:dispositionAction\" ");
|
||||
sb.append("+(@rma\\:dispositionAction:(\"cutoff\" OR \"retain\"))");
|
||||
sb.append("+ISNULL:\"rma:dispositionActionCompletedAt\" ");
|
||||
sb.append("+( ");
|
||||
sb.append("@rma\\:dispositionEventsEligible:true ");
|
||||
sb.append("OR @rma\\:dispositionAsOf:[MIN TO NOW] ");
|
||||
sb.append(") ");
|
||||
|
||||
String query = sb.toString();
|
||||
|
||||
ResultSet results = search.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
|
||||
SearchService.LANGUAGE_LUCENE, query);
|
||||
List<NodeRef> resultNodes = results.getNodeRefs();
|
||||
results.close();
|
||||
|
||||
RetryingTransactionHelper trn = trxService.getRetryingTransactionHelper();
|
||||
|
||||
for (NodeRef node : resultNodes)
|
||||
{
|
||||
final NodeRef currentNode = node;
|
||||
|
||||
RetryingTransactionCallback<Boolean> processTranCB = new RetryingTransactionCallback<Boolean>()
|
||||
{
|
||||
public Boolean execute() throws Throwable
|
||||
{
|
||||
final String dispAction = (String) nodeService.getProperty(currentNode,
|
||||
RecordsManagementModel.PROP_DISPOSITION_ACTION);
|
||||
|
||||
// Run "retain" and "cutoff" actions.
|
||||
|
||||
if (dispAction != null)
|
||||
{
|
||||
if (dispAction.equalsIgnoreCase("cutoff") ||
|
||||
dispAction.equalsIgnoreCase("retain"))
|
||||
{
|
||||
ChildAssociationRef parent = nodeService.getPrimaryParent(currentNode);
|
||||
if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION))
|
||||
{
|
||||
// Check that the action is executable
|
||||
RecordsManagementAction rmAction = rmActionService.getDispositionAction(dispAction);
|
||||
if (rmAction.isExecutable(parent.getParentRef(), null) == true)
|
||||
{
|
||||
rmActionService.executeRecordsManagementAction(parent.getParentRef(), dispAction);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Processed action: " + dispAction + "on" + parent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("The disposition action " + dispAction + " is not executable.");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Now do the work, one action in each transaction
|
||||
*/
|
||||
trn.doInTransaction(processTranCB);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
logger.debug("Job Finished");
|
||||
}
|
||||
}
|
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.module.org_alfresco_module_rm.job;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementAction;
|
||||
import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
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.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* The Disposition Lifecycle Job Finds all disposition action nodes which are
|
||||
* for "retain" or "cutOff" actions Where asOf > now OR
|
||||
* dispositionEventsEligible = true;
|
||||
*
|
||||
* Runs the cut off or retain action for
|
||||
* elligible records.
|
||||
*
|
||||
* @author mrogers
|
||||
*/
|
||||
public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecuter
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(DispositionLifecycleJobExecuter.class);
|
||||
|
||||
private RecordsManagementActionService recordsManagementActionService;
|
||||
|
||||
private NodeService nodeService;
|
||||
|
||||
private SearchService searchService;
|
||||
|
||||
public void setRecordsManagementActionService(RecordsManagementActionService recordsManagementActionService)
|
||||
{
|
||||
this.recordsManagementActionService = recordsManagementActionService;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.job.RecordsManagementJobExecuter#execute()
|
||||
*/
|
||||
public void execute()
|
||||
{
|
||||
logger.debug("Job Starting");
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("+TYPE:\"rma:dispositionAction\" ");
|
||||
sb.append("+(@rma\\:dispositionAction:(\"cutoff\" OR \"retain\"))");
|
||||
sb.append("+ISNULL:\"rma:dispositionActionCompletedAt\" ");
|
||||
sb.append("+( ");
|
||||
sb.append("@rma\\:dispositionEventsEligible:true ");
|
||||
sb.append("OR @rma\\:dispositionAsOf:[MIN TO NOW] ");
|
||||
sb.append(") ");
|
||||
|
||||
String query = sb.toString();
|
||||
|
||||
ResultSet results = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
|
||||
SearchService.LANGUAGE_LUCENE, query);
|
||||
List<NodeRef> resultNodes = results.getNodeRefs();
|
||||
results.close();
|
||||
|
||||
|
||||
for (NodeRef node : resultNodes)
|
||||
{
|
||||
final NodeRef currentNode = node;
|
||||
|
||||
RetryingTransactionCallback<Boolean> processTranCB = new RetryingTransactionCallback<Boolean>()
|
||||
{
|
||||
public Boolean execute() throws Throwable
|
||||
{
|
||||
final String dispAction = (String) nodeService.getProperty(currentNode,
|
||||
RecordsManagementModel.PROP_DISPOSITION_ACTION);
|
||||
|
||||
// Run "retain" and "cutoff" actions.
|
||||
|
||||
if (dispAction != null)
|
||||
{
|
||||
if (dispAction.equalsIgnoreCase("cutoff") ||
|
||||
dispAction.equalsIgnoreCase("retain"))
|
||||
{
|
||||
ChildAssociationRef parent = nodeService.getPrimaryParent(currentNode);
|
||||
if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION))
|
||||
{
|
||||
// Check that the action is executable
|
||||
RecordsManagementAction rmAction = recordsManagementActionService.getDispositionAction(dispAction);
|
||||
if (rmAction.isExecutable(parent.getParentRef(), null) == true)
|
||||
{
|
||||
recordsManagementActionService.executeRecordsManagementAction(parent.getParentRef(), dispAction);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Processed action: " + dispAction + "on" + parent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("The disposition action " + dispAction + " is not executable.");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Now do the work, one action in each transaction
|
||||
*/
|
||||
retryingTransactionHelper.doInTransaction(processTranCB);
|
||||
}
|
||||
|
||||
logger.debug("Job Finished");
|
||||
}
|
||||
}
|
@@ -25,19 +25,14 @@ import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.notification.RecordsManagementNotificationHelper;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
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.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
/**
|
||||
* This job finds all Vital Records which are due for review, optionally
|
||||
@@ -45,20 +40,37 @@ import org.quartz.JobExecutionException;
|
||||
*
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class NotifyOfRecordsDueForReviewJob implements Job
|
||||
public class NotifyOfRecordsDueForReviewJobExecuter extends RecordsManagementJobExecuter
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(NotifyOfRecordsDueForReviewJob.class);
|
||||
private static Log logger = LogFactory.getLog(NotifyOfRecordsDueForReviewJobExecuter.class);
|
||||
|
||||
private RecordsManagementNotificationHelper recordsManagementNotificationHelper;
|
||||
|
||||
private NodeService nodeService;
|
||||
|
||||
private SearchService searchService;
|
||||
|
||||
public void setRecordsManagementNotificationHelper(
|
||||
RecordsManagementNotificationHelper recordsManagementNotificationHelper)
|
||||
{
|
||||
this.recordsManagementNotificationHelper = recordsManagementNotificationHelper;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.job.RecordsManagementJobExecuter#execute()
|
||||
*/
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException
|
||||
{
|
||||
final RecordsManagementNotificationHelper notificationHelper = (RecordsManagementNotificationHelper)context.getJobDetail().getJobDataMap().get("recordsManagementNotificationHelper");
|
||||
final NodeService nodeService = (NodeService) context.getJobDetail().getJobDataMap().get("nodeService");
|
||||
final SearchService searchService = (SearchService) context.getJobDetail().getJobDataMap().get("searchService");
|
||||
final TransactionService trxService = (TransactionService) context.getJobDetail().getJobDataMap().get("transactionService");
|
||||
|
||||
public void execute()
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Job " + this.getClass().getSimpleName() + " starting.");
|
||||
@@ -91,8 +103,6 @@ public class NotifyOfRecordsDueForReviewJob implements Job
|
||||
//If we have something to do and a template to do it with
|
||||
if(resultNodes.size() != 0)
|
||||
{
|
||||
RetryingTransactionHelper trn = trxService.getRetryingTransactionHelper();
|
||||
|
||||
//Send the email message - but we must not retry since email is not transactional
|
||||
RetryingTransactionCallback<Boolean> txCallbackSendEmail = new RetryingTransactionCallback<Boolean>()
|
||||
{
|
||||
@@ -100,7 +110,7 @@ public class NotifyOfRecordsDueForReviewJob implements Job
|
||||
public Boolean execute() throws Throwable
|
||||
{
|
||||
// Send notification
|
||||
notificationHelper.recordsDueForReviewEmailNotification(resultNodes);
|
||||
recordsManagementNotificationHelper.recordsDueForReviewEmailNotification(resultNodes);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -122,10 +132,10 @@ public class NotifyOfRecordsDueForReviewJob implements Job
|
||||
/**
|
||||
* Now do the work, one action in each transaction
|
||||
*/
|
||||
trn.setMaxRetries(0); // don't retry the send email
|
||||
trn.doInTransaction(txCallbackSendEmail);
|
||||
trn.setMaxRetries(10);
|
||||
trn.doInTransaction(txUpdateNodesCallback);
|
||||
retryingTransactionHelper.setMaxRetries(0); // don't retry the send email
|
||||
retryingTransactionHelper.doInTransaction(txCallbackSendEmail);
|
||||
retryingTransactionHelper.setMaxRetries(10);
|
||||
retryingTransactionHelper.doInTransaction(txUpdateNodesCallback);
|
||||
}
|
||||
return null;
|
||||
}
|
@@ -24,7 +24,6 @@ import java.util.List;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.module.org_alfresco_module_rm.job.publish.PublishExecutor;
|
||||
import org.alfresco.module.org_alfresco_module_rm.job.publish.PublishExecutorRegistry;
|
||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
@@ -37,47 +36,51 @@ import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
/**
|
||||
* Job to publish any pending updates on marked node references.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class PublishUpdatesJob implements Job, RecordsManagementModel
|
||||
public class PublishUpdatesJobExecuter extends RecordsManagementJobExecuter
|
||||
{
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(PublishUpdatesJob.class);
|
||||
private static Log logger = LogFactory.getLog(PublishUpdatesJobExecuter.class);
|
||||
|
||||
/** Node service */
|
||||
private NodeService nodeService;
|
||||
|
||||
/** Search service */
|
||||
private SearchService searchService;
|
||||
|
||||
/** Retrying transaction helper */
|
||||
private RetryingTransactionHelper retryingTransactionHelper;
|
||||
private SearchService searchService;
|
||||
|
||||
/** Publish executor register */
|
||||
private PublishExecutorRegistry register;
|
||||
private PublishExecutorRegistry publishExecutorRegistry;
|
||||
|
||||
/** Behaviour filter */
|
||||
private BehaviourFilter behaviourFilter;
|
||||
|
||||
/** Indicates whether the job bean has been initialised or not */
|
||||
private boolean initialised = false;
|
||||
|
||||
/**
|
||||
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
|
||||
*/
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
// Initialise the service references
|
||||
initServices(context);
|
||||
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
public void setPublishExecutorRegistry(PublishExecutorRegistry publishExecutorRegistry)
|
||||
{
|
||||
this.publishExecutorRegistry = publishExecutorRegistry;
|
||||
}
|
||||
|
||||
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
|
||||
{
|
||||
this.behaviourFilter = behaviourFilter;
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
if (logger.isDebugEnabled() == true)
|
||||
{
|
||||
logger.debug("Job Starting");
|
||||
@@ -156,25 +159,6 @@ public class PublishUpdatesJob implements Job, RecordsManagementModel
|
||||
return retryingTransactionHelper.doInTransaction(execution, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise service based on the job execution context
|
||||
* @param context job execution context
|
||||
*/
|
||||
private void initServices(JobExecutionContext context)
|
||||
{
|
||||
if (initialised == false)
|
||||
{
|
||||
// Get references to the required services
|
||||
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||
nodeService = (NodeService)jobDataMap.get("nodeService");
|
||||
searchService = (SearchService)jobDataMap.get("searchService");
|
||||
retryingTransactionHelper = (RetryingTransactionHelper)jobDataMap.get("retryingTransactionHelper");
|
||||
register = (PublishExecutorRegistry)jobDataMap.get("publishExecutorRegistry");
|
||||
behaviourFilter = (BehaviourFilter)jobDataMap.get("behaviourFilter");
|
||||
initialised = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the node as publish in progress. This is often used as a marker to prevent any further updates
|
||||
* to a node.
|
||||
@@ -235,7 +219,7 @@ public class PublishUpdatesJob implements Job, RecordsManagementModel
|
||||
}
|
||||
|
||||
// Get the publish executor
|
||||
PublishExecutor executor = register.get(updateTo);
|
||||
PublishExecutor executor = publishExecutorRegistry.get(updateTo);
|
||||
if (executor == null)
|
||||
{
|
||||
if (logger.isDebugEnabled() == true)
|
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.module.org_alfresco_module_rm.job;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.lock.JobLockService;
|
||||
import org.alfresco.repo.lock.LockAcquisitionException;
|
||||
import org.alfresco.repo.lock.JobLockService.JobLockRefreshCallback;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
/**
|
||||
* Base records management job implementation.
|
||||
* <p>
|
||||
* Delegates job execution and ensures locking
|
||||
* is enforced.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class RecordsManagementJob implements Job
|
||||
{
|
||||
private static long DEFAULT_TIME = 2000L;
|
||||
|
||||
private JobLockService jobLockService;
|
||||
|
||||
private RecordsManagementJobExecuter jobExecuter;
|
||||
|
||||
private String jobName;
|
||||
|
||||
private QName getLockQName()
|
||||
{
|
||||
return QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, jobName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get the lock. If the lock couldn't be taken, then <tt>null</tt> is returned.
|
||||
*
|
||||
* @return Returns the lock token or <tt>null</tt>
|
||||
*/
|
||||
private String getLock()
|
||||
{
|
||||
try
|
||||
{
|
||||
return jobLockService.getLock(getLockQName(), DEFAULT_TIME);
|
||||
}
|
||||
catch (LockAcquisitionException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException
|
||||
{
|
||||
// get the job lock service
|
||||
jobLockService = (JobLockService)context.getJobDetail().getJobDataMap().get("jobLockService");
|
||||
if (jobLockService == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Job lock service has not been specified.");
|
||||
}
|
||||
|
||||
// get the job executer
|
||||
jobExecuter = (RecordsManagementJobExecuter)context.getJobDetail().getJobDataMap().get("jobExecuter");
|
||||
if (jobExecuter == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Job executer has not been specified.");
|
||||
}
|
||||
|
||||
// get the job name
|
||||
jobName = (String)context.getJobDetail().getJobDataMap().get("jobName");
|
||||
if (jobName == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Job name has not been specified.");
|
||||
}
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// try and get the lock
|
||||
String lockToken = getLock();
|
||||
if (lockToken == null)
|
||||
{
|
||||
// exit
|
||||
return null;
|
||||
}
|
||||
|
||||
// use a flag to keep track of the running job
|
||||
final AtomicBoolean running = new AtomicBoolean(true);
|
||||
jobLockService.refreshLock(lockToken, getLockQName(), DEFAULT_TIME, new JobLockRefreshCallback()
|
||||
{
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
return running.get();
|
||||
}
|
||||
@Override
|
||||
public void lockReleased()
|
||||
{
|
||||
running.set(false);
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
// do work
|
||||
jobExecuter.execute();
|
||||
}
|
||||
finally
|
||||
{
|
||||
// The lock will self-release if answer isActive in the negative
|
||||
running.set(false);
|
||||
}
|
||||
|
||||
// return
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.module.org_alfresco_module_rm.job;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
|
||||
/**
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public abstract class RecordsManagementJobExecuter implements RecordsManagementModel
|
||||
{
|
||||
protected RetryingTransactionHelper retryingTransactionHelper;
|
||||
|
||||
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
|
||||
{
|
||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||
}
|
||||
|
||||
public abstract void execute();
|
||||
}
|
Reference in New Issue
Block a user