diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index f8a9094c6a..196149832c 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -552,6 +552,7 @@ fm:commentCount cm:storeName + cm:content diff --git a/source/java/org/alfresco/opencmis/CMISConnector.java b/source/java/org/alfresco/opencmis/CMISConnector.java index 1393bbf93a..433dfe42ec 100644 --- a/source/java/org/alfresco/opencmis/CMISConnector.java +++ b/source/java/org/alfresco/opencmis/CMISConnector.java @@ -1413,6 +1413,7 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen Map props = new HashMap(); props.put(ContentModel.PROP_INITIAL_VERSION, false); props.put(ContentModel.PROP_AUTO_VERSION, false); + props.put(ContentModel.PROP_AUTO_VERSION_PROPS, false); nodeService.addAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE, props); } @@ -1429,6 +1430,7 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen Map props = new HashMap(); props.put(ContentModel.PROP_INITIAL_VERSION, false); props.put(ContentModel.PROP_AUTO_VERSION, false); + props.put(ContentModel.PROP_AUTO_VERSION_PROPS, false); nodeService.addAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE, props); } diff --git a/source/java/org/alfresco/repo/version/VersionableAspect.java b/source/java/org/alfresco/repo/version/VersionableAspect.java index d6fa5d7150..89def120b4 100644 --- a/source/java/org/alfresco/repo/version/VersionableAspect.java +++ b/source/java/org/alfresco/repo/version/VersionableAspect.java @@ -432,6 +432,7 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate // Create the auto-version Map versionProperties = new HashMap(1); versionProperties.put(Version.PROP_DESCRIPTION, I18NUtil.getMessage(MSG_AUTO_VERSION)); + versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR); createVersionImpl(nodeRef, versionProperties); } @@ -463,24 +464,15 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate Map versionedNodeRefs = (Map)AlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS); if (versionedNodeRefs == null || versionedNodeRefs.containsKey(nodeRef) == false) { - // Determine whether the node is auto versionable (for property only updates) or not - boolean autoVersion = false; - Boolean value = (Boolean)this.nodeService.getProperty(nodeRef, ContentModel.PROP_AUTO_VERSION); - if (value != null) - { - // If the value is not null then - autoVersion = value.booleanValue(); - } - boolean autoVersionProps = false; - value = (Boolean)this.nodeService.getProperty(nodeRef, ContentModel.PROP_AUTO_VERSION_PROPS); + Boolean value = (Boolean)this.nodeService.getProperty(nodeRef, ContentModel.PROP_AUTO_VERSION_PROPS); if (value != null) { // If the value is not null then autoVersionProps = value.booleanValue(); } - if ((autoVersion == true) && (autoVersionProps == true)) + if (autoVersionProps == true) { // Check for explicitly excluded props - if one or more excluded props changes then do not auto-version on this event (even if other props changed) if (excludedOnUpdatePropQNames.size() > 0) diff --git a/source/test-java/org/alfresco/opencmis/CMISTest.java b/source/test-java/org/alfresco/opencmis/CMISTest.java index 5835621bc7..107c2244a3 100644 --- a/source/test-java/org/alfresco/opencmis/CMISTest.java +++ b/source/test-java/org/alfresco/opencmis/CMISTest.java @@ -82,7 +82,9 @@ import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.tagging.TaggingService; +import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.VersionService; +import org.alfresco.service.cmr.version.VersionType; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; @@ -2753,4 +2755,249 @@ public class CMISTest withCmisService(callback, CmisVersion.CMIS_1_1); } + + /** + * Test to ensure auto version behavior for update properties, set and delete content using both Alfresco and CMIS perspectives. + * Testing different combinations of cm:initialVersion, cm:autoVersion and cm:autoVersionOnUpdateProps properties + *
+ * OnUpdateProperties MINOR version should be created if cm:initialVersion and cm:autoVersionOnUpdateProps are both TRUE + *
+ * OnContentUpdate MINOR version should be created if cm:initialVersion and cm:autoVersion are both TRUE + * + * @throws Exception + */ + @Test + public void testUpdatePropertiesSetDeleteContentVersioning() throws Exception + { + AuthenticationUtil.pushAuthentication(); + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + + final String FOLDER = "testUpdatePropertiesSetDeleteContentVersioning-" + GUID.generate(); + final String DOC1 = "documentProperties1-" + GUID.generate(); + final String DOC2 = "documentProperties2-" + GUID.generate(); + final String DOC3 = "documentProperties3-" + GUID.generate(); + final String DOC4 = "documentProperties4-" + GUID.generate(); + + try + { + final List docs = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() + { + @Override + public List execute() throws Throwable + { + // create folder + FileInfo folderInfo = fileFolderService.create(repositoryHelper.getCompanyHome(), FOLDER, ContentModel.TYPE_FOLDER); + nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, FOLDER); + assertNotNull(folderInfo); + + FileInfo document; + List docs = new ArrayList(); + // create documents + document = fileFolderService.create(folderInfo.getNodeRef(), DOC1, ContentModel.TYPE_CONTENT); + nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC1); + docs.add(document); + document = fileFolderService.create(folderInfo.getNodeRef(), DOC2, ContentModel.TYPE_CONTENT); + nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC2); + docs.add(document); + document = fileFolderService.create(folderInfo.getNodeRef(), DOC3, ContentModel.TYPE_CONTENT); + nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC3); + docs.add(document); + document = fileFolderService.create(folderInfo.getNodeRef(), DOC4, ContentModel.TYPE_CONTENT); + nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC4); + docs.add(document); + + Map props = new HashMap(); + props.put(ContentModel.PROP_TITLE, "Initial Title"); + props.put(ContentModel.PROP_DESCRIPTION, "Initial Description"); + + for (FileInfo fileInfo : docs) + { + nodeService.addAspect(fileInfo.getNodeRef(), ContentModel.ASPECT_TITLED, props); + } + + // apply versionable aspect with properties + props = new HashMap(); + // ContentModel.PROP_INITIAL_VERSION always true + props.put(ContentModel.PROP_INITIAL_VERSION, true); + + props.put(ContentModel.PROP_AUTO_VERSION, false); + props.put(ContentModel.PROP_AUTO_VERSION_PROPS, false); + versionService.ensureVersioningEnabled(docs.get(0).getNodeRef(), props); + + props.put(ContentModel.PROP_AUTO_VERSION, false); + props.put(ContentModel.PROP_AUTO_VERSION_PROPS, true); + versionService.ensureVersioningEnabled(docs.get(1).getNodeRef(), props); + + props.put(ContentModel.PROP_AUTO_VERSION, true); + props.put(ContentModel.PROP_AUTO_VERSION_PROPS, false); + versionService.ensureVersioningEnabled(docs.get(2).getNodeRef(), props); + + props.put(ContentModel.PROP_AUTO_VERSION, true); + props.put(ContentModel.PROP_AUTO_VERSION_PROPS, true); + versionService.ensureVersioningEnabled(docs.get(3).getNodeRef(), props); + + return docs; + } + }); + + assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(1).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(2).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(3).getNodeRef(), "1.0", VersionType.MAJOR); + + // update node properties using Alfresco + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() + { + @Override + public List execute() throws Throwable + { + for (FileInfo fileInfo : docs) + { + Map props = nodeService.getProperties(fileInfo.getNodeRef()); + + props.put(ContentModel.PROP_DESCRIPTION, "description-" + GUID.generate()); + props.put(ContentModel.PROP_TITLE, "title-" + GUID.generate()); + + nodeService.setProperties(fileInfo.getNodeRef(), props); + } + return null; + } + }); + + assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(1).getNodeRef(), "1.1", VersionType.MINOR); + assertVersions(docs.get(2).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(3).getNodeRef(), "1.1", VersionType.MINOR); + + // update properties using CMIS perspective + final String repositoryId = withCmisService(new CmisServiceCallback() + { + @Override + public String execute(CmisService cmisService) + { + String repositoryId = cmisService.getRepositoryInfos(null).get(0).getId(); + + for (FileInfo fileInfo : docs) + { + PropertiesImpl properties = new PropertiesImpl(); + properties.addProperty(new PropertyStringImpl(PropertyIds.DESCRIPTION, "description-" + GUID.generate())); + + cmisService.updateProperties(repositoryId, new Holder(fileInfo.getNodeRef().toString()), null, properties, null); + } + + return repositoryId; + } + }, CmisVersion.CMIS_1_1); + + assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(1).getNodeRef(), "1.2", VersionType.MINOR); + assertVersions(docs.get(2).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(3).getNodeRef(), "1.2", VersionType.MINOR); + + // CMIS setContentStream + withCmisService(new CmisServiceCallback() + { + @Override + public Void execute(CmisService cmisService) + { + for (FileInfo fileInfo : docs) + { + ContentStreamImpl contentStream = new ContentStreamImpl(null, MimetypeMap.MIMETYPE_TEXT_PLAIN, "Content " + GUID.generate()); + + cmisService.setContentStream(repositoryId, new Holder(fileInfo.getNodeRef().toString()), true, null, contentStream, null); + } + return null; + } + }, CmisVersion.CMIS_1_1); + + assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(1).getNodeRef(), "1.2", VersionType.MINOR); + assertVersions(docs.get(2).getNodeRef(), "1.1", VersionType.MINOR); + assertVersions(docs.get(3).getNodeRef(), "1.3", VersionType.MINOR); + + // update content using Alfresco + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() + { + @Override + public List execute() throws Throwable + { + for (FileInfo fileInfo : docs) + { + ContentWriter writer = contentService.getWriter(fileInfo.getNodeRef(), ContentModel.PROP_CONTENT, true); + writer.putContent("Content " + GUID.generate()); + } + return null; + } + }); + + assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(1).getNodeRef(), "1.2", VersionType.MINOR); + assertVersions(docs.get(2).getNodeRef(), "1.2", VersionType.MINOR); + assertVersions(docs.get(3).getNodeRef(), "1.4", VersionType.MINOR); + + // CMIS deleteContentStream + withCmisService(new CmisServiceCallback() + { + @Override + public Void execute(CmisService cmisService) + { + for (FileInfo fileInfo : docs) + { + cmisService.deleteContentStream(repositoryId, new Holder(fileInfo.getNodeRef().toString()), null, null); + } + return null; + } + }, CmisVersion.CMIS_1_1); + + assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); + assertVersions(docs.get(1).getNodeRef(), "1.2", VersionType.MINOR); + assertVersions(docs.get(2).getNodeRef(), "1.3", VersionType.MINOR); + assertVersions(docs.get(3).getNodeRef(), "1.5", VersionType.MINOR); + } + finally + { + AuthenticationUtil.popAuthentication(); + } + } + + private void assertVersions(final NodeRef nodeRef, final String expectedVersionLabel, final VersionType expectedVersionType) + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() + { + @Override + public List execute() throws Throwable + { + assertTrue("Node should be versionable", nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + Version version = versionService.getCurrentVersion(nodeRef); + + assertNotNull(version); + assertEquals(expectedVersionLabel, version.getVersionLabel()); + assertEquals(expectedVersionType, version.getVersionType()); + + return null; + } + }); + + withCmisService(new CmisServiceCallback() + { + @Override + public Void execute(CmisService cmisService) + { + String repositoryId = cmisService.getRepositoryInfos(null).get(0).getId(); + + ObjectData data = + cmisService.getObjectOfLatestVersion(repositoryId, nodeRef.toString(), null, Boolean.FALSE, null, null, null, null, null, null, null); + + assertNotNull(data); + + PropertyData prop = data.getProperties().getProperties().get(PropertyIds.VERSION_LABEL); + Object versionLabelCmisValue = prop.getValues().get(0); + + assertEquals(expectedVersionLabel, versionLabelCmisValue); + + return null; + } + }, CmisVersion.CMIS_1_1); + } }