diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml index f5e8590fde..87ddf5dfef 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml @@ -258,6 +258,7 @@ + ${rm.ghosting.enabled} diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml index 3975bab461..c9921401f7 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml @@ -14,7 +14,6 @@ - @@ -71,6 +70,7 @@ org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.isCurrentVersionRecorded=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.isRecordedVersion=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.getVersionRecord=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.getRecordedVersion=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.createRecordFromLatestVersion=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.isRecordedVersionDestroyed=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.destroyRecordedVersion=RM_ALLOW diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DestroyAction.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DestroyAction.java index 27b0805122..d16dd76c78 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DestroyAction.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DestroyAction.java @@ -29,6 +29,7 @@ import org.alfresco.module.org_alfresco_module_rm.action.RMDispositionActionExec import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; +import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService; import org.alfresco.repo.content.cleanup.EagerContentStoreCleaner; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; @@ -36,6 +37,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.version.Version; import org.alfresco.service.namespace.QName; import org.apache.commons.lang.StringUtils; @@ -54,6 +56,9 @@ public class DestroyAction extends RMDispositionActionExecuterAbstractBase /** Capability service */ private CapabilityService capabilityService; + + /** Recordable version service */ + private RecordableVersionService recordableVersionService; /** Indicates if ghosting is enabled or not */ private boolean ghostingEnabled = true; @@ -73,6 +78,14 @@ public class DestroyAction extends RMDispositionActionExecuterAbstractBase { this.capabilityService = capabilityService; } + + /** + * @param recordableVersionService recordable version service + */ + public void setRecordableVersionService(RecordableVersionService recordableVersionService) + { + this.recordableVersionService = recordableVersionService; + } /** * @param ghostingEnabled true if ghosting is enabled, false otherwise @@ -150,6 +163,13 @@ public class DestroyAction extends RMDispositionActionExecuterAbstractBase if (isGhostOnDestroySetForAction(action, record)) { + // mark version as destroyed + Version version = recordableVersionService.getRecordedVersion(record); + if (version != null) + { + recordableVersionService.destroyRecordedVersion(version); + } + // Add the ghosted aspect getNodeService().addAspect(record, ASPECT_GHOSTED, null); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspect.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspect.java index 165bbd9819..3eb9e0865d 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspect.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspect.java @@ -18,9 +18,6 @@ */ package org.alfresco.module.org_alfresco_module_rm.model.rma.aspect; -import static org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel.PROP_VERSIONED_NODEREF; -import static org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel.PROP_VERSION_LABEL; - import java.util.Set; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; @@ -34,9 +31,6 @@ import org.alfresco.repo.policy.annotation.BehaviourKind; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.version.Version; -import org.alfresco.service.cmr.version.VersionHistory; -import org.alfresco.service.cmr.version.VersionService; -import org.apache.commons.lang.StringUtils; /** * rmv:versionRecord behaviour bean @@ -51,22 +45,11 @@ import org.apache.commons.lang.StringUtils; public class VersionRecordAspect extends BaseBehaviourBean implements NodeServicePolicies.BeforeDeleteNodePolicy { - /** version service */ - private VersionService versionService; - /** recordable version service */ private RecordableVersionService recordableVersionService; /** relationship service */ private RelationshipService relationshipService; - - /** - * @param versionService version service - */ - public void setVersionService(VersionService versionService) - { - this.versionService = versionService; - } /** * @param recordableVersionService recordable version service @@ -93,60 +76,48 @@ public class VersionRecordAspect extends BaseBehaviourBean @Behaviour (kind = BehaviourKind.CLASS) public void beforeDeleteNode(final NodeRef nodeRef) { - final NodeRef versionedNodeRef = (NodeRef) nodeService.getProperty(nodeRef, PROP_VERSIONED_NODEREF); - if (versionedNodeRef != null) + final Version version = recordableVersionService.getRecordedVersion(nodeRef); + if (version != null) { - String versionLabel = (String) nodeService.getProperty(nodeRef, PROP_VERSION_LABEL); - if (StringUtils.isNotBlank(versionLabel)) + authenticationUtil.runAsSystem(new RunAsWork() { - final VersionHistory versionHistory = versionService.getVersionHistory(versionedNodeRef); - if (versionHistory != null) + @Override + public Void doWork() { - final Version version = versionHistory.getVersion(versionLabel); - if (version != null) + behaviourFilter.disableBehaviour(); + try { - authenticationUtil.runAsSystem(new RunAsWork() + // mark the associated version as destroyed + recordableVersionService.destroyRecordedVersion(version); + + // re-organise the versions relationships ... + // if there is only one "to" reference since a version can only have one predecessor + Set tos = relationshipService.getRelationshipsTo(nodeRef, RelationshipService.RELATIONSHIP_VERSIONS); + if (!tos.isEmpty() && tos.size() == 1) { - @Override - public Void doWork() + // if there is some "from" references + Set froms = relationshipService.getRelationshipsFrom(nodeRef, RelationshipService.RELATIONSHIP_VERSIONS); + if (!froms.isEmpty()) { - behaviourFilter.disableBehaviour(); - try + // get predecessor version relationship + Relationship to = tos.iterator().next(); + + for (Relationship from : froms) { - // mark the associated version as destroyed - recordableVersionService.destroyRecordedVersion(version); - - // re-organise the versions relationships ... - // if there is only one "to" reference since a version can only have one predecessor - Set tos = relationshipService.getRelationshipsTo(nodeRef, RelationshipService.RELATIONSHIP_VERSIONS); - if (!tos.isEmpty() && tos.size() == 1) - { - // if there is some "from" references - Set froms = relationshipService.getRelationshipsFrom(nodeRef, RelationshipService.RELATIONSHIP_VERSIONS); - if (!froms.isEmpty()) - { - // get predecessor version relationship - Relationship to = tos.iterator().next(); - - for (Relationship from : froms) - { - // point the "to" the all the "from's" - relationshipService.addRelationship(RelationshipService.RELATIONSHIP_VERSIONS, to.getSource(), from.getTarget()); - } - } - } + // point the "to" the all the "from's" + relationshipService.addRelationship(RelationshipService.RELATIONSHIP_VERSIONS, to.getSource(), from.getTarget()); } - finally - { - behaviourFilter.enableBehaviour(); - } - - return null; } - }); + } } + finally + { + behaviourFilter.enableBehaviour(); + } + + return null; } - } - } + }); + } } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java index 6687da6580..15f3757333 100755 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java @@ -56,6 +56,14 @@ public interface RecordableVersionService */ NodeRef getVersionRecord(Version version); + /** + * Gets the version that relates to the version record + * + * @param versionRecord version record node reference + * @return Version version or null if not found + */ + Version getRecordedVersion(NodeRef record); + /** * Creates a record from the latest version, marking it as recorded. *

diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java index c5d2a14408..417e66fe08 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java @@ -55,6 +55,7 @@ import org.alfresco.service.cmr.version.VersionType; import org.alfresco.service.namespace.QName; import org.alfresco.util.ParameterCheck; import org.alfresco.util.PropertyMap; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -503,67 +504,30 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl return versionRecord; } - + + /** + * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#getRecordedVersion(org.alfresco.service.cmr.repository.NodeRef) + */ @Override - protected VersionHistory buildVersionHistory(NodeRef versionHistoryRef, NodeRef nodeRef) + public Version getRecordedVersion(NodeRef versionRecord) { - VersionHistory versionHistory = super.buildVersionHistory(versionHistoryRef, nodeRef); - - // create an empty version history if appropriate - if (versionHistoryRef != null && - nodeRef != null && - versionHistory == null && - getAllVersions(versionHistoryRef).isEmpty() == true) + Version version = null; + NodeRef versionedNodeRef = (NodeRef) nodeService.getProperty(versionRecord, RecordableVersionModel.PROP_VERSIONED_NODEREF); + if (versionedNodeRef != null) { - versionHistory = new EmptyVersionHistory(); + String versionLabel = (String) nodeService.getProperty(versionRecord, RecordableVersionModel.PROP_VERSION_LABEL); + if (StringUtils.isNotBlank(versionLabel)) + { + VersionHistory versionHistory = getVersionHistory(versionedNodeRef); + if (versionHistory != null) + { + version = versionHistory.getVersion(versionLabel); + } + } } - - return versionHistory; + return version; } - - public class EmptyVersionHistory implements VersionHistory - { - private static final long serialVersionUID = 3449832161314670033L; - @Override - public Version getRootVersion() - { - return null; - } - - @Override - public Version getHeadVersion() - { - return null; - } - - @SuppressWarnings("unchecked") - @Override - public Collection getAllVersions() - { - return (Collection)Collections.EMPTY_LIST; - } - - @Override - public Version getPredecessor(Version version) - { - return null; - } - - @SuppressWarnings("unchecked") - @Override - public Collection getSuccessors(Version version) - { - return (Collection)Collections.EMPTY_LIST; - } - - @Override - public Version getVersion(String versionLabel) - { - return null; - } - } - /** * Freezes audit aspect properties. * diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeleteRecordVersionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeleteRecordVersionTest.java index 9a7e62a22a..7fd26b0bf0 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeleteRecordVersionTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeleteRecordVersionTest.java @@ -19,13 +19,18 @@ package org.alfresco.module.org_alfresco_module_rm.test.integration.version; import java.io.Serializable; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.action.impl.CompleteEventAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.DestroyAction; import org.alfresco.module.org_alfresco_module_rm.relationship.Relationship; import org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService; +import org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionPolicy; import org.alfresco.repo.content.MimetypeMap; @@ -397,4 +402,105 @@ public class DeleteRecordVersionTest extends RecordableVersionsBaseTest } }); } + + /** + * Given that a version record + * When the version record is destroyed whilst retaining the meta data + * Then the version is marked as destroyed in the collab version history + */ + public void testDetroyVerionRecordWithMetadata() + { + final NodeRef myDocument = createDocumentWithRecordVersions(); + + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private VersionHistory versionHistory; + private NodeRef recordVersion11; + + public void given() throws Exception + { + // create file plan structure + NodeRef myCategory = filePlanService.createRecordCategory(filePlan, GUID.generate()); + utils.createBasicDispositionSchedule(myCategory, GUID.generate(), GUID.generate(), true, true); + + NodeRef myRecordFolder = recordFolderService.createRecordFolder(myCategory, GUID.generate()); + + // get version history + versionHistory = versionService.getVersionHistory(myDocument); + + // file and complete all the version records into my record folder + for (Version version : versionHistory.getAllVersions()) + { + NodeRef record = recordableVersionService.getVersionRecord(version); + fileFolderService.move(record, myRecordFolder, null); + utils.completeRecord(record); + } + } + + public void when() + { + Version version11 = versionHistory.getVersion("1.1"); + recordVersion11 = recordableVersionService.getVersionRecord(version11); + + Map params = new HashMap(1); + params.put(CompleteEventAction.PARAM_EVENT_NAME, CommonRMTestUtils.DEFAULT_EVENT_NAME); + rmActionService.executeRecordsManagementAction(recordVersion11, CompleteEventAction.NAME, params); + + rmActionService.executeRecordsManagementAction(recordVersion11, CutOffAction.NAME); + + rmActionService.executeRecordsManagementAction(recordVersion11, DestroyAction.NAME); + } + + public void then() + { + // verify that the version history looks as expected + VersionHistory versionHistory = versionService.getVersionHistory(myDocument); + assertNotNull(versionHistory); + Collection versions = versionHistory.getAllVersions(); + assertEquals(3, versions.size()); + + // verify 1.2 setup as expected + Version version12 = versionHistory.getHeadVersion(); + assertEquals("1.2", version12.getVersionLabel()); + assertFalse(recordableVersionService.isRecordedVersionDestroyed(version12)); + NodeRef recordVersion12 = recordableVersionService.getVersionRecord(version12); + assertNotNull(recordVersion12); + assertFalse(recordService.isMetadataStub(recordVersion12)); + + assertTrue(relationshipService.getRelationshipsTo(recordVersion12, "versions").isEmpty()); + + Set from12 = relationshipService.getRelationshipsFrom(recordVersion12, "versions"); + assertEquals(1, from12.size()); + + // verify 1.1 setup as expected + Version version11 = versionHistory.getPredecessor(version12); + assertEquals("1.1", version11.getVersionLabel()); + assertTrue(recordableVersionService.isRecordedVersionDestroyed(version11)); + assertNotNull(recordVersion11); + assertTrue(recordService.isMetadataStub(recordVersion11)); + + Set to11 = relationshipService.getRelationshipsTo(recordVersion11, "versions"); + assertEquals(1, to11.size()); + assertEquals(recordVersion12, to11.iterator().next().getSource()); + + Set from11 = relationshipService.getRelationshipsFrom(recordVersion11, "versions"); + assertEquals(1, from11.size()); + + // verify 1.0 setup as expected + Version version10 = versionHistory.getPredecessor(version11); + assertEquals("1.0", version10.getVersionLabel()); + assertFalse(recordableVersionService.isRecordedVersionDestroyed(version10)); + NodeRef recordVersion10 = recordableVersionService.getVersionRecord(version10); + assertNotNull(recordVersion10); + assertFalse(recordService.isMetadataStub(recordVersion10)); + + Set to10 = relationshipService.getRelationshipsTo(recordVersion10, "versions"); + assertEquals(1, to10.size()); + assertEquals(recordVersion11, to10.iterator().next().getSource()); + + assertTrue(relationshipService.getRelationshipsFrom(recordVersion10, "versions").isEmpty()); + + } + }); + } } diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspectUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspectUnitTest.java index 02011c9d9a..8069678d65 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspectUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspectUnitTest.java @@ -18,7 +18,6 @@ */ package org.alfresco.module.org_alfresco_module_rm.model.rma.aspect; -import static org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel.PROP_VERSIONED_NODEREF; import static org.mockito.Matchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -53,7 +52,7 @@ public class VersionRecordAspectUnitTest extends BaseUnitTest private @InjectMocks VersionRecordAspect versionRecordAspect; /** - * given that version node ref is null + * given that there is no recorded version * before delete of record * then nothing happens */ @@ -62,7 +61,7 @@ public class VersionRecordAspectUnitTest extends BaseUnitTest { NodeRef nodeRef = generateNodeRef(); - when(mockedNodeService.getProperty(nodeRef, PROP_VERSIONED_NODEREF)) + when(mockedRecordableVersionService.getRecordedVersion(nodeRef)) .thenReturn(null); versionRecordAspect.beforeDeleteNode(nodeRef); @@ -70,89 +69,9 @@ public class VersionRecordAspectUnitTest extends BaseUnitTest verify(mockedNodeService, never()).getProperty(nodeRef, RecordableVersionModel.PROP_VERSION_LABEL); verify(mockedRecordableVersionService, never()).destroyRecordedVersion(any(Version.class)); } - + /** - * given that version node ref is not null - * and version label is null - * before delete of record - * then nothing happens - */ - @Test - public void beforeDeleteNoVersionLabel() - { - NodeRef nodeRef = generateNodeRef(); - NodeRef versionedNodeRef = generateNodeRef(); - - when(mockedNodeService.getProperty(nodeRef, PROP_VERSIONED_NODEREF)) - .thenReturn(versionedNodeRef); - when(mockedNodeService.getProperty(nodeRef, RecordableVersionModel.PROP_VERSION_LABEL)) - .thenReturn(null); - - versionRecordAspect.beforeDeleteNode(nodeRef); - - verify(mockedVersionService, never()).getVersionHistory(versionedNodeRef); - verify(mockedRecordableVersionService, never()).destroyRecordedVersion(any(Version.class)); - } - - /** - * given that version node ref is not null - * and version label is not null - * and version history is null - * before delete of record - * then nothing happens - */ - @Test - public void beforeDeleteNoVersionHistory() - { - NodeRef nodeRef = generateNodeRef(); - NodeRef versionedNodeRef = generateNodeRef(); - - when(mockedNodeService.getProperty(nodeRef, PROP_VERSIONED_NODEREF)) - .thenReturn(versionedNodeRef); - when(mockedNodeService.getProperty(nodeRef, RecordableVersionModel.PROP_VERSION_LABEL)) - .thenReturn(generateText()); - when(mockedVersionService.getVersionHistory(versionedNodeRef)) - .thenReturn(null); - - versionRecordAspect.beforeDeleteNode(nodeRef); - - verify(mockedRecordableVersionService, never()).destroyRecordedVersion(any(Version.class)); - } - - /** - * given that version node ref is not null - * and version label is not null - * and version history is not null - * and the version relating to the version label is null - * before delete of record - * then nothing happens - */ - @Test - public void beforeDeleteNoVersionForLabel() - { - NodeRef nodeRef = generateNodeRef(); - NodeRef versionedNodeRef = generateNodeRef(); - String versionLabel = generateText(); - - when(mockedNodeService.getProperty(nodeRef, PROP_VERSIONED_NODEREF)) - .thenReturn(versionedNodeRef); - when(mockedNodeService.getProperty(nodeRef, RecordableVersionModel.PROP_VERSION_LABEL)) - .thenReturn(versionLabel); - when(mockedVersionService.getVersionHistory(versionedNodeRef)) - .thenReturn(mockedVersionHistory); - when(mockedVersionHistory.getVersion(versionLabel)) - .thenReturn(null); - - versionRecordAspect.beforeDeleteNode(nodeRef); - - verify(mockedRecordableVersionService, never()).destroyRecordedVersion(any(Version.class)); - } - - /** - * given that version node ref is not null - * and version label is not null - * and version history is not null - * and the version relating to the version label is not null + * given that there is a recorded version * before delete of record * then the version is marked as destroyed */ @@ -160,16 +79,8 @@ public class VersionRecordAspectUnitTest extends BaseUnitTest public void beforeDeleteMarkVersionDestroyed() { NodeRef nodeRef = generateNodeRef(); - NodeRef versionedNodeRef = generateNodeRef(); - String versionLabel = generateText(); - when(mockedNodeService.getProperty(nodeRef, PROP_VERSIONED_NODEREF)) - .thenReturn(versionedNodeRef); - when(mockedNodeService.getProperty(nodeRef, RecordableVersionModel.PROP_VERSION_LABEL)) - .thenReturn(versionLabel); - when(mockedVersionService.getVersionHistory(versionedNodeRef)) - .thenReturn(mockedVersionHistory); - when(mockedVersionHistory.getVersion(versionLabel)) + when(mockedRecordableVersionService.getRecordedVersion(nodeRef)) .thenReturn(mockedVersion); versionRecordAspect.beforeDeleteNode(nodeRef);