RM-1097: Refactored TransferAction and TransferCompleteAction

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@57963 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Tuna Aksoy
2013-11-18 14:45:12 +00:00
parent 3c8e7ed6fc
commit 23c9d41bb4
11 changed files with 606 additions and 490 deletions

View File

@@ -19,7 +19,6 @@
package org.alfresco.module.org_alfresco_module_rm.action;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -29,8 +28,6 @@ import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.admin.RecordsManagementAdminService;
import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService;
import org.alfresco.module.org_alfresco_module_rm.event.EventCompletionDetails;
import org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEvent;
@@ -49,15 +46,12 @@ import org.alfresco.service.cmr.action.ActionDefinition;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Period;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.BeanNameAware;
@@ -475,127 +469,6 @@ public abstract class RMActionExecuterAbstractBase extends PropertySubActionExe
return null;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementService#updateNextDispositionAction(org.alfresco.service.cmr.repository.NodeRef)
*/
public void updateNextDispositionAction(NodeRef nodeRef)
{
// Get this disposition instructions for the node
DispositionSchedule di = dispositionService.getDispositionSchedule(nodeRef);
if (di != null)
{
// Get the current action node
NodeRef currentDispositionAction = null;
if (this.nodeService.hasAspect(nodeRef, ASPECT_DISPOSITION_LIFECYCLE) == true)
{
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(nodeRef, ASSOC_NEXT_DISPOSITION_ACTION, RegexQNamePattern.MATCH_ALL);
if (assocs.size() > 0)
{
currentDispositionAction = assocs.get(0).getChildRef();
}
}
if (currentDispositionAction != null)
{
// Move it to the history association
this.nodeService.moveNode(currentDispositionAction, nodeRef, ASSOC_DISPOSITION_ACTION_HISTORY, ASSOC_DISPOSITION_ACTION_HISTORY);
}
List<DispositionActionDefinition> dispositionActionDefinitions = di.getDispositionActionDefinitions();
DispositionActionDefinition currentDispositionActionDefinition = null;
DispositionActionDefinition nextDispositionActionDefinition = null;
if (currentDispositionAction == null)
{
if (dispositionActionDefinitions.isEmpty() == false)
{
// The next disposition action is the first action
nextDispositionActionDefinition = dispositionActionDefinitions.get(0);
}
}
else
{
// Get the current action
String currentADId = (String)this.nodeService.getProperty(currentDispositionAction, PROP_DISPOSITION_ACTION_ID);
currentDispositionActionDefinition = di.getDispositionActionDefinition(currentADId);
// Get the next disposition action
int index = currentDispositionActionDefinition.getIndex();
index++;
if (index < dispositionActionDefinitions.size())
{
nextDispositionActionDefinition = dispositionActionDefinitions.get(index);
}
}
if (nextDispositionActionDefinition != null)
{
if (this.nodeService.hasAspect(nodeRef, ASPECT_DISPOSITION_LIFECYCLE) == false)
{
// Add the disposition life cycle aspect
this.nodeService.addAspect(nodeRef, ASPECT_DISPOSITION_LIFECYCLE, null);
}
// Create the properties
Map<QName, Serializable> props = new HashMap<QName, Serializable>(10);
// Calculate the asOf date
Date asOfDate = null;
Period period = nextDispositionActionDefinition.getPeriod();
if (period != null)
{
Date contextDate = null;
// Get the period properties value
QName periodProperty = nextDispositionActionDefinition.getPeriodProperty();
if (periodProperty != null &&
RecordsManagementModel.PROP_DISPOSITION_AS_OF.equals(periodProperty) == false)
{
// doesn't matter if the period property isn't set ... the asOfDate will get updated later
// when the value of the period property is set
contextDate = (Date)this.nodeService.getProperty(nodeRef, periodProperty);
}
else
{
// for now use 'NOW' as the default context date
// TODO set the default period property ... cut off date or last disposition date depending on context
contextDate = new Date();
}
// Calculate the as of date
if (contextDate != null)
{
asOfDate = period.getNextDate(contextDate);
}
}
// Set the property values
props.put(PROP_DISPOSITION_ACTION_ID, nextDispositionActionDefinition.getId());
props.put(PROP_DISPOSITION_ACTION, nextDispositionActionDefinition.getName());
if (asOfDate != null)
{
props.put(PROP_DISPOSITION_AS_OF, asOfDate);
}
// Create a new disposition action object
NodeRef dispositionActionNodeRef = this.nodeService.createNode(
nodeRef,
ASSOC_NEXT_DISPOSITION_ACTION,
ASSOC_NEXT_DISPOSITION_ACTION,
TYPE_DISPOSITION_ACTION,
props).getChildRef();
// Create the events
List<RecordsManagementEvent> events = nextDispositionActionDefinition.getEvents();
for (RecordsManagementEvent event : events)
{
// For every event create an entry on the action
createEvent(event, dispositionActionNodeRef);
}
}
}
}
/**
* Creates the given records management event for the given 'next action'.
*

View File

@@ -187,7 +187,7 @@ public abstract class RMDispositionActionExecuterAbstractBase extends RMActionEx
if (nodeService.exists(actionedUponNodeRef) == true && getSetDispositionActionComplete() == true)
{
// Update the disposition schedule
updateNextDispositionAction(actionedUponNodeRef);
dispositionService.updateNextDispositionAction(actionedUponNodeRef);
}
}
else

View File

@@ -43,19 +43,19 @@ import org.apache.commons.logging.LogFactory;
* Action to implement the consequences of a change to the value of the DispositionActionDefinition
* properties. When these properties are changed on a disposition schedule, then any associated
* disposition actions may need to be updated as a consequence.
*
*
* @author Neil McErlean
*/
public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionExecuterAbstractBase
{
/** Logger */
private static Log logger = LogFactory.getLog(BroadcastDispositionActionDefinitionUpdateAction.class);
public static final String NAME = "broadcastDispositionActionDefinitionUpdate";
public static final String CHANGED_PROPERTIES = "changedProperties";
private BehaviourFilter behaviourFilter;
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
{
this.behaviourFilter = behaviourFilter;
@@ -73,14 +73,14 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
{
return;
}
List<QName> changedProps = (List<QName>)action.getParameterValue(CHANGED_PROPERTIES);
// Navigate up the containment hierarchy to get the record category grandparent and schedule.
NodeRef dispositionScheduleNode = nodeService.getPrimaryParent(actionedUponNodeRef).getParentRef();
NodeRef rmContainer = nodeService.getPrimaryParent(dispositionScheduleNode).getParentRef();
DispositionSchedule dispositionSchedule = dispositionService.getAssociatedDispositionSchedule(rmContainer);
behaviourFilter.disableBehaviour();
try
{
@@ -95,9 +95,9 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
behaviourFilter.enableBehaviour();
}
}
/**
*
*
* @param ds
* @param disposableItem
* @param dispositionActionDefinition
@@ -111,7 +111,7 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
if (itemDs != null &&
itemDs.getNodeRef().equals(ds.getNodeRef()) == true)
{
if (this.nodeService.hasAspect(disposableItem, ASPECT_DISPOSITION_LIFECYCLE))
if (nodeService.hasAspect(disposableItem, ASPECT_DISPOSITION_LIFECYCLE))
{
// disposition lifecycle already exists for node so process changes
processActionDefinitionChanges(dispositionActionDefinition, changedProps, disposableItem);
@@ -119,43 +119,43 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
else
{
// disposition lifecycle does not exist on the node so setup disposition
updateNextDispositionAction(disposableItem);
dispositionService.updateNextDispositionAction(disposableItem);
}
// update rolled up search information
rollupSearchProperties(disposableItem);
}
}
/**
* Manually update the rolled up search properties
*
*
* @param disposableItem disposable item
*/
private void rollupSearchProperties(NodeRef disposableItem)
{
DispositionAction da = dispositionService.getNextDispositionAction(disposableItem);
if (da != null)
{
{
Map<QName, Serializable> props = nodeService.getProperties(disposableItem);
props.put(PROP_RS_DISPOSITION_ACTION_NAME, da.getName());
props.put(PROP_RS_DISPOSITION_ACTION_AS_OF, da.getAsOfDate());
props.put(PROP_RS_DISPOSITION_EVENTS_ELIGIBLE, this.nodeService.getProperty(da.getNodeRef(), PROP_DISPOSITION_EVENTS_ELIGIBLE));
DispositionActionDefinition daDefinition = da.getDispositionActionDefinition();
props.put(PROP_RS_DISPOSITION_ACTION_NAME, da.getName());
props.put(PROP_RS_DISPOSITION_ACTION_AS_OF, da.getAsOfDate());
props.put(PROP_RS_DISPOSITION_EVENTS_ELIGIBLE, nodeService.getProperty(da.getNodeRef(), PROP_DISPOSITION_EVENTS_ELIGIBLE));
DispositionActionDefinition daDefinition = da.getDispositionActionDefinition();
Period period = daDefinition.getPeriod();
if (period != null)
{
props.put(PROP_RS_DISPOSITION_PERIOD, period.getPeriodType());
props.put(PROP_RS_DISPOSITION_PERIOD_EXPRESSION, period.getExpression());
props.put(PROP_RS_DISPOSITION_PERIOD_EXPRESSION, period.getExpression());
}
else
{
props.put(PROP_RS_DISPOSITION_PERIOD, null);
props.put(PROP_RS_DISPOSITION_PERIOD_EXPRESSION, null);
}
List<EventCompletionDetails> events = da.getEventCompletionDetails();
List<String> list = new ArrayList<String>(events.size());
for (EventCompletionDetails event : events)
@@ -163,7 +163,7 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
list.add(event.getEventName());
}
props.put(PROP_RS_DISPOSITION_EVENTS, (Serializable)list);
nodeService.setProperties(disposableItem, props);
}
}
@@ -171,7 +171,7 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
/**
* Processes all the changes applied to the given disposition
* action definition node for the given record or folder node.
*
*
* @param dispositionActionDef The disposition action definition node
* @param changedProps The set of properties changed on the action definition
* @param recordOrFolder The record or folder the changes potentially need to be applied to
@@ -189,12 +189,12 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
{
persistPeriodChanges(dispositionActionDef, nextAction);
}
if (changedProps.contains(PROP_DISPOSITION_EVENT) || changedProps.contains(PROP_DISPOSITION_EVENT_COMBINATION))
{
persistEventChanges(dispositionActionDef, nextAction);
}
if (changedProps.contains(PROP_DISPOSITION_ACTION_NAME))
{
String action = (String)nodeService.getProperty(dispositionActionDef, PROP_DISPOSITION_ACTION_NAME);
@@ -202,20 +202,20 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
}
}
}
/**
* Determines whether the disposition action definition (step) being
* updated has any effect on the given next action
*
*
* @param dispositionActionDef The disposition action definition node
* @param nextAction The next disposition action
* @param nextAction The next disposition action
* @return true if the step change affects the next action
*/
private boolean doesChangedStepAffectNextAction(NodeRef dispositionActionDef,
private boolean doesChangedStepAffectNextAction(NodeRef dispositionActionDef,
DispositionAction nextAction)
{
boolean affectsNextAction = false;
if (dispositionActionDef != null && nextAction != null)
{
// check whether the id of the action definition node being changed
@@ -226,10 +226,10 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
affectsNextAction = true;
}
}
return affectsNextAction;
}
/**
* Persists any changes made to the period on the given disposition action
* definition on the given next action.
@@ -240,24 +240,24 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
private void persistPeriodChanges(NodeRef dispositionActionDef, DispositionAction nextAction)
{
Date newAsOfDate = null;
Period dispositionPeriod = (Period)nodeService.getProperty(dispositionActionDef, PROP_DISPOSITION_PERIOD);
Period dispositionPeriod = (Period) nodeService.getProperty(dispositionActionDef, PROP_DISPOSITION_PERIOD);
if (dispositionPeriod != null)
{
// calculate the new as of date as we have been provided a new period
Date now = new Date();
newAsOfDate = dispositionPeriod.getNextDate(now);
}
if (logger.isDebugEnabled())
{
logger.debug("Set disposition as of date for next action '" + nextAction.getName() +
logger.debug("Set disposition as of date for next action '" + nextAction.getName() +
"' (" + nextAction.getNodeRef() + ") to: " + newAsOfDate);
}
this.nodeService.setProperty(nextAction.getNodeRef(), PROP_DISPOSITION_AS_OF, newAsOfDate);
nodeService.setProperty(nextAction.getNodeRef(), PROP_DISPOSITION_AS_OF, newAsOfDate);
}
/**
* Persists any changes made to the events on the given disposition action
* definition on the given next action.
@@ -269,7 +269,7 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
private void persistEventChanges(NodeRef dispositionActionDef, DispositionAction nextAction)
{
// go through the current events on the next action and remove any that are not present any more
List<String> stepEvents = (List<String>)nodeService.getProperty(dispositionActionDef, PROP_DISPOSITION_EVENT);
List<String> stepEvents = (List<String>) nodeService.getProperty(dispositionActionDef, PROP_DISPOSITION_EVENT);
List<EventCompletionDetails> eventsList = nextAction.getEventCompletionDetails();
List<String> nextActionEvents = new ArrayList<String>(eventsList.size());
for (EventCompletionDetails event : eventsList)
@@ -277,19 +277,19 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
// take note of the event names present on the next action
String eventName = event.getEventName();
nextActionEvents.add(eventName);
// if the event has been removed delete from next action
if (stepEvents != null && stepEvents.contains(event.getEventName()) == false)
{
// remove the child association representing the event
nodeService.removeChild(nextAction.getNodeRef(), event.getNodeRef());
if (logger.isDebugEnabled())
logger.debug("Removed '" + eventName + "' from next action '" + nextAction.getName() +
logger.debug("Removed '" + eventName + "' from next action '" + nextAction.getName() +
"' (" + nextAction.getNodeRef() + ")");
}
}
// go through the disposition action definition step events and add any new ones
if (stepEvents != null)
{
@@ -298,29 +298,29 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
if (!nextActionEvents.contains(eventName))
{
createEvent(recordsManagementEventService.getEvent(eventName), nextAction.getNodeRef());
if (logger.isDebugEnabled())
{
logger.debug("Added '" + eventName + "' to next action '" + nextAction.getName() +
logger.debug("Added '" + eventName + "' to next action '" + nextAction.getName() +
"' (" + nextAction.getNodeRef() + ")");
}
}
}
}
// NOTE: eventsList contains all the events that have been updated!
// TODO: manually update the search properties for the parent node!
// finally since events may have changed re-calculate the events eligible flag
boolean eligible = updateEventEligible(nextAction);
if (logger.isDebugEnabled())
{
logger.debug("Set events eligible flag to '" + eligible + "' for next action '" + nextAction.getName() +
logger.debug("Set events eligible flag to '" + eligible + "' for next action '" + nextAction.getName() +
"' (" + nextAction.getNodeRef() + ")");
}
}
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{

View File

@@ -18,28 +18,11 @@
*/
package org.alfresco.module.org_alfresco_module_rm.action.impl;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.action.RMDispositionActionExecuterAbstractBase;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.transfer.TransferService;
import org.alfresco.repo.action.executer.ActionExecuter;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.lang.StringUtils;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* Transfer action
@@ -48,25 +31,11 @@ import org.springframework.extensions.surf.util.I18NUtil;
*/
public class TransferAction extends RMDispositionActionExecuterAbstractBase
{
/** Transfer node reference key */
public static final String KEY_TRANSFER_NODEREF = "transferNodeRef";
/** I18N */
private static final String MSG_NODE_ALREADY_TRANSFER = "rm.action.node-already-transfer";
/** Indicates whether the transfer is an accession or not */
private boolean isAccession = false;
/** File plan service */
private FilePlanService filePlanService;
/**
* @param filePlanService file plan service
*/
public void setFilePlanService(FilePlanService filePlanService)
{
this.filePlanService = filePlanService;
}
/** transfer service */
private TransferService transferService;
/**
* Indicates whether this transfer is an accession or not
@@ -78,6 +47,14 @@ public class TransferAction extends RMDispositionActionExecuterAbstractBase
this.isAccession = isAccession;
}
/**
* @param transferService transfer service
*/
public void setTransferService(TransferService transferService)
{
this.transferService = transferService;
}
/**
* Do not set the transfer action to auto-complete
*
@@ -110,102 +87,14 @@ public class TransferAction extends RMDispositionActionExecuterAbstractBase
/**
* Create the transfer node and link the disposition lifecycle node beneath it
*
* @param dispositionLifeCycleNodeRef disposition lifecycle node
* @param action action
* @param dispositionLifeCycleNodeRef disposition lifecycle node
*/
private void doTransfer(Action action, NodeRef dispositionLifeCycleNodeRef)
{
// Get the root rm node
NodeRef root = filePlanService.getFilePlan(dispositionLifeCycleNodeRef);
// Get the transfer object
NodeRef transferNodeRef = (NodeRef)AlfrescoTransactionSupport.getResource(KEY_TRANSFER_NODEREF);
if (transferNodeRef == null)
{
// Calculate a transfer name
QName nodeDbid = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "node-dbid");
Long dbId = (Long)this.nodeService.getProperty(dispositionLifeCycleNodeRef, nodeDbid);
String transferName = StringUtils.leftPad(dbId.toString(), 10, "0");
// Create the transfer object
Map<QName, Serializable> transferProps = new HashMap<QName, Serializable>(2);
transferProps.put(ContentModel.PROP_NAME, transferName);
transferProps.put(PROP_TRANSFER_ACCESSION_INDICATOR, this.isAccession);
// setup location property from disposition schedule
DispositionAction da = dispositionService.getNextDispositionAction(dispositionLifeCycleNodeRef);
if (da != null)
{
DispositionActionDefinition actionDef = da.getDispositionActionDefinition();
if (actionDef != null)
{
transferProps.put(PROP_TRANSFER_LOCATION, actionDef.getLocation());
}
}
NodeRef transferContainer = filePlanService.getTransferContainer(root);
transferNodeRef = this.nodeService.createNode(transferContainer,
ContentModel.ASSOC_CONTAINS,
QName.createQName(RM_URI, transferName),
TYPE_TRANSFER,
transferProps).getChildRef();
// Bind the hold node reference to the transaction
AlfrescoTransactionSupport.bindResource(KEY_TRANSFER_NODEREF, transferNodeRef);
}
else
{
// ensure this node has not already in the process of being transferred
List<ChildAssociationRef> transferredAlready = nodeService.getChildAssocs(transferNodeRef, ASSOC_TRANSFERRED, ASSOC_TRANSFERRED);
for(ChildAssociationRef car : transferredAlready)
{
if(car.getChildRef().equals(dispositionLifeCycleNodeRef) == true)
{
throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NODE_ALREADY_TRANSFER, dispositionLifeCycleNodeRef.toString()));
}
}
}
// Link the record to the trasnfer object
this.nodeService.addChild(transferNodeRef,
dispositionLifeCycleNodeRef,
ASSOC_TRANSFERRED,
ASSOC_TRANSFERRED);
// Set PDF indicator flag
setPDFIndicationFlag(transferNodeRef, dispositionLifeCycleNodeRef);
// Set the transferring indicator aspect
nodeService.addAspect(dispositionLifeCycleNodeRef, ASPECT_TRANSFERRING, null);
NodeRef transferNodeRef = transferService.transfer(dispositionLifeCycleNodeRef, isAccession);
// Set the return value of the action
action.setParameterValue(ActionExecuter.PARAM_RESULT, transferNodeRef);
}
/**
*
* @param transferNodeRef
* @param dispositionLifeCycleNodeRef
*/
private void setPDFIndicationFlag(NodeRef transferNodeRef, NodeRef dispositionLifeCycleNodeRef)
{
if (recordFolderService.isRecordFolder(dispositionLifeCycleNodeRef) == true)
{
List<NodeRef> records = recordService.getRecords(dispositionLifeCycleNodeRef);
for (NodeRef record : records)
{
setPDFIndicationFlag(transferNodeRef, record);
}
}
else
{
ContentData contentData = (ContentData)nodeService.getProperty(dispositionLifeCycleNodeRef, ContentModel.PROP_CONTENT);
if (contentData != null &&
MimetypeMap.MIMETYPE_PDF.equals(contentData.getMimetype()) == true)
{
// Set the property indicator
nodeService.setProperty(transferNodeRef, PROP_TRANSFER_PDF_INDICATOR, true);
}
}
}
}

