RM-2562: Deleting records from versions produces inconsistent behaviour

* Versions are not deleted from collab version history, rather marked as destroyed (prevents inconsistencies since we don't support deleting versions well)
 * Share UI updated to acomadate above
 * Version relationship reorganised based on changes to version record history
 * Unit tests and integration tests for above
 * some unit tests relating to RM-2194
 * Hover message on version record icon in version history

+review RM



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/BRANCHES/V2.3@119284 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2015-12-02 02:09:43 +00:00
parent 11e59543bd
commit f142e7647b
24 changed files with 1405 additions and 160 deletions

View File

@@ -94,6 +94,12 @@
<type>d:text</type> <type>d:text</type>
<index enabled="false"/> <index enabled="false"/>
</property> </property>
<!-- indicates whether the version record has been destroyed or not -->
<property name="rmv:destroyed">
<title>Destroyed</title>
<type>d:boolean</type>
<default>false</default>>
</property>
</properties> </properties>
</aspect> </aspect>

View File

@@ -1060,6 +1060,7 @@
<property name="recordsManagementContainerType" ref="rma.recordsManagementContainer"/> <property name="recordsManagementContainerType" ref="rma.recordsManagementContainer"/>
<property name="renditionService" ref="RenditionService" /> <property name="renditionService" ref="RenditionService" />
<property name="dispositionService" ref="DispositionService"/> <property name="dispositionService" ref="DispositionService"/>
<property name="recordableVersionService" ref="RecordableVersionService"/>
</bean> </bean>
<bean id="recordMetadataAspectBootstrap" class="org.alfresco.module.org_alfresco_module_rm.record.RecordMetadataBootstrap" init-method="init" abstract="true"> <bean id="recordMetadataAspectBootstrap" class="org.alfresco.module.org_alfresco_module_rm.record.RecordMetadataBootstrap" init-method="init" abstract="true">

View File

@@ -12,6 +12,13 @@
</property> </property>
</bean> </bean>
<!-- Recordable version model behaviours -->
<bean id="rmv.versionRecord" class="org.alfresco.module.org_alfresco_module_rm.model.rma.aspect.VersionRecordAspect" parent="rm.baseBehaviour">
<property name="versionService" ref="VersionService" />
<property name="recordableVersionService" ref="RecordableVersionService" />
<property name="relationshipService" ref="RelationshipService" />
</bean>
<!-- extended version service bean definition --> <!-- extended version service bean definition -->
<bean id="rm.versionService" abstract="true" class="org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServiceImpl"> <bean id="rm.versionService" abstract="true" class="org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServiceImpl">
<property name="filePlanService" ref="FilePlanService" /> <property name="filePlanService" ref="FilePlanService" />
@@ -63,7 +70,10 @@
<![CDATA[ <![CDATA[
org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.isCurrentVersionRecorded=RM_ALLOW 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.isRecordedVersion=RM_ALLOW
org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.getVersionRecord=RM_ALLOW
org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.createRecordFromLatestVersion=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
org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.*=RM_DENY org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService.*=RM_DENY
]]> ]]>
</value> </value>

View File

@@ -62,7 +62,7 @@ function main()
{ {
var nodeRef = args["nodeRef"], var nodeRef = args["nodeRef"],
node = search.findNode(nodeRef), node = search.findNode(nodeRef),
versionHistory, version, p, recordNodeRef; versionHistory, version, p, recordNodeRef, isRecordedVersionDestroyed;
if (node != null) if (node != null)
{ {
@@ -73,11 +73,14 @@ function main()
{ {
version = versionHistory[i]; version = versionHistory[i];
p = getPerson(version.creator); p = getPerson(version.creator);
recordNodeRef = version.getVersionProperty("recordNodeRef"); recordNodeRef = version.getVersionProperty("recordNodeRef");
isRecordedVersionDestroyed = version.getVersionProperty("RecordedVersionDestroyed");
versions[versions.length] = versions[versions.length] =
{ {
nodeRef: version.node.nodeRef.toString(), nodeRef: version.node.nodeRef.toString(),
name: version.node.name, name: (isRecordedVersionDestroyed == true) ? "" : version.node.name,
label: version.label, label: version.label,
description: version.description, description: version.description,
createdDate: version.createdDate, createdDate: version.createdDate,
@@ -87,7 +90,8 @@ function main()
firstName: p.firstName, firstName: p.firstName,
lastName: p.lastName lastName: p.lastName
}, },
recordNodeRef: recordNodeRef ? recordNodeRef.toString() : "" recordNodeRef: recordNodeRef ? recordNodeRef.toString() : "",
isRecordedVersionDestroyed: isRecordedVersionDestroyed
}; };
} }
} }
@@ -107,7 +111,8 @@ function main()
firstName: p.firstName, firstName: p.firstName,
lastName: p.lastName lastName: p.lastName
}, },
recordNodeRef: "" recordNodeRef: "",
isRecordedVersionDestroyed: false
}; };
} }
} }

