diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordableVersionModel.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordableVersionModel.xml index 6158bea0b5..a4587c061f 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordableVersionModel.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordableVersionModel.xml @@ -94,6 +94,12 @@ d:text + + + Destroyed + d:boolean + false> + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index f79173a8a2..7ddb3f28b2 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -1060,6 +1060,7 @@ + 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 ce01a26573..3975bab461 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 @@ -11,6 +11,13 @@ + + + + + + + @@ -63,7 +70,10 @@ diff --git a/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/version/rm-version.get.js b/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/version/rm-version.get.js index 00875b74eb..6f7babb711 100644 --- a/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/version/rm-version.get.js +++ b/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/version/rm-version.get.js @@ -62,7 +62,7 @@ function main() { var nodeRef = args["nodeRef"], node = search.findNode(nodeRef), - versionHistory, version, p, recordNodeRef; + versionHistory, version, p, recordNodeRef, isRecordedVersionDestroyed; if (node != null) { @@ -73,11 +73,14 @@ function main() { version = versionHistory[i]; p = getPerson(version.creator); + recordNodeRef = version.getVersionProperty("recordNodeRef"); + isRecordedVersionDestroyed = version.getVersionProperty("RecordedVersionDestroyed"); + versions[versions.length] = { nodeRef: version.node.nodeRef.toString(), - name: version.node.name, + name: (isRecordedVersionDestroyed == true) ? "" : version.node.name, label: version.label, description: version.description, createdDate: version.createdDate, @@ -87,7 +90,8 @@ function main() firstName: p.firstName, lastName: p.lastName }, - recordNodeRef: recordNodeRef ? recordNodeRef.toString() : "" + recordNodeRef: recordNodeRef ? recordNodeRef.toString() : "", + isRecordedVersionDestroyed: isRecordedVersionDestroyed }; } } @@ -107,7 +111,8 @@ function main() firstName: p.firstName, lastName: p.lastName }, - recordNodeRef: "" + recordNodeRef: "", + isRecordedVersionDestroyed: false }; } } diff --git a/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/version/rm-version.get.json.ftl b/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/version/rm-version.get.json.ftl index 84b3ecc3de..773b1421e0 100644 --- a/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/version/rm-version.get.json.ftl +++ b/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/version/rm-version.get.json.ftl @@ -14,7 +14,8 @@ "firstName": "${v.creator.firstName!""}", "lastName": "${v.creator.lastName!""}" }, - "recordNodeRef": "${v.recordNodeRef}" + "recordNodeRef": "${v.recordNodeRef}", + "isRecordedVersionDestroyed": ${v.isRecordedVersionDestroyed?c} }<#if (v_has_next)>, ] diff --git a/rm-server/pom.xml b/rm-server/pom.xml index e843c8d6ae..8485681602 100644 --- a/rm-server/pom.xml +++ b/rm-server/pom.xml @@ -189,6 +189,12 @@ ${alfresco.base.version} + + io.takari.junit + takari-cpsuite + 1.2.7 + test + junit junit diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java index 8f8f8019c9..e43845deea 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java @@ -36,7 +36,6 @@ import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourKind; -import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -71,7 +70,7 @@ public class RecordAspect extends AbstractDisposableItem /** record service */ protected RecordService recordService; - + /** * @param extendedSecurityService extended security service */ @@ -110,7 +109,7 @@ public class RecordAspect extends AbstractDisposableItem ) public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, boolean bNew) { - AuthenticationUtil.runAsSystem(new RunAsWork() + authenticationUtil.runAsSystem(new RunAsWork() { @Override public Void doWork() @@ -173,7 +172,7 @@ public class RecordAspect extends AbstractDisposableItem // Deal with versioned records if (reference.equals(CUSTOM_REF_VERSIONS)) { - AuthenticationUtil.runAsSystem(new RunAsWork() + authenticationUtil.runAsSystem(new RunAsWork() { @Override public Void doWork() @@ -240,7 +239,7 @@ public class RecordAspect extends AbstractDisposableItem isFilePlanComponent(oldChildAssocRef.getParentRef())) { final NodeRef record = newChildAssocRef.getChildRef(); - AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + authenticationUtil.runAs(new RunAsWork() { public Object doWork() { @@ -256,7 +255,7 @@ public class RecordAspect extends AbstractDisposableItem return null; } - }, AuthenticationUtil.getAdminUserName()); + }, authenticationUtil.getAdminUserName()); } } 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 new file mode 100644 index 0000000000..165bbd9819 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspect.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2005-2014 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +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; +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.version.RecordableVersionService; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.policy.annotation.Behaviour; +import org.alfresco.repo.policy.annotation.BehaviourBean; +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 + * + * @author Roy Wetherall + * @since 2.3.1 + */ +@BehaviourBean +( + defaultType = "rmv:versionRecord" +) +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 + */ + public void setRecordableVersionService(RecordableVersionService recordableVersionService) + { + this.recordableVersionService = recordableVersionService; + } + + /** + * @param relationshipService relationship service + */ + public void setRelationshipService(RelationshipService relationshipService) + { + this.relationshipService = relationshipService; + } + + /** + * If the record is a version record then delete the associated version entry + * + * @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + @Behaviour (kind = BehaviourKind.CLASS) + public void beforeDeleteNode(final NodeRef nodeRef) + { + final NodeRef versionedNodeRef = (NodeRef) nodeService.getProperty(nodeRef, PROP_VERSIONED_NODEREF); + if (versionedNodeRef != null) + { + String versionLabel = (String) nodeService.getProperty(nodeRef, PROP_VERSION_LABEL); + if (StringUtils.isNotBlank(versionLabel)) + { + final VersionHistory versionHistory = versionService.getVersionHistory(versionedNodeRef); + if (versionHistory != null) + { + final Version version = versionHistory.getVersion(versionLabel); + if (version != null) + { + authenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() + { + behaviourFilter.disableBehaviour(); + try + { + // 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()); + } + } + } + } + finally + { + behaviourFilter.enableBehaviour(); + } + + return null; + } + }); + } + } + } + } + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java index e79acc7b42..a2e03bda6c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java @@ -18,10 +18,6 @@ */ package org.alfresco.module.org_alfresco_module_rm.record; -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 static org.apache.commons.lang.StringUtils.isNotBlank; - import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; @@ -61,7 +57,7 @@ import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; import org.alfresco.module.org_alfresco_module_rm.role.Role; import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel; -import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServiceImpl; +import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.ClassPolicyDelegate; @@ -122,8 +118,7 @@ public class RecordServiceImpl extends BaseBehaviourBean NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.OnAddAspectPolicy, NodeServicePolicies.OnRemoveAspectPolicy, - NodeServicePolicies.OnUpdatePropertiesPolicy, - NodeServicePolicies.BeforeDeleteNodePolicy + NodeServicePolicies.OnUpdatePropertiesPolicy { /** Logger */ private static Log logger = LogFactory.getLog(RecordServiceImpl.class); @@ -229,6 +224,9 @@ public class RecordServiceImpl extends BaseBehaviourBean /** records management container type */ private RecordsManagementContainerType recordsManagementContainerType; + + /** recordable version service */ + private RecordableVersionService recordableVersionService; /** list of available record meta-data aspects and the file plan types the are applicable to */ private Map> recordMetaDataAspects; @@ -382,6 +380,14 @@ public class RecordServiceImpl extends BaseBehaviourBean { this.recordsManagementContainerType = recordsManagementContainerType; } + + /** + * @param recordableVersionService recordable version service + */ + public void setRecordableVersionService(RecordableVersionService recordableVersionService) + { + this.recordableVersionService = recordableVersionService; + } /** * Init method @@ -1023,7 +1029,19 @@ public class RecordServiceImpl extends BaseBehaviourBean { recordsManagementContainerType.enable(); } - + + // if versionable, then remove without destroying version history, + // because it is being shared with the originating document + behaviourFilter.disableBehaviour(ContentModel.ASPECT_VERSIONABLE); + try + { + nodeService.removeAspect(record, ContentModel.ASPECT_VERSIONABLE); + } + finally + { + behaviourFilter.enableBehaviour(ContentModel.ASPECT_VERSIONABLE); + } + // make record makeRecord(record); @@ -1081,7 +1099,7 @@ public class RecordServiceImpl extends BaseBehaviourBean for (Version previousVersion : previousVersions) { // look for the associated record - final NodeRef previousRecord = (NodeRef)previousVersion.getVersionProperties().get(RecordableVersionServiceImpl.PROP_VERSION_RECORD); + final NodeRef previousRecord = recordableVersionService.getVersionRecord(previousVersion); if (previousRecord != null) { versionRecord = previousRecord; @@ -1808,38 +1826,5 @@ public class RecordServiceImpl extends BaseBehaviourBean // can only unlink a record from a record folder throw new RecordLinkRuntimeException("Can only unlink a record from a record folder."); } - } - - /** - * @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef) - */ - @Override - @Behaviour - ( - kind = BehaviourKind.CLASS, - type = "rma:record" - ) - public void beforeDeleteNode(NodeRef nodeRef) - { - final NodeRef versionedNodeRef = (NodeRef) nodeService.getProperty(nodeRef, PROP_VERSIONED_NODEREF); - if (versionedNodeRef != null) - { - String versionLabel = (String) nodeService.getProperty(nodeRef, PROP_VERSION_LABEL); - if (isNotBlank(versionLabel)) - { - final Version version = versionService.getVersionHistory(versionedNodeRef).getVersion(versionLabel); - - AuthenticationUtil.runAsSystem(new RunAsWork() - { - @Override - public Void doWork() - { - versionService.deleteVersion(versionedNodeRef, version); - - return null; - } - }); - } - } - } + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipImpl.java index 118f83a197..574a804cf5 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipImpl.java @@ -21,6 +21,8 @@ package org.alfresco.module.org_alfresco_module_rm.relationship; import static org.alfresco.util.ParameterCheck.mandatory; import static org.alfresco.util.ParameterCheck.mandatoryString; +import java.io.Serializable; + import org.alfresco.service.cmr.repository.NodeRef; /** @@ -29,8 +31,11 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 2.3 */ -public class RelationshipImpl implements Relationship +public class RelationshipImpl implements Relationship, Serializable { + /** serial UID */ + private static final long serialVersionUID = 9120649510198344978L; + /** The unique name of the relationship */ private String uniqueName; @@ -114,4 +119,39 @@ public class RelationshipImpl implements Relationship { this.target = target; } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj instanceof Relationship) + { + RelationshipImpl that = (RelationshipImpl) obj; + return (this.uniqueName.equals(that.uniqueName) + && this.source.equals(that.source) + && this.target.equals(that.target)); + } + else + { + return false; + } + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() + { + int prime = 31; + int result = prime + uniqueName.hashCode(); + result = (prime*result) + source.hashCode(); + return (prime*result) + target.hashCode(); + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipService.java index 0a619f53d1..dcdab7b285 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipService.java @@ -30,6 +30,9 @@ import org.alfresco.service.cmr.repository.NodeRef; */ public interface RelationshipService { + /** System relationship names */ + static final String RELATIONSHIP_VERSIONS = "versions"; + /** * Gets all the existing relationship definitions * @@ -85,14 +88,42 @@ public interface RelationshipService * @return All relationships that come out from the given node reference */ Set getRelationshipsFrom(NodeRef nodeRef); - + /** - * Gets all the relationships that go in to the given node reference + * Gets all the relationships that come out from the given node reference + * that match the a given name filter. + *