View File

@@ -18,19 +18,12 @@
*/
package org.alfresco.module.org_alfresco_module_rm.action.impl;
import java.util.Date;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.module.org_alfresco_module_rm.transfer.TransferService;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.springframework.extensions.surf.util.I18NUtil;
/**
@@ -43,6 +36,17 @@ public class TransferCompleteAction extends RMActionExecuterAbstractBase
/** I18N */
private static final String MSG_NODE_NOT_TRANSFER = "rm.action.node-not-transfer";
/** Transfer service */
protected TransferService transferService;
/**
* @param transferService transfer service
*/
public void setTransferService(TransferService transferService)
{
this.transferService = transferService;
}
/**
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action,
* org.alfresco.service.cmr.repository.NodeRef)
@@ -50,80 +54,21 @@ public class TransferCompleteAction extends RMActionExecuterAbstractBase
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
QName className = this.nodeService.getType(actionedUponNodeRef);
if (this.dictionaryService.isSubClass(className, TYPE_TRANSFER) == true)
{
boolean accessionIndicator = ((Boolean)nodeService.getProperty(actionedUponNodeRef, PROP_TRANSFER_ACCESSION_INDICATOR)).booleanValue();
String transferLocation = nodeService.getProperty(actionedUponNodeRef, PROP_TRANSFER_LOCATION).toString();
checkTransferSubClass(actionedUponNodeRef);
transferService.complete(actionedUponNodeRef);
}
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(actionedUponNodeRef, ASSOC_TRANSFERRED, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs)
{
markComplete(assoc.getChildRef(), accessionIndicator, transferLocation);
}
// Delete the transfer object
this.nodeService.deleteNode(actionedUponNodeRef);
NodeRef transferNodeRef = (NodeRef) AlfrescoTransactionSupport.getResource(TransferAction.KEY_TRANSFER_NODEREF);
if (transferNodeRef != null)
{
if (transferNodeRef.equals(actionedUponNodeRef))
{
AlfrescoTransactionSupport.bindResource(TransferAction.KEY_TRANSFER_NODEREF, null);
}
}
}
else
/**
* Checks if the actioned upon node reference is a sub class of transfer
*
* @param actionedUponNodeRef actioned upon node reference
*/
private void checkTransferSubClass(NodeRef actionedUponNodeRef)
{
QName type = nodeService.getType(actionedUponNodeRef);
if (dictionaryService.isSubClass(type, TYPE_TRANSFER) == false)
{
throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NODE_NOT_TRANSFER));
}
}
/**
* Marks the node complete
*
* @param nodeRef
* disposition lifecycle node reference
*/
private void markComplete(NodeRef nodeRef, boolean accessionIndicator, String transferLocation)
{
// Set the completed date
DispositionAction da = dispositionService.getNextDispositionAction(nodeRef);
if (da != null)
{
nodeService.setProperty(da.getNodeRef(), PROP_DISPOSITION_ACTION_COMPLETED_AT, new Date());
nodeService.setProperty(da.getNodeRef(), PROP_DISPOSITION_ACTION_COMPLETED_BY, AuthenticationUtil.getRunAsUser());
}
// Remove the transferring indicator aspect
nodeService.removeAspect(nodeRef, ASPECT_TRANSFERRING);
nodeService.setProperty(nodeRef, PROP_LOCATION, transferLocation);
// Determine which marker aspect to use
QName markerAspectQName = null;
if (accessionIndicator == true)
{
markerAspectQName = ASPECT_ASCENDED;
}
else
{
markerAspectQName = ASPECT_TRANSFERRED;
}
// Mark the object and children accordingly
nodeService.addAspect(nodeRef, markerAspectQName, null);
if (recordFolderService.isRecordFolder(nodeRef) == true)
{
List<NodeRef> records = recordService.getRecords(nodeRef);
for (NodeRef record : records)
{
nodeService.addAspect(record, markerAspectQName, null);
nodeService.setProperty(record, PROP_LOCATION, transferLocation);
}
}
// Update to the next disposition action
updateNextDispositionAction(nodeRef);
}
}

