diff --git a/source/java/org/alfresco/repo/copy/CopyServicePolicies.java b/source/java/org/alfresco/repo/copy/CopyServicePolicies.java index c1d364b83c..367ba7ebbe 100644 --- a/source/java/org/alfresco/repo/copy/CopyServicePolicies.java +++ b/source/java/org/alfresco/repo/copy/CopyServicePolicies.java @@ -33,11 +33,11 @@ import org.alfresco.service.namespace.QName; * public void init() * { * this.policyComponent.bindClassBehaviour( - * QName.createQName(NamespaceService.ALFRESCO_URI, "getCopyCallback"), + * OnCopyNodePolicy.QNAME, * ActionModel.ASPECT_ACTIONS, * new JavaBehaviour(this, "getCopyCallback")); * this.policyComponent.bindClassBehaviour( - * QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyComplete"), + * OnCopyCompletePolicy.QNAME, * ActionModel.ASPECT_ACTIONS, * new JavaBehaviour(this, "onCopyComplete")); * ... diff --git a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java index 0d7320c03a..343216f5f9 100644 --- a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java +++ b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java @@ -29,6 +29,7 @@ import java.io.Serializable; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; @@ -41,6 +42,10 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.alfresco.model.ContentModel; +import org.alfresco.repo.copy.CopyBehaviourCallback; +import org.alfresco.repo.copy.CopyDetails; +import org.alfresco.repo.copy.CopyServicePolicies; +import org.alfresco.repo.copy.DefaultCopyBehaviourCallback; import org.alfresco.repo.copy.CopyServicePolicies.BeforeCopyPolicy; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies.OnMoveNodePolicy; @@ -230,6 +235,14 @@ public class RepoTransferReceiverImpl implements TransferReceiver, NodeServicePolicies.OnMoveNodePolicy.QNAME, TransferModel.ASPECT_ALIEN, new JavaBehaviour(this, "onMoveNode", NotificationFrequency.EVERY_EVENT)); + + /** + * For every copy of a transferred node + */ + this.getPolicyComponent().bindClassBehaviour( + CopyServicePolicies.OnCopyNodePolicy.QNAME, + TransferModel.ASPECT_TRANSFERRED, + new JavaBehaviour(this, "onCopyTransferred", NotificationFrequency.EVERY_EVENT)); } @@ -1043,6 +1056,54 @@ public class RepoTransferReceiverImpl implements TransferReceiver, alienProcessor.beforeDeleteAlien(newChildAssocRef.getChildRef(), oldChildAssocRef); alienProcessor.afterMoveAlien(newChildAssocRef); } + + /** + * When a transferred node is copied, don't copy the transferred aspect. + */ + public CopyBehaviourCallback onCopyTransferred(QName classRef, + CopyDetails copyDetails) + { + return TransferredAspectCopyBehaviourCallback.INSTANCE; + } + + /** + * Extends the default copy behaviour to prevent copying of transferred aspect and properties. + * + * @author Mark Rogers + * @since 3.4 + */ + private static class TransferredAspectCopyBehaviourCallback extends DefaultCopyBehaviourCallback + { + private static final CopyBehaviourCallback INSTANCE = new TransferredAspectCopyBehaviourCallback(); + + /** + * @return Returns an empty map + */ + @Override + public Map getCopyProperties( + QName classQName, CopyDetails copyDetails, Map properties) + { + return Collections.emptyMap(); + } + + /** + * Don't copy the transferred aspect. + * + * @return Returns true always + */ + @Override + public boolean getMustCopy(QName classQName, CopyDetails copyDetails) + { + if(classQName.equals(TransferModel.ASPECT_TRANSFERRED)) + { + return false; + } + else + { + return true; + } + } + } public void setDescriptorService(DescriptorService descriptorService) { @@ -1063,5 +1124,4 @@ public class RepoTransferReceiverImpl implements TransferReceiver, { return alienProcessor; } - } diff --git a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java index 01245f53e3..8ac1887184 100644 --- a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java +++ b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java @@ -49,6 +49,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; +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.repository.Path; @@ -102,6 +103,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest private LockService lockService; private PersonService personService; private DescriptorService descriptorService; + private CopyService copyService; String COMPANY_HOME_XPATH_QUERY = "/{http://www.alfresco.org/model/application/1.0}company_home"; String GUEST_HOME_XPATH_QUERY = "/{http://www.alfresco.org/model/application/1.0}company_home/{http://www.alfresco.org/model/application/1.0}guest_home"; @@ -141,6 +143,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest this.lockService = (LockService) this.applicationContext.getBean("lockService"); this.personService = (PersonService)this.applicationContext.getBean("PersonService"); this.descriptorService = (DescriptorService)this.applicationContext.getBean("DescriptorService"); + this.copyService = (CopyService)this.applicationContext.getBean("CopyService"); authenticationComponent.setSystemUserAsCurrentUser(); setTransactionDefinition(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW)); @@ -5453,7 +5456,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest * * Step 2. Transfer in A's nodes to Repo B * - * Setup tree above. Validate that A2 is child of C2 dest. + * Setup tree above. Validat that A2 is child of C2 dest. * A4 is a child of B1 * * Step 3. Move A5 from C2 to C3 via transfer. @@ -5864,7 +5867,198 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest { endTransaction(); } - } + } + + /** + * Test the behaviour with regard to copying transferred nodes. + *

+ * Transfer node read only + *

+ * Copy transferred node. + *

+ * New node should not be locked and should not be transferred. + *

+ * This is a unit test so it does some shenanigans to send to the same instance of alfresco. + */ + public void testCopyTransferredNode() throws Exception + { + setDefaultRollback(false); + + String CONTENT_TITLE = "ContentTitle"; + + /** + * Now go ahead and create our transfer target + */ + String targetName = "testCopyTransferredNode"; + TransferTarget transferMe; + NodeRef S0NodeRef; + NodeRef A1NodeRef; + NodeRef A2NodeRef; + NodeRef A3NodeRef; + NodeRef B1NodeRef; + NodeRef B2NodeRef; + + startNewTransaction(); + try + { + /** + * Get guest home + */ + String guestHomeQuery = "/app:company_home/app:guest_home"; + ResultSet guestHomeResult = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_XPATH, guestHomeQuery); + assertEquals("", 1, guestHomeResult.length()); + NodeRef guestHome = guestHomeResult.getNodeRef(0); + + /** + * Node Source - located under guest home + */ + { + String name = GUID.generate(); + ChildAssociationRef child = nodeService.createNode(guestHome, ContentModel.ASSOC_CONTAINS, QName.createQName(name), ContentModel.TYPE_FOLDER); + S0NodeRef = child.getChildRef(); + nodeService.setProperty(S0NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(S0NodeRef, ContentModel.PROP_NAME, name); + } + + { + // Node A1 + ChildAssociationRef child = nodeService.createNode(S0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A1"), ContentModel.TYPE_FOLDER); + A1NodeRef = child.getChildRef(); + nodeService.setProperty(A1NodeRef, ContentModel.PROP_TITLE, "A1"); + nodeService.setProperty(A1NodeRef, ContentModel.PROP_NAME, "A1"); + } + + { + // Node A2 + ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A2"), ContentModel.TYPE_FOLDER); + A2NodeRef = child.getChildRef(); + nodeService.setProperty(A2NodeRef, ContentModel.PROP_TITLE, "A2"); + nodeService.setProperty(A2NodeRef, ContentModel.PROP_NAME, "A2"); + } + + { + // Node A3 + ChildAssociationRef child = nodeService.createNode(A2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A3"), ContentModel.TYPE_FOLDER); + A3NodeRef = child.getChildRef(); + nodeService.setProperty(A3NodeRef, ContentModel.PROP_TITLE, "A3"); + nodeService.setProperty(A3NodeRef, ContentModel.PROP_NAME, "A3"); + } + + { + // Node B1 + ChildAssociationRef child = nodeService.createNode(S0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B1"), ContentModel.TYPE_FOLDER); + B1NodeRef = child.getChildRef(); + nodeService.setProperty(B1NodeRef, ContentModel.PROP_TITLE, "B1"); + nodeService.setProperty(B1NodeRef, ContentModel.PROP_NAME, "B1"); + } + + { + // Node B2 + ChildAssociationRef child = nodeService.createNode(S0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B2"), ContentModel.TYPE_FOLDER); + B2NodeRef = child.getChildRef(); + nodeService.setProperty(B1NodeRef, ContentModel.PROP_TITLE, "B2"); + nodeService.setProperty(B1NodeRef, ContentModel.PROP_NAME, "B2"); + } + + + if(!transferService.targetExists(targetName)) + { + transferMe = createTransferTarget(targetName); + } + else + { + transferMe = transferService.getTransferTarget(targetName); + } + } + finally + { + endTransaction(); + } + + /** + * For unit test + * - replace the HTTP transport with the in-process transport + * - Map path from A1 to B1 (So transfer will transfer by path) + */ + TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService); + transferServiceImpl.setTransmitter(transmitter); + UnitTestTransferManifestNodeFactory testNodeFactory = new UnitTestTransferManifestNodeFactory(this.transferManifestNodeFactory); + transferServiceImpl.setTransferManifestNodeFactory(testNodeFactory); + List> pathMap = testNodeFactory.getPathMap(); + + // Map Project A to Project B + pathMap.add(new Pair(nodeService.getPath(A1NodeRef), nodeService.getPath(B1NodeRef))); + + DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + + + /** + * Step 1 + */ + logger.debug("First transfer - "); + startNewTransaction(); + try + { + /** + * Transfer our transfer target node + */ + { + TransferDefinition definition = new TransferDefinition(); + Setnodes = new HashSet(); + nodes.add(A2NodeRef); + nodes.add(A3NodeRef); + definition.setNodes(nodes); + definition.setReadOnly(true); + transferService.transfer(targetName, definition); + } + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + // Now validate that the target node exists with the correct permissions + NodeRef A2destNodeRef = testNodeFactory.getMappedNodeRef(A2NodeRef); + assertTrue("dest node ref does not exist", nodeService.exists(A2destNodeRef)); + + /** + * Copy the node A2 Dest + */ + NodeRef copiedNode = copyService.copy(A2destNodeRef, B2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A2Copy")); + assertTrue("copied node does not exist", nodeService.exists(copiedNode)); + System.out.println("copied node is " + copiedNode); + assertFalse("copied node still has transferred aspect", nodeService.hasAspect(copiedNode, TransferModel.ASPECT_TRANSFERRED)); + assertNull("copied node still has from repository id", nodeService.getProperty(copiedNode, TransferModel.PROP_FROM_REPOSITORY_ID)); + assertNull("copied node still has original repository id", nodeService.getProperty(copiedNode, TransferModel.PROP_REPOSITORY_ID)); + Set aspects = nodeService.getAspects(copiedNode); + + /** + * Copy a chain of transferred nodes - well A2dest and A3dest + */ + copiedNode = copyService.copy(A2destNodeRef, B2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A2Copy2"), true); + assertTrue("copied node does not exist", nodeService.exists(copiedNode)); + System.out.println("copied node is " + copiedNode); + assertFalse("copied node still has transferred aspect", nodeService.hasAspect(copiedNode, TransferModel.ASPECT_TRANSFERRED)); + assertNull("copied node still has from repository id", nodeService.getProperty(copiedNode, TransferModel.PROP_FROM_REPOSITORY_ID)); + assertNull("copied node still has original repository id", nodeService.getProperty(copiedNode, TransferModel.PROP_REPOSITORY_ID)); + + List children = nodeService.getChildAssocs(copiedNode); + for(ChildAssociationRef child : children) + { + assertFalse("copied node still has transferred aspect", nodeService.hasAspect(child.getChildRef(), TransferModel.ASPECT_TRANSFERRED)); + assertNull("copied node still has from repository id", nodeService.getProperty(child.getChildRef(), TransferModel.PROP_FROM_REPOSITORY_ID)); + assertNull("copied node still has original repository id", nodeService.getProperty(child.getChildRef(), TransferModel.PROP_REPOSITORY_ID)); + } + } + finally + { + endTransaction(); + } + } private void createUser(String userName, String password) {