View File

@@ -14,7 +14,8 @@
"firstName": "${v.creator.firstName!""}", "firstName": "${v.creator.firstName!""}",
"lastName": "${v.creator.lastName!""}" "lastName": "${v.creator.lastName!""}"
}, },
"recordNodeRef": "${v.recordNodeRef}" "recordNodeRef": "${v.recordNodeRef}",
"isRecordedVersionDestroyed": ${v.isRecordedVersionDestroyed?c}
}<#if (v_has_next)>,</#if> }<#if (v_has_next)>,</#if>
</#list> </#list>
] ]

View File

@@ -189,6 +189,12 @@
<version>${alfresco.base.version}</version> <version>${alfresco.base.version}</version>
</dependency> </dependency>
<!-- Test dependencies --> <!-- Test dependencies -->
<dependency>
<groupId>io.takari.junit</groupId>
<artifactId>takari-cpsuite</artifactId>
<version>1.2.7</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View File

@@ -36,7 +36,6 @@ import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind; 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.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -110,7 +109,7 @@ public class RecordAspect extends AbstractDisposableItem
) )
public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, boolean bNew) public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, boolean bNew)
{ {
AuthenticationUtil.runAsSystem(new RunAsWork<Void>() authenticationUtil.runAsSystem(new RunAsWork<Void>()
{ {
@Override @Override
public Void doWork() public Void doWork()
@@ -173,7 +172,7 @@ public class RecordAspect extends AbstractDisposableItem
// Deal with versioned records // Deal with versioned records
if (reference.equals(CUSTOM_REF_VERSIONS)) if (reference.equals(CUSTOM_REF_VERSIONS))
{ {
AuthenticationUtil.runAsSystem(new RunAsWork<Void>() authenticationUtil.runAsSystem(new RunAsWork<Void>()
{ {
@Override @Override
public Void doWork() public Void doWork()
@@ -240,7 +239,7 @@ public class RecordAspect extends AbstractDisposableItem
isFilePlanComponent(oldChildAssocRef.getParentRef())) isFilePlanComponent(oldChildAssocRef.getParentRef()))
{ {
final NodeRef record = newChildAssocRef.getChildRef(); final NodeRef record = newChildAssocRef.getChildRef();
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() authenticationUtil.runAs(new RunAsWork<Object>()
{ {
public Object doWork() public Object doWork()
{ {
@@ -256,7 +255,7 @@ public class RecordAspect extends AbstractDisposableItem
return null; return null;
} }
}, AuthenticationUtil.getAdminUserName()); }, authenticationUtil.getAdminUserName());
} }
} }

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<Void>()
{
@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<Relationship> tos = relationshipService.getRelationshipsTo(nodeRef, RelationshipService.RELATIONSHIP_VERSIONS);
if (!tos.isEmpty() && tos.size() == 1)
{
// if there is some "from" references
Set<Relationship> 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;
}
});
}
}
}
}
}
}

View File

