diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml index 2dceed950f..04f990f6d5 100644 --- a/config/alfresco/action-services-context.xml +++ b/config/alfresco/action-services-context.xml @@ -338,6 +338,9 @@ {http://www.alfresco.org/model/content/1.0}content + + true + diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index a85fc04226..8972ba2b74 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -488,7 +488,7 @@ 20 - 7 + 5 diff --git a/config/alfresco/extension/wcm-xml-metadata-extracter-context.xml.sample b/config/alfresco/extension/wcm-xml-metadata-extracter-context.xml.sample index e5f454810a..d143498d71 100644 --- a/config/alfresco/extension/wcm-xml-metadata-extracter-context.xml.sample +++ b/config/alfresco/extension/wcm-xml-metadata-extracter-context.xml.sample @@ -53,6 +53,9 @@ + + true + diff --git a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java index f4e29ba44e..33a7b1f1a5 100644 --- a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java +++ b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java @@ -56,14 +56,18 @@ import org.alfresco.service.namespace.QName; */ public class ContentMetadataExtracter extends ActionExecuterAbstractBase { - /** - * The node service - */ private NodeService nodeService; + private ContentService contentService; + private DictionaryService dictionaryService; + private MetadataExtracterRegistry metadataExtracterRegistry; + private boolean carryAspectProperties; + + public ContentMetadataExtracter() + { + carryAspectProperties = true; + } /** - * Set the node service - * * @param nodeService the node service */ public void setNodeService(NodeService nodeService) @@ -71,11 +75,6 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase this.nodeService = nodeService; } - /** - * Our content service - */ - private ContentService contentService; - /** * @param contentService The contentService to set. */ @@ -84,11 +83,6 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase this.contentService = contentService; } - /** - * The dictionary service - */ - private DictionaryService dictionaryService; - /** * @param dictService The DictionaryService to set. */ @@ -97,11 +91,6 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase this.dictionaryService = dictService; } - /** - * Our Extracter - */ - private MetadataExtracterRegistry metadataExtracterRegistry; - /** * @param metadataExtracterRegistry The metadataExtracterRegistry to set. */ @@ -110,6 +99,18 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase this.metadataExtracterRegistry = metadataExtracterRegistry; } + /** + * Whether or not aspect-related properties must be carried to the new version of the node + * + * @param carryAspectProperties true (default) to carry all aspect-linked + * properties forward. false will clean the + * aspect of any unextracted values. + */ + public void setCarryAspectProperties(boolean carryAspectProperties) + { + this.carryAspectProperties = carryAspectProperties; + } + /** * @see org.alfresco.repo.action.executer.ActionExecuter#execute(org.alfresco.service.cmr.repository.NodeRef, * NodeRef) @@ -155,6 +156,7 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase // Check that all properties have the appropriate aspect applied Set requiredAspectQNames = new HashSet(3); + Set aspectPropertyQNames = new HashSet(17); for (QName propertyQName : modifiedProperties.keySet()) { @@ -169,6 +171,21 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase { QName aspectQName = propertyContainerDef.getName(); requiredAspectQNames.add(aspectQName); + // Get all properties associated with the aspect + Set aspectProperties = propertyContainerDef.getProperties().keySet(); + aspectPropertyQNames.addAll(aspectProperties); + } + } + + if (!carryAspectProperties) + { + // Remove any node properties that are defined on the aspects but were not extracted + for (QName aspectPropertyQName : aspectPropertyQNames) + { + if (!modifiedProperties.containsKey(aspectPropertyQName)) + { + nodeProperties.remove(aspectPropertyQName); + } } } diff --git a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java index 9dbb34fadc..1150f7869a 100644 --- a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java +++ b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java @@ -78,6 +78,7 @@ import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.BaseSpringTest; import org.alfresco.util.GUID; import org.alfresco.util.PropertyMap; +import org.apache.commons.collections.map.SingletonMap; import org.hibernate.Session; import org.springframework.context.ApplicationContext; @@ -679,6 +680,95 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest 0, nodeService.getTargetAssocs(sourceNodeRef, RegexQNamePattern.MATCH_ALL).size()); } + private static final QName ASPECT_QNAME_TEST_RENDERED = QName.createQName(NAMESPACE, "rendered"); + private static final QName ASSOC_TYPE_QNAME_TEST_RENDITION = QName.createQName(NAMESPACE, "rendition-page"); + private static final QName TYPE_QNAME_TEST_RENDITION_PAGE = QName.createQName(NAMESPACE, "rendition-page"); + private static final QName PROP_QNAME_TEST_RENDITION_PAGE_CONTENT = QName.createQName(NAMESPACE, "rendition-page-content"); + public void testAspectWithChildAssociationsCreationAndRetrieval() throws Exception + { + // Create a folder. This is like the user's home folder, say. + NodeRef folderNodeRef = nodeService.createNode( + rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName(BaseNodeServiceTest.NAMESPACE, "UserX-" + GUID.generate()), + ContentModel.TYPE_FOLDER).getChildRef(); + // Create a document. This is the actual document uploaded by the user. + NodeRef fileNodeRef = nodeService.createNode( + folderNodeRef, + ContentModel.ASSOC_CONTAINS, + QName.createQName(BaseNodeServiceTest.NAMESPACE, "Uploaded.pdf"), + ContentModel.TYPE_FOLDER).getChildRef(); + // So, thus far, this is exactly what you have. Now for the bit to add some renditions. + // First, we can make some content data pages - spoofed, of course + List renditionContentPages = new ArrayList(20); + // This loop is where you will, outside of the transaction, push the page content into the repo + for(int i = 0; i < 100; i++) + { + ContentData contentData = new ContentData(null, MimetypeMap.MIMETYPE_PDF, 10245, "UTF-8"); + renditionContentPages.add(contentData); + } + + nodeService.addAspect(fileNodeRef, ASPECT_QNAME_TEST_RENDERED, null); + int pageNumber = 0; + for (ContentData renditionContentPage : renditionContentPages) + { + pageNumber++; + QName renditionQName = makePageAssocName(pageNumber); + Map properties = Collections.singletonMap( + PROP_QNAME_TEST_RENDITION_PAGE_CONTENT, + (Serializable) renditionContentPage); + nodeService.createNode( + fileNodeRef, + ASSOC_TYPE_QNAME_TEST_RENDITION, + renditionQName, + TYPE_QNAME_TEST_RENDITION_PAGE, + properties); + } + + // That's it for uploading. Now we retrieve them. + if (!nodeService.hasAspect(fileNodeRef, ASPECT_QNAME_TEST_RENDERED)) + { + // Jump to the original rendition retrieval code + return; + } + // It has the aspect, so it's the new model + List fetchedRenditionChildAssocs = nodeService.getChildAssocs( + fileNodeRef, + ASSOC_TYPE_QNAME_TEST_RENDITION, + RegexQNamePattern.MATCH_ALL); + assertEquals( + "We didn't get the correct number of pages back", + renditionContentPages.size(), + fetchedRenditionChildAssocs.size()); + // Get page ... 5. This is to prove that they are ordered. + ChildAssociationRef fetchedRenditionChildAssoc5 = fetchedRenditionChildAssocs.get(4); + QName page5QName = makePageAssocName(5); + assertEquals( + "Local name of page 5 assoc is not correct", + page5QName, + fetchedRenditionChildAssoc5.getQName()); + // Now retrieve page 5 using the NodeService + List fetchedRenditionChildAssocsPage5 = nodeService.getChildAssocs( + fileNodeRef, + ASSOC_TYPE_QNAME_TEST_RENDITION, + page5QName); + assertEquals("Expected exactly one result", 1, fetchedRenditionChildAssocsPage5.size()); + assertEquals("Targeted page retrieval was not correct", + page5QName, + fetchedRenditionChildAssocsPage5.get(0).getQName()); + } + private static final int MAX_RENDITION_PAGES = 100; + private static QName makePageAssocName(int pageNumber) + { + if (pageNumber > MAX_RENDITION_PAGES) + { + throw new IllegalArgumentException("Rendition page number may not exceed " + MAX_RENDITION_PAGES); + } + String pageLocalName = String.format("renditionpage%05d", pageNumber); + QName renditionQName = QName.createQName(NAMESPACE, pageLocalName); + return renditionQName; + } + public void testCreateNodeNoProperties() throws Exception { // flush to ensure that the pure JDBC query will work diff --git a/source/java/org/alfresco/repo/node/BaseNodeServiceTest_model.xml b/source/java/org/alfresco/repo/node/BaseNodeServiceTest_model.xml index ab0cafc0b8..210fd831fc 100644 --- a/source/java/org/alfresco/repo/node/BaseNodeServiceTest_model.xml +++ b/source/java/org/alfresco/repo/node/BaseNodeServiceTest_model.xml @@ -274,6 +274,17 @@ + + + Rendition Page + sys:base + + + d:content + true + + + @@ -351,7 +362,24 @@ - + + + Aspect for Hanging Renditions Off + + + + false + false + + + test:rendition-page + false + true + + + + +