diff --git a/config/alfresco/model/transferModel.xml b/config/alfresco/model/transferModel.xml index faf32305e8..eed3b51986 100644 --- a/config/alfresco/model/transferModel.xml +++ b/config/alfresco/model/transferModel.xml @@ -210,6 +210,13 @@ d:text true + + ContentProperties + The content URLs transferred with this node + d:text + false + true + diff --git a/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java b/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java index dcf697ce46..4e61c69025 100644 --- a/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java +++ b/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java @@ -524,16 +524,9 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB Map props = new HashMap(node.getProperties()); Map existingProps = nodeService.getProperties(nodeToUpdate); - // inject transferred property here + // inject transferred properties/aspect here injectTransferred(props); - -// if(!props.containsKey(TransferModel.PROP_REPOSITORY_ID)) -// { -// log.debug("injecting repositoryId property"); -// props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId()); -// } -// props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId()); - + // Remove the invadedBy property since that is used by the transfer service // and is local to this repository. props.remove(TransferModel.PROP_INVADED_BY); @@ -937,13 +930,33 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB * inject transferred */ private void injectTransferred(Map props) - { + { if(!props.containsKey(TransferModel.PROP_REPOSITORY_ID)) { log.debug("injecting repositoryId property"); props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId()); } props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId()); + + /** + * For each property + */ + List contentProps = new ArrayList(); + for (Serializable value : props.values()) + { + if ((value != null) && ContentData.class.isAssignableFrom(value.getClass())) + { + ContentData srcContent = (ContentData)value; + + if(srcContent.getContentUrl() != null && !srcContent.getContentUrl().isEmpty()) + { + log.debug("adding part name to from content field"); + contentProps.add(TransferCommons.URLToPartName(srcContent.getContentUrl())); + } + } + } + + props.put(TransferModel.PROP_FROM_CONTENT, (Serializable)contentProps); } public void setAlienProcessor(AlienProcessor alienProcessor) diff --git a/source/java/org/alfresco/repo/transfer/RepoRequisiteManifestProcessorImpl.java b/source/java/org/alfresco/repo/transfer/RepoRequisiteManifestProcessorImpl.java index 0e190a9d05..07b222c935 100644 --- a/source/java/org/alfresco/repo/transfer/RepoRequisiteManifestProcessorImpl.java +++ b/source/java/org/alfresco/repo/transfer/RepoRequisiteManifestProcessorImpl.java @@ -21,6 +21,7 @@ package org.alfresco.repo.transfer; import java.io.Serializable; import java.text.SimpleDateFormat; +import java.util.Collection; import java.util.Date; import java.util.Map; @@ -94,92 +95,102 @@ public class RepoRequisiteManifestProcessorImpl extends AbstractManifestProcesso { /** * there is a corresponding node so we need to check whether we already - * have the content item + * have the part for each content item */ NodeRef destinationNode = resolvedNodes.resolvedChild; - Map destinationProps = nodeService.getProperties(destinationNode); - + Map destinationProps = nodeService.getProperties(destinationNode); + /** + * For each property on the source node + */ for (Map.Entry propEntry : node.getProperties().entrySet()) { Serializable value = propEntry.getValue(); + QName propName = propEntry.getKey(); + if (log.isDebugEnabled()) { if (value == null) { - log.debug("Received a null value for property " + propEntry.getKey()); + log.debug("Received a null value for property " + propName); } } if ((value != null) && ContentData.class.isAssignableFrom(value.getClass())) { + /** + * Got a content property from source node. + */ ContentData srcContent = (ContentData)value; - + if(srcContent.getContentUrl() != null && !srcContent.getContentUrl().isEmpty() ) { - Serializable destSer = destinationProps.get(propEntry.getKey()); - if(destSer != null && ContentData.class.isAssignableFrom(destSer.getClass())) + /** + * Source Content is not empty + */ + String partName = TransferCommons.URLToPartName(srcContent.getContentUrl()); + + Serializable destSer = destinationProps.get(propName); + if(destSer != null && ContentData.class.isAssignableFrom(destSer.getClass())) { - ContentData destContent = (ContentData)destinationProps.get(propEntry.getKey()); - /** - * If the modification dates for the node are different + * Content property not empty and content property already exists on destination */ - Serializable srcModified = node.getProperties().get(ContentModel.PROP_MODIFIED); - Serializable destModified = destinationProps.get(ContentModel.PROP_MODIFIED); - - if(log.isDebugEnabled()) - { - SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); - - log.debug ("srcModified :" + srcModified + "destModified :" + destModified); - - if(srcModified instanceof Date) - { - log.debug("srcModified: " + SDF.format(srcModified)); - } - - if(destModified instanceof Date) - { - log.debug("destModified: " + SDF.format(destModified)); - } - } + ContentData destContent = (ContentData)destSer; - if(srcModified != null && - destModified != null && - srcModified instanceof Date && - destModified instanceof Date && - ((Date)srcModified).getTime() <= ((Date)destModified).getTime()) + Serializable destFromContents = destinationProps.get(TransferModel.PROP_FROM_CONTENT); + + if(destFromContents != null && Collection.class.isAssignableFrom(destFromContents.getClass())) { - if(log.isDebugEnabled()) + Collection contents = (Collection)destFromContents; + /** + * Content property not empty and content property already exists on destination + */ + if(contents.contains(partName)) { - log.debug("the modified date is the same or before - no need send content:" + node.getNodeRef()); + if(log.isDebugEnabled()) + { + log.debug("part already transferred, no need to send it again, partName:" + partName + ", nodeRef:" + node.getNodeRef()); + } + } + else + { + if(log.isDebugEnabled()) + { + log.debug("part name not transferred, requesting new content item partName:" + partName + ", nodeRef:" + node.getNodeRef()); + } + out.missingContent(node.getNodeRef(), propEntry.getKey(), TransferCommons.URLToPartName(srcContent.getContentUrl())); } } else { + // dest from contents is null if(log.isDebugEnabled()) { - log.debug("time different, require content for node : " + node.getNodeRef()); + log.debug("from contents is null, requesting new content item partName:" + partName + ", nodeRef:" + node.getNodeRef()); } out.missingContent(node.getNodeRef(), propEntry.getKey(), TransferCommons.URLToPartName(srcContent.getContentUrl())); } } else { + /** + * Content property not empty and does not exist on destination + */ if(log.isDebugEnabled()) { - log.debug("no content on destination, content is required" + propEntry.getKey() + srcContent.getContentUrl()); + log.debug("no content on destination, all content is required" + propEntry.getKey() + srcContent.getContentUrl()); } // We don't have the property on the destination node out.missingContent(node.getNodeRef(), propEntry.getKey(), TransferCommons.URLToPartName(srcContent.getContentUrl())); } - } // src content url not null - } // value is content data - } + } + } // src content url not null + } // value is content data } else { log.debug("Node does not exist on destination nodeRef:" + node.getNodeRef()); + /** * there is no corresponding node so all content properties are "missing." */ diff --git a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java index 0582ba43be..ee65e9edf9 100644 --- a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java +++ b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java @@ -40,6 +40,7 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.ContentServicePolicies; import org.alfresco.repo.copy.CopyBehaviourCallback; import org.alfresco.repo.copy.CopyDetails; import org.alfresco.repo.copy.CopyServicePolicies; @@ -96,7 +97,8 @@ public class RepoTransferReceiverImpl implements TransferReceiver, NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.BeforeDeleteNodePolicy, NodeServicePolicies.OnRestoreNodePolicy, - NodeServicePolicies.OnMoveNodePolicy + NodeServicePolicies.OnMoveNodePolicy, + ContentServicePolicies.OnContentUpdatePolicy { /** @@ -213,6 +215,14 @@ public class RepoTransferReceiverImpl implements TransferReceiver, TransferModel.ASPECT_TRANSFERRED, new JavaBehaviour(this, "onCreateChildAssociation", NotificationFrequency.EVERY_EVENT)); + /** + * For every update of a transferred node + */ + this.getPolicyComponent().bindClassBehaviour( + ContentServicePolicies.OnContentUpdatePolicy.QNAME, + TransferModel.ASPECT_TRANSFERRED, + new JavaBehaviour(this, "onContentUpdate", NotificationFrequency.EVERY_EVENT)); + /** * For every copy of a transferred node run onCopyTransferred */ @@ -1103,8 +1113,23 @@ public class RepoTransferReceiverImpl implements TransferReceiver, log.debug("onMoveNode"); log.debug("oldChildAssocRef:" + oldChildAssocRef); log.debug("newChildAssocRef:" + newChildAssocRef); - alienProcessor.beforeDeleteAlien(newChildAssocRef.getChildRef(), oldChildAssocRef); - alienProcessor.afterMoveAlien(newChildAssocRef); + + NodeRef oldParentRef = oldChildAssocRef.getParentRef(); + NodeRef newParentRef = newChildAssocRef.getParentRef(); + + if(newParentRef.equals(oldParentRef)) + { + log.debug("old parent and new parent are the same - this is a rename, do nothing"); + } + else + { + if(log.isDebugEnabled()) + { + log.debug("moving node from oldParentRef:" + oldParentRef +" to:" + newParentRef); + } + alienProcessor.beforeDeleteAlien(newChildAssocRef.getChildRef(), oldChildAssocRef); + alienProcessor.afterMoveAlien(newChildAssocRef); + } } /** @@ -1223,4 +1248,18 @@ public class RepoTransferReceiverImpl implements TransferReceiver, { return alienProcessor; } + + @Override + public void onContentUpdate(NodeRef nodeRef, boolean newContent) + { + /** + * On update of a transferred node remove the from content from property. + */ + log.debug("on content update called:" + nodeRef); + if(newContent) + { + log.debug("new content remove PROP_FROM_CONTENT from node:" + nodeRef); + nodeService.setProperty(nodeRef, TransferModel.PROP_FROM_CONTENT, null); + } + } } diff --git a/source/java/org/alfresco/repo/transfer/TransferModel.java b/source/java/org/alfresco/repo/transfer/TransferModel.java index d9bb7e7579..5c0a35201f 100644 --- a/source/java/org/alfresco/repo/transfer/TransferModel.java +++ b/source/java/org/alfresco/repo/transfer/TransferModel.java @@ -39,13 +39,13 @@ public interface TransferModel static final QName ASPECT_TRANSFERRED = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferred"); static final QName PROP_REPOSITORY_ID = QName.createQName(TRANSFER_MODEL_1_0_URI, "repositoryId"); static final QName PROP_FROM_REPOSITORY_ID = QName.createQName(TRANSFER_MODEL_1_0_URI, "fromRepositoryId"); + static final QName PROP_FROM_CONTENT = QName.createQName(TRANSFER_MODEL_1_0_URI, "fromContent"); /** * Aspect : alien */ static final QName ASPECT_ALIEN = QName.createQName(TRANSFER_MODEL_1_0_URI, "alien"); static final QName PROP_INVADED_BY = QName.createQName(TRANSFER_MODEL_1_0_URI, "invadedBy"); -// static final QName PROP_ALIEN = QName.createQName(TRANSFER_MODEL_1_0_URI, "alien"); /* * Type : Transfer Group diff --git a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java index 9204ba2603..5c8fc1e09b 100644 --- a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java +++ b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java @@ -6975,414 +6975,413 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest } } // copy node + + /** + * Test the transfer method with regard to an empty content property. ALF-4865 + * + * Step 1: create a node with an empty content property + * transfer + * + * Step 2: add non empty content property + * transfer + * + * Step 3: update from non empty content to empty content property + * transfer + * + * This is a unit test so it does some shenanigans to send to the same instance of alfresco. + */ + public void testEmptyContent() throws Exception + { + setDefaultRollback(false); + + String CONTENT_TITLE = "ContentTitle"; + String CONTENT_TITLE_UPDATED = "ContentTitleUpdated"; + Locale CONTENT_LOCALE = Locale.ENGLISH; + String CONTENT_ENCODING = "UTF-8"; + String CONTENT_STRING = "The quick brown fox jumps over the lazy dog."; + + /** + * For unit test + * - replace the HTTP transport with the in-process transport + * - replace the node factory with one that will map node refs, paths etc. + * + * Fake Repository Id + */ + TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService); + transferServiceImpl.setTransmitter(transmitter); + UnitTestTransferManifestNodeFactory testNodeFactory = new UnitTestTransferManifestNodeFactory(this.transferManifestNodeFactory); + transferServiceImpl.setTransferManifestNodeFactory(testNodeFactory); + List> pathMap = testNodeFactory.getPathMap(); + // Map company_home/guest_home to company_home so tranferred nodes and moved "up" one level. + pathMap.add(new Pair(PathHelper.stringToPath(GUEST_HOME_XPATH_QUERY), PathHelper.stringToPath(COMPANY_HOME_XPATH_QUERY))); + + DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + + /** + * Now go ahead and create our first transfer target + */ + String targetName = "testTransferEmptyContent"; + TransferTarget transferMe; + NodeRef contentNodeRef; + NodeRef savedDestinationNodeRef; + + 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); -// TODO - temp comment out of unit tests - will be tested on branch rather than head. -// /** -// * Test the transfer method with regard to an empty content property. ALF-4865 -// * -// * Step 1: create a node with an empty content property -// * transfer -// * -// * Step 2: add non empty content property -// * transfer -// * -// * Step 3: update from non empty content to empty content property -// * transfer -// * -// * This is a unit test so it does some shenanigans to send to the same instance of alfresco. -// */ -// public void testEmptyContent() throws Exception -// { -// setDefaultRollback(false); -// -// String CONTENT_TITLE = "ContentTitle"; -// String CONTENT_TITLE_UPDATED = "ContentTitleUpdated"; -// Locale CONTENT_LOCALE = Locale.ENGLISH; -// String CONTENT_ENCODING = "UTF-8"; -// String CONTENT_STRING = "The quick brown fox jumps over the lazy dog."; -// -// /** -// * For unit test -// * - replace the HTTP transport with the in-process transport -// * - replace the node factory with one that will map node refs, paths etc. -// * -// * Fake Repository Id -// */ -// TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService); -// transferServiceImpl.setTransmitter(transmitter); -// UnitTestTransferManifestNodeFactory testNodeFactory = new UnitTestTransferManifestNodeFactory(this.transferManifestNodeFactory); -// transferServiceImpl.setTransferManifestNodeFactory(testNodeFactory); -// List> pathMap = testNodeFactory.getPathMap(); -// // Map company_home/guest_home to company_home so tranferred nodes and moved "up" one level. -// pathMap.add(new Pair(PathHelper.stringToPath(GUEST_HOME_XPATH_QUERY), PathHelper.stringToPath(COMPANY_HOME_XPATH_QUERY))); -// -// DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A); -// transferServiceImpl.setDescriptorService(mockedDescriptorService); -// -// /** -// * Now go ahead and create our first transfer target -// */ -// String targetName = "testTransferEmptyContent"; -// TransferTarget transferMe; -// NodeRef contentNodeRef; -// NodeRef savedDestinationNodeRef; -// -// 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); -// -// /** -// * Create a test node with an empty content that we will read and write -// */ -// String name = GUID.generate(); -// ChildAssociationRef child = nodeService.createNode(guestHome, ContentModel.ASSOC_CONTAINS, QName.createQName(name), ContentModel.TYPE_CONTENT); -// contentNodeRef = child.getChildRef(); -// nodeService.setProperty(contentNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); -// nodeService.setProperty(contentNodeRef, ContentModel.PROP_NAME, name); -// ContentData cd = new ContentData(null, null, 0, null); -// nodeService.setProperty(contentNodeRef, ContentModel.PROP_CONTENT, cd); -// -// if(!transferService.targetExists(targetName)) -// { -// transferMe = createTransferTarget(targetName); -// } -// else -// { -// transferMe = transferService.getTransferTarget(targetName); -// } -// transferService.enableTransferTarget(targetName, true); -// } -// finally -// { -// endTransaction(); -// } -// -// SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); -// -// -// -// -// /** -// * Step 1: Transfer our node which has empty content -// */ -// logger.debug("testEmptyContent : First transfer - create new node (empty content)"); -// startNewTransaction(); -// try -// { -// ContentReader reader = contentService.getReader(contentNodeRef, ContentModel.PROP_CONTENT); -// assertNull("test setup content reader not null", reader); -// Map props = nodeService.getProperties(contentNodeRef); -// assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); -// -// TransferDefinition definition = new TransferDefinition(); -// Setnodes = new HashSet(); -// nodes.add(contentNodeRef); -// definition.setNodes(nodes); -// transferService.transfer(targetName, definition); -// -// } -// finally -// { -// endTransaction(); -// } -// -// startNewTransaction(); -// try -// { -// Serializable modifiedDate = nodeService.getProperty(contentNodeRef, ContentModel.PROP_MODIFIED); -// if(modifiedDate instanceof Date) -// { -// logger.debug("srcModified: " + SDF.format(modifiedDate)); -// } -// -// NodeRef destinationNodeRef = testNodeFactory.getMappedNodeRef(contentNodeRef); -// savedDestinationNodeRef = destinationNodeRef; -// assertTrue("content node (dest) does not exist", nodeService.exists(destinationNodeRef)); -// -// ContentReader reader = contentService.getReader(destinationNodeRef, ContentModel.PROP_CONTENT); -// assertNull("content reader not null", reader); -// Map props = nodeService.getProperties(destinationNodeRef); -// assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); -// -// } -// finally -// { -// endTransaction(); -// } -// -// /** -// * Step 2: replace empty content with new content -// */ -// logger.debug("testEmptyContent : Second transfer - replace empty content with some content"); -// -// startNewTransaction(); -// try -// { -// Serializable modifiedDate = nodeService.getProperty(contentNodeRef, ContentModel.PROP_MODIFIED); -// if(modifiedDate instanceof Date) -// { -// logger.debug("srcModified: " + SDF.format(modifiedDate)); -// } -// -// ContentWriter writer = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, true); -// writer.setLocale(CONTENT_LOCALE); -// writer.setEncoding(CONTENT_ENCODING); -// writer.putContent(CONTENT_STRING); -// } -// finally -// { -// endTransaction(); -// } -// -// startNewTransaction(); -// try -// { -// ContentReader reader = contentService.getReader(contentNodeRef, ContentModel.PROP_CONTENT); -// assertNotNull("test setup content reader not null", reader); -// Map props = nodeService.getProperties(contentNodeRef); -// assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); -// -// /** -// * Step 2: replace empty content with new content -// */ -// TransferDefinition definition = new TransferDefinition(); -// Setnodes = new HashSet(); -// nodes.add(contentNodeRef); -// definition.setNodes(nodes); -// transferService.transfer(targetName, definition); -// -// } -// finally -// { -// endTransaction(); -// } -// -// startNewTransaction(); -// try -// { -// NodeRef destinationNodeRef = testNodeFactory.getMappedNodeRef(contentNodeRef); -// -// assertEquals("test error destinationNodeRef not correct", savedDestinationNodeRef, destinationNodeRef); -// ContentReader reader = contentService.getReader(destinationNodeRef, ContentModel.PROP_CONTENT); -// assertNotNull("content reader is null", reader); -// assertEquals("content encoding is wrong", reader.getEncoding(), CONTENT_ENCODING); -// assertEquals("content locale is wrong", reader.getLocale(), CONTENT_LOCALE); -// assertTrue("content does not exist", reader.exists()); -// String contentStr = reader.getContentString(); -// assertEquals("Content is wrong", contentStr, CONTENT_STRING); -// } -// finally -// { -// endTransaction(); -// } -// -// /** -// * Step 3 - transition from a content property having content to one that is empty -// */ -// logger.debug("testEmptyContent : Third transfer - remove existing content"); -// -// startNewTransaction(); -// try -// { -// ContentData cd = new ContentData(null, null, 0, null); -// nodeService.setProperty(contentNodeRef, ContentModel.PROP_CONTENT, cd); -// } -// finally -// { -// endTransaction(); -// } -// -// startNewTransaction(); -// try -// { -// ContentReader reader = contentService.getReader(contentNodeRef, ContentModel.PROP_CONTENT); -// assertNull("test setup content reader not null", reader); -// Map props = nodeService.getProperties(contentNodeRef); -// assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); -// -// /** -// * Step 3: Transfer our node which has empty content to over-write existing -// * content -// */ -// TransferDefinition definition = new TransferDefinition(); -// Setnodes = new HashSet(); -// nodes.add(contentNodeRef); -// definition.setNodes(nodes); -// transferService.transfer(targetName, definition); -// } -// finally -// { -// endTransaction(); -// } -// -// startNewTransaction(); -// try -// { -// NodeRef destinationNodeRef = testNodeFactory.getMappedNodeRef(contentNodeRef); -// assertTrue("content node (dest) does not exist", nodeService.exists(destinationNodeRef)); -// -// ContentReader reader = contentService.getReader(destinationNodeRef, ContentModel.PROP_CONTENT); -// assertNull("content reader not null", reader); -// Map props = nodeService.getProperties(destinationNodeRef); -// assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); -// -// } -// finally -// { -// endTransaction(); -// } -// -// } // end of testEmptyContent -// -// -// /** -// * Test the transfer method with regard to a repeated update of content.by sending one node (CRUD). -// * -// * This is a unit test so it does some shenanigans to send to the same instance of alfresco. -// */ -// public void testRepeatUpdateOfContent() throws Exception -// { -// final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); -// final String CONTENT_TITLE = "ContentTitle"; -// final Locale CONTENT_LOCALE = Locale.GERMAN; -// final String CONTENT_ENCODING = "UTF-8"; -// -// /** -// * For unit test -// * - replace the HTTP transport with the in-process transport -// * - replace the node factory with one that will map node refs, paths etc. -// * -// * Fake Repository Id -// */ -// final TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService); -// transferServiceImpl.setTransmitter(transmitter); -// final UnitTestTransferManifestNodeFactory testNodeFactory = new UnitTestTransferManifestNodeFactory(this.transferManifestNodeFactory); -// transferServiceImpl.setTransferManifestNodeFactory(testNodeFactory); -// final List> pathMap = testNodeFactory.getPathMap(); -// // Map company_home/guest_home to company_home so tranferred nodes and moved "up" one level. -// pathMap.add(new Pair(PathHelper.stringToPath(GUEST_HOME_XPATH_QUERY), PathHelper.stringToPath(COMPANY_HOME_XPATH_QUERY))); -// -// DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A); -// transferServiceImpl.setDescriptorService(mockedDescriptorService); -// -// final String targetName = "testRepeatUpdateOfContent"; -// -// class TestContext -// { -// TransferTarget transferMe; -// NodeRef contentNodeRef; -// NodeRef destNodeRef; -// String contentString; -// }; -// -// RetryingTransactionCallback setupCB = new RetryingTransactionCallback() -// { -// @Override -// public TestContext execute() throws Throwable -// { -// TestContext testContext = new TestContext(); -// -// /** -// * 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); -// -// /** -// * Create a test node that we will read and write -// */ -// String name = GUID.generate(); -// ChildAssociationRef child = nodeService.createNode(guestHome, ContentModel.ASSOC_CONTAINS, QName.createQName(name), ContentModel.TYPE_CONTENT); -// testContext.contentNodeRef = child.getChildRef(); -// nodeService.setProperty(testContext.contentNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); -// nodeService.setProperty(testContext.contentNodeRef, ContentModel.PROP_NAME, name); -// -// /** -// * Make sure the transfer target exists and is enabled. -// */ -// if(!transferService.targetExists(targetName)) -// { -// testContext.transferMe = createTransferTarget(targetName); -// } -// else -// { -// testContext.transferMe = transferService.getTransferTarget(targetName); -// } -// transferService.enableTransferTarget(targetName, true); -// return testContext; -// } -// }; -// -// final TestContext testContext = tran.doInTransaction(setupCB); -// -// RetryingTransactionCallback updateContentCB = new RetryingTransactionCallback() { -// -// @Override -// public Void execute() throws Throwable -// { -// ContentWriter writer = contentService.getWriter(testContext.contentNodeRef, ContentModel.PROP_CONTENT, true); -// writer.setLocale(CONTENT_LOCALE); -// writer.setEncoding(CONTENT_ENCODING); -// writer.putContent(testContext.contentString); -// return null; -// } -// }; -// -// RetryingTransactionCallback transferCB = new RetryingTransactionCallback() { -// -// @Override -// public Void execute() throws Throwable -// { -// TransferDefinition definition = new TransferDefinition(); -// Setnodes = new HashSet(); -// nodes.add(testContext.contentNodeRef); -// definition.setNodes(nodes); -// transferService.transfer(targetName, definition); -// return null; -// } -// }; -// -// RetryingTransactionCallback checkTransferCB = new RetryingTransactionCallback() { -// -// @Override -// public Void execute() throws Throwable -// { -// // Now validate that the target node exists and has similar properties to the source -// NodeRef destNodeRef = testNodeFactory.getMappedNodeRef(testContext.contentNodeRef); -// -// ContentReader reader = contentService.getReader(destNodeRef, ContentModel.PROP_CONTENT); -// assertNotNull("content reader is null", reader); -// assertEquals("content encoding is wrong", reader.getEncoding(), CONTENT_ENCODING); -// assertEquals("content locale is wrong", reader.getLocale(), CONTENT_LOCALE); -// assertTrue("content does not exist", reader.exists()); -// String contentStr = reader.getContentString(); -// assertEquals("Content is wrong", contentStr, testContext.contentString); -// -// return null; -// } -// }; -// -// /** -// * This is the test -// */ -// for(int i = 0; i < 6 ; i++) -// { -// logger.debug("testRepeatUpdateContent - iteration:" + i); -// testContext.contentString = String.valueOf(i); -// tran.doInTransaction(updateContentCB); -// tran.doInTransaction(transferCB); -// tran.doInTransaction(checkTransferCB); -// } -// } // test repeat update content + /** + * Create a test node with an empty content that we will read and write + */ + String name = GUID.generate(); + ChildAssociationRef child = nodeService.createNode(guestHome, ContentModel.ASSOC_CONTAINS, QName.createQName(name), ContentModel.TYPE_CONTENT); + contentNodeRef = child.getChildRef(); + nodeService.setProperty(contentNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(contentNodeRef, ContentModel.PROP_NAME, name); + ContentData cd = new ContentData(null, null, 0, null); + nodeService.setProperty(contentNodeRef, ContentModel.PROP_CONTENT, cd); + + if(!transferService.targetExists(targetName)) + { + transferMe = createTransferTarget(targetName); + } + else + { + transferMe = transferService.getTransferTarget(targetName); + } + transferService.enableTransferTarget(targetName, true); + } + finally + { + endTransaction(); + } + + SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + + + + + /** + * Step 1: Transfer our node which has empty content + */ + logger.debug("testEmptyContent : First transfer - create new node (empty content)"); + startNewTransaction(); + try + { + ContentReader reader = contentService.getReader(contentNodeRef, ContentModel.PROP_CONTENT); + assertNull("test setup content reader not null", reader); + Map props = nodeService.getProperties(contentNodeRef); + assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); + + TransferDefinition definition = new TransferDefinition(); + Setnodes = new HashSet(); + nodes.add(contentNodeRef); + definition.setNodes(nodes); + transferService.transfer(targetName, definition); + + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + Serializable modifiedDate = nodeService.getProperty(contentNodeRef, ContentModel.PROP_MODIFIED); + if(modifiedDate instanceof Date) + { + logger.debug("srcModified: " + SDF.format(modifiedDate)); + } + + NodeRef destinationNodeRef = testNodeFactory.getMappedNodeRef(contentNodeRef); + savedDestinationNodeRef = destinationNodeRef; + assertTrue("content node (dest) does not exist", nodeService.exists(destinationNodeRef)); + + ContentReader reader = contentService.getReader(destinationNodeRef, ContentModel.PROP_CONTENT); + assertNull("content reader not null", reader); + Map props = nodeService.getProperties(destinationNodeRef); + assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); + + } + finally + { + endTransaction(); + } + + /** + * Step 2: replace empty content with new content + */ + logger.debug("testEmptyContent : Second transfer - replace empty content with some content"); + + startNewTransaction(); + try + { + Serializable modifiedDate = nodeService.getProperty(contentNodeRef, ContentModel.PROP_MODIFIED); + if(modifiedDate instanceof Date) + { + logger.debug("srcModified: " + SDF.format(modifiedDate)); + } + + ContentWriter writer = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, true); + writer.setLocale(CONTENT_LOCALE); + writer.setEncoding(CONTENT_ENCODING); + writer.putContent(CONTENT_STRING); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + ContentReader reader = contentService.getReader(contentNodeRef, ContentModel.PROP_CONTENT); + assertNotNull("test setup content reader not null", reader); + Map props = nodeService.getProperties(contentNodeRef); + assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); + + /** + * Step 2: replace empty content with new content + */ + TransferDefinition definition = new TransferDefinition(); + Setnodes = new HashSet(); + nodes.add(contentNodeRef); + definition.setNodes(nodes); + transferService.transfer(targetName, definition); + + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + NodeRef destinationNodeRef = testNodeFactory.getMappedNodeRef(contentNodeRef); + + assertEquals("test error destinationNodeRef not correct", savedDestinationNodeRef, destinationNodeRef); + ContentReader reader = contentService.getReader(destinationNodeRef, ContentModel.PROP_CONTENT); + assertNotNull("content reader is null", reader); + assertEquals("content encoding is wrong", reader.getEncoding(), CONTENT_ENCODING); + assertEquals("content locale is wrong", reader.getLocale(), CONTENT_LOCALE); + assertTrue("content does not exist", reader.exists()); + String contentStr = reader.getContentString(); + assertEquals("Content is wrong", contentStr, CONTENT_STRING); + } + finally + { + endTransaction(); + } + + /** + * Step 3 - transition from a content property having content to one that is empty + */ + logger.debug("testEmptyContent : Third transfer - remove existing content"); + + startNewTransaction(); + try + { + ContentData cd = new ContentData(null, null, 0, null); + nodeService.setProperty(contentNodeRef, ContentModel.PROP_CONTENT, cd); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + ContentReader reader = contentService.getReader(contentNodeRef, ContentModel.PROP_CONTENT); + assertNull("test setup content reader not null", reader); + Map props = nodeService.getProperties(contentNodeRef); + assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); + + /** + * Step 3: Transfer our node which has empty content to over-write existing + * content + */ + TransferDefinition definition = new TransferDefinition(); + Setnodes = new HashSet(); + nodes.add(contentNodeRef); + definition.setNodes(nodes); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + NodeRef destinationNodeRef = testNodeFactory.getMappedNodeRef(contentNodeRef); + assertTrue("content node (dest) does not exist", nodeService.exists(destinationNodeRef)); + + ContentReader reader = contentService.getReader(destinationNodeRef, ContentModel.PROP_CONTENT); + assertNull("content reader not null", reader); + Map props = nodeService.getProperties(destinationNodeRef); + assertTrue(props.containsKey(ContentModel.PROP_CONTENT)); + + } + finally + { + endTransaction(); + } + + } // end of testEmptyContent + + + /** + * Test the transfer method with regard to a repeated update of content.by sending one node (CRUD). + * + * This is a unit test so it does some shenanigans to send to the same instance of alfresco. + */ + public void testRepeatUpdateOfContent() throws Exception + { + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); + final String CONTENT_TITLE = "ContentTitle"; + final Locale CONTENT_LOCALE = Locale.GERMAN; + final String CONTENT_ENCODING = "UTF-8"; + + /** + * For unit test + * - replace the HTTP transport with the in-process transport + * - replace the node factory with one that will map node refs, paths etc. + * + * Fake Repository Id + */ + final TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService); + transferServiceImpl.setTransmitter(transmitter); + final UnitTestTransferManifestNodeFactory testNodeFactory = new UnitTestTransferManifestNodeFactory(this.transferManifestNodeFactory); + transferServiceImpl.setTransferManifestNodeFactory(testNodeFactory); + final List> pathMap = testNodeFactory.getPathMap(); + // Map company_home/guest_home to company_home so tranferred nodes and moved "up" one level. + pathMap.add(new Pair(PathHelper.stringToPath(GUEST_HOME_XPATH_QUERY), PathHelper.stringToPath(COMPANY_HOME_XPATH_QUERY))); + + DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + + final String targetName = "testRepeatUpdateOfContent"; + + class TestContext + { + TransferTarget transferMe; + NodeRef contentNodeRef; + NodeRef destNodeRef; + String contentString; + }; + + RetryingTransactionCallback setupCB = new RetryingTransactionCallback() + { + @Override + public TestContext execute() throws Throwable + { + TestContext testContext = new TestContext(); + + /** + * 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); + + /** + * Create a test node that we will read and write + */ + String name = GUID.generate(); + ChildAssociationRef child = nodeService.createNode(guestHome, ContentModel.ASSOC_CONTAINS, QName.createQName(name), ContentModel.TYPE_CONTENT); + testContext.contentNodeRef = child.getChildRef(); + nodeService.setProperty(testContext.contentNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(testContext.contentNodeRef, ContentModel.PROP_NAME, name); + + /** + * Make sure the transfer target exists and is enabled. + */ + if(!transferService.targetExists(targetName)) + { + testContext.transferMe = createTransferTarget(targetName); + } + else + { + testContext.transferMe = transferService.getTransferTarget(targetName); + } + transferService.enableTransferTarget(targetName, true); + return testContext; + } + }; + + final TestContext testContext = tran.doInTransaction(setupCB); + + RetryingTransactionCallback updateContentCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + ContentWriter writer = contentService.getWriter(testContext.contentNodeRef, ContentModel.PROP_CONTENT, true); + writer.setLocale(CONTENT_LOCALE); + writer.setEncoding(CONTENT_ENCODING); + writer.putContent(testContext.contentString); + return null; + } + }; + + RetryingTransactionCallback transferCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + TransferDefinition definition = new TransferDefinition(); + Setnodes = new HashSet(); + nodes.add(testContext.contentNodeRef); + definition.setNodes(nodes); + transferService.transfer(targetName, definition); + return null; + } + }; + + RetryingTransactionCallback checkTransferCB = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + // Now validate that the target node exists and has similar properties to the source + NodeRef destNodeRef = testNodeFactory.getMappedNodeRef(testContext.contentNodeRef); + + ContentReader reader = contentService.getReader(destNodeRef, ContentModel.PROP_CONTENT); + assertNotNull("content reader is null", reader); + assertEquals("content encoding is wrong", reader.getEncoding(), CONTENT_ENCODING); + assertEquals("content locale is wrong", reader.getLocale(), CONTENT_LOCALE); + assertTrue("content does not exist", reader.exists()); + String contentStr = reader.getContentString(); + assertEquals("Content is wrong", contentStr, testContext.contentString); + + return null; + } + }; + + /** + * This is the test + */ + for(int i = 0; i < 6 ; i++) + { + logger.debug("testRepeatUpdateContent - iteration:" + i); + testContext.contentString = String.valueOf(i); + tran.doInTransaction(updateContentCB); + tran.doInTransaction(transferCB); + tran.doInTransaction(checkTransferCB); + } + } // test repeat update content private void createUser(String userName, String password)