@@ -18,10 +18,6 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.record; 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.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; 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.role.Role;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService; 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.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.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.ClassPolicyDelegate; import org.alfresco.repo.policy.ClassPolicyDelegate;
@@ -122,8 +118,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnAddAspectPolicy, NodeServicePolicies.OnAddAspectPolicy,
NodeServicePolicies.OnRemoveAspectPolicy, NodeServicePolicies.OnRemoveAspectPolicy,
NodeServicePolicies.OnUpdatePropertiesPolicy, NodeServicePolicies.OnUpdatePropertiesPolicy
NodeServicePolicies.BeforeDeleteNodePolicy
{ {
/** Logger */ /** Logger */
private static Log logger = LogFactory.getLog(RecordServiceImpl.class); private static Log logger = LogFactory.getLog(RecordServiceImpl.class);
@@ -230,6 +225,9 @@ public class RecordServiceImpl extends BaseBehaviourBean
/** records management container type */ /** records management container type */
private RecordsManagementContainerType recordsManagementContainerType; 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 */ /** list of available record meta-data aspects and the file plan types the are applicable to */
private Map<QName, Set<QName>> recordMetaDataAspects; private Map<QName, Set<QName>> recordMetaDataAspects;
@@ -383,6 +381,14 @@ public class RecordServiceImpl extends BaseBehaviourBean
this.recordsManagementContainerType = recordsManagementContainerType; this.recordsManagementContainerType = recordsManagementContainerType;
} }
/**
* @param recordableVersionService recordable version service
*/
public void setRecordableVersionService(RecordableVersionService recordableVersionService)
{
this.recordableVersionService = recordableVersionService;
}
/** /**
* Init method * Init method
*/ */
@@ -1024,6 +1030,18 @@ public class RecordServiceImpl extends BaseBehaviourBean
recordsManagementContainerType.enable(); 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 // make record
makeRecord(record); makeRecord(record);
@@ -1081,7 +1099,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
for (Version previousVersion : previousVersions) for (Version previousVersion : previousVersions)
{ {
// look for the associated record // 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) if (previousRecord != null)
{ {
versionRecord = previousRecord; versionRecord = previousRecord;
@@ -1809,37 +1827,4 @@ public class RecordServiceImpl extends BaseBehaviourBean
throw new RecordLinkRuntimeException("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<Void>()
{
@Override
public Void doWork()
{
versionService.deleteVersion(versionedNodeRef, version);
return null;
}
});
}
}
}
} }

View File

@@ -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.mandatory;
import static org.alfresco.util.ParameterCheck.mandatoryString; import static org.alfresco.util.ParameterCheck.mandatoryString;
import java.io.Serializable;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
/** /**
@@ -29,8 +31,11 @@ import org.alfresco.service.cmr.repository.NodeRef;
* @author Tuna Aksoy * @author Tuna Aksoy
* @since 2.3 * @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 */ /** The unique name of the relationship */
private String uniqueName; private String uniqueName;
@@ -114,4 +119,39 @@ public class RelationshipImpl implements Relationship
{ {
this.target = target; 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();
}
} }

View File

