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:
Roy Wetherall
2012-05-16 04:51:20 +00:00
parent 6a4bfb4609
commit 54a12c4174
10 changed files with 448 additions and 279 deletions

View File

@@ -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"

View File

@@ -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>

View File

@@ -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 -->

View File

@@ -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);

View File

@@ -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");
}
}

View File

@@ -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");
}
}

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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());
}
}

View File

@@ -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();
}