diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties index f56e347fdc..f83d14dc47 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties @@ -86,3 +86,10 @@ rm.patch.v22.convertToStandardFilePlan=false # a document will be auto-versioned when its type is changed. # version.store.enableAutoVersionOnTypeChange=false + +# +# Enable auto-version to be created when there is a difference between the document and latest record state +# to ensure that the created version record matches the current document state, +# otherwise create the version record from the version history +# +rm.enableAutoVersionOnRecordCreation=false diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/records-management-service.properties b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/records-management-service.properties index f53f066f9d..20a0cf4c62 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/records-management-service.properties +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/records-management-service.properties @@ -18,4 +18,5 @@ rm.service.vital-def-missing=Vital record definition aspect is not present on no rm.service.close-record-folder-not-folder=The record folder couldn't be closed because it's not defined as a record folder.(nodeRef={0}) rm.service.node-has-aspect=The node {0} has already the aspect {1}. rm.service.final-version=Final -rm.service.final-version-description=The final archived record version \ No newline at end of file +rm.service.final-version-description=The final archived record version +rm.service.enable-autoversion-on-record-creation=Auto Version on Record Creation \ No newline at end of file diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml index 0191e398ba..3cac624ada 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml @@ -1151,4 +1151,4 @@ - \ No newline at end of file + diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 0ed6c73149..271b40b23c 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -154,6 +154,7 @@ org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.getLastCompletedDispostionAction=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.isDisposableItemCutoff=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.cutoffDisposableItem=RM.Read.0 + org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.calculateAsOfDate=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.*=RM_DENY ]]> diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml index 1f755ca57f..91c2f622ea 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml @@ -11,7 +11,7 @@ - + @@ -21,6 +21,7 @@ + @@ -44,8 +45,8 @@ - - + + @@ -56,7 +57,7 @@ - + @@ -77,6 +78,7 @@ props = new HashMap(10); - // Calculate the asOf date - Date asOfDate = null; - Period period = dispositionActionDefinition.getPeriod(); - if (period != null) - { - Date contextDate = null; - - // Get the period properties value - QName periodProperty = dispositionActionDefinition.getPeriodProperty(); - if (periodProperty != null) - { - // doesn't matter if the period property isn't set ... the asOfDate will get updated later - // when the value of the period property is set - contextDate = (Date)this.nodeService.getProperty(nodeRef, periodProperty); - } - else - { - // for now use 'NOW' as the default context date - // TODO set the default period property ... cut off date or last disposition date depending on context - contextDate = new Date(); - } - - // Calculate the as of date - if (contextDate != null) - { - asOfDate = period.getNextDate(contextDate); - } - } + Date asOfDate = calculateAsOfDate(nodeRef, dispositionActionDefinition, allowContextFromAsOf); // Set the property values props.put(PROP_DISPOSITION_ACTION_ID, dispositionActionDefinition.getId()); @@ -690,6 +662,50 @@ public class DispositionServiceImpl extends ServiceBaseImpl } } + /** + * Compute the "disposition as of" date (if necessary) for a disposition action and a node. + * + * @param nodeRef The node which the schedule applies to. + * @param dispositionActionDefinition The definition of the disposition action. + * @param allowContextFromAsOf true if the context date is allowed to be obtained from the disposition "as of" property. + * @return The new "disposition as of" date. + */ + @Override + public Date calculateAsOfDate(NodeRef nodeRef, DispositionActionDefinition dispositionActionDefinition, + boolean allowContextFromAsOf) + { + // Calculate the asOf date + Date asOfDate = null; + Period period = dispositionActionDefinition.getPeriod(); + if (period != null) + { + Date contextDate = null; + + // Get the period properties value + QName periodProperty = dispositionActionDefinition.getPeriodProperty(); + if (periodProperty != null && (allowContextFromAsOf + || !RecordsManagementModel.PROP_DISPOSITION_AS_OF.equals(periodProperty))) + { + // doesn't matter if the period property isn't set ... the asOfDate will get updated later + // when the value of the period property is set + contextDate = (Date)this.nodeService.getProperty(nodeRef, periodProperty); + } + else + { + // for now use 'NOW' as the default context date + // TODO set the default period property ... cut off date or last disposition date depending on context + contextDate = new Date(); + } + + // Calculate the as of date + if (contextDate != null) + { + asOfDate = period.getNextDate(contextDate); + } + } + return asOfDate; + } + /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#isNextDispositionActionEligible(org.alfresco.service.cmr.repository.NodeRef) */ @@ -914,63 +930,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl nodeService.addAspect(nodeRef, ASPECT_DISPOSITION_LIFECYCLE, null); } - // Create the properties - Map props = new HashMap(10); - - // Calculate the asOf date - Date asOfDate = null; - Period period = nextDispositionActionDefinition.getPeriod(); - if (period != null) - { - Date contextDate = null; - - // Get the period properties value - QName periodProperty = nextDispositionActionDefinition.getPeriodProperty(); - if (periodProperty != null && - !RecordsManagementModel.PROP_DISPOSITION_AS_OF.equals(periodProperty)) - { - // doesn't matter if the period property isn't set ... the asOfDate will get updated later - // when the value of the period property is set - contextDate = (Date) nodeService.getProperty(nodeRef, periodProperty); - } - else - { - // for now use 'NOW' as the default context date - // TODO set the default period property ... cut off date or last disposition date depending on context - contextDate = new Date(); - } - - // Calculate the as of date - if (contextDate != null) - { - asOfDate = period.getNextDate(contextDate); - } - } - - // Set the property values - props.put(PROP_DISPOSITION_ACTION_ID, nextDispositionActionDefinition.getId()); - props.put(PROP_DISPOSITION_ACTION, nextDispositionActionDefinition.getName()); - if (asOfDate != null) - { - props.put(PROP_DISPOSITION_AS_OF, asOfDate); - } - - // Create a new disposition action object - NodeRef dispositionActionNodeRef = nodeService.createNode( - nodeRef, - ASSOC_NEXT_DISPOSITION_ACTION, - ASSOC_NEXT_DISPOSITION_ACTION, - TYPE_DISPOSITION_ACTION, - props).getChildRef(); - DispositionAction da = new DispositionActionImpl(serviceRegistry, dispositionActionNodeRef); - - // Create the events - List events = nextDispositionActionDefinition.getEvents(); - for (RecordsManagementEvent event : events) - { - // For every event create an entry on the action - da.addEventCompletionDetails(event); - } + initialiseDispositionAction(nodeRef, nextDispositionActionDefinition, false); } } @@ -1025,7 +985,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl recordFolderService.closeRecordFolder(nodeRef); return null; } - }); + }); } } else diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java index bd098d3a86..5e14ec3142 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java @@ -1058,7 +1058,9 @@ public class RecordServiceImpl extends BaseBehaviourBean private NodeRef getLatestVersionRecord(NodeRef nodeRef) { NodeRef versionRecord = null; - + + + recordableVersionService.createSnapshotVersion(nodeRef); // wire record up to previous record VersionHistory versionHistory = versionService.getVersionHistory(nodeRef); if (versionHistory != null) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java index 5b6ed6fb6d..6a2c3b6e02 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java @@ -36,70 +36,93 @@ import org.alfresco.service.cmr.version.Version; * @author Roy Wetherall * @since 2.3 */ -public interface RecordableVersionService +public interface RecordableVersionService { /** * Indicates whether the current version of a node is recorded or not. *

