From c351d6fcdb796998e025fbfad50ba1504c9bbe59 Mon Sep 17 00:00:00 2001 From: Roy Wetherall Date: Tue, 10 Sep 2013 06:32:12 +0000 Subject: [PATCH] RM-895: Can't Freeze record and folder witch contains record if updated rule to Freeze is set * also dealt with exception that was not being handled by background job git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@55153 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../AuditableActionExecuterAbstractBase.java | 14 ++ ...DispositionActionExecuterAbstractBase.java | 140 ++++++++++-------- .../action/impl/FreezeAction.java | 5 +- .../job/DispositionLifecycleJobExecuter.java | 113 ++++++++------ 4 files changed, 159 insertions(+), 113 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/AuditableActionExecuterAbstractBase.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/AuditableActionExecuterAbstractBase.java index e3255f3908..28ef3b8393 100755 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/AuditableActionExecuterAbstractBase.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/AuditableActionExecuterAbstractBase.java @@ -37,21 +37,32 @@ public abstract class AuditableActionExecuterAbstractBase extends ActionExecuter /** Indicates whether the action is auditable or not */ protected boolean auditable = true; + /** Application context */ protected ApplicationContext applicationContext; + /** Records management audit service */ private RecordsManagementAuditService auditService; + /** + * @param auditable true if auditable, false otherwise + */ public void setAuditable(boolean auditable) { this.auditable = auditable; } + /** + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } + /** + * @return records management audit service + */ private RecordsManagementAuditService getAuditService() { if (auditService == null) @@ -61,6 +72,9 @@ public abstract class AuditableActionExecuterAbstractBase extends ActionExecuter return auditService; } + /** + * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#init() + */ @Override public void init() { diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMDispositionActionExecuterAbstractBase.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMDispositionActionExecuterAbstractBase.java index 6dd72a4033..0f6b36ce8f 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMDispositionActionExecuterAbstractBase.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMDispositionActionExecuterAbstractBase.java @@ -46,6 +46,9 @@ public abstract class RMDispositionActionExecuterAbstractBase extends RMActionEx private static final String MSG_NEXT_DISP_NOT_SET = "rm.action.next-disp-not-set"; private static final String MSG_NOT_NEXT_DISP = "rm.action.not-next-disp"; private static final String MSG_NOT_RECORD_FOLDER = "rm.action.not-record-folder"; + + /** Parameter value indicating whether we should be doing non-error raising state checks */ + public static final String PARAM_NO_ERROR_CHECK = "rm.no-error-check"; /** * All children of this implementation are disposition actions. @@ -97,91 +100,100 @@ public abstract class RMDispositionActionExecuterAbstractBase extends RMActionEx @Override protected void executeImpl(Action action, NodeRef actionedUponNodeRef) { - // - NodeRef nextDispositionActionNodeRef = getNextDispostionAction(actionedUponNodeRef); + NodeRef nextDispositionActionNodeRef = getNextDispostionAction(actionedUponNodeRef); + + // determine whether we should be raising errors during state checking or not + boolean checkError = true; + Boolean checkErrorValue = (Boolean)action.getParameterValue(PARAM_NO_ERROR_CHECK); + if (checkErrorValue != null) + { + checkError = checkErrorValue.booleanValue(); + } // Check the validity of the action (is it the next action, are we dealing with the correct type of object for // the disposition level? - DispositionSchedule di = checkDispositionActionExecutionValidity(actionedUponNodeRef, nextDispositionActionNodeRef, true); - - // Check the eligibility of the action - if (checkEligibility(actionedUponNodeRef) == false || - dispositionService.isNextDispositionActionEligible(actionedUponNodeRef) == true) + DispositionSchedule di = checkDispositionActionExecutionValidity(actionedUponNodeRef, nextDispositionActionNodeRef, checkError); + if (di != null) { - if (di.isRecordLevelDisposition() == true) + // Check the eligibility of the action + if (checkEligibility(actionedUponNodeRef) == false || + dispositionService.isNextDispositionActionEligible(actionedUponNodeRef) == true) { - // Check that we do indeed have a record - if (recordService.isRecord(actionedUponNodeRef) == true) + if (di.isRecordLevelDisposition() == true) { - // Can only execute disposition action on record if declared - if (recordService.isDeclared(actionedUponNodeRef) == true) + // Check that we do indeed have a record + if (recordService.isRecord(actionedUponNodeRef) == true) { - // Indicate that the disposition action is underway - this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_STARTED_AT, new Date()); - this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_STARTED_BY, AuthenticationUtil.getRunAsUser()); - - // Execute record level disposition - executeRecordLevelDisposition(action, actionedUponNodeRef); - - if (this.nodeService.exists(nextDispositionActionNodeRef) == true && - getSetDispositionActionComplete() == true) + // Can only execute disposition action on record if declared + if (recordService.isDeclared(actionedUponNodeRef) == true) { - this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_COMPLETED_AT, new Date()); - this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_COMPLETED_BY, AuthenticationUtil.getRunAsUser()); + // Indicate that the disposition action is underway + this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_STARTED_AT, new Date()); + this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_STARTED_BY, AuthenticationUtil.getRunAsUser()); + + // Execute record level disposition + executeRecordLevelDisposition(action, actionedUponNodeRef); + + if (this.nodeService.exists(nextDispositionActionNodeRef) == true && + getSetDispositionActionComplete() == true) + { + this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_COMPLETED_AT, new Date()); + this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_COMPLETED_BY, AuthenticationUtil.getRunAsUser()); + } + } + else + { + throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_RECORD_NOT_DECLARED, getName(), actionedUponNodeRef.toString())); } } else { - throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_RECORD_NOT_DECLARED, getName(), actionedUponNodeRef.toString())); + throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_EXPECTED_RECORD_LEVEL, getName(), actionedUponNodeRef.toString())); } } else { - throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_EXPECTED_RECORD_LEVEL, getName(), actionedUponNodeRef.toString())); + if (this.recordsManagementService.isRecordFolder(actionedUponNodeRef) == true) + { + if (this.recordsManagementService.isRecordFolderDeclared(actionedUponNodeRef) == true) + { + // Indicate that the disposition action is underway + this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_STARTED_AT, new Date()); + this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_STARTED_BY, AuthenticationUtil.getRunAsUser()); + + executeRecordFolderLevelDisposition(action, actionedUponNodeRef); + + // Indicate that the disposition action is compelte + if (this.nodeService.exists(nextDispositionActionNodeRef) == true && + getSetDispositionActionComplete() == true) + { + this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_COMPLETED_AT, new Date()); + this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_COMPLETED_BY, AuthenticationUtil.getRunAsUser()); + } + + } + else + { + throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NOT_ALL_RECORDS_DECLARED, getName(), actionedUponNodeRef.toString())); + } + } + else + { + throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NOT_RECORD_FOLDER, getName(), actionedUponNodeRef.toString())); + } + + } + + if (this.nodeService.exists(actionedUponNodeRef) == true && getSetDispositionActionComplete() == true) + { + // Update the disposition schedule + updateNextDispositionAction(actionedUponNodeRef); } } else { - if (this.recordsManagementService.isRecordFolder(actionedUponNodeRef) == true) - { - if (this.recordsManagementService.isRecordFolderDeclared(actionedUponNodeRef) == true) - { - // Indicate that the disposition action is underway - this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_STARTED_AT, new Date()); - this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_STARTED_BY, AuthenticationUtil.getRunAsUser()); - - executeRecordFolderLevelDisposition(action, actionedUponNodeRef); - - // Indicate that the disposition action is compelte - if (this.nodeService.exists(nextDispositionActionNodeRef) == true && - getSetDispositionActionComplete() == true) - { - this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_COMPLETED_AT, new Date()); - this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_COMPLETED_BY, AuthenticationUtil.getRunAsUser()); - } - - } - else - { - throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NOT_ALL_RECORDS_DECLARED, getName(), actionedUponNodeRef.toString())); - } - } - else - { - throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NOT_RECORD_FOLDER, getName(), actionedUponNodeRef.toString())); - } - + throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NOT_ELIGIBLE, getName(), actionedUponNodeRef.toString())); } - - if (this.nodeService.exists(actionedUponNodeRef) == true && getSetDispositionActionComplete() == true) - { - // Update the disposition schedule - updateNextDispositionAction(actionedUponNodeRef); - } - } - else - { - throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NOT_ELIGIBLE, getName(), actionedUponNodeRef.toString())); } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FreezeAction.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FreezeAction.java index a5a9b4b8b3..6281f78bcc 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FreezeAction.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FreezeAction.java @@ -57,8 +57,11 @@ public class FreezeAction extends RMActionExecuterAbstractBase if (nodeService.exists(actionedUponNodeRef) == true && nodeService.hasAspect(actionedUponNodeRef, ContentModel.ASPECT_PENDING_DELETE) == false && (recordService.isRecord(actionedUponNodeRef) == true || - recordsManagementService.isRecordFolder(actionedUponNodeRef) == true)) + recordsManagementService.isRecordFolder(actionedUponNodeRef) == true) && + freezeService.isFrozen(actionedUponNodeRef) == false) { + System.out.println("I am trying to freeze " + actionedUponNodeRef.toString()); + freezeService.freeze((String) action.getParameterValue(PARAM_REASON), actionedUponNodeRef); } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/job/DispositionLifecycleJobExecuter.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/job/DispositionLifecycleJobExecuter.java index db07a13ea1..713f763ff0 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/job/DispositionLifecycleJobExecuter.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/job/DispositionLifecycleJobExecuter.java @@ -19,8 +19,13 @@ package org.alfresco.module.org_alfresco_module_rm.job; +import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.module.org_alfresco_module_rm.action.RMDispositionActionExecuterAbstractBase; 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; @@ -73,65 +78,77 @@ public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecute */ public void executeImpl() { - 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 resultNodes = results.getNodeRefs(); - results.close(); - - - for (NodeRef node : resultNodes) + try { - final NodeRef currentNode = node; - - RetryingTransactionCallback processTranCB = new RetryingTransactionCallback() + 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 resultNodes = results.getNodeRefs(); + results.close(); + + + for (NodeRef node : resultNodes) { - public Boolean execute() throws Throwable + final NodeRef currentNode = node; + + RetryingTransactionCallback processTranCB = new RetryingTransactionCallback() { - final String dispAction = (String) nodeService.getProperty(currentNode, - RecordsManagementModel.PROP_DISPOSITION_ACTION); - - // Run "retain" and "cutoff" actions. - - if (dispAction != null) + public Boolean execute() throws Throwable { - if (dispAction.equalsIgnoreCase("cutoff") || - dispAction.equalsIgnoreCase("retain")) + final String dispAction = (String) nodeService.getProperty(currentNode, + RecordsManagementModel.PROP_DISPOSITION_ACTION); + + // Run "retain" and "cutoff" actions. + + if (dispAction != null) { - ChildAssociationRef parent = nodeService.getPrimaryParent(currentNode); - if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION)) + if (dispAction.equalsIgnoreCase("cutoff") || + dispAction.equalsIgnoreCase("retain")) { - recordsManagementActionService.executeRecordsManagementAction(parent.getParentRef(), dispAction); - if (logger.isDebugEnabled()) + ChildAssociationRef parent = nodeService.getPrimaryParent(currentNode); + if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION)) { - logger.debug("Processed action: " + dispAction + "on" + parent); + Map props = new HashMap(1); + props.put(RMDispositionActionExecuterAbstractBase.PARAM_NO_ERROR_CHECK, Boolean.FALSE); + recordsManagementActionService.executeRecordsManagementAction(parent.getParentRef(), dispAction, props); + if (logger.isDebugEnabled()) + { + logger.debug("Processed action: " + dispAction + "on" + parent); + } } + return null; } - return null; } + return Boolean.TRUE; } - return Boolean.TRUE; - } - }; - - /** - * Now do the work, one action in each transaction - */ - retryingTransactionHelper.doInTransaction(processTranCB); + }; + + /** + * Now do the work, one action in each transaction + */ + retryingTransactionHelper.doInTransaction(processTranCB); + } + + logger.debug("Job Finished"); + } + catch (AlfrescoRuntimeException exception) + { + if (logger.isDebugEnabled() == true) + { + logger.debug(exception); + } } - - logger.debug("Job Finished"); } }