@@ -30,6 +30,9 @@ import org.alfresco.service.cmr.repository.NodeRef;
*/ */
public interface RelationshipService public interface RelationshipService
{ {
/** System relationship names */
static final String RELATIONSHIP_VERSIONS = "versions";
/** /**
* Gets all the existing relationship definitions * Gets all the existing relationship definitions
* *
@@ -87,13 +90,41 @@ public interface RelationshipService
Set<Relationship> getRelationshipsFrom(NodeRef nodeRef); Set<Relationship> 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.
* <p>
* Exact match only.
* *
* @param nodeRef The node reference * @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<Relationship> 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<Relationship> getRelationshipsTo(NodeRef nodeRef); Set<Relationship> getRelationshipsTo(NodeRef nodeRef);
/**
* Gets all the relationships that go into the given node reference
* that match the a given name filter.
* <p>
* 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<Relationship> getRelationshipsTo(NodeRef nodeRef, String nameFilter);
/** /**
* Adds a relationship from the given node <code>source</code> * Adds a relationship from the given node <code>source</code>
* to the give node <code>target</code> with the given unique name * to the give node <code>target</code> with the given unique name

View File

@@ -376,16 +376,25 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen
*/ */
@Override @Override
public Set<Relationship> getRelationshipsFrom(NodeRef nodeRef) public Set<Relationship> 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<Relationship> getRelationshipsFrom(NodeRef nodeRef, String nameFilter)
{ {
mandatory("nodeRef", nodeRef); mandatory("nodeRef", nodeRef);
Set<Relationship> relationships = new HashSet<Relationship>(); Set<Relationship> relationships = new HashSet<Relationship>();
List<AssociationRef> customReferencesFrom = getNodeService().getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL); List<AssociationRef> customReferencesFrom = getNodeService().getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL);
relationships.addAll(generateRelationshipFromAssociationRef(customReferencesFrom)); relationships.addAll(generateRelationshipFromAssociationRef(customReferencesFrom, nameFilter));
List<ChildAssociationRef> customChildReferences = getNodeService().getChildAssocs(nodeRef); List<ChildAssociationRef> customChildReferences = getNodeService().getChildAssocs(nodeRef);
relationships.addAll(generateRelationshipFromParentChildAssociationRef(customChildReferences)); relationships.addAll(generateRelationshipFromParentChildAssociationRef(customChildReferences, nameFilter));
return relationships; return relationships;
} }
@@ -395,16 +404,25 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen
*/ */
@Override @Override
public Set<Relationship> getRelationshipsTo(NodeRef nodeRef) public Set<Relationship> 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<Relationship> getRelationshipsTo(NodeRef nodeRef, String nameFilter)
{ {
mandatory("nodeRef", nodeRef); mandatory("nodeRef", nodeRef);
Set<Relationship> relationships = new HashSet<Relationship>(); Set<Relationship> relationships = new HashSet<Relationship>();
List<AssociationRef> customReferencesTo = getNodeService().getSourceAssocs(nodeRef, RegexQNamePattern.MATCH_ALL); List<AssociationRef> customReferencesTo = getNodeService().getSourceAssocs(nodeRef, RegexQNamePattern.MATCH_ALL);
relationships.addAll(generateRelationshipFromAssociationRef(customReferencesTo)); relationships.addAll(generateRelationshipFromAssociationRef(customReferencesTo, nameFilter));
List<ChildAssociationRef> customParentReferences = getNodeService().getParentAssocs(nodeRef); List<ChildAssociationRef> customParentReferences = getNodeService().getParentAssocs(nodeRef);
relationships.addAll(generateRelationshipFromParentChildAssociationRef(customParentReferences)); relationships.addAll(generateRelationshipFromParentChildAssociationRef(customParentReferences, nameFilter));
return relationships; return relationships;
} }
@@ -419,6 +437,18 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen
mandatory("source", source); mandatory("source", source);
mandatory("target", target); 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)) if (getNodeService().hasAspect(target, ASPECT_FROZEN))
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -622,14 +652,15 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen
* @param associationRefs Association references * @param associationRefs Association references
* @return Relationships generated from the given association references * @return Relationships generated from the given association references
*/ */
private Set<Relationship> generateRelationshipFromAssociationRef(List<AssociationRef> associationRefs) private Set<Relationship> generateRelationshipFromAssociationRef(List<AssociationRef> associationRefs, String nameFilter)
{ {
Set<Relationship> relationships = new HashSet<Relationship>(); Set<Relationship> relationships = new HashSet<Relationship>();
for (AssociationRef associationRef : associationRefs) for (AssociationRef associationRef : associationRefs)
{ {
String uniqueName = associationRef.getTypeQName().getLocalName(); String uniqueName = associationRef.getTypeQName().getLocalName();
if (existsRelationshipDefinition(uniqueName)) if (existsRelationshipDefinition(uniqueName) &&
(nameFilter == null || uniqueName.equals(nameFilter)))
{ {
NodeRef from = associationRef.getSourceRef(); NodeRef from = associationRef.getSourceRef();
NodeRef to = associationRef.getTargetRef(); NodeRef to = associationRef.getTargetRef();
@@ -646,14 +677,15 @@ public class RelationshipServiceImpl extends RecordsManagementAdminBase implemen
* @param childAssociationRefs Child association references * @param childAssociationRefs Child association references
* @return Relationships generated from the given child association references * @return Relationships generated from the given child association references
*/ */
private Set<Relationship> generateRelationshipFromParentChildAssociationRef(List<ChildAssociationRef> childAssociationRefs) private Set<Relationship> generateRelationshipFromParentChildAssociationRef(List<ChildAssociationRef> childAssociationRefs, String nameFilter)
{ {
Set<Relationship> relationships = new HashSet<Relationship>(); Set<Relationship> relationships = new HashSet<Relationship>();
for (ChildAssociationRef childAssociationRef : childAssociationRefs) for (ChildAssociationRef childAssociationRef : childAssociationRefs)
{ {
String uniqueName = childAssociationRef.getQName().getLocalName(); String uniqueName = childAssociationRef.getQName().getLocalName();
if (existsRelationshipDefinition(uniqueName)) if (existsRelationshipDefinition(uniqueName)&&
(nameFilter == null || uniqueName.equals(nameFilter)))
{ {
NodeRef from = childAssociationRef.getParentRef(); NodeRef from = childAssociationRef.getParentRef();
NodeRef to = childAssociationRef.getChildRef(); NodeRef to = childAssociationRef.getChildRef();

View File

@@ -41,6 +41,7 @@ public interface RecordableVersionModel
QName ASPECT_RECORDED_VERSION = QName.createQName(RMV_URI, "recordedVersion"); QName ASPECT_RECORDED_VERSION = QName.createQName(RMV_URI, "recordedVersion");
QName PROP_RECORD_NODE_REF = QName.createQName(RMV_URI, "recordNodeRef"); QName PROP_RECORD_NODE_REF = QName.createQName(RMV_URI, "recordNodeRef");
QName PROP_FROZEN_OWNER = QName.createQName(RMV_URI, "frozenOwner"); QName PROP_FROZEN_OWNER = QName.createQName(RMV_URI, "frozenOwner");
QName PROP_DESTROYED = QName.createQName(RMV_URI, "destroyed");
/** version record aspect */ /** version record aspect */
QName ASPECT_VERSION_RECORD = QName.createQName(RMV_URI, "versionRecord"); QName ASPECT_VERSION_RECORD = QName.createQName(RMV_URI, "versionRecord");

View File

@@ -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 static org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl.RECORD_MODEL_URIS;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; 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) * @see org.alfresco.repo.version.Node2ServiceImpl#getAspects(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@SuppressWarnings("unchecked")
@Override @Override
public Set<QName> getAspects(NodeRef nodeRef) throws InvalidNodeRefException public Set<QName> getAspects(NodeRef nodeRef) throws InvalidNodeRefException
{ {
@@ -190,10 +192,17 @@ public class RecordableVersionNodeServiceImpl extends Node2ServiceImpl
if (dbNodeService.hasAspect(converted, ASPECT_RECORDED_VERSION)) if (dbNodeService.hasAspect(converted, ASPECT_RECORDED_VERSION))
{ {
NodeRef record = (NodeRef)dbNodeService.getProperty(converted, PROP_RECORD_NODE_REF); NodeRef record = (NodeRef)dbNodeService.getProperty(converted, PROP_RECORD_NODE_REF);
if (dbNodeService.exists(record))
{
Set<QName> aspects = dbNodeService.getAspects(record); Set<QName> aspects = dbNodeService.getAspects(record);
return processAspects(aspects); return processAspects(aspects);
} }
else else
{
return (Set<QName>)Collections.EMPTY_SET;
}
}
else
{ {
return super.getAspects(nodeRef); return super.getAspects(nodeRef);
} }

View File

@@ -47,6 +47,15 @@ public interface RecordableVersionService
*/ */
boolean isRecordedVersion(Version version); 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. * Creates a record from the latest version, marking it as recorded.
* <p> * <p>
@@ -54,8 +63,26 @@ public interface RecordableVersionService
* version is already recorded. * version is already recorded.
* *
* @param nodeRef node reference * @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); 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.
* <p>
* Note this method does not destroy the associated record, instead it marks the
* version as destroyed.
*
* @param version version
*/
void destroyRecordedVersion(Version version);
} }

View File

@@ -76,7 +76,8 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
public static final String KEY_FILE_PLAN = "file-plan"; public static final String KEY_FILE_PLAN = "file-plan";
/** version record property */ /** 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 */ /** version aspect property names */
private static final String[] VERSION_PROPERTY_NAMES = new String[] private static final String[] VERSION_PROPERTY_NAMES = new String[]
@@ -491,7 +492,8 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
{ {
// look for the associated record // look for the associated record
final NodeRef previousRecord = (NodeRef)previousVersion.getVersionProperties().get(PROP_VERSION_RECORD); final NodeRef previousRecord = (NodeRef)previousVersion.getVersionProperties().get(PROP_VERSION_RECORD);
if (previousRecord != null) if (previousRecord != null &&
nodeService.exists(previousRecord))
{ {
versionRecord = previousRecord; versionRecord = previousRecord;
break; break;
@@ -502,6 +504,66 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
return versionRecord; 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<Version> getAllVersions()
{
return (Collection<Version>)Collections.EMPTY_LIST;
}
@Override
public Version getPredecessor(Version version)
{
return null;
}
@SuppressWarnings("unchecked")
@Override
public Collection<Version> getSuccessors(Version version)
{
return (Collection<Version>)Collections.EMPTY_LIST;
}
@Override
public Version getVersion(String versionLabel)
{
return null;
}
}
/** /**
* Freezes audit aspect properties. * Freezes audit aspect properties.
* *
@@ -533,12 +595,18 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
{ {
Version version = super.getVersion(versionRef); Version version = super.getVersion(versionRef);
// place the version record reference in the version properties
NodeRef record = (NodeRef)dbNodeService.getProperty(versionRef, PROP_RECORD_NODE_REF); NodeRef record = (NodeRef)dbNodeService.getProperty(versionRef, PROP_RECORD_NODE_REF);
if (record != null) if (record != null)
{ {
version.getVersionProperties().put(PROP_VERSION_RECORD, record); 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; return version;
} }
@@ -579,10 +647,31 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
@Override @Override
public boolean isRecordedVersion(Version version) public boolean isRecordedVersion(Version version)
{ {
boolean result = true; NodeRef versionNodeRef = getVersionNodeRef(version);
if (version.getVersionProperties().get(PROP_VERSION_RECORD) == null) 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)
{ {
result = false; NodeRef result = null;
NodeRef versionNodeRef = getVersionNodeRef(version);
if (dbNodeService.hasAspect(versionNodeRef, RecordableVersionModel.ASPECT_RECORDED_VERSION))
{
// 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; return result;
} }
@@ -737,6 +826,47 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
return record; 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 * Helper method to get the version number of a given version by inspecting the
* name of the parent association. * name of the parent association.

View File

@@ -169,7 +169,7 @@ public class AdHocRecordableVersionsTest extends RecordableVersionsBaseTest
public Void doWork() throws Exception public Void doWork() throws Exception
{ {
// add custom meta-data to record // add custom meta-data to record
NodeRef record = (NodeRef)version.getVersionProperties().get(RecordableVersionServiceImpl.PROP_VERSION_RECORD); NodeRef record = recordableVersionService.getVersionRecord(version);
assertNotNull(record); assertNotNull(record);
recordService.addRecordType(record, TestModel.ASPECT_RECORD_METADATA); recordService.addRecordType(record, TestModel.ASPECT_RECORD_METADATA);
nodeService.setProperty(record, TestModel.PROPERTY_RECORD_METADATA, "Peter Wetherall"); nodeService.setProperty(record, TestModel.PROPERTY_RECORD_METADATA, "Peter Wetherall");

View File

@@ -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.relationship.Relationship;
import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel; 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.RecordableVersionPolicy;
import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServiceImpl;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.Version;
@@ -131,7 +130,7 @@ public class AutoRecordableVersionsTest extends RecordableVersionsBaseTest
checkRecordedVersion(dmDocument, null, "0.3"); checkRecordedVersion(dmDocument, null, "0.3");
Version version = versionService.getCurrentVersion(dmDocument); Version version = versionService.getCurrentVersion(dmDocument);
NodeRef record = (NodeRef)version.getVersionProperties().get(RecordableVersionServiceImpl.PROP_VERSION_RECORD); NodeRef record = recordableVersionService.getVersionRecord(version);
boolean foundPrevious = false; boolean foundPrevious = false;
Set<Relationship> relationships = relationshipService.getRelationshipsFrom(record); Set<Relationship> relationships = relationshipService.getRelationshipsFrom(record);

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<QName, Serializable> props = new HashMap<QName, Serializable>(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<QName, Serializable> props = new HashMap<QName, Serializable>(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<Relationship> from = relationshipService.getRelationshipsFrom(versionRecord);
assertTrue(from.isEmpty());
Set<Relationship> 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<Relationship> 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<Relationship> 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<Relationship> 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<Relationship> 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<Relationship> 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<Relationship> 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());
}
});
}
}

View File

@@ -19,15 +19,18 @@
package org.alfresco.module.org_alfresco_module_rm.test.integration.version; package org.alfresco.module.org_alfresco_module_rm.test.integration.version;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.model.ContentModel; 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.test.util.BaseRMTestCase;
import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel; 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.repo.content.MimetypeMap;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef; 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.cmr.version.VersionHistory;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap; import org.alfresco.util.PropertyMap;
/** /**
* Recordable versions base integration test
*
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.3 * @since 2.3
*/ */
@@ -56,6 +62,15 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen
+ "user and smart because we support more open standards than any other ECM platform, while delivering all " + "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() * @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); checkAspects(frozen, beforeAspects);
// record version node reference is available on version // 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); assertNotNull(record);
// check that the version record information has been added // check that the version record information has been added
@@ -191,7 +206,7 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen
assertEquals(versionLabel, version.getVersionLabel()); assertEquals(versionLabel, version.getVersionLabel());
// record version node reference is available on version // 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); assertNull(record);
// check the version history // check the version history
@@ -268,4 +283,120 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen
} }
} }
/**
* 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<NodeRef>()
{
@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<QName, Serializable> props = new HashMap<QName, Serializable>(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<Void>()
{
@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<Void>()
{
@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<Void>()
{
@Override
public Void run() throws Exception
{
// verify that the version history looks as expected
VersionHistory versionHistory = versionService.getVersionHistory(myDocument);
assertNotNull(versionHistory);
Collection<Version> 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<Relationship> 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<Relationship> to11 = relationshipService.getRelationshipsTo(recordVersion11, "versions");
assertEquals(1, to11.size());
assertEquals(recordVersion12, to11.iterator().next().getSource());
Set<Relationship> 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<Relationship> 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;
}
} }

View File

@@ -34,7 +34,8 @@ import org.junit.runners.Suite.SuiteClasses;
AdHocRecordableVersionsTest.class, AdHocRecordableVersionsTest.class,
AutoRecordableVersionsTest.class, AutoRecordableVersionsTest.class,
DeclareAsRecordVersionTest.class, DeclareAsRecordVersionTest.class,
AutoVersionTest.class AutoVersionTest.class,
DeleteRecordVersionTest.class
}) })
public class VersionTestSuite public class VersionTestSuite
{ {

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@@ -18,33 +18,9 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.test; package org.alfresco.module.org_alfresco_module_rm.test;
import org.alfresco.module.org_alfresco_module_rm.action.dm.DeclareAsVersionRecordActionUnitTest; import org.junit.extensions.cpsuite.ClasspathSuite;
import org.alfresco.module.org_alfresco_module_rm.action.impl.FileReportActionUnitTest; import org.junit.extensions.cpsuite.ClasspathSuite.ClassnameFilters;
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.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
/** /**
* All unit test suite. * All unit test suite.
@@ -52,51 +28,12 @@ import org.junit.runners.Suite.SuiteClasses;
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.2 * @since 2.2
*/ */
@RunWith(Suite.class) @RunWith(ClasspathSuite.class)
@SuiteClasses( @ClassnameFilters({
{ // Execute all test classes ending with "UnitTest"
RecordMetadataBootstrapUnitTest.class, ".*UnitTest",
RecordsManagementTypeFormFilterUnitTest.class, // Put the test classes you want to exclude here
DispositionLifecycleJobExecuterUnitTest.class, "!.*FilePlanPermissionServiceImplUnitTest"
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
}) })
public class AllUnitTestSuite public class AllUnitTestSuite
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2014 Alfresco Software Limited. * Copyright (C) 2005-2015 Alfresco Software Limited.
* *
* This file is part of Alfresco * This file is part of Alfresco
* *
@@ -18,6 +18,8 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.version; 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.any;
import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyString; 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.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collections; import java.util.Collections;
@@ -419,9 +422,16 @@ public class RecordableVersionServiceImplUnitTest extends BaseUnitTest
{ {
// latest version is already recorded // latest version is already recorded
Version mockedVersion = mock(VersionImpl.class); Version mockedVersion = mock(VersionImpl.class);
doReturn(Collections.singletonMap(RecordableVersionServiceImpl.PROP_VERSION_RECORD, generateNodeRef())).when(mockedVersion).getVersionProperties(); NodeRef versionNodeRef = generateNodeRef();
doReturn(true).when(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE); when(mockedVersion.getFrozenStateNodeRef())
doReturn(mockedVersion).when(recordableVersionService).getCurrentVersion(nodeRef); .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 // create record from version
recordableVersionService.createRecordFromLatestVersion(filePlan, nodeRef); recordableVersionService.createRecordFromLatestVersion(filePlan, nodeRef);
@@ -495,4 +505,157 @@ public class RecordableVersionServiceImplUnitTest extends BaseUnitTest
RecordableVersionModel.ASPECT_RECORDED_VERSION, RecordableVersionModel.ASPECT_RECORDED_VERSION,
Collections.singletonMap(RecordableVersionModel.PROP_RECORD_NODE_REF, (Serializable)newRecordNodeRef)); 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);
}
} }