+ * Exact match only. * * @param nodeRef The node reference - * @return All relationships that go in to the given node reference + * @param nameFilter Name filter for results + * @return All relationships that come out from the given node reference + * + * @since 2.3.1 + */ + Set getRelationshipsFrom(NodeRef nodeRef, String nameFilter); + + /** + * Gets all the relationships that go into the given node reference + * + * @param nodeRef The node reference + * @return All relationships that go into the given node reference */ Set getRelationshipsTo(NodeRef nodeRef); + + /** + * Gets all the relationships that go into the given node reference + * that match the a given name filter. + *

+ * Exact match only. + * + * @param nodeRef The node reference + * @param nameFilter Name filter for results + * @return All relationships that go into the given node reference + * + * @since 2.3.1 + */ + Set getRelationshipsTo(NodeRef nodeRef, String nameFilter); /** * Adds a relationship from the given node source diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipServiceImpl.java index 92b4fa7be4..df7487e6ad 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/relationship/RelationshipServiceImpl.java @@ -376,16 +376,25 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen */ @Override public Set getRelationshipsFrom(NodeRef nodeRef) + { + return getRelationshipsFrom(nodeRef, null); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService#getRelationshipsFrom(org.alfresco.service.cmr.repository.NodeRef, String) + */ + @Override + public Set getRelationshipsFrom(NodeRef nodeRef, String nameFilter) { mandatory("nodeRef", nodeRef); Set relationships = new HashSet(); List customReferencesFrom = getNodeService().getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL); - relationships.addAll(generateRelationshipFromAssociationRef(customReferencesFrom)); + relationships.addAll(generateRelationshipFromAssociationRef(customReferencesFrom, nameFilter)); List customChildReferences = getNodeService().getChildAssocs(nodeRef); - relationships.addAll(generateRelationshipFromParentChildAssociationRef(customChildReferences)); + relationships.addAll(generateRelationshipFromParentChildAssociationRef(customChildReferences, nameFilter)); return relationships; } @@ -395,20 +404,29 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen */ @Override public Set getRelationshipsTo(NodeRef nodeRef) + { + return getRelationshipsTo(nodeRef, null); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService#getRelationshipsTo(org.alfresco.service.cmr.repository.NodeRef, String) + */ + @Override + public Set getRelationshipsTo(NodeRef nodeRef, String nameFilter) { mandatory("nodeRef", nodeRef); Set relationships = new HashSet(); List customReferencesTo = getNodeService().getSourceAssocs(nodeRef, RegexQNamePattern.MATCH_ALL); - relationships.addAll(generateRelationshipFromAssociationRef(customReferencesTo)); + relationships.addAll(generateRelationshipFromAssociationRef(customReferencesTo, nameFilter)); List customParentReferences = getNodeService().getParentAssocs(nodeRef); - relationships.addAll(generateRelationshipFromParentChildAssociationRef(customParentReferences)); + relationships.addAll(generateRelationshipFromParentChildAssociationRef(customParentReferences, nameFilter)); return relationships; } - + /** * @see org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService#addRelationship(java.lang.String, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef) */ @@ -418,7 +436,19 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen mandatoryString("uniqueName", uniqueName); mandatory("source", source); mandatory("target", target); - + + // check the source node exists + if (!getNodeService().exists(source)) + { + throw new AlfrescoRuntimeException("Can't create relationship '" + uniqueName + "', because source node doesn't exist."); + } + + // check the target node exists + if (!getNodeService().exists(target)) + { + throw new AlfrescoRuntimeException("Can't create relationship " + uniqueName + ", because target node doesn't exist."); + } + if (getNodeService().hasAspect(target, ASPECT_FROZEN)) { StringBuilder sb = new StringBuilder(); @@ -622,14 +652,15 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen * @param associationRefs Association references * @return Relationships generated from the given association references */ - private Set generateRelationshipFromAssociationRef(List associationRefs) + private Set generateRelationshipFromAssociationRef(List associationRefs, String nameFilter) { Set relationships = new HashSet(); for (AssociationRef associationRef : associationRefs) { String uniqueName = associationRef.getTypeQName().getLocalName(); - if (existsRelationshipDefinition(uniqueName)) + if (existsRelationshipDefinition(uniqueName) && + (nameFilter == null || uniqueName.equals(nameFilter))) { NodeRef from = associationRef.getSourceRef(); NodeRef to = associationRef.getTargetRef(); @@ -646,14 +677,15 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen * @param childAssociationRefs Child association references * @return Relationships generated from the given child association references */ - private Set generateRelationshipFromParentChildAssociationRef(List childAssociationRefs) + private Set generateRelationshipFromParentChildAssociationRef(List childAssociationRefs, String nameFilter) { Set relationships = new HashSet(); for (ChildAssociationRef childAssociationRef : childAssociationRefs) { String uniqueName = childAssociationRef.getQName().getLocalName(); - if (existsRelationshipDefinition(uniqueName)) + if (existsRelationshipDefinition(uniqueName)&& + (nameFilter == null || uniqueName.equals(nameFilter))) { NodeRef from = childAssociationRef.getParentRef(); NodeRef to = childAssociationRef.getChildRef(); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionModel.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionModel.java index f21b28043d..180b191bfd 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionModel.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionModel.java @@ -41,6 +41,7 @@ public interface RecordableVersionModel QName ASPECT_RECORDED_VERSION = QName.createQName(RMV_URI, "recordedVersion"); QName PROP_RECORD_NODE_REF = QName.createQName(RMV_URI, "recordNodeRef"); QName PROP_FROZEN_OWNER = QName.createQName(RMV_URI, "frozenOwner"); + QName PROP_DESTROYED = QName.createQName(RMV_URI, "destroyed"); /** version record aspect */ QName ASPECT_VERSION_RECORD = QName.createQName(RMV_URI, "versionRecord"); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionNodeServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionNodeServiceImpl.java index c90dc17da9..78759b8713 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionNodeServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionNodeServiceImpl.java @@ -21,6 +21,7 @@ package org.alfresco.module.org_alfresco_module_rm.version; import static org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl.RECORD_MODEL_URIS; import java.io.Serializable; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -181,6 +182,7 @@ public class RecordableVersionNodeServiceImpl extends Node2ServiceImpl /** * @see org.alfresco.repo.version.Node2ServiceImpl#getAspects(org.alfresco.service.cmr.repository.NodeRef) */ + @SuppressWarnings("unchecked") @Override public Set getAspects(NodeRef nodeRef) throws InvalidNodeRefException { @@ -190,8 +192,15 @@ public class RecordableVersionNodeServiceImpl extends Node2ServiceImpl if (dbNodeService.hasAspect(converted, ASPECT_RECORDED_VERSION)) { NodeRef record = (NodeRef)dbNodeService.getProperty(converted, PROP_RECORD_NODE_REF); - Set aspects = dbNodeService.getAspects(record); - return processAspects(aspects); + if (dbNodeService.exists(record)) + { + Set aspects = dbNodeService.getAspects(record); + return processAspects(aspects); + } + else + { + return (Set)Collections.EMPTY_SET; + } } else { 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 e5b0c8c6f2..6687da6580 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 @@ -47,6 +47,15 @@ public interface RecordableVersionService */ boolean isRecordedVersion(Version version); + /** + * If the version is a recorded version, gets the related version + * record. + * + * @param version version + * @return NodeRef node reference of version record + */ + NodeRef getVersionRecord(Version version); + /** * Creates a record from the latest version, marking it as recorded. *

@@ -54,8 +63,26 @@ public interface RecordableVersionService * version is already recorded. * * @param nodeRef node reference - * @return NodeRef node reference to the crated record. + * @return NodeRef node reference to the created record. */ NodeRef createRecordFromLatestVersion(NodeRef filePlan, NodeRef nodeRef); + + /** + * Indicates whether a record version is destroyed or not. + * + * @param version version + * @return boolean true if destroyed, false otherwise + */ + boolean isRecordedVersionDestroyed(Version version); + + /** + * Marks a recorded version as destroyed. + *

+ * Note this method does not destroy the associated record, instead it marks the + * version as destroyed. + * + * @param version version + */ + void destroyRecordedVersion(Version version); } 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 a148fd3016..c5d2a14408 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 @@ -76,7 +76,8 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl public static final String KEY_FILE_PLAN = "file-plan"; /** version record property */ - public static final String PROP_VERSION_RECORD = "RecordVersion"; + protected static final String PROP_VERSION_RECORD = "RecordVersion"; + protected static final String PROP_RECORDED_VERSION_DESTROYED = "RecordedVersionDestroyed"; /** version aspect property names */ private static final String[] VERSION_PROPERTY_NAMES = new String[] @@ -491,7 +492,8 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl { // look for the associated record final NodeRef previousRecord = (NodeRef)previousVersion.getVersionProperties().get(PROP_VERSION_RECORD); - if (previousRecord != null) + if (previousRecord != null && + nodeService.exists(previousRecord)) { versionRecord = previousRecord; break; @@ -502,6 +504,66 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl return versionRecord; } + @Override + protected VersionHistory buildVersionHistory(NodeRef versionHistoryRef, NodeRef nodeRef) + { + VersionHistory versionHistory = super.buildVersionHistory(versionHistoryRef, nodeRef); + + // create an empty version history if appropriate + if (versionHistoryRef != null && + nodeRef != null && + versionHistory == null && + getAllVersions(versionHistoryRef).isEmpty() == true) + { + versionHistory = new EmptyVersionHistory(); + } + + return versionHistory; + } + + 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. * @@ -533,12 +595,18 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl { Version version = super.getVersion(versionRef); + // place the version record reference in the version properties NodeRef record = (NodeRef)dbNodeService.getProperty(versionRef, PROP_RECORD_NODE_REF); if (record != null) - { + { version.getVersionProperties().put(PROP_VERSION_RECORD, record); } + // place information about the destruction of the version record in the properties + Boolean destroyed = (Boolean)dbNodeService.getProperty(versionRef, PROP_DESTROYED); + if (destroyed == null) { destroyed = Boolean.FALSE; } + version.getVersionProperties().put(PROP_RECORDED_VERSION_DESTROYED, destroyed); + return version; } @@ -579,10 +647,31 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl @Override public boolean isRecordedVersion(Version version) { - boolean result = true; - if (version.getVersionProperties().get(PROP_VERSION_RECORD) == null) + NodeRef versionNodeRef = getVersionNodeRef(version); + return dbNodeService.hasAspect(versionNodeRef, RecordableVersionModel.ASPECT_RECORDED_VERSION); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#getVersionRecord(org.alfresco.service.cmr.version.Version) + */ + @Override + public NodeRef getVersionRecord(Version version) + { + NodeRef result = null; + NodeRef versionNodeRef = getVersionNodeRef(version); + if (dbNodeService.hasAspect(versionNodeRef, RecordableVersionModel.ASPECT_RECORDED_VERSION)) { - result = false; + // get the version record + result = (NodeRef)dbNodeService.getProperty(versionNodeRef, RecordableVersionModel.PROP_RECORD_NODE_REF); + + // check that the version record exists + if (result != null && + !dbNodeService.exists(result)) + { + throw new AlfrescoRuntimeException("Version record node doesn't exist. Indicates version has not been updated " + + "when associated version record was deleted. " + + "(nodeRef=" + result.toString() + ")"); + } } return result; } @@ -737,6 +826,47 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl return record; } + /** + * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#isRecordedVersionDestroyed(org.alfresco.service.cmr.version.Version) + */ + @Override + public boolean isRecordedVersionDestroyed(Version version) + { + boolean result = false; + + // get the version node reference + NodeRef versionNodeRef = getVersionNodeRef(version); + + // get the destroyed property value + Boolean isDestroyed = (Boolean)dbNodeService.getProperty(versionNodeRef, PROP_DESTROYED); + if (isDestroyed != null) + { + result = isDestroyed.booleanValue(); + } + + return result; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#destroyRecordedVersion(org.alfresco.service.cmr.version.Version) + */ + @Override + public void destroyRecordedVersion(Version version) + { + // get the version node reference + NodeRef versionNodeRef = getVersionNodeRef(version); + + // if it's a recorded version + if (dbNodeService.hasAspect(versionNodeRef, ASPECT_RECORDED_VERSION)) + { + // mark it as destroyed + dbNodeService.setProperty(versionNodeRef, PROP_DESTROYED, true); + + // clear the record node reference property + dbNodeService.setProperty(versionNodeRef, RecordableVersionModel.PROP_RECORD_NODE_REF, null); + } + } + /** * Helper method to get the version number of a given version by inspecting the * name of the parent association. diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersionsTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersionsTest.java index c7b1e08f4c..b8a2ed6e94 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersionsTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersionsTest.java @@ -169,7 +169,7 @@ public class AdHocRecordableVersionsTest extends RecordableVersionsBaseTest public Void doWork() throws Exception { // add custom meta-data to record - NodeRef record = (NodeRef)version.getVersionProperties().get(RecordableVersionServiceImpl.PROP_VERSION_RECORD); + NodeRef record = recordableVersionService.getVersionRecord(version); assertNotNull(record); recordService.addRecordType(record, TestModel.ASPECT_RECORD_METADATA); nodeService.setProperty(record, TestModel.PROPERTY_RECORD_METADATA, "Peter Wetherall"); diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersionsTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersionsTest.java index a9e4d678a3..81a49f3652 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersionsTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersionsTest.java @@ -24,7 +24,6 @@ import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.relationship.Relationship; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionPolicy; -import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServiceImpl; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.version.Version; @@ -131,7 +130,7 @@ public class AutoRecordableVersionsTest extends RecordableVersionsBaseTest checkRecordedVersion(dmDocument, null, "0.3"); Version version = versionService.getCurrentVersion(dmDocument); - NodeRef record = (NodeRef)version.getVersionProperties().get(RecordableVersionServiceImpl.PROP_VERSION_RECORD); + NodeRef record = recordableVersionService.getVersionRecord(version); boolean foundPrevious = false; Set relationships = relationshipService.getRelationshipsFrom(record); 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 new file mode 100644 index 0000000000..9a7e62a22a --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeleteRecordVersionTest.java @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2005-2014 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.version; + +import java.io.Serializable; +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.relationship.Relationship; +import org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService; +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; +import org.alfresco.service.cmr.repository.ContentWriter; +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.namespace.QName; +import org.alfresco.util.GUID; + + +/** + * Recordable version history integration tests. + * + * @author Roy Wetherall + * @since 2.3.1 + */ +public class DeleteRecordVersionTest extends RecordableVersionsBaseTest +{ + /** + * Given that a document is created + * And the initial version is record + * When I delete the version record + * Then the version is deleted + * And the version history is not deleted + * + * @see https://issues.alfresco.com/jira/browse/RM-2562 + */ + public void testDeleteFirstRecordedVersion() + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private NodeRef myDocument; + + public void given() throws Exception + { + // create a document + myDocument = fileFolderService.create(dmFolder, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef(); + + // make versionable + Map props = new HashMap(2); + props.put(RecordableVersionModel.PROP_RECORDABLE_VERSION_POLICY, RecordableVersionPolicy.ALL); + props.put(RecordableVersionModel.PROP_FILE_PLAN, filePlan); + nodeService.addAspect(myDocument, RecordableVersionModel.ASPECT_VERSIONABLE, props); + nodeService.addAspect(myDocument, ContentModel.ASPECT_VERSIONABLE, null); + } + + public void when() + { + // check the initial version label + assertEquals("1.0", nodeService.getProperty(myDocument, ContentModel.PROP_VERSION_LABEL)); + + // check that the version history contains a single version that is recorded + VersionHistory versionHistory = versionService.getVersionHistory(myDocument); + assertNotNull(versionHistory); + assertEquals(1, versionHistory.getAllVersions().size()); + + // check the recorded version is not marked as destroyed + Version version = versionHistory.getHeadVersion(); + assertNotNull(version); + assertFalse(recordableVersionService.isRecordedVersionDestroyed(version)); + + Version head = versionHistory.getHeadVersion(); + NodeRef record = recordableVersionService.getVersionRecord(head); + assertTrue(recordService.isRecord(record)); + + // record should not have a version history because it is immutable + assertFalse(nodeService.hasAspect(record, ContentModel.ASPECT_VERSIONABLE)); + VersionHistory recordVersionHistory = versionService.getVersionHistory(record); + assertNull(recordVersionHistory); + + // destroy record + nodeService.deleteNode(record); + } + + public void then() + { + // document is still versionable + assertTrue(nodeService.hasAspect(myDocument, ContentModel.ASPECT_VERSIONABLE)); + + // check the initial version label + assertEquals("1.0", nodeService.getProperty(myDocument, ContentModel.PROP_VERSION_LABEL)); + + // still has a version history, but the version is marked as destroyed + VersionHistory versionHistory = versionService.getVersionHistory(myDocument); + assertNotNull(versionHistory); + assertEquals(1, versionHistory.getAllVersions().size()); + + // check the recorded version is marked as destroyed and the record version is not longer available + Version version = versionHistory.getHeadVersion(); + assertNotNull(version); + assertTrue(recordableVersionService.isRecordedVersionDestroyed(version)); + assertNull(recordableVersionService.getVersionRecord(version)); + } + }); + } + + /** + * Given that a document is created + * And the initial version is record + * And the associated version record is deleted + * When a new version is created + * Then a new associated version record is created + * And the version is 1.1 (not 1.0 since this was deleted, but the version history maintained) + * + * @see https://issues.alfresco.com/jira/browse/RM-2562 + */ + public void testDeleteFirstRecordedVersionAndCreateNewVersion() + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private NodeRef myDocument; + + public void given() throws Exception + { + // create a document + myDocument = fileFolderService.create(dmFolder, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef(); + ContentWriter writer = fileFolderService.getWriter(myDocument); + writer.setEncoding("UTF-8"); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.putContent(GUID.generate()); + + // make versionable + Map props = new HashMap(2); + props.put(RecordableVersionModel.PROP_RECORDABLE_VERSION_POLICY, RecordableVersionPolicy.ALL); + props.put(RecordableVersionModel.PROP_FILE_PLAN, filePlan); + nodeService.addAspect(myDocument, RecordableVersionModel.ASPECT_VERSIONABLE, props); + nodeService.addAspect(myDocument, ContentModel.ASPECT_VERSIONABLE, null); + } + + public void when() + { + // get the created version record + VersionHistory versionHistory = versionService.getVersionHistory(myDocument); + Version head = versionHistory.getHeadVersion(); + NodeRef record = recordableVersionService.getVersionRecord(head); + + // destroy record + nodeService.deleteNode(record); + + // update the content to create a new version (and version record) + ContentWriter writer = fileFolderService.getWriter(myDocument); + writer.putContent(GUID.generate()); + } + + public void then() + { + // document is still versionable + assertTrue(nodeService.hasAspect(myDocument, ContentModel.ASPECT_VERSIONABLE)); + + // check the version number has been incremented + assertEquals("1.1", nodeService.getProperty(myDocument, ContentModel.PROP_VERSION_LABEL)); + + // still has a version history, with 2 enties + VersionHistory versionHistory = versionService.getVersionHistory(myDocument); + assertNotNull(versionHistory); + assertEquals(2, versionHistory.getAllVersions().size()); + + // latest version is current + Version head = versionHistory.getHeadVersion(); + assertFalse(recordableVersionService.isRecordedVersionDestroyed(head)); + assertNotNull(recordableVersionService.getVersionRecord(head)); + + // first version is destroyed + Version destroyed = versionHistory.getPredecessor(head); + assertTrue(recordableVersionService.isRecordedVersionDestroyed(destroyed)); + assertNull(recordableVersionService.getVersionRecord(destroyed)); + + // get the version record for the current version + NodeRef versionRecord = recordableVersionService.getVersionRecord(head); + assertNotNull(versionRecord); + assertTrue(nodeService.exists(versionRecord)); + + Set from = relationshipService.getRelationshipsFrom(versionRecord); + assertTrue(from.isEmpty()); + + Set to = relationshipService.getRelationshipsTo(versionRecord); + assertTrue(to.isEmpty()); + } + }); + } + + /** + * Given a chain of version records (1.0, 1.1, 1.2) which are all related + * When I delete version record 1.0 + * Then 1.1 is the oldest version + */ + public void testDeleteOldestVersion() + { + final NodeRef myDocument = createDocumentWithRecordVersions(); + + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private VersionHistory versionHistory; + + public void given() throws Exception + { + // get version history + versionHistory = versionService.getVersionHistory(myDocument); + } + + public void when() + { + Version version10 = versionHistory.getVersion("1.0"); + NodeRef recordVersion10 = recordableVersionService.getVersionRecord(version10); + + // delete record version 1.0 + nodeService.deleteNode(recordVersion10); + } + + public void then() + { + // check the deleted version + Version version10 = versionHistory.getVersion("1.0"); + assertNotNull(version10); + assertTrue(recordableVersionService.isRecordedVersionDestroyed(version10)); + NodeRef recordVersion10 = recordableVersionService.getVersionRecord(version10); + assertNull(recordVersion10); + + // verify 1.2 setup as expected + Version version12 = versionHistory.getHeadVersion(); + assertEquals("1.2", version12.getVersionLabel()); + NodeRef recordVersion12 = recordableVersionService.getVersionRecord(version12); + assertNotNull(recordVersion12); + + assertTrue(relationshipService.getRelationshipsTo(recordVersion12, RelationshipService.RELATIONSHIP_VERSIONS).isEmpty()); + + Set from12 = relationshipService.getRelationshipsFrom(recordVersion12, RelationshipService.RELATIONSHIP_VERSIONS); + assertEquals(1, from12.size()); + + // verify 1.1 setup as expected + Version version11 = versionHistory.getPredecessor(version12); + assertEquals("1.1", version11.getVersionLabel()); + NodeRef recordVersion11 = recordableVersionService.getVersionRecord(version11); + assertNotNull(recordVersion11); + + Set to11 = relationshipService.getRelationshipsTo(recordVersion11, RelationshipService.RELATIONSHIP_VERSIONS); + assertEquals(1, to11.size()); + assertEquals(recordVersion12, to11.iterator().next().getSource()); + + assertTrue(relationshipService.getRelationshipsFrom(recordVersion11, RelationshipService.RELATIONSHIP_VERSIONS).isEmpty()); + } + }); + } + + /** + * Given a chain of version records (1.0, 1.1, 1.2) which are all related + * When I delete version record 1.1 + * Then 1.2 now 'versions' 1.0 + */ + public void testDeleteMiddleVersion() + { + final NodeRef myDocument = createDocumentWithRecordVersions(); + + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private VersionHistory versionHistory; + + public void given() throws Exception + { + // get version history + versionHistory = versionService.getVersionHistory(myDocument); + } + + public void when() + { + Version version11 = versionHistory.getVersion("1.1"); + NodeRef recordVersion11 = recordableVersionService.getVersionRecord(version11); + + // delete record version 1.1 + nodeService.deleteNode(recordVersion11); + } + + public void then() + { + // check the deleted version + Version version11 = versionHistory.getVersion("1.1"); + assertNotNull(version11); + assertTrue(recordableVersionService.isRecordedVersionDestroyed(version11)); + NodeRef recordVersion11 = recordableVersionService.getVersionRecord(version11); + assertNull(recordVersion11); + + // verify 1.2 setup as expected + Version version12 = versionHistory.getHeadVersion(); + assertEquals("1.2", version12.getVersionLabel()); + NodeRef recordVersion12 = recordableVersionService.getVersionRecord(version12); + assertNotNull(recordVersion12); + + assertTrue(relationshipService.getRelationshipsTo(recordVersion12, RelationshipService.RELATIONSHIP_VERSIONS).isEmpty()); + + Set from12 = relationshipService.getRelationshipsFrom(recordVersion12, RelationshipService.RELATIONSHIP_VERSIONS); + assertEquals(1, from12.size()); + + // verify 1.0 setup as expected + Version version10 = versionHistory.getVersion("1.0"); + assertEquals("1.0", version10.getVersionLabel()); + NodeRef recordVersion10 = recordableVersionService.getVersionRecord(version10); + assertNotNull(recordVersion10); + + Set to10 = relationshipService.getRelationshipsTo(recordVersion10, RelationshipService.RELATIONSHIP_VERSIONS); + assertEquals(1, to10.size()); + assertEquals(recordVersion12, to10.iterator().next().getSource()); + + assertTrue(relationshipService.getRelationshipsFrom(recordVersion10, RelationshipService.RELATIONSHIP_VERSIONS).isEmpty()); + + } + }); + } + + /** + * Given a chain of version records (1.0, 1.1, 1.2) which are all related + * When I delete version record 1.2 + * Then 1.1 is the most recent version + */ + public void testDeleteLatestVersion() + { + final NodeRef myDocument = createDocumentWithRecordVersions(); + + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private VersionHistory versionHistory; + + public void given() throws Exception + { + // get version history + versionHistory = versionService.getVersionHistory(myDocument); + } + + public void when() + { + Version version10 = versionHistory.getVersion("1.0"); + NodeRef recordVersion10 = recordableVersionService.getVersionRecord(version10); + + // delete record version 1.0 + nodeService.deleteNode(recordVersion10); + } + + public void then() + { + // check the deleted version + Version version10 = versionHistory.getVersion("1.0"); + assertNotNull(version10); + assertTrue(recordableVersionService.isRecordedVersionDestroyed(version10)); + NodeRef recordVersion10 = recordableVersionService.getVersionRecord(version10); + assertNull(recordVersion10); + + // verify 1.2 setup as expected + Version version12 = versionHistory.getHeadVersion(); + assertEquals("1.2", version12.getVersionLabel()); + NodeRef recordVersion12 = recordableVersionService.getVersionRecord(version12); + assertNotNull(recordVersion12); + + assertTrue(relationshipService.getRelationshipsTo(recordVersion12, RelationshipService.RELATIONSHIP_VERSIONS).isEmpty()); + + Set from12 = relationshipService.getRelationshipsFrom(recordVersion12, RelationshipService.RELATIONSHIP_VERSIONS); + assertEquals(1, from12.size()); + + // verify 1.1 setup as expected + Version version11 = versionHistory.getPredecessor(version12); + assertEquals("1.1", version11.getVersionLabel()); + NodeRef recordVersion11 = recordableVersionService.getVersionRecord(version11); + assertNotNull(recordVersion11); + + Set to11 = relationshipService.getRelationshipsTo(recordVersion11, RelationshipService.RELATIONSHIP_VERSIONS); + assertEquals(1, to11.size()); + assertEquals(recordVersion12, to11.iterator().next().getSource()); + + assertTrue(relationshipService.getRelationshipsFrom(recordVersion11, RelationshipService.RELATIONSHIP_VERSIONS).isEmpty()); + } + }); + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/RecordableVersionsBaseTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/RecordableVersionsBaseTest.java index 2e2679884c..32f1269bf3 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/RecordableVersionsBaseTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/RecordableVersionsBaseTest.java @@ -19,15 +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.HashSet; import java.util.Map; import java.util.Set; import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.relationship.Relationship; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel; -import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServiceImpl; +import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionPolicy; +import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; @@ -35,9 +38,12 @@ import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.VersionHistory; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; import org.alfresco.util.PropertyMap; /** + * Recordable versions base integration test + * * @author Roy Wetherall * @since 2.3 */ @@ -54,7 +60,16 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen protected static final String CONTENT = "Simple + Smart. A smarter way to build, a smarter way to deploy. Its simple because we focus on the end " + "user and smart because we support more open standards than any other ECM platform, while delivering all " - + "the value a traditional platform provides."; + + "the value a traditional platform provides."; + + protected RecordableVersionService recordableVersionService; + + @Override + protected void initServices() + { + super.initServices(); + recordableVersionService = (RecordableVersionService)applicationContext.getBean("RecordableVersionService"); + } /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#isCollaborationSiteTest() @@ -150,7 +165,7 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen checkAspects(frozen, beforeAspects); // record version node reference is available on version - NodeRef record = (NodeRef)version.getVersionProperties().get(RecordableVersionServiceImpl.PROP_VERSION_RECORD); + NodeRef record = recordableVersionService.getVersionRecord(version); assertNotNull(record); // check that the version record information has been added @@ -191,7 +206,7 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen assertEquals(versionLabel, version.getVersionLabel()); // record version node reference is available on version - NodeRef record = (NodeRef)version.getVersionProperties().get(RecordableVersionServiceImpl.PROP_VERSION_RECORD); + NodeRef record = recordableVersionService.getVersionRecord(version); assertNull(record); // check the version history @@ -267,5 +282,121 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen fail("Aspects in the frozen state, but not in origional. " + frozenAspects.toString()); } } + + /** + * Creates a document with three versions (1.0, 1.1, 1.2) all of which + * are recorded. + * + * @return NodeRef node reference + */ + protected NodeRef createDocumentWithRecordVersions() + { + // create document and initial version (1.0) + final NodeRef myDocument = doTestInTransaction(new Test() + { + @Override + public NodeRef run() throws Exception + { + // create a document + NodeRef testDoc = fileFolderService.create(dmFolder, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef(); + ContentWriter writer = fileFolderService.getWriter(testDoc); + writer.setEncoding("UTF-8"); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.putContent(GUID.generate()); + + // make versionable + Map props = new HashMap(2); + props.put(RecordableVersionModel.PROP_RECORDABLE_VERSION_POLICY, RecordableVersionPolicy.ALL); + props.put(RecordableVersionModel.PROP_FILE_PLAN, filePlan); + nodeService.addAspect(testDoc, RecordableVersionModel.ASPECT_VERSIONABLE, props); + nodeService.addAspect(testDoc, ContentModel.ASPECT_VERSIONABLE, null); + + return testDoc; + } + }); + + // create 1.1 + doTestInTransaction(new Test() + { + @Override + public Void run() throws Exception + { + // update content + ContentWriter writer = fileFolderService.getWriter(myDocument); + writer.putContent(GUID.generate()); + + return null; + } + }); + + // create 1.2 + doTestInTransaction(new Test() + { + @Override + public Void run() throws Exception + { + // update content + ContentWriter writer = fileFolderService.getWriter(myDocument); + writer.putContent(GUID.generate()); + + return null; + } + }); + + // we do these checks to ensure that the test data is in the correct state before we + // start to manipulate the versions and execute tests + doTestInTransaction(new Test() + { + @Override + public Void run() throws Exception + { + // 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()); + NodeRef recordVersion12 = recordableVersionService.getVersionRecord(version12); + assertNotNull(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()); + NodeRef recordVersion11 = recordableVersionService.getVersionRecord(version11); + assertNotNull(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()); + NodeRef recordVersion10 = recordableVersionService.getVersionRecord(version10); + assertNotNull(recordVersion10); + + Set to10 = relationshipService.getRelationshipsTo(recordVersion10, "versions"); + assertEquals(1, to10.size()); + assertEquals(recordVersion11, to10.iterator().next().getSource()); + + assertTrue(relationshipService.getRelationshipsFrom(recordVersion10, "versions").isEmpty()); + + return null; + } + }); + + return myDocument; + } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/VersionTestSuite.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/VersionTestSuite.java index 1b970e0134..4cf00fec8a 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/VersionTestSuite.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/VersionTestSuite.java @@ -34,7 +34,8 @@ import org.junit.runners.Suite.SuiteClasses; AdHocRecordableVersionsTest.class, AutoRecordableVersionsTest.class, DeclareAsRecordVersionTest.class, - AutoVersionTest.class + AutoVersionTest.class, + DeleteRecordVersionTest.class }) public class VersionTestSuite { 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 new file mode 100644 index 0000000000..02011c9d9a --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/VersionRecordAspectUnitTest.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +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; +import static org.mockito.Mockito.when; + +import org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; +import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel; +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.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +/** + * Version record aspect unit tests + * + * @author Roy Wetherall + * @since 2.3.1 + */ +public class VersionRecordAspectUnitTest extends BaseUnitTest +{ + /** service mocks */ + private @Mock VersionHistory mockedVersionHistory; + private @Mock Version mockedVersion; + private @Mock VersionService mockedVersionService; + private @Mock RelationshipService mockedRelationshipService; + + /** test object */ + private @InjectMocks VersionRecordAspect versionRecordAspect; + + /** + * given that version node ref is null + * before delete of record + * then nothing happens + */ + @Test + public void beforeDeleteNoVersionNodeRef() + { + NodeRef nodeRef = generateNodeRef(); + + when(mockedNodeService.getProperty(nodeRef, PROP_VERSIONED_NODEREF)) + .thenReturn(null); + + versionRecordAspect.beforeDeleteNode(nodeRef); + + 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 + * before delete of record + * then the version is marked as destroyed + */ + @Test + 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)) + .thenReturn(mockedVersion); + + versionRecordAspect.beforeDeleteNode(nodeRef); + + verify(mockedRecordableVersionService).destroyRecordedVersion(mockedVersion); + } +} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java index bd622f09f3..ff73cacd40 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java @@ -18,33 +18,9 @@ */ package org.alfresco.module.org_alfresco_module_rm.test; -import org.alfresco.module.org_alfresco_module_rm.action.dm.DeclareAsVersionRecordActionUnitTest; -import org.alfresco.module.org_alfresco_module_rm.action.impl.FileReportActionUnitTest; -import org.alfresco.module.org_alfresco_module_rm.action.impl.UnlinkFromActionUnitTest; -import org.alfresco.module.org_alfresco_module_rm.bootstrap.BootstrapImporterModuleComponentUnitTest; -import org.alfresco.module.org_alfresco_module_rm.bootstrap.RecordContributorsGroupBootstrapComponentUnitTest; -import org.alfresco.module.org_alfresco_module_rm.capability.RMEntryVoterUnitTest; -import org.alfresco.module.org_alfresco_module_rm.capability.declarative.condition.CapabilityDeclarativeConditionSuite; -import org.alfresco.module.org_alfresco_module_rm.capability.impl.EditNonRecordsMetadataCapabilityUnitTest; -import org.alfresco.module.org_alfresco_module_rm.forms.RecordsManagementTypeFormFilterUnitTest; -import org.alfresco.module.org_alfresco_module_rm.hold.HoldServiceImplUnitTest; -import org.alfresco.module.org_alfresco_module_rm.job.DispositionLifecycleJobExecuterUnitTest; -import org.alfresco.module.org_alfresco_module_rm.jscript.app.evaluator.FrozenEvaluatorUnitTest; -import org.alfresco.module.org_alfresco_module_rm.jscript.app.evaluator.TransferEvaluatorUnitTest; -import org.alfresco.module.org_alfresco_module_rm.model.compatibility.DictionaryBootstrapPostProcessorUnitTest; -import org.alfresco.module.org_alfresco_module_rm.patch.v22.PatchV22Suite; -import org.alfresco.module.org_alfresco_module_rm.record.RecordMetadataBootstrapUnitTest; -import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImplUnitTest; -import org.alfresco.module.org_alfresco_module_rm.recorded.version.config.RecordedVersionConfigGetTest; -import org.alfresco.module.org_alfresco_module_rm.recorded.version.config.RecordedVersionConfigPostTest; -import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldPostUnitTest; -import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldPutUnitTest; -import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldsGetUnitTest; -import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServiceImplUnitTest; -import org.alfresco.repo.action.parameter.DateParameterProcessorUnitTest; +import org.junit.extensions.cpsuite.ClasspathSuite; +import org.junit.extensions.cpsuite.ClasspathSuite.ClassnameFilters; import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; /** * All unit test suite. @@ -52,51 +28,12 @@ import org.junit.runners.Suite.SuiteClasses; * @author Roy Wetherall * @since 2.2 */ -@RunWith(Suite.class) -@SuiteClasses( -{ - RecordMetadataBootstrapUnitTest.class, - RecordsManagementTypeFormFilterUnitTest.class, - DispositionLifecycleJobExecuterUnitTest.class, - DictionaryBootstrapPostProcessorUnitTest.class, - DateParameterProcessorUnitTest.class, - RMEntryVoterUnitTest.class, - - // services - RecordServiceImplUnitTest.class, - HoldServiceImplUnitTest.class, - // FilePlanPermissionServiceImplUnitTest.class, // removed because test unreliable on Bamboo - RecordableVersionServiceImplUnitTest.class, - - // evaluators - TransferEvaluatorUnitTest.class, - FrozenEvaluatorUnitTest.class, - - // capabilities - EditNonRecordsMetadataCapabilityUnitTest.class, - - // web scripts - HoldsGetUnitTest.class, - HoldPostUnitTest.class, - HoldPutUnitTest.class, - - // action implementations - FileReportActionUnitTest.class, - UnlinkFromActionUnitTest.class, - DeclareAsVersionRecordActionUnitTest.class, - - // recorded version config - RecordedVersionConfigGetTest.class, - RecordedVersionConfigPostTest.class, - - // bootstrap - BootstrapImporterModuleComponentUnitTest.class, - RecordContributorsGroupBootstrapComponentUnitTest.class, - - // suites by package - CapabilityDeclarativeConditionSuite.class, - PatchV22Suite.class - +@RunWith(ClasspathSuite.class) +@ClassnameFilters({ + // Execute all test classes ending with "UnitTest" + ".*UnitTest", + // Put the test classes you want to exclude here + "!.*FilePlanPermissionServiceImplUnitTest" }) public class AllUnitTestSuite { diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImplUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImplUnitTest.java index 21d590dd27..19dd235cae 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImplUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImplUnitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Alfresco Software Limited. + * Copyright (C) 2005-2015 Alfresco Software Limited. * * This file is part of Alfresco * @@ -18,6 +18,8 @@ */ package org.alfresco.module.org_alfresco_module_rm.version; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.anyString; @@ -27,6 +29,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.io.Serializable; import java.util.Collections; @@ -419,9 +422,16 @@ public class RecordableVersionServiceImplUnitTest extends BaseUnitTest { // latest version is already recorded Version mockedVersion = mock(VersionImpl.class); - doReturn(Collections.singletonMap(RecordableVersionServiceImpl.PROP_VERSION_RECORD, generateNodeRef())).when(mockedVersion).getVersionProperties(); - doReturn(true).when(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE); - doReturn(mockedVersion).when(recordableVersionService).getCurrentVersion(nodeRef); + NodeRef versionNodeRef = generateNodeRef(); + when(mockedVersion.getFrozenStateNodeRef()) + .thenReturn(versionNodeRef); + + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) + .thenReturn(true); + when(mockedDbNodeService.hasAspect(versionNodeRef, RecordableVersionModel.ASPECT_RECORDED_VERSION)) + .thenReturn(true); + doReturn(mockedVersion) + .when(recordableVersionService).getCurrentVersion(nodeRef); // create record from version recordableVersionService.createRecordFromLatestVersion(filePlan, nodeRef); @@ -495,4 +505,157 @@ public class RecordableVersionServiceImplUnitTest extends BaseUnitTest RecordableVersionModel.ASPECT_RECORDED_VERSION, Collections.singletonMap(RecordableVersionModel.PROP_RECORD_NODE_REF, (Serializable)newRecordNodeRef)); } + + + /** + * given the destroyed prop isn't set + * when I ask if the version is destroyed + * then the result is false + */ + @Test + public void propNotSetVersionNotDestroyed() + { + // set up version + Version mockedVersion = mock(VersionImpl.class); + NodeRef versionNodeRef = generateNodeRef(); + when(mockedVersion.getFrozenStateNodeRef()) + .thenReturn(versionNodeRef); + + // set prop not set + when(mockedDbNodeService.getProperty(versionNodeRef, RecordableVersionModel.PROP_DESTROYED)) + .thenReturn(null); + + // is version destroyed + assertFalse(recordableVersionService.isRecordedVersionDestroyed(mockedVersion)); + } + + /** + * given the destroyed prop is set + * when I ask if the version is destroyed + * then the result matches the value set in the destroy property + */ + @Test + public void propSetVersionDestroyed() + { + // set up version + Version mockedVersion = mock(VersionImpl.class); + NodeRef versionNodeRef = generateNodeRef(); + when(mockedVersion.getFrozenStateNodeRef()) + .thenReturn(versionNodeRef); + + // set prop + when(mockedDbNodeService.getProperty(versionNodeRef, RecordableVersionModel.PROP_DESTROYED)) + .thenReturn(Boolean.TRUE); + + // is version destroyed + assertTrue(recordableVersionService.isRecordedVersionDestroyed(mockedVersion)); + + // set prop + when(mockedDbNodeService.getProperty(versionNodeRef, RecordableVersionModel.PROP_DESTROYED)) + .thenReturn(Boolean.FALSE); + + // is version destroyed + assertFalse(recordableVersionService.isRecordedVersionDestroyed(mockedVersion)); + } + + /** + * given that the version node doesn't have the recorded version aspect applied + * when I mark the version as destroyed + * then nothing happens + */ + @Test + public void noAspectMarkAsDestroyed() + { + // set up version + Version mockedVersion = mock(VersionImpl.class); + NodeRef versionNodeRef = generateNodeRef(); + when(mockedVersion.getFrozenStateNodeRef()) + .thenReturn(versionNodeRef); + + // indicate that the version doesn't have the aspect + when(mockedDbNodeService.hasAspect(versionNodeRef, RecordableVersionModel.ASPECT_RECORDED_VERSION)) + .thenReturn(false); + + // mark as destroyed + recordableVersionService.destroyRecordedVersion(mockedVersion); + + // verify nothing happened + verify(mockedDbNodeService, never()) + .setProperty(versionNodeRef, RecordableVersionModel.PROP_DESTROYED, Boolean.TRUE); + } + + /** + * given that the version node ref has the recorded version aspect applied + * and the record version reference exists + * when I mark the version as destroyed + * then the version is marked as destroyed + */ + @Test + public void markAsDestroyed() + { + // set up version + Version mockedVersion = mock(VersionImpl.class); + NodeRef versionNodeRef = generateNodeRef(); + NodeRef versionRecordNodeRef = generateNodeRef(); + when(mockedVersion.getFrozenStateNodeRef()) + .thenReturn(versionNodeRef); + when(mockedDbNodeService.exists(versionRecordNodeRef)) + .thenReturn(true); + + // indicate that the version doesn't have the aspect + when(mockedDbNodeService.hasAspect(versionNodeRef, RecordableVersionModel.ASPECT_RECORDED_VERSION)) + .thenReturn(true); + + // indicate that the associated version record exists + when(mockedDbNodeService.getProperty(versionNodeRef, RecordableVersionModel.PROP_RECORD_NODE_REF)) + .thenReturn(versionRecordNodeRef); + + // mark as destroyed + recordableVersionService.destroyRecordedVersion(mockedVersion); + + // verify that the version was marked as destroyed + verify(mockedDbNodeService) + .setProperty(versionNodeRef, RecordableVersionModel.PROP_DESTROYED, Boolean.TRUE); + // and the reference to the version record was cleared + verify(mockedDbNodeService) + .setProperty(versionNodeRef, RecordableVersionModel.PROP_RECORD_NODE_REF, null); + } + + /** + * given that the version node ref has the recorded version aspect applied + * and the associated version record has been deleted + * when I mark the version as destroyed + * then the version is marked as destroyed + * and the reference to the deleted version record is removed + */ + @Test + public void markAsDestroyedClearNodeRef() + { + // set up version + Version mockedVersion = mock(VersionImpl.class); + NodeRef versionNodeRef = generateNodeRef(); + NodeRef versionRecordNodeRef = generateNodeRef(); + when(mockedVersion.getFrozenStateNodeRef()) + .thenReturn(versionNodeRef); + when(mockedDbNodeService.exists(versionRecordNodeRef)) + .thenReturn(false); + + // indicate that the version doesn't have the aspect + when(mockedDbNodeService.hasAspect(versionNodeRef, RecordableVersionModel.ASPECT_RECORDED_VERSION)) + .thenReturn(true); + + // indicate that the associated version record exists + when(mockedDbNodeService.getProperty(versionNodeRef, RecordableVersionModel.PROP_RECORD_NODE_REF)) + .thenReturn(versionRecordNodeRef); + + // mark as destroyed + recordableVersionService.destroyRecordedVersion(mockedVersion); + + // verify that the version was marked as destroyed + verify(mockedDbNodeService) + .setProperty(versionNodeRef, RecordableVersionModel.PROP_DESTROYED, Boolean.TRUE); + // and the reference to the version record was cleared + verify(mockedDbNodeService) + .setProperty(versionNodeRef, RecordableVersionModel.PROP_RECORD_NODE_REF, null); + } } \ No newline at end of file