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
This commit is contained in:
Roy Wetherall
2013-09-10 06:32:12 +00:00
parent 24ff46e982
commit c351d6fcdb
4 changed files with 159 additions and 113 deletions

View File

@@ -37,21 +37,32 @@ public abstract class AuditableActionExecuterAbstractBase extends ActionExecuter
/** Indicates whether the action is auditable or not */ /** Indicates whether the action is auditable or not */
protected boolean auditable = true; protected boolean auditable = true;
/** Application context */
protected ApplicationContext applicationContext; protected ApplicationContext applicationContext;
/** Records management audit service */
private RecordsManagementAuditService auditService; private RecordsManagementAuditService auditService;
/**
* @param auditable true if auditable, false otherwise
*/
public void setAuditable(boolean auditable) public void setAuditable(boolean auditable)
{ {
this.auditable = auditable; this.auditable = auditable;
} }
/**
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{ {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
} }
/**
* @return records management audit service
*/
private RecordsManagementAuditService getAuditService() private RecordsManagementAuditService getAuditService()
{ {
if (auditService == null) if (auditService == null)
@@ -61,6 +72,9 @@ public abstract class AuditableActionExecuterAbstractBase extends ActionExecuter
return auditService; return auditService;
} }
/**
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#init()
*/
@Override @Override
public void init() public void init()
{ {

View File

@@ -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_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_NEXT_DISP = "rm.action.not-next-disp";
private static final String MSG_NOT_RECORD_FOLDER = "rm.action.not-record-folder"; 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. * All children of this implementation are disposition actions.
@@ -97,91 +100,100 @@ public abstract class RMDispositionActionExecuterAbstractBase extends RMActionEx
@Override @Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef) 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 // Check the validity of the action (is it the next action, are we dealing with the correct type of object for
// the disposition level? // the disposition level?
DispositionSchedule di = checkDispositionActionExecutionValidity(actionedUponNodeRef, nextDispositionActionNodeRef, true); DispositionSchedule di = checkDispositionActionExecutionValidity(actionedUponNodeRef, nextDispositionActionNodeRef, checkError);
if (di != null)
// Check the eligibility of the action
if (checkEligibility(actionedUponNodeRef) == false ||
dispositionService.isNextDispositionActionEligible(actionedUponNodeRef) == true)
{ {
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 (di.isRecordLevelDisposition() == true)
if (recordService.isRecord(actionedUponNodeRef) == true)
{ {
// Can only execute disposition action on record if declared // Check that we do indeed have a record
if (recordService.isDeclared(actionedUponNodeRef) == true) if (recordService.isRecord(actionedUponNodeRef) == true)
{ {
// Indicate that the disposition action is underway // Can only execute disposition action on record if declared
this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_STARTED_AT, new Date()); if (recordService.isDeclared(actionedUponNodeRef) == true)
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()); // Indicate that the disposition action is underway
this.nodeService.setProperty(nextDispositionActionNodeRef, PROP_DISPOSITION_ACTION_COMPLETED_BY, AuthenticationUtil.getRunAsUser()); 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 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 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 else
{ {
if (this.recordsManagementService.isRecordFolder(actionedUponNodeRef) == true) throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NOT_ELIGIBLE, getName(), actionedUponNodeRef.toString()));
{
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
{
throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NOT_ELIGIBLE, getName(), actionedUponNodeRef.toString()));
} }
} }

View File

@@ -57,8 +57,11 @@ public class FreezeAction extends RMActionExecuterAbstractBase
if (nodeService.exists(actionedUponNodeRef) == true && if (nodeService.exists(actionedUponNodeRef) == true &&
nodeService.hasAspect(actionedUponNodeRef, ContentModel.ASPECT_PENDING_DELETE) == false && nodeService.hasAspect(actionedUponNodeRef, ContentModel.ASPECT_PENDING_DELETE) == false &&
(recordService.isRecord(actionedUponNodeRef) == true || (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); freezeService.freeze((String) action.getParameterValue(PARAM_REASON), actionedUponNodeRef);
} }
} }

View File

@@ -19,8 +19,13 @@
package org.alfresco.module.org_alfresco_module_rm.job; package org.alfresco.module.org_alfresco_module_rm.job;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List; 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.action.RecordsManagementActionService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
@@ -73,65 +78,77 @@ public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecute
*/ */
public void executeImpl() public void executeImpl()
{ {
logger.debug("Job Starting"); try
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; logger.debug("Job Starting");
RetryingTransactionCallback<Boolean> processTranCB = new RetryingTransactionCallback<Boolean>() 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)
{ {
public Boolean execute() throws Throwable final NodeRef currentNode = node;
RetryingTransactionCallback<Boolean> processTranCB = new RetryingTransactionCallback<Boolean>()
{ {
final String dispAction = (String) nodeService.getProperty(currentNode, public Boolean execute() throws Throwable
RecordsManagementModel.PROP_DISPOSITION_ACTION);
// Run "retain" and "cutoff" actions.
if (dispAction != null)
{ {
if (dispAction.equalsIgnoreCase("cutoff") || final String dispAction = (String) nodeService.getProperty(currentNode,
dispAction.equalsIgnoreCase("retain")) RecordsManagementModel.PROP_DISPOSITION_ACTION);
// Run "retain" and "cutoff" actions.
if (dispAction != null)
{ {
ChildAssociationRef parent = nodeService.getPrimaryParent(currentNode); if (dispAction.equalsIgnoreCase("cutoff") ||
if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION)) dispAction.equalsIgnoreCase("retain"))
{ {
recordsManagementActionService.executeRecordsManagementAction(parent.getParentRef(), dispAction); ChildAssociationRef parent = nodeService.getPrimaryParent(currentNode);
if (logger.isDebugEnabled()) if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION))
{ {
logger.debug("Processed action: " + dispAction + "on" + parent); Map<String, Serializable> props = new HashMap<String, Serializable>(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
/** */
* Now do the work, one action in each transaction retryingTransactionHelper.doInTransaction(processTranCB);
*/ }
retryingTransactionHelper.doInTransaction(processTranCB);
logger.debug("Job Finished");
}
catch (AlfrescoRuntimeException exception)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(exception);
}
} }
logger.debug("Job Finished");
} }
} }