mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
RM-1445m Implemented link-to rule. Also fixed RM-1466 and RM-1470 while refactoring common code
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@68076 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -19,6 +19,8 @@ import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -27,13 +29,16 @@ import org.springframework.util.StringUtils;
|
||||
* @author Mark Hibbins
|
||||
* @since 2.2
|
||||
*/
|
||||
public abstract class CopyMoveFileToBaseAction extends RMActionExecuterAbstractBase
|
||||
public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstractBase
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(CopyMoveLinkFileToBaseAction.class);
|
||||
|
||||
/** action parameters */
|
||||
public static final String PARAM_DESTINATION_RECORD_FOLDER = "destinationRecordFolder";
|
||||
public static final String PARAM_PATH = "path";
|
||||
public static final String PARAM_CREATE_RECORD_PATH = "createRecordPath";
|
||||
public static final String ACTION_FILETO = "fileTo";
|
||||
public static final String ACTION_LINKTO = "linkTo";
|
||||
|
||||
/** file folder service */
|
||||
private FileFolderService fileFolderService;
|
||||
@@ -42,11 +47,11 @@ public abstract class CopyMoveFileToBaseAction extends RMActionExecuterAbstractB
|
||||
private FilePlanService filePlanService;
|
||||
|
||||
/** action modes */
|
||||
public enum CopyMoveFileToActionMode
|
||||
public enum CopyMoveLinkFileToActionMode
|
||||
{
|
||||
COPY, MOVE
|
||||
COPY, MOVE, LINK
|
||||
};
|
||||
protected CopyMoveFileToActionMode mode;
|
||||
protected CopyMoveLinkFileToActionMode mode;
|
||||
|
||||
/**
|
||||
* @param fileFolderService file folder service
|
||||
@@ -80,22 +85,20 @@ public abstract class CopyMoveFileToBaseAction extends RMActionExecuterAbstractB
|
||||
@Override
|
||||
protected void executeImpl(final Action action, final NodeRef actionedUponNodeRef)
|
||||
{
|
||||
if (nodeService.exists(actionedUponNodeRef) &&
|
||||
(freezeService.isFrozen(actionedUponNodeRef) == false) &&
|
||||
(!ACTION_FILETO.equals(action.getActionDefinitionName()) || !recordService.isFiled(actionedUponNodeRef)) &&
|
||||
(!(ACTION_FILETO.equals(action.getActionDefinitionName()) && RecordsManagementModel.TYPE_UNFILED_RECORD_CONTAINER.equals(nodeService.getType(actionedUponNodeRef)))))
|
||||
String actionName = action.getActionDefinitionName();
|
||||
if (isOkToProceedWithAction(actionedUponNodeRef, actionName))
|
||||
{
|
||||
boolean targetIsUnfiledRecord;
|
||||
QName actionedUponType = nodeService.getType(actionedUponNodeRef);;
|
||||
|
||||
boolean targetIsUnfiledRecords;
|
||||
if (ACTION_FILETO.equals(action.getActionDefinitionName()))
|
||||
{
|
||||
targetIsUnfiledRecord = false;
|
||||
targetIsUnfiledRecords = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
QName actionedUponType = nodeService.getType(actionedUponNodeRef);
|
||||
targetIsUnfiledRecord = (dictionaryService.isSubClass(actionedUponType, ContentModel.TYPE_CONTENT) && !recordService
|
||||
.isFiled(actionedUponNodeRef))
|
||||
|| RecordsManagementModel.TYPE_UNFILED_RECORD_FOLDER.equals(actionedUponType);
|
||||
targetIsUnfiledRecords = (dictionaryService.isSubClass(actionedUponType, ContentModel.TYPE_CONTENT) && !recordService.isFiled(actionedUponNodeRef))
|
||||
|| TYPE_UNFILED_RECORD_FOLDER.equals(actionedUponType);
|
||||
}
|
||||
|
||||
// first look to see if the destination record folder has been specified
|
||||
@@ -103,13 +106,11 @@ public abstract class CopyMoveFileToBaseAction extends RMActionExecuterAbstractB
|
||||
if (recordFolder == null)
|
||||
{
|
||||
// get the reference to the record folder based on the relative path
|
||||
recordFolder = createOrResolvePath(action, actionedUponNodeRef, targetIsUnfiledRecord);
|
||||
recordFolder = createOrResolvePath(action, actionedUponNodeRef, targetIsUnfiledRecords);
|
||||
}
|
||||
|
||||
if (recordFolder == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Unable to execute file to action, because the destination record folder could not be determined.");
|
||||
}
|
||||
// now we have the reference to the target folder we can do some final checks to see if the action is valid
|
||||
validateActionPostPathResolution(actionedUponNodeRef, recordFolder, actionName, targetIsUnfiledRecords);
|
||||
|
||||
final NodeRef finalRecordFolder = recordFolder;
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
@@ -119,19 +120,23 @@ public abstract class CopyMoveFileToBaseAction extends RMActionExecuterAbstractB
|
||||
{
|
||||
try
|
||||
{
|
||||
if(mode == CopyMoveFileToActionMode.MOVE)
|
||||
if(mode == CopyMoveLinkFileToActionMode.MOVE)
|
||||
{
|
||||
fileFolderService.move(actionedUponNodeRef, finalRecordFolder, null);
|
||||
}
|
||||
else
|
||||
else if(mode == CopyMoveLinkFileToActionMode.COPY)
|
||||
{
|
||||
fileFolderService.copy(actionedUponNodeRef, finalRecordFolder, null);
|
||||
}
|
||||
else if(mode == CopyMoveLinkFileToActionMode.LINK)
|
||||
{
|
||||
recordService.link(actionedUponNodeRef, finalRecordFolder);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException fileNotFound)
|
||||
{
|
||||
throw new AlfrescoRuntimeException(
|
||||
"Unable to execute file to action, because the " + (mode == CopyMoveFileToActionMode.MOVE ? "move" : "copy") + " operation failed.",
|
||||
"Unable to execute file to action, because the " + (mode == CopyMoveLinkFileToActionMode.MOVE ? "move" : "copy") + " operation failed.",
|
||||
fileNotFound
|
||||
);
|
||||
}
|
||||
@@ -142,6 +147,83 @@ public abstract class CopyMoveFileToBaseAction extends RMActionExecuterAbstractB
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the passed parameters to the action are valid for the given action
|
||||
*
|
||||
* @param actionedUponNodeRef
|
||||
* @param actionName
|
||||
* @return
|
||||
*/
|
||||
private boolean isOkToProceedWithAction(NodeRef actionedUponNodeRef, String actionName)
|
||||
{
|
||||
// Check that the incoming parameters are valid prior to performing any action
|
||||
boolean okToProceed = false;
|
||||
if(nodeService.exists(actionedUponNodeRef) && !freezeService.isFrozen(actionedUponNodeRef))
|
||||
{
|
||||
QName actionedUponType = nodeService.getType(actionedUponNodeRef);
|
||||
if(ACTION_FILETO.equals(actionName))
|
||||
{
|
||||
// file to action can only be performed on unfiled records
|
||||
okToProceed = !recordService.isFiled(actionedUponNodeRef) && dictionaryService.isSubClass(actionedUponType, ContentModel.TYPE_CONTENT);
|
||||
if(!okToProceed && logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Unable to run " + actionName + " action on a node that isn't unfiled and a sub-class of content type");
|
||||
}
|
||||
}
|
||||
else if(ACTION_LINKTO.equals(actionName))
|
||||
{
|
||||
// link to action can only be performed on filed records
|
||||
okToProceed = recordService.isFiled(actionedUponNodeRef) && dictionaryService.isSubClass(actionedUponType, ContentModel.TYPE_CONTENT);
|
||||
if(!okToProceed && logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Unable to run " + actionName + " action on a node that isn't filed and a sub-class of content type");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
okToProceed = true;
|
||||
}
|
||||
}
|
||||
return okToProceed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a final validation for the parameters and the resolve target path
|
||||
*
|
||||
* @param actionedUponNodeRef
|
||||
* @param target
|
||||
* @param actionName
|
||||
* @param targetIsUnfiledRecords
|
||||
*/
|
||||
private void validateActionPostPathResolution(NodeRef actionedUponNodeRef, NodeRef target, String actionName, boolean targetIsUnfiledRecords)
|
||||
{
|
||||
QName actionedUponType = nodeService.getType(actionedUponNodeRef);
|
||||
// now we have the reference to the target folder we can do some final checks to see if the action is valid
|
||||
if (target == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Unable to run " + actionName + " action, because the destination record folder could not be determined.");
|
||||
}
|
||||
if(targetIsUnfiledRecords)
|
||||
{
|
||||
QName targetFolderType = nodeService.getType(target);
|
||||
if(!TYPE_UNFILED_RECORD_CONTAINER.equals(targetFolderType) && !TYPE_UNFILED_RECORD_FOLDER.equals(targetFolderType))
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Unable to run " + actionName + " action, because the destination record folder is an inappropriate type.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(recordFolderService.isRecordFolder(target) && !dictionaryService.isSubClass(actionedUponType, ContentModel.TYPE_CONTENT) && (recordFolderService.isRecordFolder(actionedUponNodeRef) || filePlanService.isRecordCategory(actionedUponNodeRef)))
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Unable to run " + actionName + " action, because the destination record folder is an inappropriate type. A record folder cannot contain another folder or a category");
|
||||
}
|
||||
else if(filePlanService.isRecordCategory(target) && dictionaryService.isSubClass(actionedUponType, ContentModel.TYPE_CONTENT))
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Unable to run " + actionName + " action, because the destination record folder is an inappropriate type. A record category cannot contain a record");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or resolve the path specified in the action's path parameter
|
||||
*
|
||||
@@ -197,12 +279,8 @@ public abstract class CopyMoveFileToBaseAction extends RMActionExecuterAbstractB
|
||||
if(create)
|
||||
{
|
||||
creating = true;
|
||||
nodeRef = createChild(
|
||||
action,
|
||||
parent,
|
||||
childName,
|
||||
targetisUnfiledRecords,
|
||||
lastPathElement && (ContentModel.TYPE_CONTENT.equals(nodeService.getType(actionedUponNodeRef)) || RecordsManagementModel.TYPE_NON_ELECTRONIC_DOCUMENT.equals(nodeService.getType(actionedUponNodeRef))));
|
||||
boolean lastAsFolder = lastPathElement && (ContentModel.TYPE_CONTENT.equals(nodeService.getType(actionedUponNodeRef)) || RecordsManagementModel.TYPE_NON_ELECTRONIC_DOCUMENT.equals(nodeService.getType(actionedUponNodeRef)));
|
||||
nodeRef = createChild(action, parent, childName, targetisUnfiledRecords, lastAsFolder);
|
||||
}
|
||||
else
|
||||
{
|
@@ -7,7 +7,7 @@ package org.alfresco.module.org_alfresco_module_rm.action.impl;
|
||||
* @author Mark Hibbins
|
||||
* @since 2.2
|
||||
*/
|
||||
public class CopyToAction extends CopyMoveFileToBaseAction
|
||||
public class CopyToAction extends CopyMoveLinkFileToBaseAction
|
||||
{
|
||||
/** action name */
|
||||
public static final String NAME = "copyTo";
|
||||
@@ -16,6 +16,6 @@ public class CopyToAction extends CopyMoveFileToBaseAction
|
||||
public void init()
|
||||
{
|
||||
super.init();
|
||||
this.mode = CopyMoveFileToActionMode.COPY;
|
||||
this.mode = CopyMoveLinkFileToActionMode.COPY;
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ package org.alfresco.module.org_alfresco_module_rm.action.impl;
|
||||
* @author Roy Wetherall
|
||||
* @since 2.1
|
||||
*/
|
||||
public class FileToAction extends CopyMoveFileToBaseAction
|
||||
public class FileToAction extends CopyMoveLinkFileToBaseAction
|
||||
{
|
||||
/** action name */
|
||||
public static final String NAME = "fileTo";
|
||||
@@ -16,6 +16,6 @@ public class FileToAction extends CopyMoveFileToBaseAction
|
||||
public void init()
|
||||
{
|
||||
super.init();
|
||||
this.mode = CopyMoveFileToActionMode.MOVE;
|
||||
this.mode = CopyMoveLinkFileToActionMode.MOVE;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,21 @@
|
||||
package org.alfresco.module.org_alfresco_module_rm.action.impl;
|
||||
|
||||
|
||||
/**
|
||||
* Link To action implementation.
|
||||
*
|
||||
* @author Mark Hibbins
|
||||
* @since 2.2
|
||||
*/
|
||||
public class LinkToAction extends CopyMoveLinkFileToBaseAction
|
||||
{
|
||||
/** action name */
|
||||
public static final String NAME = "linkTo";
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
super.init();
|
||||
this.mode = CopyMoveLinkFileToActionMode.LINK;
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ package org.alfresco.module.org_alfresco_module_rm.action.impl;
|
||||
* @author Mark Hibbins
|
||||
* @since 2.2
|
||||
*/
|
||||
public class MoveToAction extends CopyMoveFileToBaseAction
|
||||
public class MoveToAction extends CopyMoveLinkFileToBaseAction
|
||||
{
|
||||
/** action name */
|
||||
public static final String NAME = "moveTo";
|
||||
@@ -16,6 +16,6 @@ public class MoveToAction extends CopyMoveFileToBaseAction
|
||||
public void init()
|
||||
{
|
||||
super.init();
|
||||
this.mode = CopyMoveFileToActionMode.MOVE;
|
||||
this.mode = CopyMoveLinkFileToActionMode.MOVE;
|
||||
}
|
||||
}
|
@@ -39,19 +39,19 @@ public interface RecordService
|
||||
/**
|
||||
* Register a record metadata aspect.
|
||||
* <p>
|
||||
* The file plan type indicates which file plan type the aspect applied to. Null indicates that
|
||||
* The file plan type indicates which file plan type the aspect applied to. Null indicates that
|
||||
* the aspect applies to rma:filePlan.
|
||||
* <p>
|
||||
* A record metadata aspect can be registered more than once if it applies to more than one
|
||||
* A record metadata aspect can be registered more than once if it applies to more than one
|
||||
* file plan type.
|
||||
*
|
||||
*
|
||||
* @param recordMetadataAspect record metadata aspect qualified name
|
||||
* @param filePlanType file plan type
|
||||
*
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
void registerRecordMetadataAspect(QName recordMetadataAspect, QName filePlanType);
|
||||
|
||||
|
||||
/**
|
||||
* Disables the property editable check.
|
||||
*/
|
||||
@@ -66,35 +66,35 @@ public interface RecordService
|
||||
* Gets a list of all the record meta-data aspects
|
||||
*
|
||||
* @return {@link Set}<{@link QName}> list of record meta-data aspects
|
||||
*
|
||||
*
|
||||
* @deprecated since 2.2, file plan component required to provide context
|
||||
*/
|
||||
@Deprecated
|
||||
Set<QName> getRecordMetaDataAspects();
|
||||
|
||||
|
||||
/**
|
||||
* Gets a list of all the record metadata aspects relevant to the file plan type of the
|
||||
* file plan component provided.
|
||||
* <p>
|
||||
* If a null context is provided all record meta-data aspects are returned, but this is not
|
||||
* If a null context is provided all record meta-data aspects are returned, but this is not
|
||||
* recommended.
|
||||
*
|
||||
* @param nodeRef node reference to file plan component providing context
|
||||
* @return {@link Set}<{@link QName}> list of record meta-data aspects
|
||||
*
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
Set<QName> getRecordMetadataAspects(NodeRef nodeRef);
|
||||
|
||||
|
||||
/**
|
||||
* Gets a list of all the record metadata aspect that relate to the provided file plan type.
|
||||
* <p>
|
||||
* If null is provided for the file plan type then record metadata aspects for the default
|
||||
* If null is provided for the file plan type then record metadata aspects for the default
|
||||
* file plan type (rma:filePlan) are returned.
|
||||
*
|
||||
*
|
||||
* @param filePlanType file plan type
|
||||
* @return{@link Set}<{@link QName}> list of record meta-data aspects
|
||||
*
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
Set<QName> getRecordMetadataAspects(QName filePlanType);
|
||||
@@ -214,4 +214,12 @@ public interface RecordService
|
||||
* @param nodeRef The document node reference from which a record will be created
|
||||
*/
|
||||
void makeRecord(NodeRef nodeRef);
|
||||
|
||||
/**
|
||||
* Creates a link for the specified document in target
|
||||
*
|
||||
* @param nodeRef The document node reference for which a link will be created
|
||||
* @param folder The folder in which the link will be created
|
||||
*/
|
||||
void link(NodeRef nodeRef, NodeRef folder);
|
||||
}
|
||||
|
@@ -635,7 +635,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
if (getRecordMetadataAspectsMap().containsKey(recordMetadataAspect))
|
||||
{
|
||||
// get the current set of file plan types for this aspect
|
||||
filePlanTypes = (Set<QName>)getRecordMetadataAspectsMap().get(recordMetadataAspect);
|
||||
filePlanTypes = getRecordMetadataAspectsMap().get(recordMetadataAspect);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -717,6 +717,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createRecord(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, boolean)
|
||||
*/
|
||||
@Override
|
||||
public void createRecord(final NodeRef filePlan, final NodeRef nodeRef, final boolean isLinked)
|
||||
{
|
||||
ParameterCheck.mandatory("filePlan", filePlan);
|
||||
@@ -773,7 +774,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
|
||||
// save the information about the originating details
|
||||
Map<QName, Serializable> aspectProperties = new HashMap<QName, Serializable>(3);
|
||||
aspectProperties.put(PROP_RECORD_ORIGINATING_LOCATION, (Serializable) parentAssoc.getParentRef());
|
||||
aspectProperties.put(PROP_RECORD_ORIGINATING_LOCATION, parentAssoc.getParentRef());
|
||||
aspectProperties.put(PROP_RECORD_ORIGINATING_USER_ID, userId);
|
||||
aspectProperties.put(PROP_RECORD_ORIGINATING_CREATION_DATE, new Date());
|
||||
nodeService.addAspect(nodeRef, ASPECT_RECORD_ORIGINATING_DETAILS, aspectProperties);
|
||||
@@ -1391,4 +1392,19 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
logger.info(I18NUtil.getMessage(MSG_NODE_HAS_ASPECT, nodeRef.toString(), typeQName.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#link(NodeRef, NodeRef)
|
||||
*/
|
||||
@Override
|
||||
public void link(NodeRef nodeRef, NodeRef folder)
|
||||
{
|
||||
ParameterCheck.mandatory("nodeRef", nodeRef);
|
||||
ParameterCheck.mandatory("folder", folder);
|
||||
|
||||
if(isRecord(nodeRef) && isRecordFolder(folder))
|
||||
{
|
||||
nodeService.addChild(folder, nodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, nodeService.getProperty(nodeRef, ContentModel.PROP_NAME).toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user