* Returns false if not versionable or no version. * - * @param nodeRef node reference - * @return boolean true if latest version recorded, false otherwise + * @param nodeRef node reference + * @return boolean true if latest version recorded, false otherwise */ boolean isCurrentVersionRecorded(NodeRef nodeRef); - + /** * Indicates whether a version is recorded or not. * - * @param version version - * @return boolean true if recorded version, false otherwise + * @param version version + * @return boolean true if recorded version, false otherwise */ boolean isRecordedVersion(Version version); - + /** - * If the version is a recorded version, gets the related version - * record. + * If the version is a recorded version, gets the related version record. * - * @param version version - * @return NodeRef node reference of version record + * @param version version + * @return NodeRef node reference of version record */ NodeRef getVersionRecord(Version version); - + /** * Gets the version that relates to the version record * * @param versionRecord version record node reference - * @return Version version or null if not found + * @return Version version or null if not found */ Version getRecordedVersion(NodeRef record); - + + /** + * Creates a record from the latest frozen version, marking it as recorded. + *

+ * Does not create a record if the node is not versionable or the latest version is already recorded. + * + * @param nodeRef node reference + * @return NodeRef node reference to the created record. + */ + NodeRef createRecordFromLatestVersion(NodeRef filePlan, NodeRef nodeRef); + /** * Creates a record from the latest version, marking it as recorded. *

- * Does not create a record if the node is not versionable or the latest - * version is already recorded. + * Does not create a record if the node is not versionable or the latest version is already recorded. + * + * @param nodeRef parent node reference + * @param nodeRef node reference + * @param autoVersion true, create new record version from latest version, false creates a record from the latest frozen version + * @return NodeRef node reference to the created record. * - * @param nodeRef node reference - * @return NodeRef node reference to the created record. */ - NodeRef createRecordFromLatestVersion(NodeRef filePlan, NodeRef nodeRef); - + NodeRef createRecordFromLatestVersion(NodeRef filePlan, NodeRef nodeRef, boolean autoVersion); + /** * Indicates whether a record version is destroyed or not. * - * @param version version - * @return boolean true if destroyed, false otherwise + * @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. + * Note this method does not destroy the associated record, instead it marks the version as destroyed. * - * @param version version + * @param version version */ void destroyRecordedVersion(Version version); + /** + * Flag that indicate to create new version on record creation if current node is modified + * + * @return boolean true to auto-version on record creation, false to use latest versioned version + */ + boolean isEnableAutoVersionOnRecordCreation(); + + /** + * Create a snapshot version of current node + * + * @param nodeRef node reference + */ + void createSnapshotVersion(NodeRef nodeRef); } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java index b8ed5adedd..d7e8128fc1 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java @@ -33,6 +33,7 @@ import static org.codehaus.plexus.util.StringUtils.isNotBlank; import java.io.Serializable; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -66,6 +67,7 @@ import org.alfresco.util.PropertyMap; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.I18NUtil; /** * Recordable version service implementation @@ -88,6 +90,12 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl protected static final String PROP_VERSION_RECORD = "RecordVersion"; protected static final String PROP_RECORDED_VERSION_DESTROYED = "RecordedVersionDestroyed"; + /** I18N */ + private static final String AUTO_VERSION_ON_RECORD_CREATION = "rm.service.enable-autoversion-on-record-creation"; + + /** flag that enable auto-version on record creation */ + private boolean isEnableAutoVersionOnRecordCreation = false; + /** version aspect property names */ private static final String[] VERSION_PROPERTY_NAMES = new String[] { @@ -122,15 +130,15 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl /** cm object type */ private CmObjectType cmObjectType; - + /** extended permission service */ private ExtendedPermissionService extendedPermissionService; - + /** extended security service */ private ExtendedSecurityService extendedSecurityService; /** - * @param filePlanService file plan service + * @param filePlanService file plan service */ public void setFilePlanService(FilePlanService filePlanService) { @@ -138,7 +146,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl } /** - * @param authenticationUtil authentication util helper + * @param authenticationUtil authentication util helper */ public void setAuthenticationUtil(AuthenticationUtil authenticationUtil) { @@ -146,7 +154,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl } /** - * @param relationshipService relationship service + * @param relationshipService relationship service */ public void setRelationshipService(RelationshipService relationshipService) { @@ -162,7 +170,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl } /** - * @param modelSecurityService model security service + * @param modelSecurityService model security service */ public void setModelSecurityService(ModelSecurityService modelSecurityService) { @@ -176,7 +184,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl { this.cmObjectType = cmObjectType; } - + /** * @param extendedPermissionService extended permission service */ @@ -184,9 +192,9 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl { this.extendedPermissionService = extendedPermissionService; } - + /** - * @param extendedSecurityService extended security service + * @param extendedSecurityService extended security service */ public void setExtendedSecurityService(ExtendedSecurityService extendedSecurityService) { @@ -194,7 +202,21 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl } /** - * @see org.alfresco.repo.version.Version2ServiceImpl#createVersion(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, int) + * @param isEnableAutoVersionOnRecordCreation + */ + public void setEnableAutoVersionOnRecordCreation(boolean isEnableAutoVersionOnRecordCreation) + { + this.isEnableAutoVersionOnRecordCreation = isEnableAutoVersionOnRecordCreation; + } + + public boolean isEnableAutoVersionOnRecordCreation() + { + return isEnableAutoVersionOnRecordCreation; + } + + /** + * @see org.alfresco.repo.version.Version2ServiceImpl#createVersion(org.alfresco.service.cmr.repository.NodeRef, + * java.util.Map, int) */ @Override protected Version createVersion(NodeRef nodeRef, Map origVersionProperties, int versionNumber) throws ReservedVersionNameException @@ -214,7 +236,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl VersionType versionType = null; if (origVersionProperties != null) { - versionType = (VersionType)origVersionProperties.get(VersionModel.PROP_VERSION_TYPE); + versionType = (VersionType) origVersionProperties.get(VersionModel.PROP_VERSION_TYPE); } // determine whether this is a recorded version or not @@ -241,12 +263,12 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl } /** - * @param nodeRef node reference - * @return {@link NodeRef} associated file plan, default if none + * @param nodeRef node reference + * @return {@link NodeRef} associated file plan, default if none */ private NodeRef getFilePlan(NodeRef nodeRef) { - NodeRef filePlan = (NodeRef)nodeService.getProperty(nodeRef, PROP_FILE_PLAN); + NodeRef filePlan = (NodeRef) nodeService.getProperty(nodeRef, PROP_FILE_PLAN); if (filePlan == null) { filePlan = getFilePlan(); @@ -255,7 +277,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl } /** - * @return {@link NodeRef} default file plan, exception if none + * @return {@link NodeRef} default file plan, exception if none */ private NodeRef getFilePlan() { @@ -285,7 +307,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl boolean result = false; if (nodeService.hasAspect(nodeRef, RecordableVersionModel.ASPECT_VERSIONABLE)) { - String policyString = (String)nodeService.getProperty(nodeRef, PROP_RECORDABLE_VERSION_POLICY); + String policyString = (String) nodeService.getProperty(nodeRef, PROP_RECORDABLE_VERSION_POLICY); if (policyString != null) { RecordableVersionPolicy policy = RecordableVersionPolicy.valueOf(policyString.toUpperCase()); @@ -315,7 +337,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl NodeRef version = null; if (versionProperties.containsKey(KEY_RECORDABLE_VERSION) && - ((Boolean)versionProperties.get(KEY_RECORDABLE_VERSION)).booleanValue()) + ((Boolean)versionProperties.get(KEY_RECORDABLE_VERSION)).booleanValue()) { // create a recorded version version = createNewRecordedVersion(sourceTypeRef, versionHistoryRef, standardVersionProperties, versionProperties, versionNumber, nodeDetails); @@ -332,13 +354,13 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl /** * Creates a new recorded version * - * @param sourceTypeRef source type name - * @param versionHistoryRef version history reference - * @param standardVersionProperties standard version properties - * @param versionProperties version properties - * @param versionNumber version number - * @param nodeDetails policy scope - * @return {@link NodeRef} record version + * @param sourceTypeRef source type name + * @param versionHistoryRef version history reference + * @param standardVersionProperties standard version properties + * @param versionProperties version properties + * @param versionNumber version number + * @param nodeDetails policy scope + * @return {@link NodeRef} record version */ protected NodeRef createNewRecordedVersion(QName sourceTypeRef, NodeRef versionHistoryRef, @@ -365,14 +387,14 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl try { // get the destination file plan - final NodeRef filePlan = (NodeRef)versionProperties.get(KEY_FILE_PLAN); + final NodeRef filePlan = (NodeRef) versionProperties.get(KEY_FILE_PLAN); if (filePlan == null) { throw new AlfrescoRuntimeException("Can't create a new recorded version, because no file plan has been specified in the version properties."); } // create a copy of the source node and place in the file plan - final NodeRef nodeRef = (NodeRef)standardVersionProperties.get(Version2Model.PROP_QNAME_FROZEN_NODE_REF); + final NodeRef nodeRef = (NodeRef) standardVersionProperties.get(Version2Model.PROP_QNAME_FROZEN_NODE_REF); cmObjectType.disableCopy(); try @@ -418,7 +440,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl nodeService.addAspect(versionNodeRef, Version2Model.ASPECT_VERSION, standardVersionProperties); // add the recordedVersion aspect with link to record - nodeService.addAspect(versionNodeRef, ASPECT_RECORDED_VERSION, Collections.singletonMap(PROP_RECORD_NODE_REF, (Serializable)record)); + nodeService.addAspect(versionNodeRef, ASPECT_RECORDED_VERSION, Collections.singletonMap(PROP_RECORD_NODE_REF, (Serializable) record)); // freeze auditable aspect information freezeAuditableAspect(nodeRef, versionNodeRef); @@ -459,8 +481,8 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl /** * Helper method to link the record to the previous version record * - * @param nodeRef noderef source node reference - * @param record record record node reference + * @param nodeRef noderef source node reference + * @param record record record node reference */ private void linkToPreviousVersionRecord(final NodeRef nodeRef, final NodeRef record) { @@ -483,8 +505,8 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl /** * Helper to get the latest version record for a given document (ie non-record) * - * @param nodeRef node reference - * @return NodeRef latest version record, null otherwise + * @param nodeRef node reference + * @return NodeRef latest version record, null otherwise */ private NodeRef getLatestVersionRecord(NodeRef nodeRef) { @@ -498,7 +520,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl for (Version previousVersion : previousVersions) { // 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 && nodeService.exists(previousRecord)) { @@ -510,7 +532,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl return versionRecord; } - + /** * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#getRecordedVersion(org.alfresco.service.cmr.repository.NodeRef) */ @@ -563,20 +585,21 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl @Override protected Version getVersion(NodeRef 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) - { + { 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); + Boolean destroyed = (Boolean) dbNodeService.getProperty(versionRef, PROP_DESTROYED); if (destroyed == null) { destroyed = Boolean.FALSE; } version.getVersionProperties().put(PROP_RECORDED_VERSION_DESTROYED, destroyed); - + return version; } @@ -595,22 +618,22 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl dbNodeService.setProperty(nodeRef, PROP_RECORDABLE_VERSION_POLICY, versionPolicy); } } - + /** * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#isLatestVersionRecorded(org.alfresco.service.cmr.repository.NodeRef) */ @Override public boolean isCurrentVersionRecorded(NodeRef nodeRef) { - boolean result = false; + boolean result = false; Version version = getCurrentVersion(nodeRef); if (version != null) { result = isRecordedVersion(version); - } + } return result; } - + /** * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#isRecordedVersion(org.alfresco.service.cmr.version.Version) */ @@ -620,7 +643,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl 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) */ @@ -632,8 +655,8 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl if (dbNodeService.hasAspect(versionNodeRef, RecordableVersionModel.ASPECT_RECORDED_VERSION)) { // get the version record - result = (NodeRef)dbNodeService.getProperty(versionNodeRef, RecordableVersionModel.PROP_RECORD_NODE_REF); - + result = (NodeRef) dbNodeService.getProperty(versionNodeRef, RecordableVersionModel.PROP_RECORD_NODE_REF); + // check that the version record exists if (result != null && !dbNodeService.exists(result)) @@ -645,47 +668,59 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl } return result; } - + /** * Create Version Store Ref * - * @param store ref - * @return store ref for version store + * @param store ref + * @return store ref for version store */ public StoreRef convertStoreRef(StoreRef storeRef) { return new StoreRef(StoreRef.PROTOCOL_WORKSPACE, storeRef.getIdentifier()); } - + /** * Convert the incomming node ref (with the version store protocol specified) * to the internal representation with the workspace protocol. * - * @param nodeRef the incomming verison protocol node reference - * @return the internal version node reference + * @param nodeRef the incomming verison protocol node reference + * @return the internal version node reference */ public NodeRef convertNodeRef(NodeRef nodeRef) { return new NodeRef(convertStoreRef(nodeRef.getStoreRef()), nodeRef.getId()); } + /** + * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#createRecordFromLatestVersion(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, autoVersion) + */ + @Override + public NodeRef createRecordFromLatestVersion(final NodeRef filePlan, final NodeRef nodeRef, final boolean isEnableAutoVersionOnRecordCreation) + { + setEnableAutoVersionOnRecordCreation(isEnableAutoVersionOnRecordCreation); + + return createRecordFromLatestVersion(filePlan, nodeRef); + } + /** * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#createRecordFromLatestVersion(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef) */ @Override public NodeRef createRecordFromLatestVersion(final NodeRef filePlan, final NodeRef nodeRef) - { + { ParameterCheck.mandatory("filePlan", filePlan); ParameterCheck.mandatory("nodeRef", nodeRef); - + NodeRef record = null; - + // check for versionable aspect if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) { + createSnapshotVersion(nodeRef); // get the latest version final Version currentVersion = getCurrentVersion(nodeRef); - + if (currentVersion != null && !isRecordedVersion(currentVersion)) { @@ -696,19 +731,19 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl { // get the documents readers and writers Pair, Set> readersAndWriters = extendedPermissionService.getReadersAndWriters(nodeRef); - + // grab the frozen state NodeRef currentFrozenState = currentVersion.getFrozenStateNodeRef(); - + // determine the type of the object QName type = nodeService.getType(currentFrozenState); - + // grab all the properties Map properties = nodeService.getProperties(currentFrozenState); - + // grab all the aspects Set aspects = nodeService.getAspects(currentFrozenState); - + // create the record NodeRef record = recordService.createRecordFromContent( filePlan, @@ -716,14 +751,14 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl type, properties, null); - + // apply aspects to record for (QName aspect : aspects) { // add the aspect, properties have already been set nodeService.addAspect(record, aspect, null); } - + // apply version record aspect to record PropertyMap versionRecordProps = new PropertyMap(3); versionRecordProps.put(PROP_VERSIONED_NODEREF, nodeRef); @@ -733,38 +768,38 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl // wire record up to previous record linkToPreviousVersionRecord(nodeRef, record); - + // set the extended security extendedSecurityService.set(record, readersAndWriters); - + return record; } }); - + // get the version history NodeRef versionHistoryRef = getVersionHistoryNodeRef(nodeRef); - + // get details from the version before we remove it int versionNumber = getVersionNumber(currentVersion); Map versionProperties = getVersionAspectProperties(currentVersion); QName sourceTypeRef = getVersionType(currentVersion); - + // patch-up owner information, which needs to be frozen for recorded versions - String owner = (String)nodeService.getProperty(currentVersion.getFrozenStateNodeRef(), ContentModel.PROP_OWNER); + String owner = (String) nodeService.getProperty(currentVersion.getFrozenStateNodeRef(), ContentModel.PROP_OWNER); if (owner != null) { versionProperties.put(PROP_FROZEN_OWNER, owner); } - + // delete the current version this.dbNodeService.deleteNode(convertNodeRef(currentVersion.getFrozenStateNodeRef())); - + // create a new version history if we need to if (!nodeService.exists(versionHistoryRef)) { versionHistoryRef = createVersionHistory(nodeRef); } - + // create recorded version nodeRef ChildAssociationRef childAssocRef = dbNodeService.createNode( versionHistoryRef, @@ -778,34 +813,34 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl nodeService.addAspect(versionNodeRef, Version2Model.ASPECT_VERSION, versionProperties); // add the recordedVersion aspect with link to record - nodeService.addAspect(versionNodeRef, ASPECT_RECORDED_VERSION, Collections.singletonMap(PROP_RECORD_NODE_REF, (Serializable)record)); + nodeService.addAspect(versionNodeRef, ASPECT_RECORDED_VERSION, Collections.singletonMap(PROP_RECORD_NODE_REF, (Serializable) record)); } } - + return record; } - + /** - * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#isRecordedVersionDestroyed(org.alfresco.service.cmr.version.Version) + * @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); + NodeRef versionNodeRef = getVersionNodeRef(version); // get the destroyed property value - Boolean isDestroyed = (Boolean)dbNodeService.getProperty(versionNodeRef, PROP_DESTROYED); + 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) */ @@ -814,24 +849,24 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl { // 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); - } + 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. * - * @param version version - * @return int version number + * @param version version + * @return int version number */ private int getVersionNumber(Version version) { @@ -841,11 +876,11 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl String versionNumber = fullVersionNumber.substring(fullVersionNumber.indexOf("-") + 1); return Integer.parseInt(versionNumber); } - + /** * Helper method to get all the version aspect properties from an existing version * - * @param version version + * @param version version * @return Map property values */ private Map getVersionAspectProperties(Version version) @@ -857,7 +892,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl { QName propertyQName = QName.createQName(Version2Model.NAMESPACE_URI, propertyName); result.put(propertyQName, versionProps.get(propertyQName)); - + if (propertyName.equals(Version2Model.PROP_FROZEN_NODE_DBID)) { System.out.println(versionProps.get(propertyQName)); @@ -865,7 +900,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl } return result; } - + /** * Helper method to get the type of a versions frozen state * @@ -875,16 +910,57 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl private QName getVersionType(Version version) { return nodeService.getType(getVersionNodeRef(version)); - } - + } + /** * Helper method to get the internal node reference of a version * - * @param version version - * @return NodeRef internal node reference to version + * @param version version + * @return NodeRef internal node reference to version */ private NodeRef getVersionNodeRef(Version version) { - return convertNodeRef(version.getFrozenStateNodeRef()); + return convertNodeRef(version.getFrozenStateNodeRef()); + } + + /** + * Check if current version of the node is modified compared with versioned version + * + * @param nodeRef internal node reference + * @return boolean true if nodeRef is modified, otherwise false + */ + public boolean isCurrentVersionDirty(NodeRef nodeRef) + { + if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) { return false; } + + // get the latest version + Version currentVersion = getCurrentVersion(nodeRef); + Date modificationDate = (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); + + if (currentVersion == null) { return true; } + + // grab the frozen state + NodeRef currentFrozenState = currentVersion.getFrozenStateNodeRef(); + Date frozenModificationDate = (Date) nodeService.getProperty(currentFrozenState, ContentModel.PROP_MODIFIED); + + boolean versionStoreOutdated = ((frozenModificationDate != null) && (modificationDate.getTime() > frozenModificationDate.getTime())); + return versionStoreOutdated; + } + + /** + * @see RecordableVersionService#createSnapshotVersion(NodeRef) + */ + public void createSnapshotVersion(NodeRef nodeRef) + { + boolean autoVersion = isEnableAutoVersionOnRecordCreation(); + // if the flag autoversion on record creation set, create new version on dirty nodes + if (autoVersion && isCurrentVersionDirty(nodeRef)) + { + Map autoVersionProperties = new HashMap(2); + autoVersionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR); + autoVersionProperties.put(VersionModel.PROP_DESCRIPTION, I18NUtil.getMessage(AUTO_VERSION_ON_RECORD_CREATION)); + createVersion(nodeRef, autoVersionProperties); + } + } } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateDispositionScheduleTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateDispositionScheduleTest.java new file mode 100644 index 0000000000..7bcd0d47da --- /dev/null +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateDispositionScheduleTest.java @@ -0,0 +1,172 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * 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 . + * #L% + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.disposition; + +import static org.alfresco.module.org_alfresco_module_rm.test.util.bdt.BehaviourTest.test; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import com.google.common.collect.ImmutableMap; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.DestroyAction; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; +import org.alfresco.module.org_alfresco_module_rm.job.publish.DispositionActionDefinitionPublishExecutor; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils; +import org.alfresco.module.org_alfresco_module_rm.test.util.bdt.BehaviourTest; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.extensions.webscripts.GUID; + +/** + * Integration tests for updating the disposition schedule. + * + * @author Tom Page + * @since 2.3.1 + */ +public class UpdateDispositionScheduleTest extends BaseRMTestCase +{ + /** A unique prefix for the constants in this test. */ + protected static final String TEST_PREFIX = UpdateDispositionScheduleTest.class.getName() + GUID.generate() + "_"; + /** The name to use for the category. */ + protected static final String CATEGORY_NAME = TEST_PREFIX + "Category"; + /** The name to use for the folder. */ + protected static final String FOLDER_NAME = TEST_PREFIX + "Folder"; + /** The name to use for the record. */ + protected static final String RECORD_NAME = TEST_PREFIX + "Record"; + + /** The executor for the disposition update job. */ + private DispositionActionDefinitionPublishExecutor dispositionActionDefinitionPublishExecutor; + /** The internal disposition service is used to avoid permissions issues when updating the record. */ + private DispositionService internalDispositionService; + + /** The category node. */ + private NodeRef category; + /** The folder node. */ + private NodeRef folder; + /** The record node. */ + private NodeRef record; + /** The 'disposition as of' date from before the 'when' step. */ + private Date originalAsOfDate; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + BehaviourTest.initBehaviourTests(retryingTransactionHelper); + + // Get the application context + applicationContext = ApplicationContextHelper.getApplicationContext(getConfigLocations()); + dispositionActionDefinitionPublishExecutor = applicationContext.getBean(DispositionActionDefinitionPublishExecutor.class); + internalDispositionService = (DispositionService) applicationContext.getBean("dispositionService"); + } + + /** + * RM-3386 + *

+     * Given a record subject to a disposition schedule
+     * And the next step is due to run at some period after the date the content was created
+     * When I update the period of the next step (and wait for this to be processed)
+     * Then the "as of" date is updated to be at the new period after the creation date.
+     * 
+ */ + public void testUpdatePeriod() + { + test() + .given(() -> { + // Create a category. + category = filePlanService.createRecordCategory(filePlan, CATEGORY_NAME); + // Create a disposition schedule for the category (Cut off immediately, then Destroy 1 year after the creation date). + DispositionSchedule dispSched = utils.createBasicDispositionSchedule(category, "instructions", "authority", true, false); + Map cutOffParams = ImmutableMap.of(PROP_DISPOSITION_ACTION_NAME, CutOffAction.NAME, + PROP_DISPOSITION_DESCRIPTION, "description", + PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_IMMEDIATELY); + dispositionService.addDispositionActionDefinition(dispSched, cutOffParams); + Map destroyParams = ImmutableMap.of(PROP_DISPOSITION_ACTION_NAME, DestroyAction.NAME, + PROP_DISPOSITION_DESCRIPTION, "description", + PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_ONE_YEAR, + PROP_DISPOSITION_PERIOD_PROPERTY, ContentModel.PROP_CREATED); + dispositionService.addDispositionActionDefinition(dispSched, destroyParams); + // Create a folder containing a record within the category. + folder = recordFolderService.createRecordFolder(category, FOLDER_NAME); + record = fileFolderService.create(folder, RECORD_NAME, ContentModel.TYPE_CONTENT).getNodeRef(); + + dispositionService.cutoffDisposableItem(record); + // Ensure the update has been applied to the record. + internalDispositionService.updateNextDispositionAction(record); + + originalAsOfDate = dispositionService.getNextDispositionAction(record).getAsOfDate(); + }) + .when(() -> { + // Update the Destroy step to be 3 years after the creation date. + DispositionSchedule dispSched = dispositionService.getDispositionSchedule(category); + DispositionActionDefinition destroy = dispSched.getDispositionActionDefinitionByName(DestroyAction.NAME); + Map destroyParams = ImmutableMap.of(PROP_DISPOSITION_ACTION_NAME, DestroyAction.NAME, + PROP_DISPOSITION_DESCRIPTION, "description", + PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_THREE_YEARS, + PROP_DISPOSITION_PERIOD_PROPERTY, ContentModel.PROP_CREATED); + dispositionService.updateDispositionActionDefinition(destroy, destroyParams); + + // Make the disposition action definition update job run. + dispositionActionDefinitionPublishExecutor.publish(destroy.getNodeRef()); + }) + .then() + .expect(true) + .from(() -> aboutTwoYearsApart(originalAsOfDate, dispositionService.getNextDispositionAction(record).getAsOfDate())) + .because("Increasing the destroy period by two years should increase the 'as of' date by two years."); + } + + /** + * Check that the two given dates are approximately two years apart. + *

+ * This actually just checks that they're more than one and less than three years apart, because leap years make + * things hard to calculate. + * + * @return true if the two dates are about two years apart. + */ + private boolean aboutTwoYearsApart(Date start, Date end) + { + long days = daysBetween(start, end); + long yearInDays = 365; + return (yearInDays < days) && (days < 3 * yearInDays); + } + + /** Find the number of days between the two dates. */ + private long daysBetween(Date start, Date end) + { + return TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime()); + } +} diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeclareAsRecordVersionTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeclareAsRecordVersionTest.java index 596d569525..1b370b73f4 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeclareAsRecordVersionTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeclareAsRecordVersionTest.java @@ -28,20 +28,23 @@ package org.alfresco.module.org_alfresco_module_rm.test.integration.version; import java.io.Serializable; +import java.util.Date; import java.util.HashMap; import java.util.Map; +import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServiceImpl; import org.alfresco.repo.version.VersionModel; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.VersionType; +import org.alfresco.service.namespace.QName; import org.alfresco.util.GUID; /** * Declare as record version integration tests - * + * * @author Roy Wetherall * @since 2.3 */ @@ -49,7 +52,7 @@ public class DeclareAsRecordVersionTest extends RecordableVersionsBaseTest { /** recordable version service */ private RecordableVersionService recordableVersionService; - + /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#initServices() */ @@ -57,56 +60,56 @@ public class DeclareAsRecordVersionTest extends RecordableVersionsBaseTest protected void initServices() { super.initServices(); - recordableVersionService = (RecordableVersionService)applicationContext.getBean("RecordableVersionService"); + recordableVersionService = (RecordableVersionService) applicationContext.getBean("RecordableVersionService"); } - + /** - * Given versionable content with a non-recorded latest version - * When I declare a version record + * Given versionable content with a non-recorded latest version + * When I declare a version record * Then the latest version is recorded and a record is created */ public void testDeclareLatestVersionAsRecord() { doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator) - { + { private NodeRef versionRecord; - private Map versionProperties; - + private Map versionProperties; + public void given() throws Exception { // setup version properties versionProperties = new HashMap(4); versionProperties.put(Version.PROP_DESCRIPTION, DESCRIPTION); versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR); - + // create version versionService.createVersion(dmDocument, versionProperties); - + // assert that the latest version is not recorded assertFalse(recordableVersionService.isCurrentVersionRecorded(dmDocument)); } - + public void when() - { + { // create version record from latest version versionRecord = recordableVersionService.createRecordFromLatestVersion(filePlan, dmDocument); - } - + } + public void then() { // check the created record assertNotNull(versionRecord); assertTrue(recordService.isRecord(versionRecord)); - + // assert the current version is recorded assertTrue(recordableVersionService.isCurrentVersionRecorded(dmDocument)); - + // check the recorded version checkRecordedVersion(dmDocument, DESCRIPTION, "0.1"); } - }); - } - + }); + } + /** * Given versionable content with a recorded latest version * When I declare a version record @@ -116,10 +119,10 @@ public class DeclareAsRecordVersionTest extends RecordableVersionsBaseTest public void testDeclareLatestVersionAsRecordButAlreadyRecorded() { doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator) - { + { private NodeRef versionRecord; - private Map versionProperties; - + private Map versionProperties; + public void given() throws Exception { // setup version properties @@ -128,90 +131,270 @@ public class DeclareAsRecordVersionTest extends RecordableVersionsBaseTest versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR); versionProperties.put(RecordableVersionServiceImpl.KEY_RECORDABLE_VERSION, true); versionProperties.put(RecordableVersionServiceImpl.KEY_FILE_PLAN, filePlan); - + // create version versionService.createVersion(dmDocument, versionProperties); - + // assert that the latest version is not recorded assertTrue(recordableVersionService.isCurrentVersionRecorded(dmDocument)); } - + public void when() - { + { // create version record from latest version versionRecord = recordableVersionService.createRecordFromLatestVersion(filePlan, dmDocument); - } - + } + public void then() { // check that a record was not created assertNull(versionRecord); - - // assert the current version is recorded + + // assert the current version is recorded assertTrue(recordableVersionService.isCurrentVersionRecorded(dmDocument)); - + // check the recorded version checkRecordedVersion(dmDocument, DESCRIPTION, "0.1"); } - }); + }); } /** - * Given that a document is a specialized type - * When version is declared as a record - * Then the record is the same type as the source document + * Given that a document is a specialized type + * When version is declared as a record + * Then the record is the same type as the source document * * @see https://issues.alfresco.com/jira/browse/RM-2194 */ public void testSpecializedContentType() { doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator) - { + { private NodeRef customDocument; private NodeRef versionRecord; - private Map versionProperties; - + private Map versionProperties; + public void given() throws Exception { - // create content + // create content customDocument = fileFolderService.create(dmFolder, GUID.generate(), TYPE_CUSTOM_TYPE).getNodeRef(); prepareContent(customDocument); - + // setup version properties versionProperties = new HashMap(2); versionProperties.put(Version.PROP_DESCRIPTION, DESCRIPTION); versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR); - + // create version versionService.createVersion(customDocument, versionProperties); - + // assert that the latest version is not recorded assertFalse(recordableVersionService.isCurrentVersionRecorded(customDocument)); } - + public void when() - { + { // create version record from latest version versionRecord = recordableVersionService.createRecordFromLatestVersion(filePlan, customDocument); - } - + } + public void then() { // check the created record assertNotNull(versionRecord); assertTrue(recordService.isRecord(versionRecord)); - + // check the record type is correct assertEquals(TYPE_CUSTOM_TYPE, nodeService.getType(versionRecord)); - + // assert the current version is recorded assertTrue(recordableVersionService.isCurrentVersionRecorded(customDocument)); - + // check the recorded version checkRecordedVersion(customDocument, DESCRIPTION, "0.1"); } - }); - + }); + + } + + /** + * Given versionable content with a recorded latest version and autoversion is true + * When I declare this version record and contains local modifications + * Then a new minor version is created for document + * + * @see https://issues.alfresco.com/jira/browse/RM-2368 + */ + public void testCreateRecordFromLatestVersionAutoTrue() + { + doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator) + { + private NodeRef myDocument; + private NodeRef versionedRecord; + private Map versionProperties; + private Date createdDate; + private Date modificationDate; + private String record_name = "initial_name"; + private String AUTO_VERSION_DESCRIPTION = "Auto Version on Record Creation"; + private boolean autoVersion = true; + + public void given() throws Exception + { + // create a document + myDocument = fileFolderService.create(dmFolder, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef(); + createdDate = (Date) nodeService.getProperty(myDocument, ContentModel.PROP_CREATED); + modificationDate = (Date) nodeService.getProperty(myDocument, ContentModel.PROP_MODIFIED); + assertTrue("Modified date must be after or on creation date", createdDate.getTime() == modificationDate.getTime()); + + // Set initial set of properties + Map properties = new HashMap(3); + // Ensure default behaviour autoversion on change properties is set to false + properties.put(ContentModel.PROP_AUTO_VERSION_PROPS, false); + // Set initial name + properties.put(ContentModel.PROP_NAME, "initial_name"); + nodeService.setProperties(myDocument, properties); + nodeService.setProperty(myDocument, ContentModel.PROP_DESCRIPTION, DESCRIPTION); + nodeService.addAspect(myDocument, ContentModel.ASPECT_OWNABLE, null); + // make sure document is versionable + nodeService.addAspect(myDocument, ContentModel.ASPECT_VERSIONABLE, null); + // Change Type to a custom document + nodeService.setType(myDocument, TYPE_CUSTOM_TYPE); + + // setup version properties + versionProperties = new HashMap(2); + versionProperties.put(Version.PROP_DESCRIPTION, DESCRIPTION); + versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR); + + // create initial version + versionService.createVersion(myDocument, versionProperties); + } + + public void when() + { + // Apply a custom aspect + nodeService.addAspect(myDocument, ContentModel.ASPECT_TITLED, null); + // Update properties + nodeService.setProperty(myDocument, ContentModel.PROP_NAME, "updated_name"); + nodeService.setProperty(myDocument, ContentModel.PROP_DESCRIPTION, DESCRIPTION); + // test RM-2368 + versionedRecord = recordableVersionService.createRecordFromLatestVersion(filePlan, myDocument, autoVersion); + } + + public void then() + { + // Properties updated / flag as modified + // check the created record + assertNotNull(versionedRecord); + assertTrue(recordService.isRecord(versionedRecord)); + + // check the record type is correct + assertEquals(TYPE_CUSTOM_TYPE, nodeService.getType(versionedRecord)); + + // assert the current version is recorded + assertTrue(recordableVersionService.isCurrentVersionRecorded(myDocument)); + + // get name of record + record_name = (String) nodeService.getProperty(versionedRecord, ContentModel.PROP_NAME); + + // new version is create, current node was modified + assertTrue("Name was updated:", record_name.contains("updated_name")); + // check record + checkRecordedVersion(myDocument, AUTO_VERSION_DESCRIPTION, "1.1"); + + } + + }); + } + + /** + * + * Given versionable content with a recorded latest version and autoversion is false + * When I declare this version record and contains local modifications + * Then a record is created from latest version + * + * @see https://issues.alfresco.com/jira/browse/RM-2368 + */ + public void testCreateRecordFromLatestVersion() + { + doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator) + { + private NodeRef myDocument; + private NodeRef versionedRecord; + private Map versionProperties; + private Date createdDate; + private Date modificationDate; + private String record_name = "initial_name"; + private boolean autoVersion = false; + + public void given() throws Exception + { + // create a document + myDocument = fileFolderService.create(dmFolder, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef(); + createdDate = (Date) nodeService.getProperty(myDocument, ContentModel.PROP_CREATED); + modificationDate = (Date) nodeService.getProperty(myDocument, ContentModel.PROP_MODIFIED); + assertTrue("Modified date must be after or on creation date", createdDate.getTime() == modificationDate.getTime()); + + // Set initial set of properties + Map properties = new HashMap(3); + // Ensure default behaviour autoversion on change properties is set to false + properties.put(ContentModel.PROP_AUTO_VERSION_PROPS, false); + // Set initial name + properties.put(ContentModel.PROP_NAME, "initial_name"); + nodeService.setProperties(myDocument, properties); + nodeService.setProperty(myDocument, ContentModel.PROP_DESCRIPTION, DESCRIPTION); + nodeService.addAspect(myDocument, ContentModel.ASPECT_OWNABLE, null); + // make sure document is versionable + nodeService.addAspect(myDocument, ContentModel.ASPECT_VERSIONABLE, null); + // Change Type to a custom document + nodeService.setType(myDocument, TYPE_CUSTOM_TYPE); + + // setup version properties + versionProperties = new HashMap(2); + versionProperties.put(Version.PROP_DESCRIPTION, DESCRIPTION); + versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR); + + // create initial version + versionService.createVersion(myDocument, versionProperties); + } + + public void when() + { + // Apply a custom aspect + nodeService.addAspect(myDocument, ContentModel.ASPECT_TITLED, null); + // Update properties + nodeService.setProperty(myDocument, ContentModel.PROP_NAME, "initial_name"); + nodeService.setProperty(myDocument, ContentModel.PROP_DESCRIPTION, DESCRIPTION); + // test RM-2368 + versionedRecord = recordableVersionService.createRecordFromLatestVersion(filePlan, myDocument, autoVersion); + } + + public void then() + { + // Properties updated / flag as modified + // check the created record + assertNotNull(versionedRecord); + assertTrue(recordService.isRecord(versionedRecord)); + + // check the record type is correct + assertEquals(TYPE_CUSTOM_TYPE, nodeService.getType(versionedRecord)); + + // assert the current version is recorded + assertTrue(recordableVersionService.isCurrentVersionRecorded(myDocument)); + + // get name of record + record_name = (String) nodeService.getProperty(versionedRecord, ContentModel.PROP_NAME); + + // record is created based on existing frozen, which does not contain any modification of node + assertTrue("Name is not modified: ", record_name.contains("initial_name")); + checkRecordedVersion(myDocument, DESCRIPTION, "1.0"); + + } + + + }); + + } + + } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java index 53e4bb898d..df5266be21 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java @@ -66,7 +66,7 @@ import org.springframework.context.ApplicationContext; /** * Common RM test utility methods. - * + * * @author Roy Wetherall */ public class CommonRMTestUtils implements RecordsManagementModel @@ -87,10 +87,12 @@ public class CommonRMTestUtils implements RecordsManagementModel public static final String PERIOD_NONE = "none|0"; public static final String PERIOD_IMMEDIATELY = "immediately|0"; public static final String PERIOD_ONE_WEEK = "week|1"; + public static final String PERIOD_ONE_YEAR = "year|1"; + public static final String PERIOD_THREE_YEARS = "year|3"; /** * Constructor - * + * * @param applicationContext application context */ public CommonRMTestUtils(ApplicationContext applicationContext) @@ -106,7 +108,7 @@ public class CommonRMTestUtils implements RecordsManagementModel /** * Create a disposition schedule - * + * * @param container record category * @return {@link DispositionSchedule} created disposition schedule node reference */ @@ -140,15 +142,15 @@ public class CommonRMTestUtils implements RecordsManagementModel boolean extendedDispositionSchedule) { return createDispositionSchedule( - container, - dispositionInstructions, - dispositionAuthority, - isRecordLevel, - defaultDispositionActions, - extendedDispositionSchedule, + container, + dispositionInstructions, + dispositionAuthority, + isRecordLevel, + defaultDispositionActions, + extendedDispositionSchedule, DEFAULT_EVENT_NAME); } - + /** * Create test disposition schedule */ @@ -203,7 +205,7 @@ public class CommonRMTestUtils implements RecordsManagementModel /** * Helper method to create a record in a record folder. - * + * * @param recordFolder record folder * @param name name of record * @return {@link NodeRef} record node reference @@ -215,7 +217,7 @@ public class CommonRMTestUtils implements RecordsManagementModel /** * Helper method to create a record in a record folder. - * + * * @param recordFolder record folder * @param name name of the record * @param title title of the record @@ -230,7 +232,7 @@ public class CommonRMTestUtils implements RecordsManagementModel /** * Helper method to create a record in a record folder. - * + * * @param recordFolder record folder * @param name name of record * @param properties properties of the record @@ -250,10 +252,10 @@ public class CommonRMTestUtils implements RecordsManagementModel return record; } - + /** * Helper method to create a record in a record folder. - * + * * @param recordFolder record folder * @param name name of record * @param properties properties of the record @@ -273,7 +275,7 @@ public class CommonRMTestUtils implements RecordsManagementModel return record; } - + /** * Helper to consolidate creation of contentless record */ @@ -292,10 +294,10 @@ public class CommonRMTestUtils implements RecordsManagementModel ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name), ContentModel.TYPE_CONTENT, - properties).getChildRef(); - return record; + properties).getChildRef(); + return record; } - + /** * Helper method to complete record. */ @@ -309,8 +311,8 @@ public class CommonRMTestUtils implements RecordsManagementModel modelSecurityService.setEnabled(false); try { - nodeService.setProperty(record, RecordsManagementModel.PROP_DATE_FILED, new Date()); - nodeService.setProperty(record, ContentModel.PROP_TITLE, "titleValue"); + nodeService.setProperty(record, RecordsManagementModel.PROP_DATE_FILED, new Date()); + nodeService.setProperty(record, ContentModel.PROP_TITLE, "titleValue"); actionService.executeRecordsManagementAction(record, "declareRecord"); } finally @@ -323,7 +325,7 @@ public class CommonRMTestUtils implements RecordsManagementModel }, AuthenticationUtil.getAdminUserName()); - } + } public void closeFolder(final NodeRef recordFolder) { @@ -361,10 +363,10 @@ public class CommonRMTestUtils implements RecordsManagementModel return filePlanRoleService.createRole(filePlan, roleName, roleName, capabilities); } - + /** * Helper method to complete event on disposable item - * + * * @param disposableItem disposable item (record or record folder) * @param eventName event name */ @@ -373,8 +375,8 @@ public class CommonRMTestUtils implements RecordsManagementModel // build action properties Map params = new HashMap(1); params.put(CompleteEventAction.PARAM_EVENT_NAME, eventName); - + // complete event - actionService.executeRecordsManagementAction(disposableItem, CompleteEventAction.NAME, params); + actionService.executeRecordsManagementAction(disposableItem, CompleteEventAction.NAME, params); } -} +} \ No newline at end of file diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateActionUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateActionUnitTest.java new file mode 100644 index 0000000000..f83249dc51 --- /dev/null +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateActionUnitTest.java @@ -0,0 +1,103 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * 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 . + * #L% + */ + +package org.alfresco.module.org_alfresco_module_rm.action.impl; + +import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.PROP_DISPOSITION_AS_OF; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Date; + +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for {@link BroadcastDispositionActionDefinitionUpdateAction}. + * + * @author Tom Page + * @since 2.3.1 + */ +public class BroadcastDispositionActionDefinitionUpdateActionUnitTest +{ + /** The node under the category containing information about the definition of the action. */ + private static final NodeRef DISPOSITION_ACTION_DEF_NODE = new NodeRef("disposition://Action/Def"); + /** The node containing the details of the next disposition step for the content. */ + private static final NodeRef NEXT_ACTION_NODE_REF = new NodeRef("next://Step/"); + /** The node being subject to the disposition step. */ + private static final NodeRef CONTENT_NODE_REF = new NodeRef("content://Node/Ref"); + + /** The class under test. */ + private BroadcastDispositionActionDefinitionUpdateAction action = new BroadcastDispositionActionDefinitionUpdateAction(); + + private NodeService mockNodeService = mock(NodeService.class); + private DispositionService mockDispositionService = mock(DispositionService.class); + + /** Inject the mock services into the class under test and link the content and next action nodes. */ + @Before + public void setUp() + { + action.setNodeService(mockNodeService); + action.setDispositionService(mockDispositionService); + + ChildAssociationRef mockAssocRef = mock(ChildAssociationRef.class); + when(mockNodeService.getPrimaryParent(NEXT_ACTION_NODE_REF)).thenReturn(mockAssocRef); + when(mockAssocRef.getParentRef()).thenReturn(CONTENT_NODE_REF); + } + + /** + * Check that the disposition service is used to determine the "disposition as of" date when changes are made to the + * disposition period. + */ + @Test + public void testPersistPeriodChanges() + { + // Set up the data associated with the next disposition action. + DispositionAction mockAction = mock(DispositionAction.class); + when(mockAction.getNodeRef()).thenReturn(NEXT_ACTION_NODE_REF); + DispositionActionDefinition mockDispositionActionDefinition = mock(DispositionActionDefinition.class); + when(mockAction.getDispositionActionDefinition()).thenReturn(mockDispositionActionDefinition); + when(mockAction.getName()).thenReturn("mockAction"); + // Set up the disposition service to return a known "disposition as of" date. + Date asOfDate = new Date(); + when(mockDispositionService.calculateAsOfDate(CONTENT_NODE_REF, mockDispositionActionDefinition, false)) + .thenReturn(asOfDate); + + // Call the method under test. + action.persistPeriodChanges(DISPOSITION_ACTION_DEF_NODE, mockAction); + + // Check that the "disposition as of" date has been set on the next action. + verify(mockNodeService).setProperty(NEXT_ACTION_NODE_REF, PROP_DISPOSITION_AS_OF, asOfDate); + } +} diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImplUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImplUnitTest.java new file mode 100644 index 0000000000..0e9a44d001 --- /dev/null +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImplUnitTest.java @@ -0,0 +1,102 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * 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 . + * #L% + */ + +package org.alfresco.module.org_alfresco_module_rm.disposition; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Date; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.Period; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for {@link DispositionServiceImpl}. + * + * @author Tom Page + * @since 2.3.1 + */ +public class DispositionServiceImplUnitTest +{ + /** The node being subject to the disposition step. */ + NodeRef CONTENT_NODE_REF = new NodeRef("content://node/"); + + /** The class under test. */ + private DispositionServiceImpl dispositionService = new DispositionServiceImpl(); + + private NodeService mockNodeService = mock(NodeService.class); + + @Before + public void setUp() + { + dispositionService.setNodeService(mockNodeService); + } + + /** + * Check that the relevant information is retrieved from the DispositionActionDefinition in order to determine the + * "disposition as of" date. + */ + @Test + public void testCalculateAsOfDate() + { + // Set up a mock for the disposition action definition. + DispositionActionDefinition mockDispositionActionDefinition = mock(DispositionActionDefinition.class); + Period mockPeriod = mock(Period.class); + when(mockDispositionActionDefinition.getPeriod()).thenReturn(mockPeriod); + when(mockDispositionActionDefinition.getPeriodProperty()).thenReturn(ContentModel.PROP_CREATED); + // Set up a created date and another date that is some Period later. + Date createdDate = new Date(1234567890); + when(mockNodeService.getProperty(CONTENT_NODE_REF, ContentModel.PROP_CREATED)).thenReturn(createdDate); + Date nextDate = new Date(1240000000); + when(mockPeriod.getNextDate(createdDate)).thenReturn(nextDate); + + // Call the method under test. + Date asOfDate = dispositionService.calculateAsOfDate(CONTENT_NODE_REF, mockDispositionActionDefinition, true); + + assertEquals("Unexpected calculation for 'as of' date", nextDate, asOfDate); + } + + /** Check that the calculated "disposition as of" date is null if a null period is given. */ + @Test + public void testCalculateAsOfDate_nullPeriod() + { + DispositionActionDefinition mockDispositionActionDefinition = mock(DispositionActionDefinition.class); + when(mockDispositionActionDefinition.getPeriod()).thenReturn(null); + + // Call the method under test. + Date asOfDate = dispositionService.calculateAsOfDate(CONTENT_NODE_REF, mockDispositionActionDefinition, true); + + assertNull("It should not be possible to determine the 'as of' date.", asOfDate); + } +} diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseWebScriptUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseWebScriptUnitTest.java index 3f3105f9b8..7ca4481384 100644 --- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseWebScriptUnitTest.java +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseWebScriptUnitTest.java @@ -46,7 +46,7 @@ import org.json.JSONObject; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.extensions.surf.util.Content; -import org.springframework.extensions.webscripts.AbstractWebScript; +import org.springframework.extensions.webscripts.AbstractWebScript; import org.springframework.extensions.webscripts.Container; import org.springframework.extensions.webscripts.Description; import org.springframework.extensions.webscripts.Description.RequiredCache; @@ -83,7 +83,7 @@ public abstract class BaseWebScriptUnitTest extends BaseUnitTest /** * @return declarative webscript */ - protected abstract AbstractWebScript getWebScript(); + protected abstract AbstractWebScript getWebScript(); /** * @return classpath location of webscript template @@ -151,7 +151,7 @@ public abstract class BaseWebScriptUnitTest extends BaseUnitTest */ protected String executeWebScript(Map parameters, String content) throws Exception { - AbstractWebScript webScript = getWebScript(); + AbstractWebScript webScript = getWebScript(); String template = getWebScriptTemplate(); // initialise webscript @@ -173,7 +173,7 @@ public abstract class BaseWebScriptUnitTest extends BaseUnitTest * @return {@link WebScriptRequest} mocked web script request */ @SuppressWarnings("rawtypes") - protected WebScriptRequest getMockedWebScriptRequest(AbstractWebScript webScript, final Map parameters, String content) throws Exception + protected WebScriptRequest getMockedWebScriptRequest(AbstractWebScript webScript, final Map parameters, String content) throws Exception { Match match = new Match(null, parameters, null, webScript); org.springframework.extensions.webscripts.Runtime mockedRuntime = mock(org.springframework.extensions.webscripts.Runtime.class); diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/repo/web/scripts/roles/DynamicAuthoritiesGetUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/repo/web/scripts/roles/DynamicAuthoritiesGetUnitTest.java index 4f903a2b75..3c9043e096 100644 --- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/repo/web/scripts/roles/DynamicAuthoritiesGetUnitTest.java +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/repo/web/scripts/roles/DynamicAuthoritiesGetUnitTest.java @@ -24,24 +24,6 @@ * along with Alfresco. If not, see . * #L% */ -/* - * 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.repo.web.scripts.roles; @@ -49,14 +31,14 @@ import static java.util.Collections.emptyMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -64,7 +46,7 @@ import static org.mockito.Mockito.when; import java.io.File; import java.io.Serializable; -import java.util.ArrayList; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -87,9 +69,9 @@ import org.alfresco.repo.domain.patch.PatchDAO; import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.repo.web.scripts.content.ContentStreamer; -import org.alfresco.service.cmr.model.FileFolderService; -import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.repo.web.scripts.content.ContentStreamer; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PermissionService; @@ -105,11 +87,11 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import org.springframework.extensions.webscripts.AbstractWebScript; -import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.AbstractWebScript; +import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; +import org.springframework.extensions.webscripts.WebScriptResponse; /** * DynamicAuthoritiesGet Unit Test @@ -140,17 +122,17 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme private TransactionService mockedTransactionService; @Mock private RetryingTransactionHelper mockedRetryingTransactionHelper; - @Mock - private ContentStreamer contentStreamer; - @Mock - private FileFolderService mockedFileFolderService; + @Mock + private ContentStreamer contentStreamer; + @Mock + private FileFolderService mockedFileFolderService; /** test component */ @InjectMocks private DynamicAuthoritiesGet webScript; @Override - protected AbstractWebScript getWebScript() + protected AbstractWebScript getWebScript() { return webScript; } @@ -172,7 +154,7 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme webScript.setNodeService(mockedNodeService); webScript.setPermissionService(mockedPermissionService); webScript.setExtendedSecurityService(mockedExtendedSecurityService); - webScript.setFileFolderService(mockedFileFolderService); + webScript.setFileFolderService(mockedFileFolderService); // setup retrying transaction helper Answer doInTransactionAnswer = new Answer() { @@ -200,7 +182,7 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme /** * Given that there are no nodes with the extended security aspect * When the action is executed Nothing happens - * + * * @throws Exception */ @SuppressWarnings({ "unchecked" }) @@ -237,7 +219,7 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme * Then the aspect is removed * And the dynamic authorities permissions are cleared * And extended security is set via the updated API - * + * * @throws Exception */ @SuppressWarnings("unchecked") @@ -246,7 +228,7 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme { List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); - when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) + when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) .thenReturn(Collections.emptyList()); ids.stream().forEach((i) -> { @@ -282,8 +264,8 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme /** * Given that there are non-records with the extended security aspect * When the web script is executed - * Then the aspect is removed And the dynamic authorities permissions are cleared - * + * Then the aspect is removed And the dynamic authorities permissions are cleared + * * @throws Exception */ @SuppressWarnings("unchecked") @@ -292,7 +274,7 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme { List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); - when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) + when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) .thenReturn(Collections.emptyList()); ids.stream().forEach((i) -> { @@ -328,50 +310,50 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme @Test public void missingBatchSizeParameter() throws Exception { - try - { - executeJSONWebScript(emptyMap()); - fail("Expected exception as parameter batchsize is mandatory."); - } - catch (WebScriptException e) - { - assertEquals("If parameter batchsize is not provided then 'Bad request' should be returned.", - Status.STATUS_BAD_REQUEST, e.getStatus()); - } + try + { + executeJSONWebScript(emptyMap()); + fail("Expected exception as parameter batchsize is mandatory."); + } + catch (WebScriptException e) + { + assertEquals("If parameter batchsize is not provided then 'Bad request' should be returned.", + Status.STATUS_BAD_REQUEST, e.getStatus()); + } } @Test public void invalidBatchSizeParameter() throws Exception { - try - { + try + { // Set up parameters. Map parameters = ImmutableMap.of("batchsize", "dd"); - executeJSONWebScript(parameters); - fail("Expected exception as parameter batchsize is invalid."); - } - catch (WebScriptException e) - { - assertEquals("If parameter batchsize is invalid then 'Bad request' should be returned.", - Status.STATUS_BAD_REQUEST, e.getStatus()); - } + executeJSONWebScript(parameters); + fail("Expected exception as parameter batchsize is invalid."); + } + catch (WebScriptException e) + { + assertEquals("If parameter batchsize is invalid then 'Bad request' should be returned.", + Status.STATUS_BAD_REQUEST, e.getStatus()); + } } @Test public void batchSizeShouldBeGraterThanZero() throws Exception { - try - { + try + { // Set up parameters. Map parameters = ImmutableMap.of("batchsize", "0"); - executeJSONWebScript(parameters); - fail("Expected exception as parameter batchsize is not a number greater than 0."); - } - catch (WebScriptException e) - { - assertEquals("If parameter batchsize is not a number greater than 0 then 'Bad request' should be returned.", - Status.STATUS_BAD_REQUEST, e.getStatus()); - } + executeJSONWebScript(parameters); + fail("Expected exception as parameter batchsize is not a number greater than 0."); + } + catch (WebScriptException e) + { + assertEquals("If parameter batchsize is not a number greater than 0 then 'Bad request' should be returned.", + Status.STATUS_BAD_REQUEST, e.getStatus()); + } } @Test @@ -393,7 +375,7 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme { List ids = Stream.of(1l, 2l, 3l,4l).collect(Collectors.toList()); - when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) + when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) .thenReturn(Collections.emptyList()); ids.stream().forEach((i) -> { @@ -421,7 +403,7 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme { List ids = Stream.of(1l, 2l, 3l, 4l, 5l).collect(Collectors.toList()); - when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) + when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) .thenReturn(Collections.emptyList()); ids.stream().forEach((i) -> { @@ -443,302 +425,302 @@ public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest impleme String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed first 4 records.\"}"; assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Test - public void recordsWithExtendedSecurityAspectAndNullWritersAndReaders() throws Exception - { - List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); - - when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) - .thenReturn(Collections.emptyList()); - - ids.stream().forEach((i) -> { - NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); - when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair(i, nodeRef)); - when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); - when(mockedNodeService.getProperty(nodeRef, PROP_READERS)).thenReturn(null); - when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)).thenReturn(null); - - }); - - // Set up parameters. - Map parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4"); - JSONObject json = executeJSONWebScript(parameters); - assertNotNull(json); - String actualJSONString = json.toString(); - ObjectMapper mapper = new ObjectMapper(); - String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}"; - assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); - ArgumentCaptor readerKeysCaptor = ArgumentCaptor.forClass(Set.class); - ArgumentCaptor writersKeysCaptor = ArgumentCaptor.forClass(Set.class); - - verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_READERS)); - verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_WRITERS)); - verify(mockedNodeService, times(3)).removeAspect(any(NodeRef.class), eq(ASPECT_EXTENDED_SECURITY)); - verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class), - eq(ExtendedReaderDynamicAuthority.EXTENDED_READER)); - verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class), - eq(ExtendedWriterDynamicAuthority.EXTENDED_WRITER)); - verify(mockedExtendedSecurityService, times(3)).set(any(NodeRef.class), readerKeysCaptor.capture(), - writersKeysCaptor.capture()); - List allReaderKeySets = readerKeysCaptor.getAllValues(); - List allWritersKeySets = writersKeysCaptor.getAllValues(); - for (Set keySet : allReaderKeySets) - { - assertNull(keySet); - } - for (Set keySet : allWritersKeySets) - { - assertNull(keySet); - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Test - public void recordsWithExtendedSecurityAspectAndNullWriters() throws Exception - { - List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); - - when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) - .thenReturn(Collections.emptyList()); - - ids.stream().forEach((i) -> { - NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); - when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair(i, nodeRef)); - when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); - when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) - .thenReturn((Serializable) Collections.emptyMap()); - when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)).thenReturn(null); - - }); - - // Set up parameters. - Map parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4"); - JSONObject json = executeJSONWebScript(parameters); - assertNotNull(json); - String actualJSONString = json.toString(); - ObjectMapper mapper = new ObjectMapper(); - String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}"; - assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); - ArgumentCaptor readerKeysCaptor = ArgumentCaptor.forClass(Set.class); - ArgumentCaptor writersKeysCaptor = ArgumentCaptor.forClass(Set.class); - - verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_READERS)); - verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_WRITERS)); - verify(mockedNodeService, times(3)).removeAspect(any(NodeRef.class), eq(ASPECT_EXTENDED_SECURITY)); - verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class), - eq(ExtendedReaderDynamicAuthority.EXTENDED_READER)); - verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class), - eq(ExtendedWriterDynamicAuthority.EXTENDED_WRITER)); - verify(mockedExtendedSecurityService, times(3)).set(any(NodeRef.class), readerKeysCaptor.capture(), - writersKeysCaptor.capture()); - List allReaderKeySets = readerKeysCaptor.getAllValues(); - List allWritersKeySets = writersKeysCaptor.getAllValues(); - for (Set keySet : allReaderKeySets) - { - assertNotNull(keySet); - } - for (Set keySet : allWritersKeySets) - { - assertNull(keySet); - } - } - - /** + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void recordsWithExtendedSecurityAspectAndNullWritersAndReaders() throws Exception + { + List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); + + when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) + .thenReturn(Collections.emptyList()); + + ids.stream().forEach((i) -> { + NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); + when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair(i, nodeRef)); + when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); + when(mockedNodeService.getProperty(nodeRef, PROP_READERS)).thenReturn(null); + when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)).thenReturn(null); + + }); + + // Set up parameters. + Map parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4"); + JSONObject json = executeJSONWebScript(parameters); + assertNotNull(json); + String actualJSONString = json.toString(); + ObjectMapper mapper = new ObjectMapper(); + String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}"; + assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); + ArgumentCaptor readerKeysCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor writersKeysCaptor = ArgumentCaptor.forClass(Set.class); + + verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_READERS)); + verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_WRITERS)); + verify(mockedNodeService, times(3)).removeAspect(any(NodeRef.class), eq(ASPECT_EXTENDED_SECURITY)); + verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class), + eq(ExtendedReaderDynamicAuthority.EXTENDED_READER)); + verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class), + eq(ExtendedWriterDynamicAuthority.EXTENDED_WRITER)); + verify(mockedExtendedSecurityService, times(3)).set(any(NodeRef.class), readerKeysCaptor.capture(), + writersKeysCaptor.capture()); + List allReaderKeySets = readerKeysCaptor.getAllValues(); + List allWritersKeySets = writersKeysCaptor.getAllValues(); + for (Set keySet : allReaderKeySets) + { + assertNull(keySet); + } + for (Set keySet : allWritersKeySets) + { + assertNull(keySet); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void recordsWithExtendedSecurityAspectAndNullWriters() throws Exception + { + List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); + + when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) + .thenReturn(Collections.emptyList()); + + ids.stream().forEach((i) -> { + NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); + when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair(i, nodeRef)); + when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); + when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) + .thenReturn((Serializable) Collections.emptyMap()); + when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)).thenReturn(null); + + }); + + // Set up parameters. + Map parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4"); + JSONObject json = executeJSONWebScript(parameters); + assertNotNull(json); + String actualJSONString = json.toString(); + ObjectMapper mapper = new ObjectMapper(); + String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}"; + assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); + ArgumentCaptor readerKeysCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor writersKeysCaptor = ArgumentCaptor.forClass(Set.class); + + verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_READERS)); + verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_WRITERS)); + verify(mockedNodeService, times(3)).removeAspect(any(NodeRef.class), eq(ASPECT_EXTENDED_SECURITY)); + verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class), + eq(ExtendedReaderDynamicAuthority.EXTENDED_READER)); + verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class), + eq(ExtendedWriterDynamicAuthority.EXTENDED_WRITER)); + verify(mockedExtendedSecurityService, times(3)).set(any(NodeRef.class), readerKeysCaptor.capture(), + writersKeysCaptor.capture()); + List allReaderKeySets = readerKeysCaptor.getAllValues(); + List allWritersKeySets = writersKeysCaptor.getAllValues(); + for (Set keySet : allReaderKeySets) + { + assertNotNull(keySet); + } + for (Set keySet : allWritersKeySets) + { + assertNull(keySet); + } + } + + /** * Given I have records that require migration * And I am interested in knowning which records are migrated * When I run the migration tool - * Then I will be returned a CSV file containing the name and node reference of the record migrated - * - * @throws Exception - */ - @SuppressWarnings("unchecked") - @Test - public void processWithCSVFile() throws Exception - { - List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); - when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) - .thenReturn(Collections.emptyList()); - - ids.stream().forEach((i) -> { - NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); - when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair(i, nodeRef)); - when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); - when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) - .thenReturn((Serializable) Collections.emptyMap()); - when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)) - .thenReturn((Serializable) Collections.emptyMap()); - String name = "name" + i; - when(mockedNodeService.getProperty(nodeRef, ContentModel.PROP_NAME)).thenReturn((Serializable) name); - }); - - ArgumentCaptor csvFileCaptor = ArgumentCaptor.forClass(File.class); - // Set up parameters. - Map parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4", "export", - "true"); - executeWebScript(parameters); - - verify(contentStreamer, times(1)).streamContent(any(WebScriptRequest.class), any(WebScriptResponse.class), - csvFileCaptor.capture(), any(Long.class), any(Boolean.class), any(String.class), any(Map.class)); - - File fileForDownload = csvFileCaptor.getValue(); - assertNotNull(fileForDownload); - } - - /** + * Then I will be returned a CSV file containing the name and node reference of the record migrated + * + * @throws Exception + */ + @SuppressWarnings("unchecked") + @Test + public void processWithCSVFile() throws Exception + { + List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); + when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) + .thenReturn(Collections.emptyList()); + + ids.stream().forEach((i) -> { + NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); + when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair(i, nodeRef)); + when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); + when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) + .thenReturn((Serializable) Collections.emptyMap()); + when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)) + .thenReturn((Serializable) Collections.emptyMap()); + String name = "name" + i; + when(mockedNodeService.getProperty(nodeRef, ContentModel.PROP_NAME)).thenReturn((Serializable) name); + }); + + ArgumentCaptor csvFileCaptor = ArgumentCaptor.forClass(File.class); + // Set up parameters. + Map parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4", "export", + "true"); + executeWebScript(parameters); + + verify(contentStreamer, times(1)).streamContent(any(WebScriptRequest.class), any(WebScriptResponse.class), + csvFileCaptor.capture(), any(Long.class), any(Boolean.class), any(String.class), any(Map.class)); + + File fileForDownload = csvFileCaptor.getValue(); + assertNotNull(fileForDownload); + } + + /** * Given that I have record that require migration - * And I'm not interested in knowing which records were migrated + * And I'm not interested in knowing which records were migrated * When I run the migration tool - * Then I will not be returned a CSV file of details. - * - * @throws Exception - */ - @SuppressWarnings("unchecked") - @Test - public void processedWithouthCSVFile() throws Exception - { - List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); - when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) - .thenReturn(Collections.emptyList()); - - ids.stream().forEach((i) -> { - NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); - when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair(i, nodeRef)); - when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); - when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) - .thenReturn((Serializable) Collections.emptyMap()); - when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)) - .thenReturn((Serializable) Collections.emptyMap()); - }); - - Map parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4", "export", - "false"); - JSONObject json = executeJSONWebScript(parameters); - assertNotNull(json); - String actualJSONString = json.toString(); - ObjectMapper mapper = new ObjectMapper(); - String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}"; - assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); - - verify(contentStreamer, never()).streamContent(any(WebScriptRequest.class), any(WebScriptResponse.class), - any(File.class), any(Long.class), any(Boolean.class), any(String.class), any(Map.class)); - } - - @Test - public void invalidParentNodeRefParameter() throws Exception - { - try - { - // Set up parameters. - Map parameters = ImmutableMap.of("batchsize", "10", "parentNodeRef", "invalidNodeRef"); - executeJSONWebScript(parameters); - fail("Expected exception as parameter parentNodeRef is invalid."); - } - catch (WebScriptException e) - { - assertEquals("If parameter parentNodeRef is invalid then 'Internal server error' should be returned.", - Status.STATUS_INTERNAL_SERVER_ERROR, e.getStatus()); - } - } - - @Test - public void inexistentParentNodeRefParameter() throws Exception - { - try - { - NodeRef parentNodeRef = AlfMock.generateNodeRef(mockedNodeService); - when(mockedNodeService.exists(parentNodeRef)).thenReturn(false); - // Set up parameters. - Map parameters = ImmutableMap.of("batchsize", "10", "parentNodeRef", - parentNodeRef.toString()); - executeJSONWebScript(parameters); - fail("Expected exception as parameter parentNodeRef does not exist."); - } - catch (WebScriptException e) - { - assertEquals("If parameter parentNodeRef is does not exist then 'Bad Reequest' should be returned.", - Status.STATUS_BAD_REQUEST, e.getStatus()); - } - } - - @SuppressWarnings("unchecked") - @Test - public void processedWithParentNodeRef() throws Exception - { - List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); - NodeRef parentNodeRef = AlfMock.generateNodeRef(mockedNodeService); - List children = new ArrayList(); - ids.stream().forEach((i) -> { - NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); - when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); - when(mockedNodeService.hasAspect(nodeRef, ASPECT)).thenReturn(true); - when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) - .thenReturn((Serializable) Collections.emptyMap()); - when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)) - .thenReturn((Serializable) Collections.emptyMap()); - String name = "name" + i; - when(mockedNodeService.getProperty(nodeRef, ContentModel.PROP_NAME)).thenReturn((Serializable) name); - FileInfo mockedFileInfo = mock(FileInfo.class); - when(mockedFileInfo.getNodeRef()).thenReturn(nodeRef); - children.add(mockedFileInfo); - }); - when(mockedFileFolderService.search(eq(parentNodeRef), eq("*"), eq(true), eq(true), eq(true))) - .thenReturn(children); - - Map parameters = ImmutableMap.of("batchsize", "3", "maxProcessedRecords", "4", "export", - "false", "parentNodeRef", parentNodeRef.toString()); - JSONObject json = executeJSONWebScript(parameters); - assertNotNull(json); - String actualJSONString = json.toString(); - ObjectMapper mapper = new ObjectMapper(); - String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}"; - assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); - - verify(contentStreamer, never()).streamContent(any(WebScriptRequest.class), any(WebScriptResponse.class), - any(File.class), any(Long.class), any(Boolean.class), any(String.class), any(Map.class)); - } - - @SuppressWarnings("unchecked") - @Test - public void processedWithParentNodeRefWithFirstTwoBatchesAlreadyProcessed() throws Exception - { - List ids = Stream.of(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l).collect(Collectors.toList()); - NodeRef parentNodeRef = AlfMock.generateNodeRef(mockedNodeService); - List children = new ArrayList(); - ids.stream().forEach((i) -> { - NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); - when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); - if (i <= 6l) - { - when(mockedNodeService.hasAspect(nodeRef, ASPECT)).thenReturn(false); - } - else - { - when(mockedNodeService.hasAspect(nodeRef, ASPECT)).thenReturn(true); - } - when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) - .thenReturn((Serializable) Collections.emptyMap()); - when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)) - .thenReturn((Serializable) Collections.emptyMap()); - String name = "name" + i; - when(mockedNodeService.getProperty(nodeRef, ContentModel.PROP_NAME)).thenReturn((Serializable) name); - FileInfo mockedFileInfo = mock(FileInfo.class); - when(mockedFileInfo.getNodeRef()).thenReturn(nodeRef); - children.add(mockedFileInfo); - }); - when(mockedFileFolderService.search(eq(parentNodeRef), eq("*"), eq(true), eq(true), eq(true))) - .thenReturn(children); - - Map parameters = ImmutableMap.of("batchsize", "3", "parentNodeRef", parentNodeRef.toString()); - JSONObject json = executeJSONWebScript(parameters); - assertNotNull(json); - String actualJSONString = json.toString(); - ObjectMapper mapper = new ObjectMapper(); - String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 2 records.\"}"; - assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); - - verify(contentStreamer, never()).streamContent(any(WebScriptRequest.class), any(WebScriptResponse.class), - any(File.class), any(Long.class), any(Boolean.class), any(String.class), any(Map.class)); - } + * Then I will not be returned a CSV file of details. + * + * @throws Exception + */ + @SuppressWarnings("unchecked") + @Test + public void processedWithouthCSVFile() throws Exception + { + List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); + when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong())).thenReturn(ids) + .thenReturn(Collections.emptyList()); + + ids.stream().forEach((i) -> { + NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); + when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair(i, nodeRef)); + when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); + when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) + .thenReturn((Serializable) Collections.emptyMap()); + when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)) + .thenReturn((Serializable) Collections.emptyMap()); + }); + + Map parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4", "export", + "false"); + JSONObject json = executeJSONWebScript(parameters); + assertNotNull(json); + String actualJSONString = json.toString(); + ObjectMapper mapper = new ObjectMapper(); + String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}"; + assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); + + verify(contentStreamer, never()).streamContent(any(WebScriptRequest.class), any(WebScriptResponse.class), + any(File.class), any(Long.class), any(Boolean.class), any(String.class), any(Map.class)); + } + + @Test + public void invalidParentNodeRefParameter() throws Exception + { + try + { + // Set up parameters. + Map parameters = ImmutableMap.of("batchsize", "10", "parentNodeRef", "invalidNodeRef"); + executeJSONWebScript(parameters); + fail("Expected exception as parameter parentNodeRef is invalid."); + } + catch (WebScriptException e) + { + assertEquals("If parameter parentNodeRef is invalid then 'Internal server error' should be returned.", + Status.STATUS_INTERNAL_SERVER_ERROR, e.getStatus()); + } + } + + @Test + public void inexistentParentNodeRefParameter() throws Exception + { + try + { + NodeRef parentNodeRef = AlfMock.generateNodeRef(mockedNodeService); + when(mockedNodeService.exists(parentNodeRef)).thenReturn(false); + // Set up parameters. + Map parameters = ImmutableMap.of("batchsize", "10", "parentNodeRef", + parentNodeRef.toString()); + executeJSONWebScript(parameters); + fail("Expected exception as parameter parentNodeRef does not exist."); + } + catch (WebScriptException e) + { + assertEquals("If parameter parentNodeRef is does not exist then 'Bad Reequest' should be returned.", + Status.STATUS_BAD_REQUEST, e.getStatus()); + } + } + + @SuppressWarnings("unchecked") + @Test + public void processedWithParentNodeRef() throws Exception + { + List ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList()); + NodeRef parentNodeRef = AlfMock.generateNodeRef(mockedNodeService); + List children = new ArrayList(); + ids.stream().forEach((i) -> { + NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); + when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); + when(mockedNodeService.hasAspect(nodeRef, ASPECT)).thenReturn(true); + when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) + .thenReturn((Serializable) Collections.emptyMap()); + when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)) + .thenReturn((Serializable) Collections.emptyMap()); + String name = "name" + i; + when(mockedNodeService.getProperty(nodeRef, ContentModel.PROP_NAME)).thenReturn((Serializable) name); + FileInfo mockedFileInfo = mock(FileInfo.class); + when(mockedFileInfo.getNodeRef()).thenReturn(nodeRef); + children.add(mockedFileInfo); + }); + when(mockedFileFolderService.search(eq(parentNodeRef), eq("*"), eq(true), eq(true), eq(true))) + .thenReturn(children); + + Map parameters = ImmutableMap.of("batchsize", "3", "maxProcessedRecords", "4", "export", + "false", "parentNodeRef", parentNodeRef.toString()); + JSONObject json = executeJSONWebScript(parameters); + assertNotNull(json); + String actualJSONString = json.toString(); + ObjectMapper mapper = new ObjectMapper(); + String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}"; + assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); + + verify(contentStreamer, never()).streamContent(any(WebScriptRequest.class), any(WebScriptResponse.class), + any(File.class), any(Long.class), any(Boolean.class), any(String.class), any(Map.class)); + } + + @SuppressWarnings("unchecked") + @Test + public void processedWithParentNodeRefWithFirstTwoBatchesAlreadyProcessed() throws Exception + { + List ids = Stream.of(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l).collect(Collectors.toList()); + NodeRef parentNodeRef = AlfMock.generateNodeRef(mockedNodeService); + List children = new ArrayList(); + ids.stream().forEach((i) -> { + NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService); + when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true); + if (i <= 6l) + { + when(mockedNodeService.hasAspect(nodeRef, ASPECT)).thenReturn(false); + } + else + { + when(mockedNodeService.hasAspect(nodeRef, ASPECT)).thenReturn(true); + } + when(mockedNodeService.getProperty(nodeRef, PROP_READERS)) + .thenReturn((Serializable) Collections.emptyMap()); + when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS)) + .thenReturn((Serializable) Collections.emptyMap()); + String name = "name" + i; + when(mockedNodeService.getProperty(nodeRef, ContentModel.PROP_NAME)).thenReturn((Serializable) name); + FileInfo mockedFileInfo = mock(FileInfo.class); + when(mockedFileInfo.getNodeRef()).thenReturn(nodeRef); + children.add(mockedFileInfo); + }); + when(mockedFileFolderService.search(eq(parentNodeRef), eq("*"), eq(true), eq(true), eq(true))) + .thenReturn(children); + + Map parameters = ImmutableMap.of("batchsize", "3", "parentNodeRef", parentNodeRef.toString()); + JSONObject json = executeJSONWebScript(parameters); + assertNotNull(json); + String actualJSONString = json.toString(); + ObjectMapper mapper = new ObjectMapper(); + String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 2 records.\"}"; + assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString)); + + verify(contentStreamer, never()).streamContent(any(WebScriptRequest.class), any(WebScriptResponse.class), + any(File.class), any(Long.class), any(Boolean.class), any(String.class), any(Map.class)); + } } \ No newline at end of file