View File

@@ -209,4 +209,11 @@ public interface DispositionService
* @since 2.0
*/
boolean isCutoff(NodeRef nodeRef);
/**
* Updates the next disposition action
*
* @param nodeRef node reference
*/
void updateNextDispositionAction(NodeRef nodeRef);
}

View File

@@ -845,4 +845,128 @@ public class DispositionServiceImpl implements
ParameterCheck.mandatory("nodeRef", nodeRef);
return nodeService.hasAspect(nodeRef, ASPECT_CUT_OFF);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#updateNextDispositionAction(NodeRef)
*/
@Override
public void updateNextDispositionAction(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
// Get this disposition instructions for the node
DispositionSchedule di = getDispositionSchedule(nodeRef);
if (di != null)
{
// Get the current action node
NodeRef currentDispositionAction = null;
if (nodeService.hasAspect(nodeRef, ASPECT_DISPOSITION_LIFECYCLE) == true)
{
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ASSOC_NEXT_DISPOSITION_ACTION, RegexQNamePattern.MATCH_ALL);
if (assocs.size() > 0)
{
currentDispositionAction = assocs.get(0).getChildRef();
}
}
if (currentDispositionAction != null)
{
// Move it to the history association
nodeService.moveNode(currentDispositionAction, nodeRef, ASSOC_DISPOSITION_ACTION_HISTORY, ASSOC_DISPOSITION_ACTION_HISTORY);
}
List<DispositionActionDefinition> dispositionActionDefinitions = di.getDispositionActionDefinitions();
DispositionActionDefinition currentDispositionActionDefinition = null;
DispositionActionDefinition nextDispositionActionDefinition = null;
if (currentDispositionAction == null)
{
if (dispositionActionDefinitions.isEmpty() == false)
{
// The next disposition action is the first action
nextDispositionActionDefinition = dispositionActionDefinitions.get(0);
}
}
else
{
// Get the current action
String currentADId = (String) nodeService.getProperty(currentDispositionAction, PROP_DISPOSITION_ACTION_ID);
currentDispositionActionDefinition = di.getDispositionActionDefinition(currentADId);
// Get the next disposition action
int index = currentDispositionActionDefinition.getIndex();
index++;
if (index < dispositionActionDefinitions.size())
{
nextDispositionActionDefinition = dispositionActionDefinitions.get(index);
}
}
if (nextDispositionActionDefinition != null)
{
if (nodeService.hasAspect(nodeRef, ASPECT_DISPOSITION_LIFECYCLE) == false)
{
// Add the disposition life cycle aspect
nodeService.addAspect(nodeRef, ASPECT_DISPOSITION_LIFECYCLE, null);
}
// Create the properties
Map<QName, Serializable> props = new HashMap<QName, Serializable>(10);
// Calculate the asOf date
Date asOfDate = null;
Period period = nextDispositionActionDefinition.getPeriod();
if (period != null)
{
Date contextDate = null;
// Get the period properties value
QName periodProperty = nextDispositionActionDefinition.getPeriodProperty();
if (periodProperty != null &&
RecordsManagementModel.PROP_DISPOSITION_AS_OF.equals(periodProperty) == false)
{
// doesn't matter if the period property isn't set ... the asOfDate will get updated later
// when the value of the period property is set
contextDate = (Date) nodeService.getProperty(nodeRef, periodProperty);
}
else
{
// for now use 'NOW' as the default context date
// TODO set the default period property ... cut off date or last disposition date depending on context
contextDate = new Date();
}
// Calculate the as of date
if (contextDate != null)
{
asOfDate = period.getNextDate(contextDate);
}
}
// Set the property values
props.put(PROP_DISPOSITION_ACTION_ID, nextDispositionActionDefinition.getId());
props.put(PROP_DISPOSITION_ACTION, nextDispositionActionDefinition.getName());
if (asOfDate != null)
{
props.put(PROP_DISPOSITION_AS_OF, asOfDate);
}
// Create a new disposition action object
NodeRef dispositionActionNodeRef = nodeService.createNode(
nodeRef,
ASSOC_NEXT_DISPOSITION_ACTION,
ASSOC_NEXT_DISPOSITION_ACTION,
TYPE_DISPOSITION_ACTION,
props).getChildRef();
// Create the events
List<RecordsManagementEvent> events = nextDispositionActionDefinition.getEvents();
for (RecordsManagementEvent event : events)
{
// For every event create an entry on the action
createEvent(event, dispositionActionNodeRef);
}
}
}
}
}

