diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 5010836d9d..1fff44ff5a 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -470,6 +470,9 @@ + + + diff --git a/source/java/org/alfresco/repo/action/executer/CopyActionExecuter.java b/source/java/org/alfresco/repo/action/executer/CopyActionExecuter.java index f28530c976..a604312af4 100644 --- a/source/java/org/alfresco/repo/action/executer/CopyActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/CopyActionExecuter.java @@ -21,6 +21,7 @@ package org.alfresco.repo.action.executer; import java.util.List; +import org.alfresco.model.ContentModel; import org.alfresco.repo.action.ParameterDefinitionImpl; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ParameterDefinition; @@ -28,6 +29,7 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.rule.RuleServiceException; import org.alfresco.service.namespace.QName; /** @@ -39,11 +41,14 @@ import org.alfresco.service.namespace.QName; */ public class CopyActionExecuter extends ActionExecuterAbstractBase { + public static final String ERR_OVERWRITE = "Unable to overwrite copy because more than one have been found."; + public static final String NAME = "copy"; public static final String PARAM_DESTINATION_FOLDER = "destination-folder"; public static final String PARAM_ASSOC_TYPE_QNAME = "assoc-type"; public static final String PARAM_ASSOC_QNAME = "assoc-name"; public static final String PARAM_DEEP_COPY = "deep-copy"; + public static final String PARAM_OVERWRITE_COPY = "overwrite-copy"; /** * Node operations service @@ -55,17 +60,30 @@ public class CopyActionExecuter extends ActionExecuterAbstractBase */ private NodeService nodeService; + /** + * Sets the node service + * + * @param nodeService the node service + */ public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } + /** + * Sets the copy service + * + * @param copyService the copy service + */ public void setCopyService(CopyService copyService) { this.copyService = copyService; } + /** + * @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefintions(java.util.List) + */ @Override protected void addParameterDefintions(List paramList) { @@ -73,6 +91,7 @@ public class CopyActionExecuter extends ActionExecuterAbstractBase paramList.add(new ParameterDefinitionImpl(PARAM_ASSOC_TYPE_QNAME, DataTypeDefinition.QNAME, true, getParamDisplayLabel(PARAM_ASSOC_TYPE_QNAME))); paramList.add(new ParameterDefinitionImpl(PARAM_ASSOC_QNAME, DataTypeDefinition.QNAME, true, getParamDisplayLabel(PARAM_ASSOC_QNAME))); paramList.add(new ParameterDefinitionImpl(PARAM_DEEP_COPY, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_DEEP_COPY))); + paramList.add(new ParameterDefinitionImpl(PARAM_OVERWRITE_COPY, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_OVERWRITE_COPY))); } /** @@ -86,15 +105,70 @@ public class CopyActionExecuter extends ActionExecuterAbstractBase QName destinationAssocTypeQName = (QName)ruleAction.getParameterValue(PARAM_ASSOC_TYPE_QNAME); QName destinationAssocQName = (QName)ruleAction.getParameterValue(PARAM_ASSOC_QNAME); - // TODO get this from a parameter value + // Get the deep copy value boolean deepCopy = false; + Boolean deepCopyValue = (Boolean)ruleAction.getParameterValue(PARAM_DEEP_COPY); + if (deepCopyValue != null) + { + deepCopy = deepCopyValue.booleanValue(); + } - this.copyService.copy( + // Get the overwirte value + boolean overwrite = true; + Boolean overwriteValue = (Boolean)ruleAction.getParameterValue(PARAM_OVERWRITE_COPY); + if (overwriteValue != null) + { + overwrite = overwriteValue.booleanValue(); + } + + // Since we are overwriting we need to figure out whether the destination node exists + NodeRef destinationNodeRef = null; + if (overwrite == true) + { + // Try and find copies of the actioned upon node reference + List copies = this.copyService.getCopies(actionedUponNodeRef); + if (copies != null && copies.isEmpty() == false) + { + for (NodeRef copy : copies) + { + // Ignore if the copy is a working copy + if (this.nodeService.hasAspect(copy, ContentModel.ASPECT_WORKING_COPY) == false) + { + // We can assume that we are looking for a node created by this action so the primary parent will + // match the destination folder + NodeRef parent = this.nodeService.getPrimaryParent(copy).getParentRef(); + if (parent.equals(destinationParent) == true) + { + if (destinationNodeRef == null) + { + destinationNodeRef = copy; + } + else + { + throw new RuleServiceException(ERR_OVERWRITE); + } + } + + } + } + } + } + + if (destinationNodeRef != null) + { + // Overwrite the state of the destination node ref with the actioned upon node state + this.copyService.copy(actionedUponNodeRef, destinationNodeRef); + } + else + { + // Create a new copy of the node + this.copyService.copy( actionedUponNodeRef, destinationParent, destinationAssocTypeQName, destinationAssocQName, deepCopy); + } } } } diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java index 4d28fea482..a94828df59 100644 --- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java @@ -33,6 +33,7 @@ import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NoTransformerException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.rule.RuleServiceException; import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -44,6 +45,9 @@ import org.apache.commons.logging.LogFactory; */ public class TransformActionExecuter extends ActionExecuterAbstractBase { + /** Error messages */ + public static final String ERR_OVERWRITE = "Unable to overwrite copy because more than one have been found."; + /** * The logger */ @@ -57,6 +61,7 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase public static final String PARAM_DESTINATION_FOLDER = "destination-folder"; public static final String PARAM_ASSOC_TYPE_QNAME = "assoc-type"; public static final String PARAM_ASSOC_QNAME = "assoc-name"; + public static final String PARAM_OVERWRITE_COPY = "overwrite-copy"; private DictionaryService dictionaryService; private NodeService nodeService; @@ -124,6 +129,7 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase paramList.add(new ParameterDefinitionImpl(PARAM_DESTINATION_FOLDER, DataTypeDefinition.NODE_REF, true, getParamDisplayLabel(PARAM_DESTINATION_FOLDER))); paramList.add(new ParameterDefinitionImpl(PARAM_ASSOC_TYPE_QNAME, DataTypeDefinition.QNAME, true, getParamDisplayLabel(PARAM_ASSOC_TYPE_QNAME))); paramList.add(new ParameterDefinitionImpl(PARAM_ASSOC_QNAME, DataTypeDefinition.QNAME, true, getParamDisplayLabel(PARAM_ASSOC_QNAME))); + paramList.add(new ParameterDefinitionImpl(PARAM_OVERWRITE_COPY, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_OVERWRITE_COPY))); } /** @@ -154,14 +160,59 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase QName destinationAssocTypeQName = (QName)ruleAction.getParameterValue(PARAM_ASSOC_TYPE_QNAME); QName destinationAssocQName = (QName)ruleAction.getParameterValue(PARAM_ASSOC_QNAME); - // Copy the content node - NodeRef copyNodeRef = this.copyService.copy( - actionedUponNodeRef, - destinationParent, - destinationAssocTypeQName, - destinationAssocQName, - false); - + // Get the overwirte value + boolean overwrite = true; + Boolean overwriteValue = (Boolean)ruleAction.getParameterValue(PARAM_OVERWRITE_COPY); + if (overwriteValue != null) + { + overwrite = overwriteValue.booleanValue(); + } + + // Since we are overwriting we need to figure out whether the destination node exists + NodeRef copyNodeRef = null; + if (overwrite == true) + { + // Try and find copies of the actioned upon node reference + List copies = this.copyService.getCopies(actionedUponNodeRef); + if (copies != null && copies.isEmpty() == false) + { + for (NodeRef copy : copies) + { + // Ignore if the copy is a working copy + if (this.nodeService.hasAspect(copy, ContentModel.ASPECT_WORKING_COPY) == false) + { + // We can assume that we are looking for a node created by this action so the primary parent will + // match the destination folder + NodeRef parent = this.nodeService.getPrimaryParent(copy).getParentRef(); + if (parent.equals(destinationParent) == true) + { + if (copyNodeRef == null) + { + copyNodeRef = copy; + } + else + { + throw new RuleServiceException(ERR_OVERWRITE); + } + } + + } + } + } + } + + boolean newCopy = false; + if (copyNodeRef == null) + { + // Copy the content node + copyNodeRef = this.copyService.copy( + actionedUponNodeRef, + destinationParent, + destinationAssocTypeQName, + destinationAssocQName, + false); + newCopy = true; + } // Get the content reader ContentReader contentReader = this.contentService.getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT); @@ -179,15 +230,18 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase contentWriter.setMimetype(mimeType); // new mimetype contentWriter.setEncoding(contentReader.getEncoding()); // original encoding - // Adjust the name of the copy - String originalName = (String)nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_NAME); - String newName = transformName(originalName, originalMimetype, mimeType); - nodeService.setProperty(copyNodeRef, ContentModel.PROP_NAME, newName); - String originalTitle = (String)nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_TITLE); - if (originalTitle != null && originalTitle.length() > 0) + if (newCopy == true) { - String newTitle = transformName(originalTitle, originalMimetype, mimeType); - nodeService.setProperty(copyNodeRef, ContentModel.PROP_TITLE, newTitle); + // Adjust the name of the copy + String originalName = (String)nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_NAME); + String newName = transformName(originalName, originalMimetype, mimeType); + nodeService.setProperty(copyNodeRef, ContentModel.PROP_NAME, newName); + String originalTitle = (String)nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_TITLE); + if (originalTitle != null && originalTitle.length() > 0) + { + String newTitle = transformName(originalTitle, originalMimetype, mimeType); + nodeService.setProperty(copyNodeRef, ContentModel.PROP_TITLE, newTitle); + } } // Try and transform the content @@ -204,8 +258,11 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase " writer: " + contentWriter + "\n" + " action: " + this); } - // TODO: Revisit this for alternative solutions - nodeService.deleteNode(copyNodeRef); + //if (newCopy == true) + //{ + // TODO: Revisit this for alternative solutions + // nodeService.deleteNode(copyNodeRef); + // } } } diff --git a/source/java/org/alfresco/repo/copy/CopyServiceImpl.java b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java index 95bf7bb7bb..02b7581739 100644 --- a/source/java/org/alfresco/repo/copy/CopyServiceImpl.java +++ b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java @@ -17,6 +17,7 @@ package org.alfresco.repo.copy; import java.io.Serializable; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -31,10 +32,10 @@ import org.alfresco.repo.policy.PolicyScope; import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.dictionary.ClassDefinition; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.InvalidTypeException; import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -44,6 +45,8 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.rule.RuleService; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; @@ -56,29 +59,22 @@ import org.alfresco.util.ParameterCheck; */ public class CopyServiceImpl implements CopyService { - /** - * The node service - */ + /** The node service */ private NodeService nodeService; - /** - * The dictionary service - */ + /** The dictionary service*/ private DictionaryService dictionaryService; - /** - * Policy component - */ + /** The search service */ + private SearchService searchService; + + /** Policy component */ private PolicyComponent policyComponent; - /** - * Rule service - */ + /** Rule service */ private RuleService ruleService; - /** - * Policy delegates - */ + /** Policy delegates */ private ClassPolicyDelegate onCopyNodeDelegate; private ClassPolicyDelegate onCopyCompleteDelegate; @@ -112,6 +108,16 @@ public class CopyServiceImpl implements CopyService this.policyComponent = policyComponent; } + /** + * Sets the search service + * + * @param searchService the search service + */ + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + /** * Set the rule service * @@ -804,4 +810,33 @@ public class CopyServiceImpl implements CopyService { // Do nothing since we do not want the copy from aspect to be relative to the copied nodes } + + public List getCopies(NodeRef nodeRef) + { + List copies = new ArrayList(); + + // Do a search to find the origional document + ResultSet resultSet = null; + try + { + resultSet = this.searchService.query( + nodeRef.getStoreRef(), + SearchService.LANGUAGE_LUCENE, + "+@\\{http\\://www.alfresco.org/model/content/1.0\\}" + ContentModel.PROP_COPY_REFERENCE.getLocalName() + ":\"" + nodeRef.toString() + "\""); + + for (NodeRef copy : resultSet.getNodeRefs()) + { + copies.add(copy); + } + } + finally + { + if (resultSet != null) + { + resultSet.close(); + } + } + + return copies; + } } diff --git a/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java b/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java index 157054d040..93b42a7d8e 100644 --- a/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java +++ b/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java @@ -315,22 +315,33 @@ public class CopyServiceImplTest extends BaseSpringTest */ public void testCopyToNewNode() { + // Check that the node has no copies + List copies = this.copyService.getCopies(this.sourceNodeRef); + assertNotNull(copies); + assertTrue(copies.isEmpty()); + // Copy to new node without copying children NodeRef copy = this.copyService.copy( this.sourceNodeRef, this.rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{test}copyAssoc")); - checkCopiedNode(this.sourceNodeRef, copy, true, true, false); + checkCopiedNode(this.sourceNodeRef, copy, true, true, false); + List copies2 = this.copyService.getCopies(this.sourceNodeRef); + assertNotNull(copies2); + assertEquals(1, copies2.size()); // Copy to new node, copying children NodeRef copy2 = this.copyService.copy( this.sourceNodeRef, this.rootNodeRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("{test}copyAssoc"), + QName.createQName("{test}copyAssoc2"), true); checkCopiedNode(this.sourceNodeRef, copy2, true, true, true); + List copies3 = this.copyService.getCopies(this.sourceNodeRef); + assertNotNull(copies3); + assertEquals(2, copies3.size()); // Check that a copy of a copy works correctly NodeRef copyOfCopy = this.copyService.copy( diff --git a/source/java/org/alfresco/service/cmr/repository/CopyService.java b/source/java/org/alfresco/service/cmr/repository/CopyService.java index 86a1746e77..cbc50da65e 100644 --- a/source/java/org/alfresco/service/cmr/repository/CopyService.java +++ b/source/java/org/alfresco/service/cmr/repository/CopyService.java @@ -16,6 +16,8 @@ */ package org.alfresco.service.cmr.repository; +import java.util.List; + import org.alfresco.service.namespace.QName; /** @@ -115,5 +117,13 @@ public interface CopyService * @param sourceNodeRef the source node reference * @param destinationNodeRef the destination node reference */ - public void copy(NodeRef sourceNodeRef, NodeRef destinationNodeRef); + public void copy(NodeRef sourceNodeRef, NodeRef destinationNodeRef); + + /** + * Gets all the copies of a given node that have been made using this service. + * + * @param nodeRef the origional node reference + * @return a list of copies, empty is none + */ + public List getCopies(NodeRef nodeRef); }