View File

@@ -37,4 +37,24 @@ public interface TransferService
* @since 2.0
*/
boolean isTransfer(NodeRef nodeRef);
/**
* Create the transfer node and link the disposition lifecycle node beneath it
*
* @param nodeRef node reference to transfer
* @param isAccession Indicates whether this transfer is an accession or not
* @return Returns the transfer object node reference
*
* @since 2.2
*/
NodeRef transfer(NodeRef nodeRef, boolean isAccession);
/**
* Completes the transfer for the given node.
*
* @param nodeRef node reference to complete the transfer
*
* @since 2.2
*/
void complete(NodeRef nodeRef);
}

View File

@@ -18,9 +18,33 @@
*/
package org.alfresco.module.org_alfresco_module_rm.transfer;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.lang.StringUtils;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
@@ -31,6 +55,56 @@ import org.springframework.extensions.surf.util.ParameterCheck;
*/
public class TransferServiceImpl extends ServiceBaseImpl implements TransferService, RecordsManagementModel
{
/** Transfer node reference key */
public static final String KEY_TRANSFER_NODEREF = "transferNodeRef";
/** I18N */
private static final String MSG_NODE_ALREADY_TRANSFER = "rm.action.node-already-transfer";
/** File Plan Service */
protected FilePlanService filePlanService;
/** Disposition service */
protected DispositionService dispositionService;
/** Record service */
protected RecordService recordService;
/** Record folder service */
protected RecordFolderService recordFolderService;
/**
* @param filePlanService file plan service
*/
public void setFilePlanService(FilePlanService filePlanService)
{
this.filePlanService = filePlanService;
}
/**
* @param dispositionService disposition service
*/
public void setDispositionService(DispositionService dispositionService)
{
this.dispositionService = dispositionService;
}
/**
* @param recordService record service
*/
public void setRecordService(RecordService recordService)
{
this.recordService = recordService;
}
/**
* @param recordFolderService record folder service
*/
public void setRecordFolderService(RecordFolderService recordFolderService)
{
this.recordFolderService = recordFolderService;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#isTransfer(NodeRef)
*/
@@ -40,4 +114,181 @@ public class TransferServiceImpl extends ServiceBaseImpl implements TransferServ
ParameterCheck.mandatory("nodeRef", nodeRef);
return instanceOf(nodeRef, TYPE_TRANSFER);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#transfer(NodeRef, boolean)
*/
@Override
public NodeRef transfer(NodeRef nodeRef, boolean isAccession)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
// Get the root rm node
NodeRef root = filePlanService.getFilePlan(nodeRef);
// Get the transfer object
NodeRef transferNodeRef = (NodeRef)AlfrescoTransactionSupport.getResource(KEY_TRANSFER_NODEREF);
if (transferNodeRef == null)
{
// Calculate a transfer name
QName nodeDbid = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "node-dbid");
Long dbId = (Long) nodeService.getProperty(nodeRef, nodeDbid);
String transferName = StringUtils.leftPad(dbId.toString(), 10, "0");
// Create the transfer object
Map<QName, Serializable> transferProps = new HashMap<QName, Serializable>(2);
transferProps.put(ContentModel.PROP_NAME, transferName);
transferProps.put(PROP_TRANSFER_ACCESSION_INDICATOR, isAccession);
// setup location property from disposition schedule
DispositionAction da = dispositionService.getNextDispositionAction(nodeRef);
if (da != null)
{
DispositionActionDefinition actionDef = da.getDispositionActionDefinition();
if (actionDef != null)
{
transferProps.put(PROP_TRANSFER_LOCATION, actionDef.getLocation());
}
}
NodeRef transferContainer = filePlanService.getTransferContainer(root);
transferNodeRef = nodeService.createNode(transferContainer,
ContentModel.ASSOC_CONTAINS,
QName.createQName(RM_URI, transferName),
TYPE_TRANSFER,
transferProps).getChildRef();
// Bind the hold node reference to the transaction
AlfrescoTransactionSupport.bindResource(KEY_TRANSFER_NODEREF, transferNodeRef);
}
else
{
// ensure this node has not already in the process of being transferred
List<ChildAssociationRef> transferredAlready = nodeService.getChildAssocs(transferNodeRef, ASSOC_TRANSFERRED, ASSOC_TRANSFERRED);
for(ChildAssociationRef car : transferredAlready)
{
if(car.getChildRef().equals(nodeRef) == true)
{
throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NODE_ALREADY_TRANSFER, nodeRef.toString()));
}
}
}
// Link the record to the trasnfer object
nodeService.addChild(transferNodeRef,
nodeRef,
ASSOC_TRANSFERRED,
ASSOC_TRANSFERRED);
// Set PDF indicator flag
setPDFIndicationFlag(transferNodeRef, nodeRef);
// Set the transferring indicator aspect
nodeService.addAspect(nodeRef, ASPECT_TRANSFERRING, null);
return transferNodeRef;
}
/**
*
* @param transferNodeRef
* @param dispositionLifeCycleNodeRef
*/
private void setPDFIndicationFlag(NodeRef transferNodeRef, NodeRef dispositionLifeCycleNodeRef)
{
if (recordFolderService.isRecordFolder(dispositionLifeCycleNodeRef) == true)
{
List<NodeRef> records = recordService.getRecords(dispositionLifeCycleNodeRef);
for (NodeRef record : records)
{
setPDFIndicationFlag(transferNodeRef, record);
}
}
else
{
ContentData contentData = (ContentData)nodeService.getProperty(dispositionLifeCycleNodeRef, ContentModel.PROP_CONTENT);
if (contentData != null &&
MimetypeMap.MIMETYPE_PDF.equals(contentData.getMimetype()) == true)
{
// Set the property indicator
nodeService.setProperty(transferNodeRef, PROP_TRANSFER_PDF_INDICATOR, true);
}
}
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#complete(NodeRef)
*/
@Override
public void complete(NodeRef nodeRef)
{
boolean accessionIndicator = ((Boolean)nodeService.getProperty(nodeRef, PROP_TRANSFER_ACCESSION_INDICATOR)).booleanValue();
String transferLocation = nodeService.getProperty(nodeRef, PROP_TRANSFER_LOCATION).toString();
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ASSOC_TRANSFERRED, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs)
{
markComplete(assoc.getChildRef(), accessionIndicator, transferLocation);
}
// Delete the transfer object
nodeService.deleteNode(nodeRef);
NodeRef transferNodeRef = (NodeRef) AlfrescoTransactionSupport.getResource(KEY_TRANSFER_NODEREF);
if (transferNodeRef != null)
{
if (transferNodeRef.equals(nodeRef))
{
AlfrescoTransactionSupport.bindResource(KEY_TRANSFER_NODEREF, null);
}
}
}
/**
* Marks the node complete
*
* @param nodeRef
* disposition lifecycle node reference
*/
private void markComplete(NodeRef nodeRef, boolean accessionIndicator, String transferLocation)
{
// Set the completed date
DispositionAction da = dispositionService.getNextDispositionAction(nodeRef);
if (da != null)
{
nodeService.setProperty(da.getNodeRef(), PROP_DISPOSITION_ACTION_COMPLETED_AT, new Date());
nodeService.setProperty(da.getNodeRef(), PROP_DISPOSITION_ACTION_COMPLETED_BY, AuthenticationUtil.getRunAsUser());
}
// Remove the transferring indicator aspect
nodeService.removeAspect(nodeRef, ASPECT_TRANSFERRING);
nodeService.setProperty(nodeRef, PROP_LOCATION, transferLocation);
// Determine which marker aspect to use
QName markerAspectQName = null;
if (accessionIndicator == true)
{
markerAspectQName = ASPECT_ASCENDED;
}
else
{
markerAspectQName = ASPECT_TRANSFERRED;
}
// Mark the object and children accordingly
nodeService.addAspect(nodeRef, markerAspectQName, null);
if (recordFolderService.isRecordFolder(nodeRef) == true)
{
List<NodeRef> records = recordService.getRecords(nodeRef);
for (NodeRef record : records)
{
nodeService.addAspect(record, markerAspectQName, null);
nodeService.setProperty(record, PROP_LOCATION, transferLocation);
}
}
// Update to the next disposition action
dispositionService.updateNextDispositionAction(nodeRef);
}
}