From a7f6ae427e5ad3298266c222cf8d2b285beb46ee Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Fri, 19 May 2017 14:45:02 +0100 Subject: [PATCH 01/18] RM-4431 Complete Record Action REST API --- .../api/records/RecordsEntityResource.java | 80 +++++++++++++++++++ .../main/webapp/definitions/gs-core-api.yaml | 45 ++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java index 4aef34e7d0..f7b3b5ee25 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java @@ -30,6 +30,13 @@ package org.alfresco.rm.rest.api.records; import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank; import static org.alfresco.util.ParameterCheck.mandatory; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.repo.activities.ActivityType; @@ -57,6 +64,7 @@ import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ParameterCheck; import org.springframework.beans.factory.InitializingBean; @@ -230,6 +238,78 @@ public class RecordsEntityResource implements BinaryResourceAction.Read, return nodesModelFactory.createRecord(info, parameters, null, false); } + @Operation ("complete") + @WebApiDescription (title = "Complete record", description = "Complete a record.") + public Record completeRecord(String recordId, Void body, Parameters parameters) + { + checkNotBlank("recordId", recordId); + mandatory("parameters", parameters); + + // Get record + NodeRef record = apiUtils.validateRecord(recordId); + + // Complete the record + //TODO this should probably be something like recordService.complete(record); + completeRecord(record); + + // return record state + FileInfo info = fileFolderService.getFileInfo(record); + return nodesModelFactory.createRecord(info, parameters, null, false); + } + + /* Temporary helper method just to do the complete record action. + Should probably live elsewhere, maybe RecordsImpl + */ + private void completeRecord(NodeRef record) { + boolean checkMandatoryPropertiesEnabled = true; + + if (! recordService.isDeclared(record)) + { + List missingProperties = new ArrayList<>(5); + if (checkMandatoryPropertiesEnabled && mandatoryPropertiesSet(record, missingProperties)) + { + //TODO error here; + } + else + { + recordService.disablePropertyEditableCheck(); + //try + //{ + // Add the declared aspect + Map declaredProps = new HashMap<>(2); + declaredProps.put(RecordsManagementModel.PROP_DECLARED_AT, new Date()); + //TODO declaredProps.put(RecordsManagementModel.PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); + nodeService.addAspect(record, RecordsManagementModel.ASPECT_DECLARED_RECORD, declaredProps); + + /* TODO + AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() + { + // remove all owner related rights + getOwnableService().setOwner(record, OwnableService.NO_OWNER); + return null; + } + }); + */ + //} finally + //{ + // recordService.enablePropertyEditableCheck(); + //} + } + } + } + + /* TODO + * this is temporary partly because there is an error in the original code + */ + private boolean mandatoryPropertiesSet(NodeRef nodeRef, List missingProperties) { + + return true; + } + + @Override @WebApiDescription(title = "Delete record", description="Deletes a record with id 'recordId'") public void delete(String recordId, Parameters parameters) diff --git a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml index 1fc288cfda..0bd0b05d9c 100644 --- a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml +++ b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml @@ -1677,9 +1677,9 @@ paths: description: | Invalid parameter: the update request is invalid or **recordId** is not a valid format or **recordBodyUpdate** is invalid '401': - description: If authentication fails + description: If authentication '403': - description: If current user does not have permission to update **recordId** + description: If current user does not have permission to update **recordId**fails '404': description: If **recordId** does not exist '409': @@ -1800,6 +1800,47 @@ paths: description: Unexpected error schema: $ref: '#/definitions/Error' + '/records/{recordId}/complete': + put: + tags: + - records + summary: Complete a record + description: | + Completes the record **recordId**. + operationId: completeRecord + parameters: + - $ref: '#/parameters/recordIdParam' + - $ref: '#/parameters/recordEntryIncludeParam' + - $ref: '#/parameters/fieldsParam' + consumes: + - application/json + produces: + - application/json + responses: + '200': + description: Successful response + schema: + $ref: '#/definitions/RecordEntry' + '400': + description: | + Invalid parameter: **recordIdParam** is not a valid format or + **recordIdParam** is not a record + '401': + description: Authentication failed + '403': + description: >- + Current user does not have permission to complete record + **recordIdParam** + '404': + description: | + **recordIdParam** does not exist + '409': + description: | + **recordIdParam** is already completed + default: + description: Unexpected error + schema: + $ref: '#/definitions/Error' ## Files '/files/{fileId}/declare': post: From 8665ddafb97ace847e39efc89e92c9bba5561388 Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Thu, 1 Jun 2017 14:08:16 +0100 Subject: [PATCH 02/18] RM-4431 CompleteRecordActionRestAPI --- .../requests/gscore/api/RecordsAPI.java | 26 ++ .../records/CompleteRecordTests.java | 338 ++++++++++++++++++ .../record/RecordService.java | 15 + .../record/RecordServiceImpl.java | 90 +++++ .../api/records/RecordsEntityResource.java | 93 ++--- .../main/webapp/definitions/gs-core-api.yaml | 6 +- 6 files changed, 509 insertions(+), 59 deletions(-) create mode 100644 rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java index ab403834f6..27e7faf5c6 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java @@ -139,6 +139,32 @@ public class RecordsAPI extends RMModelRequest )); } + /** + * Complete the record recordId + * + * @param recordId The id of the record to complete + * @return The {@link Record} with the given properties + * @throws Exception for the following cases: + *
    + *
  • Invalid parameter: {@code recordBodyFile} is not a valid format,{@code recordId} is not a record
  • + *
  • authentication fails
  • + *
  • current user does not have permission to file to {@code fileplanComponentId}
  • + *
  • {@code recordId} does not exist
  • + *
  • model integrity exception: the record is already complete
  • + *
  • model integrity exception: the record has missing meta-data
  • + *
+ */ + public Record completeRecord(String recordId, String parameters) throws Exception + { + mandatoryString("recordId", recordId); + + return getRmRestWrapper().processModel(Record.class, simpleRequest( + POST, + "/records/{recordId}/complete?{parameters}", + recordId, + parameters + )); + } /** * Deletes a record. * diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java new file mode 100644 index 0000000000..23a81fce5b --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java @@ -0,0 +1,338 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 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.rest.rm.community.records; + +import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.IMAGE_FILE; +import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createElectronicRecordModel; +import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createNonElectronicRecordModel; +import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.getFile; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; +import static org.testng.Assert.assertEquals; + +import javax.xml.namespace.QName; +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.rest.rm.community.base.BaseRMRestTest; +import org.alfresco.rest.rm.community.model.record.Record; +import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI; +import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI; +import org.alfresco.test.AlfrescoTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * This class contains the tests for + * Complete Record Action REST API + * + * @author Sara Aspery + * @since 2.6 + */ +public class CompleteRecordTests extends BaseRMRestTest +{ + private static final Boolean COMPLETE = true; + private static final Boolean INCOMPLETE = false; + private static final String parameters = "include=isCompleted"; + + /** + * Incomplete records with mandatory meta-data present + */ + @DataProvider (name = "IncompleteRecordsMandatoryMetadataPresent") + public Object[][] getIncompleteRecordsMandatoryMetadataPresent() throws Exception + { + createRMSiteIfNotExists(); + createMandatoryMetadata(); + + // create record folder + String recordFolderId = createCategoryFolderInFilePlan().getId(); + RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); + + //create electronic record in record folder + Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, + getFile(IMAGE_FILE)); + assertStatusCode(CREATED); + setMandatoryMetadata(electronicRecord); + // TODO verfiy mandatory metadata is present + + //create non-electronic record in record folder + Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); + assertStatusCode(CREATED); + setMandatoryMetadata(nonElectronicRecord); + + return new String[][] + { + // an arbitrary record folder + { electronicRecord.getId(), nonElectronicRecord.getId() }, + }; + } + + /** + * Incomplete records with mandatory meta-data missing + */ + @DataProvider (name = "IncompleteRecordsMandatoryMetadataMissing") + public Object[][] getIncompleteRecordsMandatoryMetadataMissing() throws Exception + { + createRMSiteIfNotExists(); + createMandatoryMetadata(); + + String recordFolderId = createCategoryFolderInFilePlan().getId(); + RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); + + //create electronic record in record folder + Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, + getFile(IMAGE_FILE)); + assertStatusCode(CREATED); + + //create non-electronic record in record folder + Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); + assertStatusCode(CREATED); + + return new String[][] + { + // an arbitrary record folder + { electronicRecord.getId(), nonElectronicRecord.getId() }, + }; + } + + // TODO repeat previous 2 providers but with config set to not chk for mandatory data + + /** + * Document to be completed is not a record + */ + @DataProvider (name = "Supplied node is not a record") + // TODO include is a document but not a record + + public Object[][] getNodesWhichAreNotRecords() throws Exception + { + //create record folder + String recordFolderId = createCategoryFolderInFilePlan().getId(); + RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); + Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, + getFile(IMAGE_FILE)); + assertStatusCode(CREATED); + + //create non-electronic record in record folder + Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); + assertStatusCode(CREATED); + + return new String[][] + { + { createCategoryFolderInFilePlan().getId() }, + + }; + } + + /** + * Incomplete records with mandatory meta-data missing + */ + @DataProvider (name = "FrozenRecords") + public Object[][] getFrozenRecords() throws Exception + { + // TODO consider adding method to BaseRMRestTest eg. createRMSiteIfNotExists(DOD5015); + createRMSiteIfNotExists(); + + // TODO add custom metadata to record model, and do not populate it + //create electronic record in record folder + String recordFolderId = createCategoryFolderInFilePlan().getId(); + RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); + Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, + getFile(IMAGE_FILE)); + assertStatusCode(CREATED); + + //create non-electronic record in record folder + Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); + assertStatusCode(CREATED); + + return new String[][] + { + // an arbitrary record folder + { electronicRecord.getId(), nonElectronicRecord.getId() }, + }; + } + + // TODO Add test for authentication fails (see yaml file) + // TODO Add test for user does not have permission to complete record + + /** + *
+     * Given the repository is configured to check mandatory data before completing a record
+     * And an incomplete record with all mandatory meta-data present
+     * When I complete the record
+     * Then the record is successfully completed
+     * 
+ */ + @Test + ( + dataProvider = "IncompleteRecordsMandatoryMetadataPresent", + description = "Can complete electronic and non-electronic records with mandatory metadata present" + ) + @AlfrescoTest (jira = "RM-4431") + public void completeRecordWithMandatoryMetadataPresent(String electronicRecordId, String nonElectronicRecordId) + throws Exception + { + // Get the recordsAPI + RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); + Record electronicRecord = recordsAPI.getRecord(electronicRecordId); + Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); + + for (Record record : Arrays.asList(electronicRecord, nonElectronicRecord)) + { + Record recordModel; + // Verify the record is incomplete + recordModel = recordsAPI.getRecord(record.getId(), parameters); + assertEquals(recordModel.getIsCompleted(), INCOMPLETE); + + // Complete record + recordModel = recordsAPI.completeRecord(record.getId(), parameters); + assertStatusCode(CREATED); + + // Verify the record has been completed + assertEquals(recordModel.getIsCompleted(), COMPLETE); + } + } + + /** + *
+     * Given the repository is configured to check mandatory data before completing a record
+     * And an incomplete record with missing mandatory meta-data
+     * When I complete the record
+     * Then I receive an error indicating that I can't complete the operation,
+     * because some of the mandatory meta-data of the record is missing
+     * 
+ */ + @Test + ( + dataProvider = "IncompleteRecordsMandatoryMetadataMissing", + description = "Cannot complete electronic and non-electronic records with mandatory metadata missing" + ) + @AlfrescoTest (jira = "RM-4431") + public void completeRecordWithMandatoryMetadataMissing(String electronicRecordId, String nonElectronicRecordId) + throws Exception + { + // Get the recordsAPI + RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); + Record electronicRecord = recordsAPI.getRecord(electronicRecordId); + Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); + + for (Record record : Arrays.asList(nonElectronicRecord)) + { + Record recordModel; + // Verify the record is incomplete + recordModel = recordsAPI.getRecord(record.getId(), parameters); + assertEquals(recordModel.getIsCompleted(), INCOMPLETE); + + //Verify the record has missing mandatory metadata + // TODO change next line to get custom metadata and check not populated + //assertEquals(recordModel. .getProperties() .getTitle(), INCOMPLETE); + + // Complete record + recordModel = recordsAPI.completeRecord(record.getId(), parameters); + assertStatusCode(UNPROCESSABLE_ENTITY); + + // Verify the record has not been completed + assertEquals(recordModel.getIsCompleted(), INCOMPLETE); + } + } + + /** + *
+     * Given a document that is not a record or any non-document node
+     * When I complete the item
+     * Then I receive an unsupported operation error
+     * 
+ */ + @Test + ( + dataProvider = "Supplied node is not a record", + description = "Cannot complete a document that is not a record" + ) + @AlfrescoTest (jira = "RM-4431") + public void completeNonRecord(String nonRecordId) + throws Exception + { + // Get the recordsAPI + RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); + Record recordModel; + recordModel = recordsAPI.completeRecord(nonRecordId, parameters); + assertStatusCode(BAD_REQUEST); + } + + /** + *
+     * Given a record that is already completed
+     * When I complete the record
+     * Then I receive an error indicating that I can't complete the operation, because the record is already complete
+     * 
+ */ + @Test + ( + dataProvider = "IncompleteRecordsMandatoryMetadataPresent", + description = "Cannot complete a record that is already completed" + ) + @AlfrescoTest (jira = "RM-4431") + public void completeAlreadyCompletedRecord(String electronicRecordId, String nonElectronicRecordId) + throws Exception + { + // Get the recordsAPI + RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); + Record electronicRecord = recordsAPI.getRecord(electronicRecordId); + Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); + + for (Record record : Arrays.asList(nonElectronicRecord)) + { + Record recordModel; + // If the record is incomplete, complete it + recordModel = recordsAPI.getRecord(record.getId(), parameters); + if (recordModel.getIsCompleted().equals(INCOMPLETE)) + { + recordModel = recordsAPI.completeRecord(record.getId(), parameters); + } + + // Verify the record is already completed + assertEquals(recordModel.getIsCompleted(), COMPLETE); + + // Complete record + recordModel = recordsAPI.completeRecord(record.getId(), parameters); + assertStatusCode(UNPROCESSABLE_ENTITY); + } + } + + + private void createMandatoryMetadata() + { + } + + private void setMandatoryMetadata(Record record) + { + } +} diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java index 52c2711314..e7e7a16ab1 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java @@ -213,6 +213,21 @@ public interface RecordService */ void file(NodeRef record); + /** + * Indicates whether all the mandatory metadata for the record is populated or not + * + * @param record record for which to check if all mandatory metadata is populated + * @return boolean true if all mandatory metadata is populated, false otherwise + */ + boolean isMandatoryPropertiesPopulated(NodeRef record); + + /** + * Completes a record. + * + * @param record record to be completed + */ + void complete(NodeRef record); + /** * Rejects a record with the provided reason * 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 bbf8449374..064c601f74 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 @@ -78,6 +78,7 @@ import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService; import org.alfresco.repo.content.ContentServicePolicies; import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.repo.policy.ClassPolicyDelegate; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; @@ -91,6 +92,7 @@ import org.alfresco.repo.security.permissions.impl.ExtendedPermissionService; import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.ClassDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; @@ -1302,6 +1304,94 @@ public class RecordServiceImpl extends BaseBehaviourBean } } + /** + * Helper method to 'complete' a record. + * + * @param record node reference to record + */ + public void complete(NodeRef record) + { + ParameterCheck.mandatory("item", record); + + // TODO get this from config + boolean checkMandatoryPropertiesEnabled = true; + + if (!checkMandatoryPropertiesEnabled || (isMandatoryPropertiesPopulated(record))) + { + disablePropertyEditableCheck(); + // Add the declared aspect + Map declaredProps = new HashMap<>(2); + declaredProps.put(RecordsManagementModel.PROP_DECLARED_AT, new Date()); + declaredProps.put(RecordsManagementModel.PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); + nodeService.addAspect(record, RecordsManagementModel.ASPECT_DECLARED_RECORD, declaredProps); + enablePropertyEditableCheck(); + } + } + + /** + * Helper method to determine whether a record's mandatory properties are set. + * + * @param nodeRef node reference to record + * @return boolean true if all mandatory metadata properties are set, false otherwise + */ + public boolean isMandatoryPropertiesPopulated(NodeRef nodeRef) + { + boolean result = true; + + // check for missing mandatory metadata from type definitions + Map nodeRefProps = nodeService.getProperties(nodeRef); + QName nodeRefType = nodeService.getType(nodeRef); + + TypeDefinition typeDef = dictionaryService.getType(nodeRefType); + for (PropertyDefinition propDef : typeDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + result = false; + break; + } + } + + // check for missing mandatory metadata from aspect definitions + if (result) + { + // TODO change to aspects = getAspects(nodeRef) ? + Set aspects = nodeService.getAspects(nodeRef); + for (QName aspect : aspects) + { + AspectDefinition aspectDef = dictionaryService.getAspect(aspect); + for (PropertyDefinition propDef : aspectDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + result = false; + break; + } + } + } + } + + // check for missing mandatory metadata from custom aspect definitions + if (result) + { + Collection aspects = dictionaryService.getAspects(RM_CUSTOM_MODEL); + for (QName aspect : aspects) + { + AspectDefinition aspectDef = dictionaryService.getAspect(aspect); + for (PropertyDefinition propDef : aspectDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + result = false; + break; + } + } + } + } + + return result; + } + /** * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#rejectRecord(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) */ diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java index f7b3b5ee25..6ce1ff28d6 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java @@ -27,20 +27,26 @@ package org.alfresco.rm.rest.api.records; +import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel.RM_CUSTOM_MODEL; import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank; import static org.alfresco.util.ParameterCheck.mandatory; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; + +import com.sun.xml.bind.v2.TODO; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.repo.activities.ActivityType; import org.alfresco.repo.node.integrity.IntegrityException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.rest.framework.BinaryProperties; import org.alfresco.rest.framework.Operation; @@ -58,6 +64,10 @@ import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils; import org.alfresco.rm.rest.api.model.Record; import org.alfresco.rm.rest.api.model.TargetContainer; import org.alfresco.service.cmr.activities.ActivityPoster; +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; @@ -67,8 +77,10 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ParameterCheck; +import org.opensaml.ws.security.provider.MandatoryAuthenticatedMessageRule; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.ConcurrencyFailureException; +import sun.util.resources.cldr.naq.CalendarData_naq_NA; /** * An implementation of an Entity Resource for a record @@ -91,6 +103,7 @@ public class RecordsEntityResource implements BinaryResourceAction.Read, private RecordService recordService; private NodeService nodeService; private TransactionService transactionService; + private DictionaryService dictionaryService; public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory) { @@ -122,6 +135,11 @@ public class RecordsEntityResource implements BinaryResourceAction.Read, this.transactionService = transactionService; } + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + /** * Download content * @@ -240,7 +258,7 @@ public class RecordsEntityResource implements BinaryResourceAction.Read, @Operation ("complete") @WebApiDescription (title = "Complete record", description = "Complete a record.") - public Record completeRecord(String recordId, Void body, Parameters parameters) + public Record completeRecord(String recordId, Void body, Parameters parameters, WithResponse withResponse) { checkNotBlank("recordId", recordId); mandatory("parameters", parameters); @@ -249,67 +267,30 @@ public class RecordsEntityResource implements BinaryResourceAction.Read, NodeRef record = apiUtils.validateRecord(recordId); // Complete the record - //TODO this should probably be something like recordService.complete(record); - completeRecord(record); + if (!recordService.isDeclared(record)) + { + //TODO: move this to appropriate place when resolved + boolean checkMandatoryPropertiesEnabled = true; // TODO + if (checkMandatoryPropertiesEnabled && (!recordService.isMandatoryPropertiesPopulated(record))) + { + throw new IntegrityException("Model integrity exception: the record has missing mandatory meta-data.", + null); + } + else + { + recordService.complete(record); + } + } + else + { + throw new IntegrityException("Model integrity exception: the record is already completed.", null); + } // return record state FileInfo info = fileFolderService.getFileInfo(record); return nodesModelFactory.createRecord(info, parameters, null, false); } - /* Temporary helper method just to do the complete record action. - Should probably live elsewhere, maybe RecordsImpl - */ - private void completeRecord(NodeRef record) { - boolean checkMandatoryPropertiesEnabled = true; - - if (! recordService.isDeclared(record)) - { - List missingProperties = new ArrayList<>(5); - if (checkMandatoryPropertiesEnabled && mandatoryPropertiesSet(record, missingProperties)) - { - //TODO error here; - } - else - { - recordService.disablePropertyEditableCheck(); - //try - //{ - // Add the declared aspect - Map declaredProps = new HashMap<>(2); - declaredProps.put(RecordsManagementModel.PROP_DECLARED_AT, new Date()); - //TODO declaredProps.put(RecordsManagementModel.PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); - nodeService.addAspect(record, RecordsManagementModel.ASPECT_DECLARED_RECORD, declaredProps); - - /* TODO - AuthenticationUtil.runAsSystem(new RunAsWork() - { - @Override - public Void doWork() - { - // remove all owner related rights - getOwnableService().setOwner(record, OwnableService.NO_OWNER); - return null; - } - }); - */ - //} finally - //{ - // recordService.enablePropertyEditableCheck(); - //} - } - } - } - - /* TODO - * this is temporary partly because there is an error in the original code - */ - private boolean mandatoryPropertiesSet(NodeRef nodeRef, List missingProperties) { - - return true; - } - - @Override @WebApiDescription(title = "Delete record", description="Deletes a record with id 'recordId'") public void delete(String recordId, Parameters parameters) diff --git a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml index 0bd0b05d9c..37c2aa2838 100644 --- a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml +++ b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml @@ -1801,7 +1801,7 @@ paths: schema: $ref: '#/definitions/Error' '/records/{recordId}/complete': - put: + post: tags: - records summary: Complete a record @@ -1834,9 +1834,9 @@ paths: '404': description: | **recordIdParam** does not exist - '409': + '422': description: | - **recordIdParam** is already completed + Model integrity exception: the record is already completed default: description: Unexpected error schema: From 21c881593ae433deec3876eb4d01c264e2e1c2aa Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Wed, 14 Jun 2017 19:38:45 +0100 Subject: [PATCH 03/18] Move the code for completing a record from DeclareRecordAction to RecordServiceImpl --- .../rm-action-context.xml | 3 +- .../rm-service-context.xml | 4 + .../action/impl/DeclareRecordAction.java | 220 +----------------- .../record/RecordService.java | 7 + .../record/RecordServiceImpl.java | 213 ++++++++++++++++- .../record/CompleteRecordTest.java | 34 +-- 6 files changed, 252 insertions(+), 229 deletions(-) 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 73adaab087..9d658f65cc 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 @@ -388,8 +388,7 @@ - - + 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 c2fd343d4b..6916b0bd36 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 @@ -1076,6 +1076,9 @@ + + + @@ -1152,6 +1155,7 @@ org.alfresco.module.org_alfresco_module_rm.record.RecordService.makeRecord=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.record.RecordService.link=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.record.RecordService.unlink=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.record.RecordService.complete=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.record.RecordService.*=RM_DENY ]]> diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java index 180ef6b895..09e0b02b99 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java @@ -27,33 +27,11 @@ package org.alfresco.module.org_alfresco_module_rm.action.impl; -import static org.alfresco.module.org_alfresco_module_rm.record.RecordUtils.generateRecordIdentifier; - -import java.io.Serializable; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase; -import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl; -import org.alfresco.module.org_alfresco_module_rm.util.TransactionalResourceHelper; -import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.service.cmr.action.Action; -import org.alfresco.service.cmr.dictionary.AspectDefinition; -import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.security.OwnableService; -import org.alfresco.service.namespace.QName; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.extensions.surf.util.I18NUtil; +import org.alfresco.util.ParameterCheck; /** * Declare record action @@ -65,33 +43,17 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase /** action name */ public static final String NAME = "declareRecord"; - /** I18N */ - private static final String MSG_UNDECLARED_ONLY_RECORDS = "rm.action.undeclared-only-records"; - private static final String MSG_NO_DECLARE_MAND_PROP = "rm.action.no-declare-mand-prop"; - - /** Logger */ - private static Log logger = LogFactory.getLog(DeclareRecordAction.class); - - /** check mandatory properties */ - private boolean checkMandatoryPropertiesEnabled = true; - - /** transactional resource helper */ - private TransactionalResourceHelper transactionalResourceHelper; + /** Record service */ + private RecordService recordService; /** - * @param checkMandatoryPropertiesEnabled true if check mandatory properties is enabled, false otherwise + * Sets the record service + * + * @param recordService record service */ - public void setCheckMandatoryPropertiesEnabled(boolean checkMandatoryPropertiesEnabled) + public void setRecordService(RecordService recordService) { - this.checkMandatoryPropertiesEnabled = checkMandatoryPropertiesEnabled; - } - - /** - * @param transactionalResourceHelper - */ - public void setTransactionalResourceHelper(TransactionalResourceHelper transactionalResourceHelper) - { - this.transactionalResourceHelper = transactionalResourceHelper; + this.recordService = recordService; } /** @@ -100,167 +62,7 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase @Override protected void executeImpl(final Action action, final NodeRef actionedUponNodeRef) { - if (getNodeService().exists(actionedUponNodeRef) && - getRecordService().isRecord(actionedUponNodeRef) && - !getFreezeService().isFrozen(actionedUponNodeRef)) - { - if (!getRecordService().isDeclared(actionedUponNodeRef)) - { - // if the record is newly created make sure the record identifier is set before completing the record - Set newRecords = transactionalResourceHelper.getSet(RecordServiceImpl.KEY_NEW_RECORDS); - if(newRecords.contains(actionedUponNodeRef)) - { - generateRecordIdentifier(getNodeService(), getIdentifierService(), actionedUponNodeRef); - } - - List missingProperties = new ArrayList<>(5); - // Aspect not already defined - check mandatory properties then add - if (!checkMandatoryPropertiesEnabled || - mandatoryPropertiesSet(actionedUponNodeRef, missingProperties)) - { - getRecordService().disablePropertyEditableCheck(); - try - { - // Add the declared aspect - Map declaredProps = new HashMap<>(2); - declaredProps.put(PROP_DECLARED_AT, new Date()); - declaredProps.put(PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); - this.getNodeService().addAspect(actionedUponNodeRef, ASPECT_DECLARED_RECORD, declaredProps); - - AuthenticationUtil.runAsSystem(new RunAsWork() - { - @Override - public Void doWork() - { - // remove all owner related rights - getOwnableService().setOwner(actionedUponNodeRef, OwnableService.NO_OWNER); - return null; - } - }); - } - finally - { - getRecordService().enablePropertyEditableCheck(); - } - } - else - { - logger.debug(buildMissingPropertiesErrorString(missingProperties)); - action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, "missingProperties"); - } - } - } - else - { - if (logger.isWarnEnabled()) - { - logger.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, actionedUponNodeRef.toString())); - } - } - } - - private String buildMissingPropertiesErrorString(List missingProperties) - { - StringBuilder builder = new StringBuilder(255); - builder.append(I18NUtil.getMessage(MSG_NO_DECLARE_MAND_PROP)); - builder.append(" "); - for (String missingProperty : missingProperties) - { - builder.append(missingProperty).append(", "); - } - return builder.toString(); - } - - /** - * Helper method to check whether all the mandatory properties of the node have been set - * - * @param nodeRef node reference - * @return boolean true if all mandatory properties are set, false otherwise - */ - private boolean mandatoryPropertiesSet(NodeRef nodeRef, List missingProperties) - { - boolean result = true; - - Map nodeRefProps = this.getNodeService().getProperties(nodeRef); - - QName nodeRefType = this.getNodeService().getType(nodeRef); - - TypeDefinition typeDef = this.getDictionaryService().getType(nodeRefType); - for (PropertyDefinition propDef : typeDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties); - - result = false; - break; - } - } - - if (result) - { - Set aspects = this.getNodeService().getAspects(nodeRef); - for (QName aspect : aspects) - { - AspectDefinition aspectDef = this.getDictionaryService().getAspect(aspect); - for (PropertyDefinition propDef : aspectDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties); - - result = false; - break; - } - } - } - } - - // check for missing mandatory metadata from custom aspect definitions - if (result) - { - QName aspect = ASPECT_RECORD; - if (nodeRefType.equals(TYPE_NON_ELECTRONIC_DOCUMENT)) - { - aspect = TYPE_NON_ELECTRONIC_DOCUMENT; - } - - // get customAspectImpl - String localName = aspect.toPrefixString(getNamespaceService()).replace(":", ""); - localName = MessageFormat.format("{0}CustomProperties", localName); - QName customAspect = QName.createQName(RM_CUSTOM_URI, localName); - - AspectDefinition aspectDef = this.getDictionaryService().getAspect(customAspect); - - for (PropertyDefinition propDef : aspectDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties); - - result = false; - break; - } - } - } - - return result; - } - - /** - * Log information about missing properties. - * - * @param propDef property definition - * @param missingProperties missing properties - */ - private void logMissingProperty(PropertyDefinition propDef, List missingProperties) - { - if (logger.isWarnEnabled()) - { - StringBuilder msg = new StringBuilder(); - msg.append("Mandatory property missing: ").append(propDef.getName()); - logger.warn(msg.toString()); - } - missingProperties.add(propDef.getName().toString()); + ParameterCheck.mandatory("actionedUponNodeRef", actionedUponNodeRef); + recordService.complete(actionedUponNodeRef); } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java index 52c2711314..c97c19ef2f 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java @@ -278,4 +278,11 @@ public interface RecordService * @since 2.3 */ void unlink(NodeRef record, NodeRef recordFolder); + + /** + * Completes a record + * + * @param nodeRef Record node reference + */ + void complete(NodeRef nodeRef); } 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 85f3a01d5e..31efc724f7 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 @@ -34,6 +34,7 @@ import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.TRANSACTI import static org.alfresco.repo.policy.annotation.BehaviourKind.ASSOCIATION; import java.io.Serializable; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -62,6 +63,7 @@ import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedul import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; import org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; +import org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService; import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel; @@ -81,9 +83,9 @@ import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServi import org.alfresco.repo.content.ContentServicePolicies; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.integrity.IncompleteNodeTagger; +import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.ClassPolicyDelegate; import org.alfresco.repo.policy.PolicyComponent; -import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourKind; @@ -94,6 +96,7 @@ import org.alfresco.repo.security.permissions.impl.ExtendedPermissionService; import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.ClassDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; @@ -158,6 +161,8 @@ public class RecordServiceImpl extends BaseBehaviourBean private static final String MSG_NODE_HAS_ASPECT = "rm.service.node-has-aspect"; private static final String FINAL_VERSION = "rm.service.final-version"; private static final String FINAL_DESCRIPTION = "rm.service.final-version-description"; + private static final String MSG_UNDECLARED_ONLY_RECORDS = "rm.action.undeclared-only-records"; + private static final String MSG_NO_DECLARE_MAND_PROP = "rm.action.no-declare-mand-prop"; /** Always edit property array */ private static final QName[] ALWAYS_EDIT_PROPERTIES = new QName[] @@ -168,6 +173,11 @@ public class RecordServiceImpl extends BaseBehaviourBean /** always edit model URI's */ private List alwaysEditURIs; + /** + * check mandatory properties + */ + private boolean checkMandatoryPropertiesEnabled = true; + /** * @param alwaysEditURIs the alwaysEditURIs to set */ @@ -263,6 +273,12 @@ public class RecordServiceImpl extends BaseBehaviourBean /** list of available record meta-data aspects and the file plan types the are applicable to */ private Map> recordMetaDataAspects; + /** Freeze service */ + private FreezeService freezeService; + + /** Namespace service */ + private NamespaceService namespaceService; + /** policies */ private ClassPolicyDelegate beforeFileRecord; private ClassPolicyDelegate onFileRecord; @@ -422,6 +438,30 @@ public class RecordServiceImpl extends BaseBehaviourBean this.incompleteNodeTagger = incompleteNodeTagger; } + /** + * @param freezeService freeze service + */ + public void setFreezeService(FreezeService freezeService) + { + this.freezeService = freezeService; + } + + /** + * @param namespaceService namespace service + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * @param checkMandatoryPropertiesEnabled true if check mandatory properties is enabled, false otherwise + */ + public void setCheckMandatoryPropertiesEnabled(boolean checkMandatoryPropertiesEnabled) + { + this.checkMandatoryPropertiesEnabled = checkMandatoryPropertiesEnabled; + } + /** * Init method */ @@ -1922,4 +1962,175 @@ public class RecordServiceImpl extends BaseBehaviourBean incompleteNodeTagger.beforeCommit(false); } } + + /** + * Completes a record + * + * @param nodeRef Record node reference + */ + @Override + public void complete(NodeRef nodeRef) + { + if (nodeService.exists(nodeRef) && isRecord(nodeRef) && !freezeService.isFrozen(nodeRef)) + { + if (!isDeclared(nodeRef)) + { + // if the record is newly created make sure the record identifier is set before completing the record + Set newRecords = transactionalResourceHelper.getSet(RecordServiceImpl.KEY_NEW_RECORDS); + if (newRecords.contains(nodeRef)) + { + generateRecordIdentifier(nodeService, identifierService, nodeRef); + } + + List missingProperties = new ArrayList<>(5); + // Aspect not already defined - check mandatory properties then add + if (!checkMandatoryPropertiesEnabled || mandatoryPropertiesSet(nodeRef, missingProperties)) + { + disablePropertyEditableCheck(); + try + { + // Add the declared aspect + Map declaredProps = new HashMap<>(2); + declaredProps.put(PROP_DECLARED_AT, new Date()); + declaredProps.put(PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); + nodeService.addAspect(nodeRef, ASPECT_DECLARED_RECORD, declaredProps); + + AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() + { + // remove all owner related rights + ownableService.setOwner(nodeRef, OwnableService.NO_OWNER); + return null; + } + }); + } + finally + { + enablePropertyEditableCheck(); + } + } + else + { + LOGGER.debug(buildMissingPropertiesErrorString(missingProperties)); + + // FIXME: + //action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, "missingProperties"); + } + } + } + else + { + if (LOGGER.isWarnEnabled()) + { + LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString())); + } + } + } + + private String buildMissingPropertiesErrorString(List missingProperties) + { + StringBuilder builder = new StringBuilder(255); + builder.append(I18NUtil.getMessage(MSG_NO_DECLARE_MAND_PROP)); + builder.append(" "); + for (String missingProperty : missingProperties) + { + builder.append(missingProperty).append(", "); + } + return builder.toString(); + } + + /** + * Helper method to check whether all the mandatory properties of the node have been set + * + * @param nodeRef node reference + * @return boolean true if all mandatory properties are set, false otherwise + */ + private boolean mandatoryPropertiesSet(NodeRef nodeRef, List missingProperties) + { + boolean result = true; + + Map nodeRefProps = nodeService.getProperties(nodeRef); + + QName nodeRefType = nodeService.getType(nodeRef); + + TypeDefinition typeDef = dictionaryService.getType(nodeRefType); + for (PropertyDefinition propDef : typeDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + logMissingProperty(propDef, missingProperties); + + result = false; + break; + } + } + + if (result) + { + Set aspects = nodeService.getAspects(nodeRef); + for (QName aspect : aspects) + { + AspectDefinition aspectDef = dictionaryService.getAspect(aspect); + for (PropertyDefinition propDef : aspectDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + logMissingProperty(propDef, missingProperties); + + result = false; + break; + } + } + } + } + + // check for missing mandatory metadata from custom aspect definitions + if (result) + { + QName aspect = ASPECT_RECORD; + if (nodeRefType.equals(TYPE_NON_ELECTRONIC_DOCUMENT)) + { + aspect = TYPE_NON_ELECTRONIC_DOCUMENT; + } + + // get customAspectImpl + String localName = aspect.toPrefixString(namespaceService).replace(":", ""); + localName = MessageFormat.format("{0}CustomProperties", localName); + QName customAspect = QName.createQName(RM_CUSTOM_URI, localName); + + AspectDefinition aspectDef = dictionaryService.getAspect(customAspect); + + for (PropertyDefinition propDef : aspectDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + logMissingProperty(propDef, missingProperties); + + result = false; + break; + } + } + } + + return result; + } + + /** + * Log information about missing properties. + * + * @param propDef property definition + * @param missingProperties missing properties + */ + private void logMissingProperty(PropertyDefinition propDef, List missingProperties) + { + if (LOGGER.isWarnEnabled()) + { + StringBuilder msg = new StringBuilder(); + msg.append("Mandatory property missing: ").append(propDef.getName()); + LOGGER.warn(msg.toString()); + } + missingProperties.add(propDef.getName().toString()); + } } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java index b73ecc6f78..7642f101bb 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java @@ -32,8 +32,8 @@ import java.util.HashMap; import java.util.Map; import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionResult; -import org.alfresco.module.org_alfresco_module_rm.action.impl.DeclareRecordAction; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel; +import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; @@ -55,9 +55,9 @@ public class CompleteRecordTest extends BaseRMTestCase private static final boolean OPTIONAL_METADATA = false; /** - * complete record action + * Record service impl */ - private DeclareRecordAction action; + private RecordServiceImpl recordServiceImpl; /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#initServices() @@ -67,8 +67,8 @@ public class CompleteRecordTest extends BaseRMTestCase { super.initServices(); - // get the action - action = (DeclareRecordAction) applicationContext.getBean("declareRecord"); + // get the record service + recordServiceImpl = (RecordServiceImpl) applicationContext.getBean("recordService"); } /** @@ -80,7 +80,7 @@ public class CompleteRecordTest extends BaseRMTestCase super.tearDownImpl(); // ensure action is returned to original state - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); } /** @@ -100,7 +100,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); @@ -140,7 +140,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); @@ -183,7 +183,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that has a mandatory property) for electronic records defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, MANDATORY_METADATA); @@ -229,7 +229,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // define the custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, MANDATORY_METADATA); @@ -279,7 +279,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that has a mandatory property) for non-electronic records defineCustomMetadata(CUSTOM_NON_ELECTRONIC_TEST, TYPE_NON_ELECTRONIC_DOCUMENT, MANDATORY_METADATA); @@ -326,7 +326,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_NON_ELECTRONIC_TEST, TYPE_NON_ELECTRONIC_DOCUMENT, MANDATORY_METADATA); @@ -375,7 +375,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that does not have a mandatory property) defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, OPTIONAL_METADATA); @@ -422,7 +422,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the record custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, MANDATORY_METADATA); @@ -469,7 +469,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the non-electronic record custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_NON_ELECTRONIC_TEST, TYPE_NON_ELECTRONIC_DOCUMENT, MANDATORY_METADATA); @@ -515,7 +515,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // disable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(false); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(false); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); @@ -555,7 +555,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(false); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(false); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); From 95a406cb304ce9fa4a4be07ac3caba9c4f98f068 Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Thu, 15 Jun 2017 11:04:23 +0100 Subject: [PATCH 04/18] updated from master --- .../records/CompleteRecordTests.java | 9 +--- .../api/records/RecordsEntityResource.java | 2 +- .../main/webapp/definitions/gs-core-api.yaml | 41 +++++++++++++++++++ 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java index 23a81fce5b..f683dcf6fa 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java @@ -35,13 +35,7 @@ import static org.springframework.http.HttpStatus.CREATED; import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; import static org.testng.Assert.assertEquals; -import javax.xml.namespace.QName; -import java.io.Serializable; import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; import org.alfresco.rest.rm.community.base.BaseRMRestTest; import org.alfresco.rest.rm.community.model.record.Record; @@ -153,7 +147,7 @@ public class CompleteRecordTests extends BaseRMRestTest } /** - * Incomplete records with mandatory meta-data missing + * Record to be completed is frozen */ @DataProvider (name = "FrozenRecords") public Object[][] getFrozenRecords() throws Exception @@ -330,6 +324,7 @@ public class CompleteRecordTests extends BaseRMRestTest private void createMandatoryMetadata() { + } private void setMandatoryMetadata(Record record) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java index 6ce1ff28d6..6c437b3951 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java @@ -283,7 +283,7 @@ public class RecordsEntityResource implements BinaryResourceAction.Read, } else { - throw new IntegrityException("Model integrity exception: the record is already completed.", null); + throw new IntegrityException("Model integrity exception: the record is frozen or already completed.", null); } // return record state diff --git a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml index a9a7e3f9a7..1c80b65973 100644 --- a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml +++ b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml @@ -1799,6 +1799,47 @@ paths: description: Unexpected error schema: $ref: '#/definitions/Error' + '/records/{recordId}/complete': + post: + tags: + - records + summary: Complete a record + description: | + Completes the record **recordId**. + operationId: completeRecord + parameters: + - $ref: '#/parameters/recordIdParam' + - $ref: '#/parameters/recordEntryIncludeParam' + - $ref: '#/parameters/fieldsParam' + consumes: + - application/json + produces: + - application/json + responses: + '200': + description: Successful response + schema: + $ref: '#/definitions/RecordEntry' + '400': + description: | + Invalid parameter: **recordIdParam** is not a valid format or + **recordIdParam** is not a record + '401': + description: Authentication failed + '403': + description: >- + Current user does not have permission to complete record + **recordIdParam** + '404': + description: | + **recordIdParam** does not exist + '422': + description: | + Model integrity exception: the record is frozen or already completed + default: + description: Unexpected error + schema: + $ref: '#/definitions/Error' ## Files '/files/{fileId}/declare': post: From 29a057adeb3db3111b61bd82718f4c2352b0b0bb Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Mon, 19 Jun 2017 18:06:34 +0100 Subject: [PATCH 05/18] more_declare_record_refactoring --- .../action/impl/DeclareRecordAction.java | 11 +- .../record/RecordServiceImpl.java | 115 +++++++++--------- 2 files changed, 67 insertions(+), 59 deletions(-) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java index 09e0b02b99..65d5fbae6a 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java @@ -29,6 +29,8 @@ package org.alfresco.module.org_alfresco_module_rm.action.impl; import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase; import org.alfresco.module.org_alfresco_module_rm.record.RecordService; +import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.util.ParameterCheck; @@ -63,6 +65,13 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase protected void executeImpl(final Action action, final NodeRef actionedUponNodeRef) { ParameterCheck.mandatory("actionedUponNodeRef", actionedUponNodeRef); - recordService.complete(actionedUponNodeRef); + try + { + recordService.complete(actionedUponNodeRef); + } + catch (IntegrityException e) { + action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, e.getMessage()); + } + } } 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 31efc724f7..93612725a0 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 @@ -83,6 +83,7 @@ import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServi import org.alfresco.repo.content.ContentServicePolicies; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.integrity.IncompleteNodeTagger; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.ClassPolicyDelegate; import org.alfresco.repo.policy.PolicyComponent; @@ -2014,11 +2015,13 @@ public class RecordServiceImpl extends BaseBehaviourBean else { LOGGER.debug(buildMissingPropertiesErrorString(missingProperties)); - - // FIXME: - //action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, "missingProperties"); + throw new IntegrityException("The record has missing mandatory properties.", null); } } + else + { + throw new IntegrityException("The record is already completed.", null); + } } else { @@ -2026,6 +2029,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString())); } + throw new IntegrityException("The record does not exist or is frozen.", null); } } @@ -2047,74 +2051,49 @@ public class RecordServiceImpl extends BaseBehaviourBean * @param nodeRef node reference * @return boolean true if all mandatory properties are set, false otherwise */ - private boolean mandatoryPropertiesSet(NodeRef nodeRef, List missingProperties) + private boolean mandatoryPropertiesSet(final NodeRef nodeRef, final List missingProperties) { - boolean result = true; - Map nodeRefProps = nodeService.getProperties(nodeRef); - QName nodeRefType = nodeService.getType(nodeRef); + // check for missing mandatory metadata from type definitions TypeDefinition typeDef = dictionaryService.getType(nodeRefType); - for (PropertyDefinition propDef : typeDef.getProperties().values()) + checkDefinitionMandatoryPropsSet(typeDef, nodeRefProps, missingProperties); + + // check for missing mandatory metadata from aspect definitions + Set aspects = nodeService.getAspects(nodeRef); + for (QName aspect : aspects) { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties); - - result = false; - break; - } - } - - if (result) - { - Set aspects = nodeService.getAspects(nodeRef); - for (QName aspect : aspects) - { - AspectDefinition aspectDef = dictionaryService.getAspect(aspect); - for (PropertyDefinition propDef : aspectDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties); - - result = false; - break; - } - } - } + AspectDefinition aspectDef = dictionaryService.getAspect(aspect); + checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties); } // check for missing mandatory metadata from custom aspect definitions - if (result) + QName customAspect = getCustomAspectImpl(nodeRefType); + AspectDefinition aspectDef = dictionaryService.getAspect(customAspect); + checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties); + + return missingProperties.isEmpty(); + } + + /** + * Helper method to check whether all the definition mandatory properties of the node have been set + * + * @param classDef the ClassDefinition defining the properties to be checked + * @param nodeRefProps the properties of the node to be checked + * @param missingProperties the list of mandatory properties found to be missing (currently only the first one) + * @return boolean true if all mandatory properties are set, false otherwise + */ + private void checkDefinitionMandatoryPropsSet(final ClassDefinition classDef, final Map nodeRefProps, + final List missingProperties) + { + for (PropertyDefinition propDef : classDef.getProperties().values()) { - QName aspect = ASPECT_RECORD; - if (nodeRefType.equals(TYPE_NON_ELECTRONIC_DOCUMENT)) + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) { - aspect = TYPE_NON_ELECTRONIC_DOCUMENT; - } - - // get customAspectImpl - String localName = aspect.toPrefixString(namespaceService).replace(":", ""); - localName = MessageFormat.format("{0}CustomProperties", localName); - QName customAspect = QName.createQName(RM_CUSTOM_URI, localName); - - AspectDefinition aspectDef = dictionaryService.getAspect(customAspect); - - for (PropertyDefinition propDef : aspectDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties); - - result = false; - break; - } + logMissingProperty(propDef, missingProperties);; } } - - return result; } /** @@ -2133,4 +2112,24 @@ public class RecordServiceImpl extends BaseBehaviourBean } missingProperties.add(propDef.getName().toString()); } + + /** + * Helper method to get the custom aspect for a given nodeRef type + * + * @param nodeRefType the node type for which to return custom aspect QName + * @return QName custom aspect + */ + private QName getCustomAspectImpl(QName nodeRefType) + { + QName aspect = ASPECT_RECORD; + if (nodeRefType.equals(TYPE_NON_ELECTRONIC_DOCUMENT)) + { + aspect = TYPE_NON_ELECTRONIC_DOCUMENT; + } + + // get customAspectImpl + String localName = aspect.toPrefixString(namespaceService).replace(":", ""); + localName = MessageFormat.format("{0}CustomProperties", localName); + return QName.createQName(RM_CUSTOM_URI, localName); + } } From 15b1bc41cddc3af55ae673f8f6b1917fc6497a27 Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Tue, 20 Jun 2017 08:27:09 +0100 Subject: [PATCH 06/18] Revert "Merge branch 'feature/refactor_declare_record_action' into RM-4431_CompleteRecordActionRestAPI" This reverts commit 6ff91795881a27b0bb1cc104980f9cf96fb9d1dc, reversing changes made to 75b35cdcd798c5c600f46b95ec883b2bd67bec31. --- .../rm-action-context.xml | 3 +- .../rm-service-context.xml | 4 - .../action/impl/DeclareRecordAction.java | 219 ++++++++++++- .../record/RecordService.java | 7 - .../record/RecordServiceImpl.java | 298 ++++++------------ .../record/CompleteRecordTest.java | 34 +- 6 files changed, 312 insertions(+), 253 deletions(-) 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 9d658f65cc..73adaab087 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 @@ -388,7 +388,8 @@ - + + 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 6916b0bd36..c2fd343d4b 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 @@ -1076,9 +1076,6 @@ - - - @@ -1155,7 +1152,6 @@ org.alfresco.module.org_alfresco_module_rm.record.RecordService.makeRecord=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.record.RecordService.link=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.record.RecordService.unlink=RM_ALLOW - org.alfresco.module.org_alfresco_module_rm.record.RecordService.complete=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.record.RecordService.*=RM_DENY ]]> diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java index 65d5fbae6a..180ef6b895 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java @@ -27,13 +27,33 @@ package org.alfresco.module.org_alfresco_module_rm.action.impl; +import static org.alfresco.module.org_alfresco_module_rm.record.RecordUtils.generateRecordIdentifier; + +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase; -import org.alfresco.module.org_alfresco_module_rm.record.RecordService; +import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl; +import org.alfresco.module.org_alfresco_module_rm.util.TransactionalResourceHelper; import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; -import org.alfresco.repo.node.integrity.IntegrityException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.ParameterCheck; +import org.alfresco.service.cmr.security.OwnableService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.I18NUtil; /** * Declare record action @@ -45,17 +65,33 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase /** action name */ public static final String NAME = "declareRecord"; - /** Record service */ - private RecordService recordService; + /** I18N */ + private static final String MSG_UNDECLARED_ONLY_RECORDS = "rm.action.undeclared-only-records"; + private static final String MSG_NO_DECLARE_MAND_PROP = "rm.action.no-declare-mand-prop"; + + /** Logger */ + private static Log logger = LogFactory.getLog(DeclareRecordAction.class); + + /** check mandatory properties */ + private boolean checkMandatoryPropertiesEnabled = true; + + /** transactional resource helper */ + private TransactionalResourceHelper transactionalResourceHelper; /** - * Sets the record service - * - * @param recordService record service + * @param checkMandatoryPropertiesEnabled true if check mandatory properties is enabled, false otherwise */ - public void setRecordService(RecordService recordService) + public void setCheckMandatoryPropertiesEnabled(boolean checkMandatoryPropertiesEnabled) { - this.recordService = recordService; + this.checkMandatoryPropertiesEnabled = checkMandatoryPropertiesEnabled; + } + + /** + * @param transactionalResourceHelper + */ + public void setTransactionalResourceHelper(TransactionalResourceHelper transactionalResourceHelper) + { + this.transactionalResourceHelper = transactionalResourceHelper; } /** @@ -64,14 +100,167 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase @Override protected void executeImpl(final Action action, final NodeRef actionedUponNodeRef) { - ParameterCheck.mandatory("actionedUponNodeRef", actionedUponNodeRef); - try + if (getNodeService().exists(actionedUponNodeRef) && + getRecordService().isRecord(actionedUponNodeRef) && + !getFreezeService().isFrozen(actionedUponNodeRef)) { - recordService.complete(actionedUponNodeRef); + if (!getRecordService().isDeclared(actionedUponNodeRef)) + { + // if the record is newly created make sure the record identifier is set before completing the record + Set newRecords = transactionalResourceHelper.getSet(RecordServiceImpl.KEY_NEW_RECORDS); + if(newRecords.contains(actionedUponNodeRef)) + { + generateRecordIdentifier(getNodeService(), getIdentifierService(), actionedUponNodeRef); + } + + List missingProperties = new ArrayList<>(5); + // Aspect not already defined - check mandatory properties then add + if (!checkMandatoryPropertiesEnabled || + mandatoryPropertiesSet(actionedUponNodeRef, missingProperties)) + { + getRecordService().disablePropertyEditableCheck(); + try + { + // Add the declared aspect + Map declaredProps = new HashMap<>(2); + declaredProps.put(PROP_DECLARED_AT, new Date()); + declaredProps.put(PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); + this.getNodeService().addAspect(actionedUponNodeRef, ASPECT_DECLARED_RECORD, declaredProps); + + AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() + { + // remove all owner related rights + getOwnableService().setOwner(actionedUponNodeRef, OwnableService.NO_OWNER); + return null; + } + }); + } + finally + { + getRecordService().enablePropertyEditableCheck(); + } + } + else + { + logger.debug(buildMissingPropertiesErrorString(missingProperties)); + action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, "missingProperties"); + } + } } - catch (IntegrityException e) { - action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, e.getMessage()); + else + { + if (logger.isWarnEnabled()) + { + logger.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, actionedUponNodeRef.toString())); + } + } + } + + private String buildMissingPropertiesErrorString(List missingProperties) + { + StringBuilder builder = new StringBuilder(255); + builder.append(I18NUtil.getMessage(MSG_NO_DECLARE_MAND_PROP)); + builder.append(" "); + for (String missingProperty : missingProperties) + { + builder.append(missingProperty).append(", "); + } + return builder.toString(); + } + + /** + * Helper method to check whether all the mandatory properties of the node have been set + * + * @param nodeRef node reference + * @return boolean true if all mandatory properties are set, false otherwise + */ + private boolean mandatoryPropertiesSet(NodeRef nodeRef, List missingProperties) + { + boolean result = true; + + Map nodeRefProps = this.getNodeService().getProperties(nodeRef); + + QName nodeRefType = this.getNodeService().getType(nodeRef); + + TypeDefinition typeDef = this.getDictionaryService().getType(nodeRefType); + for (PropertyDefinition propDef : typeDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + logMissingProperty(propDef, missingProperties); + + result = false; + break; + } } + if (result) + { + Set aspects = this.getNodeService().getAspects(nodeRef); + for (QName aspect : aspects) + { + AspectDefinition aspectDef = this.getDictionaryService().getAspect(aspect); + for (PropertyDefinition propDef : aspectDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + logMissingProperty(propDef, missingProperties); + + result = false; + break; + } + } + } + } + + // check for missing mandatory metadata from custom aspect definitions + if (result) + { + QName aspect = ASPECT_RECORD; + if (nodeRefType.equals(TYPE_NON_ELECTRONIC_DOCUMENT)) + { + aspect = TYPE_NON_ELECTRONIC_DOCUMENT; + } + + // get customAspectImpl + String localName = aspect.toPrefixString(getNamespaceService()).replace(":", ""); + localName = MessageFormat.format("{0}CustomProperties", localName); + QName customAspect = QName.createQName(RM_CUSTOM_URI, localName); + + AspectDefinition aspectDef = this.getDictionaryService().getAspect(customAspect); + + for (PropertyDefinition propDef : aspectDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + logMissingProperty(propDef, missingProperties); + + result = false; + break; + } + } + } + + return result; + } + + /** + * Log information about missing properties. + * + * @param propDef property definition + * @param missingProperties missing properties + */ + private void logMissingProperty(PropertyDefinition propDef, List missingProperties) + { + if (logger.isWarnEnabled()) + { + StringBuilder msg = new StringBuilder(); + msg.append("Mandatory property missing: ").append(propDef.getName()); + logger.warn(msg.toString()); + } + missingProperties.add(propDef.getName().toString()); } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java index 24bfb76579..e7e7a16ab1 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java @@ -293,11 +293,4 @@ public interface RecordService * @since 2.3 */ void unlink(NodeRef record, NodeRef recordFolder); - - /** - * Completes a record - * - * @param nodeRef Record node reference - */ - void complete(NodeRef nodeRef); } 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 93612725a0..040768700e 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 @@ -34,7 +34,6 @@ import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.TRANSACTI import static org.alfresco.repo.policy.annotation.BehaviourKind.ASSOCIATION; import java.io.Serializable; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -63,7 +62,6 @@ import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedul import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; import org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; -import org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService; import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel; @@ -84,9 +82,9 @@ import org.alfresco.repo.content.ContentServicePolicies; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.integrity.IncompleteNodeTagger; import org.alfresco.repo.node.integrity.IntegrityException; -import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.ClassPolicyDelegate; import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourKind; @@ -162,8 +160,6 @@ public class RecordServiceImpl extends BaseBehaviourBean private static final String MSG_NODE_HAS_ASPECT = "rm.service.node-has-aspect"; private static final String FINAL_VERSION = "rm.service.final-version"; private static final String FINAL_DESCRIPTION = "rm.service.final-version-description"; - private static final String MSG_UNDECLARED_ONLY_RECORDS = "rm.action.undeclared-only-records"; - private static final String MSG_NO_DECLARE_MAND_PROP = "rm.action.no-declare-mand-prop"; /** Always edit property array */ private static final QName[] ALWAYS_EDIT_PROPERTIES = new QName[] @@ -174,11 +170,6 @@ public class RecordServiceImpl extends BaseBehaviourBean /** always edit model URI's */ private List alwaysEditURIs; - /** - * check mandatory properties - */ - private boolean checkMandatoryPropertiesEnabled = true; - /** * @param alwaysEditURIs the alwaysEditURIs to set */ @@ -274,12 +265,6 @@ public class RecordServiceImpl extends BaseBehaviourBean /** list of available record meta-data aspects and the file plan types the are applicable to */ private Map> recordMetaDataAspects; - /** Freeze service */ - private FreezeService freezeService; - - /** Namespace service */ - private NamespaceService namespaceService; - /** policies */ private ClassPolicyDelegate beforeFileRecord; private ClassPolicyDelegate onFileRecord; @@ -439,30 +424,6 @@ public class RecordServiceImpl extends BaseBehaviourBean this.incompleteNodeTagger = incompleteNodeTagger; } - /** - * @param freezeService freeze service - */ - public void setFreezeService(FreezeService freezeService) - { - this.freezeService = freezeService; - } - - /** - * @param namespaceService namespace service - */ - public void setNamespaceService(NamespaceService namespaceService) - { - this.namespaceService = namespaceService; - } - - /** - * @param checkMandatoryPropertiesEnabled true if check mandatory properties is enabled, false otherwise - */ - public void setCheckMandatoryPropertiesEnabled(boolean checkMandatoryPropertiesEnabled) - { - this.checkMandatoryPropertiesEnabled = checkMandatoryPropertiesEnabled; - } - /** * Init method */ @@ -1386,6 +1347,94 @@ public class RecordServiceImpl extends BaseBehaviourBean } } + /** + * Helper method to 'complete' a record. + * + * @param record node reference to record + */ + public void complete(NodeRef record) + { + ParameterCheck.mandatory("item", record); + + // TODO get this from config + boolean checkMandatoryPropertiesEnabled = true; + + if (!checkMandatoryPropertiesEnabled || (isMandatoryPropertiesPopulated(record))) + { + disablePropertyEditableCheck(); + // Add the declared aspect + Map declaredProps = new HashMap<>(2); + declaredProps.put(RecordsManagementModel.PROP_DECLARED_AT, new Date()); + declaredProps.put(RecordsManagementModel.PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); + nodeService.addAspect(record, RecordsManagementModel.ASPECT_DECLARED_RECORD, declaredProps); + enablePropertyEditableCheck(); + } + } + + /** + * Helper method to determine whether a record's mandatory properties are set. + * + * @param nodeRef node reference to record + * @return boolean true if all mandatory metadata properties are set, false otherwise + */ + public boolean isMandatoryPropertiesPopulated(NodeRef nodeRef) + { + boolean result = true; + + // check for missing mandatory metadata from type definitions + Map nodeRefProps = nodeService.getProperties(nodeRef); + QName nodeRefType = nodeService.getType(nodeRef); + + TypeDefinition typeDef = dictionaryService.getType(nodeRefType); + for (PropertyDefinition propDef : typeDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + result = false; + break; + } + } + + // check for missing mandatory metadata from aspect definitions + if (result) + { + // TODO change to aspects = getAspects(nodeRef) ? + Set aspects = nodeService.getAspects(nodeRef); + for (QName aspect : aspects) + { + AspectDefinition aspectDef = dictionaryService.getAspect(aspect); + for (PropertyDefinition propDef : aspectDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + result = false; + break; + } + } + } + } + + // check for missing mandatory metadata from custom aspect definitions + if (result) + { + Collection aspects = dictionaryService.getAspects(RM_CUSTOM_MODEL); + for (QName aspect : aspects) + { + AspectDefinition aspectDef = dictionaryService.getAspect(aspect); + for (PropertyDefinition propDef : aspectDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + result = false; + break; + } + } + } + } + + return result; + } + /** * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#rejectRecord(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) */ @@ -1963,173 +2012,4 @@ public class RecordServiceImpl extends BaseBehaviourBean incompleteNodeTagger.beforeCommit(false); } } - - /** - * Completes a record - * - * @param nodeRef Record node reference - */ - @Override - public void complete(NodeRef nodeRef) - { - if (nodeService.exists(nodeRef) && isRecord(nodeRef) && !freezeService.isFrozen(nodeRef)) - { - if (!isDeclared(nodeRef)) - { - // if the record is newly created make sure the record identifier is set before completing the record - Set newRecords = transactionalResourceHelper.getSet(RecordServiceImpl.KEY_NEW_RECORDS); - if (newRecords.contains(nodeRef)) - { - generateRecordIdentifier(nodeService, identifierService, nodeRef); - } - - List missingProperties = new ArrayList<>(5); - // Aspect not already defined - check mandatory properties then add - if (!checkMandatoryPropertiesEnabled || mandatoryPropertiesSet(nodeRef, missingProperties)) - { - disablePropertyEditableCheck(); - try - { - // Add the declared aspect - Map declaredProps = new HashMap<>(2); - declaredProps.put(PROP_DECLARED_AT, new Date()); - declaredProps.put(PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); - nodeService.addAspect(nodeRef, ASPECT_DECLARED_RECORD, declaredProps); - - AuthenticationUtil.runAsSystem(new RunAsWork() - { - @Override - public Void doWork() - { - // remove all owner related rights - ownableService.setOwner(nodeRef, OwnableService.NO_OWNER); - return null; - } - }); - } - finally - { - enablePropertyEditableCheck(); - } - } - else - { - LOGGER.debug(buildMissingPropertiesErrorString(missingProperties)); - throw new IntegrityException("The record has missing mandatory properties.", null); - } - } - else - { - throw new IntegrityException("The record is already completed.", null); - } - } - else - { - if (LOGGER.isWarnEnabled()) - { - LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString())); - } - throw new IntegrityException("The record does not exist or is frozen.", null); - } - } - - private String buildMissingPropertiesErrorString(List missingProperties) - { - StringBuilder builder = new StringBuilder(255); - builder.append(I18NUtil.getMessage(MSG_NO_DECLARE_MAND_PROP)); - builder.append(" "); - for (String missingProperty : missingProperties) - { - builder.append(missingProperty).append(", "); - } - return builder.toString(); - } - - /** - * Helper method to check whether all the mandatory properties of the node have been set - * - * @param nodeRef node reference - * @return boolean true if all mandatory properties are set, false otherwise - */ - private boolean mandatoryPropertiesSet(final NodeRef nodeRef, final List missingProperties) - { - Map nodeRefProps = nodeService.getProperties(nodeRef); - QName nodeRefType = nodeService.getType(nodeRef); - - // check for missing mandatory metadata from type definitions - TypeDefinition typeDef = dictionaryService.getType(nodeRefType); - checkDefinitionMandatoryPropsSet(typeDef, nodeRefProps, missingProperties); - - // check for missing mandatory metadata from aspect definitions - Set aspects = nodeService.getAspects(nodeRef); - for (QName aspect : aspects) - { - AspectDefinition aspectDef = dictionaryService.getAspect(aspect); - checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties); - } - - // check for missing mandatory metadata from custom aspect definitions - QName customAspect = getCustomAspectImpl(nodeRefType); - AspectDefinition aspectDef = dictionaryService.getAspect(customAspect); - checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties); - - return missingProperties.isEmpty(); - } - - /** - * Helper method to check whether all the definition mandatory properties of the node have been set - * - * @param classDef the ClassDefinition defining the properties to be checked - * @param nodeRefProps the properties of the node to be checked - * @param missingProperties the list of mandatory properties found to be missing (currently only the first one) - * @return boolean true if all mandatory properties are set, false otherwise - */ - private void checkDefinitionMandatoryPropsSet(final ClassDefinition classDef, final Map nodeRefProps, - final List missingProperties) - { - for (PropertyDefinition propDef : classDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties);; - } - } - } - - /** - * Log information about missing properties. - * - * @param propDef property definition - * @param missingProperties missing properties - */ - private void logMissingProperty(PropertyDefinition propDef, List missingProperties) - { - if (LOGGER.isWarnEnabled()) - { - StringBuilder msg = new StringBuilder(); - msg.append("Mandatory property missing: ").append(propDef.getName()); - LOGGER.warn(msg.toString()); - } - missingProperties.add(propDef.getName().toString()); - } - - /** - * Helper method to get the custom aspect for a given nodeRef type - * - * @param nodeRefType the node type for which to return custom aspect QName - * @return QName custom aspect - */ - private QName getCustomAspectImpl(QName nodeRefType) - { - QName aspect = ASPECT_RECORD; - if (nodeRefType.equals(TYPE_NON_ELECTRONIC_DOCUMENT)) - { - aspect = TYPE_NON_ELECTRONIC_DOCUMENT; - } - - // get customAspectImpl - String localName = aspect.toPrefixString(namespaceService).replace(":", ""); - localName = MessageFormat.format("{0}CustomProperties", localName); - return QName.createQName(RM_CUSTOM_URI, localName); - } } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java index 7642f101bb..b73ecc6f78 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java @@ -32,8 +32,8 @@ import java.util.HashMap; import java.util.Map; import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionResult; +import org.alfresco.module.org_alfresco_module_rm.action.impl.DeclareRecordAction; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel; -import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; @@ -55,9 +55,9 @@ public class CompleteRecordTest extends BaseRMTestCase private static final boolean OPTIONAL_METADATA = false; /** - * Record service impl + * complete record action */ - private RecordServiceImpl recordServiceImpl; + private DeclareRecordAction action; /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#initServices() @@ -67,8 +67,8 @@ public class CompleteRecordTest extends BaseRMTestCase { super.initServices(); - // get the record service - recordServiceImpl = (RecordServiceImpl) applicationContext.getBean("recordService"); + // get the action + action = (DeclareRecordAction) applicationContext.getBean("declareRecord"); } /** @@ -80,7 +80,7 @@ public class CompleteRecordTest extends BaseRMTestCase super.tearDownImpl(); // ensure action is returned to original state - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); } /** @@ -100,7 +100,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); @@ -140,7 +140,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); @@ -183,7 +183,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that has a mandatory property) for electronic records defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, MANDATORY_METADATA); @@ -229,7 +229,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); // define the custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, MANDATORY_METADATA); @@ -279,7 +279,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that has a mandatory property) for non-electronic records defineCustomMetadata(CUSTOM_NON_ELECTRONIC_TEST, TYPE_NON_ELECTRONIC_DOCUMENT, MANDATORY_METADATA); @@ -326,7 +326,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_NON_ELECTRONIC_TEST, TYPE_NON_ELECTRONIC_DOCUMENT, MANDATORY_METADATA); @@ -375,7 +375,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that does not have a mandatory property) defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, OPTIONAL_METADATA); @@ -422,7 +422,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); // create the record custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, MANDATORY_METADATA); @@ -469,7 +469,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); + action.setCheckMandatoryPropertiesEnabled(true); // create the non-electronic record custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_NON_ELECTRONIC_TEST, TYPE_NON_ELECTRONIC_DOCUMENT, MANDATORY_METADATA); @@ -515,7 +515,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // disable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(false); + action.setCheckMandatoryPropertiesEnabled(false); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); @@ -555,7 +555,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // enable mandatory parameter check - recordServiceImpl.setCheckMandatoryPropertiesEnabled(false); + action.setCheckMandatoryPropertiesEnabled(false); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); From 57b3460b58b7e60cce5126ce2783b698f3119da8 Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Tue, 20 Jun 2017 11:12:22 +0100 Subject: [PATCH 07/18] include_declare_record_refactoring_in_Rest --- .../rm-action-context.xml | 3 +- .../rm-service-context.xml | 1984 +++++++++-------- .../action/impl/DeclareRecordAction.java | 225 +- .../record/RecordService.java | 380 ++-- .../record/RecordServiceImpl.java | 718 +++--- .../record/CompleteRecordTest.java | 34 +- 6 files changed, 1669 insertions(+), 1675 deletions(-) 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 73adaab087..9d658f65cc 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 @@ -388,8 +388,7 @@ - - + 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 c2fd343d4b..2a9b9accf5 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 @@ -1,10 +1,10 @@ - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - + + + + + + + - + - + - + - - - + + + - - - org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService - - - - - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService + + + + + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - - - - - - - - - - - + + + + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.transfer.TransferService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.transfer.TransferService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - + + - - - org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - + + + + + + + - - - + + + - - - org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - + class="org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanServiceImpl"> + + - - - org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService - - - - - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService + + + + + + + + + + + + + + + + - + - - - - + + + - - - + + + - - - - - - - - + class="org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionServiceImpl" + init-method="init"> + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - + + + + + + + + - + - - - org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService + + + + + + + + + + + + - + - - - - + + + - - - + + + - + - - - - - + + + + + - - - org.alfresco.module.org_alfresco_module_rm.model.security.ModelSecurityService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.model.security.ModelSecurityService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - + + + + - - - org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - + + + + - - - org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEventService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEventService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - - - - - - + + + + + + - + - + rma:recordCategory @@ -798,38 +817,39 @@ - - - org.alfresco.module.org_alfresco_module_rm.admin.RecordsManagementAdminService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.admin.RecordsManagementAdminService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - - - - - - - - cm:lastThumbnailModification - cm:autoVersion - cm:autoVersionOnUpdateProps - cm:initialVersion - - - + + + + + + + + + + + + + + + cm:lastThumbnailModification + cm:autoVersion + cm:autoVersionOnUpdateProps + cm:initialVersion + + + - - - org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1090,46 +1118,48 @@ http://www.alfresco.org/model/rendition/1.0 - - - - + + + + - - - org.alfresco.module.org_alfresco_module_rm.record.RecordService - - - - - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.record.RecordService + + + + + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - + @@ -1173,22 +1205,23 @@ - + - - - + + + - + - + @@ -1211,25 +1244,25 @@ + class="org.alfresco.module.org_alfresco_module_rm.security.FilePlanAuthenticationServiceImpl" /> org.alfresco.module.org_alfresco_module_rm.security.FilePlanAuthenticationService - + - - - + + + - + @@ -1241,16 +1274,18 @@ - - + + - + - + + + Thread-Index @@ -1263,110 +1298,112 @@ - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - - - - org.alfresco.module.org_alfresco_module_rm.email.CustomEmailMappingService - - - - customEmailMappingService - - - - - - - - - + + + + org.alfresco.module.org_alfresco_module_rm.email.CustomEmailMappingService + + + + customEmailMappingService + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + - + - + - + - - - - - - org.alfresco.caveatConfigTransactionalCache - - - - - + + + + + + org.alfresco.caveatConfigTransactionalCache + + + + + - + {http://www.alfresco.org/model/recordsmanagement/1.0}recordComponentIdentifier @@ -1374,7 +1411,7 @@ - + {http://www.alfresco.org/model/rmcustom/1.0}rmcustom @@ -1382,14 +1419,15 @@ - - - + + + - - - - + + + - - - + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - org.alfresco.module.org_alfresco_module_rm.caveat.RMCaveatConfigService - - - - caveatConfigService - - - - - - - - - + + + + org.alfresco.module.org_alfresco_module_rm.caveat.RMCaveatConfigService + + + + caveatConfigService + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.dataset.DataSetService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.dataset.DataSetService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - + + + - - - - + + + + @@ -1526,7 +1567,7 @@ - + @@ -1536,13 +1577,13 @@ org.alfresco.module.org_alfresco_module_rm.hold.HoldService - + - - - + + + @@ -1575,8 +1616,10 @@ - - + + @@ -1584,20 +1627,21 @@ org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService - + - - - + + + - + - + @@ -1628,8 +1672,9 @@ - - + + @@ -1637,20 +1682,21 @@ org.alfresco.module.org_alfresco_module_rm.recordableversion.RecordableVersionConfigService - + - - - + + + - + - + diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java index 180ef6b895..fe21ae45cd 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java @@ -27,33 +27,13 @@ package org.alfresco.module.org_alfresco_module_rm.action.impl; -import static org.alfresco.module.org_alfresco_module_rm.record.RecordUtils.generateRecordIdentifier; - -import java.io.Serializable; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase; -import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl; -import org.alfresco.module.org_alfresco_module_rm.util.TransactionalResourceHelper; +import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.service.cmr.action.Action; -import org.alfresco.service.cmr.dictionary.AspectDefinition; -import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.security.OwnableService; -import org.alfresco.service.namespace.QName; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.extensions.surf.util.I18NUtil; +import org.alfresco.util.ParameterCheck; /** * Declare record action @@ -62,36 +42,24 @@ import org.springframework.extensions.surf.util.I18NUtil; */ public class DeclareRecordAction extends RMActionExecuterAbstractBase { - /** action name */ + /** + * action name + */ public static final String NAME = "declareRecord"; - /** I18N */ - private static final String MSG_UNDECLARED_ONLY_RECORDS = "rm.action.undeclared-only-records"; - private static final String MSG_NO_DECLARE_MAND_PROP = "rm.action.no-declare-mand-prop"; - - /** Logger */ - private static Log logger = LogFactory.getLog(DeclareRecordAction.class); - - /** check mandatory properties */ - private boolean checkMandatoryPropertiesEnabled = true; - - /** transactional resource helper */ - private TransactionalResourceHelper transactionalResourceHelper; + /** + * Record service + */ + private RecordService recordService; /** - * @param checkMandatoryPropertiesEnabled true if check mandatory properties is enabled, false otherwise + * Sets the record service + * + * @param recordService record service */ - public void setCheckMandatoryPropertiesEnabled(boolean checkMandatoryPropertiesEnabled) + public void setRecordService(RecordService recordService) { - this.checkMandatoryPropertiesEnabled = checkMandatoryPropertiesEnabled; - } - - /** - * @param transactionalResourceHelper - */ - public void setTransactionalResourceHelper(TransactionalResourceHelper transactionalResourceHelper) - { - this.transactionalResourceHelper = transactionalResourceHelper; + this.recordService = recordService; } /** @@ -100,167 +68,14 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase @Override protected void executeImpl(final Action action, final NodeRef actionedUponNodeRef) { - if (getNodeService().exists(actionedUponNodeRef) && - getRecordService().isRecord(actionedUponNodeRef) && - !getFreezeService().isFrozen(actionedUponNodeRef)) + ParameterCheck.mandatory("actionedUponNodeRef", actionedUponNodeRef); + try { - if (!getRecordService().isDeclared(actionedUponNodeRef)) - { - // if the record is newly created make sure the record identifier is set before completing the record - Set newRecords = transactionalResourceHelper.getSet(RecordServiceImpl.KEY_NEW_RECORDS); - if(newRecords.contains(actionedUponNodeRef)) - { - generateRecordIdentifier(getNodeService(), getIdentifierService(), actionedUponNodeRef); - } - - List missingProperties = new ArrayList<>(5); - // Aspect not already defined - check mandatory properties then add - if (!checkMandatoryPropertiesEnabled || - mandatoryPropertiesSet(actionedUponNodeRef, missingProperties)) - { - getRecordService().disablePropertyEditableCheck(); - try - { - // Add the declared aspect - Map declaredProps = new HashMap<>(2); - declaredProps.put(PROP_DECLARED_AT, new Date()); - declaredProps.put(PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); - this.getNodeService().addAspect(actionedUponNodeRef, ASPECT_DECLARED_RECORD, declaredProps); - - AuthenticationUtil.runAsSystem(new RunAsWork() - { - @Override - public Void doWork() - { - // remove all owner related rights - getOwnableService().setOwner(actionedUponNodeRef, OwnableService.NO_OWNER); - return null; - } - }); - } - finally - { - getRecordService().enablePropertyEditableCheck(); - } - } - else - { - logger.debug(buildMissingPropertiesErrorString(missingProperties)); - action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, "missingProperties"); - } - } - } - else + recordService.complete(actionedUponNodeRef); + } catch (IntegrityException e) { - if (logger.isWarnEnabled()) - { - logger.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, actionedUponNodeRef.toString())); - } - } - } - - private String buildMissingPropertiesErrorString(List missingProperties) - { - StringBuilder builder = new StringBuilder(255); - builder.append(I18NUtil.getMessage(MSG_NO_DECLARE_MAND_PROP)); - builder.append(" "); - for (String missingProperty : missingProperties) - { - builder.append(missingProperty).append(", "); - } - return builder.toString(); - } - - /** - * Helper method to check whether all the mandatory properties of the node have been set - * - * @param nodeRef node reference - * @return boolean true if all mandatory properties are set, false otherwise - */ - private boolean mandatoryPropertiesSet(NodeRef nodeRef, List missingProperties) - { - boolean result = true; - - Map nodeRefProps = this.getNodeService().getProperties(nodeRef); - - QName nodeRefType = this.getNodeService().getType(nodeRef); - - TypeDefinition typeDef = this.getDictionaryService().getType(nodeRefType); - for (PropertyDefinition propDef : typeDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties); - - result = false; - break; - } + action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, e.getMessage()); } - if (result) - { - Set aspects = this.getNodeService().getAspects(nodeRef); - for (QName aspect : aspects) - { - AspectDefinition aspectDef = this.getDictionaryService().getAspect(aspect); - for (PropertyDefinition propDef : aspectDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties); - - result = false; - break; - } - } - } - } - - // check for missing mandatory metadata from custom aspect definitions - if (result) - { - QName aspect = ASPECT_RECORD; - if (nodeRefType.equals(TYPE_NON_ELECTRONIC_DOCUMENT)) - { - aspect = TYPE_NON_ELECTRONIC_DOCUMENT; - } - - // get customAspectImpl - String localName = aspect.toPrefixString(getNamespaceService()).replace(":", ""); - localName = MessageFormat.format("{0}CustomProperties", localName); - QName customAspect = QName.createQName(RM_CUSTOM_URI, localName); - - AspectDefinition aspectDef = this.getDictionaryService().getAspect(customAspect); - - for (PropertyDefinition propDef : aspectDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - logMissingProperty(propDef, missingProperties); - - result = false; - break; - } - } - } - - return result; - } - - /** - * Log information about missing properties. - * - * @param propDef property definition - * @param missingProperties missing properties - */ - private void logMissingProperty(PropertyDefinition propDef, List missingProperties) - { - if (logger.isWarnEnabled()) - { - StringBuilder msg = new StringBuilder(); - msg.append("Mandatory property missing: ").append(propDef.getName()); - logger.warn(msg.toString()); - } - missingProperties.add(propDef.getName().toString()); } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java index e7e7a16ab1..f9cfaf2255 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java @@ -55,9 +55,8 @@ public interface RecordService * A record metadata aspect can be registered more than once if it applies to more than one * file plan type. * - * @param recordMetadataAspect record metadata aspect qualified name - * @param filePlanType file plan type - * + * @param recordMetadataAspect record metadata aspect qualified name + * @param filePlanType file plan type * @since 2.2 */ void registerRecordMetadataAspect(QName recordMetadataAspect, QName filePlanType); @@ -72,8 +71,7 @@ public interface RecordService /** * Disables the property editable check for a given node in this transaction only. * - * @param nodeRef node reference - * + * @param nodeRef node reference * @since 2.2 */ void disablePropertyEditableCheck(NodeRef nodeRef); @@ -84,213 +82,199 @@ public interface RecordService void enablePropertyEditableCheck(); /** - * Gets a list of all the record meta-data aspects - * - * @return {@link Set}<{@link QName}> list of record meta-data aspects - * - * @deprecated since 2.2, file plan component required to provide context - */ - @Deprecated - Set getRecordMetaDataAspects(); - - /** - * Indicates whether the provided aspect is a registered record meta-data - * aspect. - * - * @param aspect aspect {@link QName} - * @return boolean true if the aspect is a registered record meta-data aspect, false otherwise - * - * @since 2.3 - */ - boolean isRecordMetadataAspect(QName aspect); - - /** - * Indicates whther the provided property is declared on a registered record - * meta-data aspect. - * - * @param property property {@link QName} - * @return boolean true if the property is declared on a registered record meta-data aspect, - * false otherwise - * - * @since 2.3 - */ - boolean isRecordMetadataProperty(QName property); - - /** - * Gets a list of all the record metadata aspects relevant to the file plan type of the - * file plan component provided. - *

- * If a null context is provided all record meta-data aspects are returned, but this is not - * recommended. - * - * @param nodeRef node reference to file plan component providing context - * @return {@link Set}<{@link QName}> list of record meta-data aspects - * - * @since 2.2 - */ - Set getRecordMetadataAspects(NodeRef nodeRef); - - /** - * Gets a list of all the record metadata aspect that relate to the provided file plan type. - *

- * If null is provided for the file plan type then record metadata aspects for the default - * file plan type (rma:filePlan) are returned. - * - * @param filePlanType file plan type - * @return{@link Set}<{@link QName}> list of record meta-data aspects - * - * @since 2.2 - */ - Set getRecordMetadataAspects(QName filePlanType); - - /** - * Checks whether if the given node reference is a record or not - * - * @param nodeRef node reference to be checked - * @return boolean true if the node reference is a record, false otherwise - */ - boolean isRecord(NodeRef nodeRef); - - /** - * Indicates whether the record is declared - * - * @param nodeRef node reference of the record for which the check would be performed - * @return boolean true if record is declared, false otherwise - */ - boolean isDeclared(NodeRef nodeRef); - - /** - * Creates a new unfiled record from an existing node. - *

- * Note that the node reference of the record will be the same as the original - * document. - * - * @param filePlan The filePlan in which the record should be placed. filePlan can be null in this case the default RM site will be used. - * @param nodeRef The node from which the record will be created - * @param isLinked indicates if the newly created record is linked to it's original location or not. - */ - void createRecord(NodeRef filePlan, NodeRef nodeRef, boolean isLinked); - - /** - * Links the newly created record to it's original location. - * - * @see #createRecord(NodeRef, NodeRef, boolean) - */ - void createRecord(NodeRef filePlan, NodeRef nodeRef); - - /** - * Creates a record from a copy of the node reference provided. - * - * @param filePlan file plan - * @param nodeRef node reference - */ - NodeRef createRecordFromCopy(NodeRef filePlan, NodeRef nodeRef); - - /** - * Creates a new document in the unfiled records container if the given node reference is a file plan - * node reference otherwise the node reference will be used as the destination for the new record. - * - * @param parent parent node reference - * @param name name of the new record - * @param type content type, cm:content if null - * @param properties properties - * @param reader content reader - */ - NodeRef createRecordFromContent(NodeRef parent, String name, QName type, Map properties, ContentReader reader); - - /** - * Indicates whether the record is filed or not - * - * @param nodeRef record - * @return boolean true if filed, false otherwise - */ - boolean isFiled(NodeRef record); - - /** - * 'File' a new document that arrived in the file plan structure. - * - * @param nodeRef record - */ - void file(NodeRef record); + * Gets a list of all the record meta-data aspects + * + * @return {@link Set}<{@link QName}> list of record meta-data aspects + * @deprecated since 2.2, file plan component required to provide context + */ + @Deprecated + Set getRecordMetaDataAspects(); /** - * Indicates whether all the mandatory metadata for the record is populated or not + * Indicates whether the provided aspect is a registered record meta-data + * aspect. * - * @param record record for which to check if all mandatory metadata is populated - * @return boolean true if all mandatory metadata is populated, false otherwise + * @param aspect aspect {@link QName} + * @return boolean true if the aspect is a registered record meta-data aspect, false otherwise + * @since 2.3 */ - boolean isMandatoryPropertiesPopulated(NodeRef record); + boolean isRecordMetadataAspect(QName aspect); /** - * Completes a record. + * Indicates whther the provided property is declared on a registered record + * meta-data aspect. * - * @param record record to be completed + * @param property property {@link QName} + * @return boolean true if the property is declared on a registered record meta-data aspect, + * false otherwise + * @since 2.3 */ - void complete(NodeRef record); + boolean isRecordMetadataProperty(QName property); - /** - * Rejects a record with the provided reason - * - * @param nodeRef The record which will be rejected - * @param reason The reason for rejection - */ - void rejectRecord(NodeRef nodeRef, String reason); + /** + * Gets a list of all the record metadata aspects relevant to the file plan type of the + * file plan component provided. + *

+ * If a null context is provided all record meta-data aspects are returned, but this is not + * recommended. + * + * @param nodeRef node reference to file plan component providing context + * @return {@link Set}<{@link QName}> list of record meta-data aspects + * @since 2.2 + */ + Set getRecordMetadataAspects(NodeRef nodeRef); - /** - * Indicates whether a property of a record is editable for the current user or not. - * - * @param record record - * @param property property - * @return boolean true if editable, false otherwise. - */ - boolean isPropertyEditable(NodeRef record, QName property); + /** + * Gets a list of all the record metadata aspect that relate to the provided file plan type. + *

+ * If null is provided for the file plan type then record metadata aspects for the default + * file plan type (rma:filePlan) are returned. + * + * @param filePlanType file plan type + * @return{@link Set}<{@link QName}> list of record meta-data aspects + * @since 2.2 + */ + Set getRecordMetadataAspects(QName filePlanType); - /** - * Indicates whether the given node (record or record folder) is a metadata stub or not. - * - * @param nodeRef node reference - * @return boolean true if a metadata stub, false otherwise - */ - boolean isMetadataStub(NodeRef nodeRef); + /** + * Checks whether if the given node reference is a record or not + * + * @param nodeRef node reference to be checked + * @return boolean true if the node reference is a record, false otherwise + */ + boolean isRecord(NodeRef nodeRef); - /** - * Gets a list of all the records within a record folder - * - * @param recordFolder record folder - * @return List list of records in the record folder - */ - List getRecords(NodeRef recordFolder); + /** + * Indicates whether the record is declared + * + * @param nodeRef node reference of the record for which the check would be performed + * @return boolean true if record is declared, false otherwise + */ + boolean isDeclared(NodeRef nodeRef); - /** - * Adds the specified type to the record - * - * @param nodeRef Record node reference - * @param typeQName Type to add - */ - void addRecordType(NodeRef nodeRef, QName typeQName); + /** + * Creates a new unfiled record from an existing node. + *

+ * Note that the node reference of the record will be the same as the original + * document. + * + * @param filePlan The filePlan in which the record should be placed. filePlan can be null in this case the default RM site will be used. + * @param nodeRef The node from which the record will be created + * @param isLinked indicates if the newly created record is linked to it's original location or not. + */ + void createRecord(NodeRef filePlan, NodeRef nodeRef, boolean isLinked); - /** - * Creates a record from the given document - * - * @param nodeRef The document node reference from which a record will be created - */ - void makeRecord(NodeRef nodeRef); + /** + * Links the newly created record to it's original location. + * + * @see #createRecord(NodeRef, NodeRef, boolean) + */ + void createRecord(NodeRef filePlan, NodeRef nodeRef); - /** - * Links a record to a record folder - * - * @param record the record to link - * @param recordFolder the record folder to link it to - */ - void link(NodeRef record, NodeRef recordFolder); + /** + * Creates a record from a copy of the node reference provided. + * + * @param filePlan file plan + * @param nodeRef node reference + */ + NodeRef createRecordFromCopy(NodeRef filePlan, NodeRef nodeRef); - /** - * Unlinks a record from a specified record folder. - * - * @param record the record to unlink - * @param recordFolder the record folder to unlink it from - * - * @since 2.3 - */ - void unlink(NodeRef record, NodeRef recordFolder); + /** + * Creates a new document in the unfiled records container if the given node reference is a file plan + * node reference otherwise the node reference will be used as the destination for the new record. + * + * @param parent parent node reference + * @param name name of the new record + * @param type content type, cm:content if null + * @param properties properties + * @param reader content reader + */ + NodeRef createRecordFromContent(NodeRef parent, String name, QName type, Map properties, ContentReader reader); + + /** + * Indicates whether the record is filed or not + * + * @param record Record node reference + * @return boolean true if filed, false otherwise + */ + boolean isFiled(NodeRef record); + + /** + * 'File' a new document that arrived in the file plan structure. + * + * @param record Record node reference + */ + void file(NodeRef record); + + /** + * Rejects a record with the provided reason + * + * @param nodeRef The record which will be rejected + * @param reason The reason for rejection + */ + void rejectRecord(NodeRef nodeRef, String reason); + + /** + * Indicates whether a property of a record is editable for the current user or not. + * + * @param record record + * @param property property + * @return boolean true if editable, false otherwise. + */ + boolean isPropertyEditable(NodeRef record, QName property); + + /** + * Indicates whether the given node (record or record folder) is a metadata stub or not. + * + * @param nodeRef node reference + * @return boolean true if a metadata stub, false otherwise + */ + boolean isMetadataStub(NodeRef nodeRef); + + /** + * Gets a list of all the records within a record folder + * + * @param recordFolder record folder + * @return List list of records in the record folder + */ + List getRecords(NodeRef recordFolder); + + /** + * Adds the specified type to the record + * + * @param nodeRef Record node reference + * @param typeQName Type to add + */ + void addRecordType(NodeRef nodeRef, QName typeQName); + + /** + * Creates a record from the given document + * + * @param nodeRef The document node reference from which a record will be created + */ + void makeRecord(NodeRef nodeRef); + + /** + * Links a record to a record folder + * + * @param record the record to link + * @param recordFolder the record folder to link it to + */ + void link(NodeRef record, NodeRef recordFolder); + + /** + * Unlinks a record from a specified record folder. + * + * @param record the record to unlink + * @param recordFolder the record folder to unlink it from + * @since 2.3 + */ + void unlink(NodeRef record, NodeRef recordFolder); + + /** + * Completes a record + * + * @param nodeRef Record node reference + */ + void complete(NodeRef nodeRef); } 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 040768700e..fc9b8af4b3 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 @@ -34,6 +34,7 @@ import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.TRANSACTI import static org.alfresco.repo.policy.annotation.BehaviourKind.ASSOCIATION; import java.io.Serializable; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -62,6 +63,7 @@ import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedul import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; import org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; +import org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService; import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel; @@ -82,9 +84,9 @@ import org.alfresco.repo.content.ContentServicePolicies; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.integrity.IncompleteNodeTagger; import org.alfresco.repo.node.integrity.IntegrityException; +import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.ClassPolicyDelegate; import org.alfresco.repo.policy.PolicyComponent; -import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourKind; @@ -134,42 +136,63 @@ import org.springframework.extensions.surf.util.I18NUtil; */ @BehaviourBean public class RecordServiceImpl extends BaseBehaviourBean - implements RecordService, - RecordsManagementModel, - RecordsManagementCustomModel, - NodeServicePolicies.OnAddAspectPolicy, - NodeServicePolicies.OnCreateChildAssociationPolicy, - NodeServicePolicies.OnRemoveAspectPolicy, - NodeServicePolicies.OnUpdatePropertiesPolicy, - ContentServicePolicies.OnContentUpdatePolicy + implements RecordService, + RecordsManagementModel, + RecordsManagementCustomModel, + NodeServicePolicies.OnAddAspectPolicy, + NodeServicePolicies.OnCreateChildAssociationPolicy, + NodeServicePolicies.OnRemoveAspectPolicy, + NodeServicePolicies.OnUpdatePropertiesPolicy, + ContentServicePolicies.OnContentUpdatePolicy { - /** Logger */ + /** + * Logger + */ private static final Logger LOGGER = LoggerFactory.getLogger(RecordServiceImpl.class); - /** Sync Model URI */ + /** + * Sync Model URI + */ private static final String SYNC_MODEL_1_0_URI = "http://www.alfresco.org/model/sync/1.0"; - /** Synced aspect */ + /** + * Synced aspect + */ private static final QName ASPECT_SYNCED = QName.createQName(SYNC_MODEL_1_0_URI, "synced"); - /** transation data key */ + /** + * transation data key + */ private static final String KEY_IGNORE_ON_UPDATE = "ignoreOnUpdate"; public static final String KEY_NEW_RECORDS = "newRecords"; - /** I18N */ + /** + * I18N + */ private static final String MSG_NODE_HAS_ASPECT = "rm.service.node-has-aspect"; private static final String FINAL_VERSION = "rm.service.final-version"; private static final String FINAL_DESCRIPTION = "rm.service.final-version-description"; + private static final String MSG_UNDECLARED_ONLY_RECORDS = "rm.action.undeclared-only-records"; + private static final String MSG_NO_DECLARE_MAND_PROP = "rm.action.no-declare-mand-prop"; - /** Always edit property array */ + /** + * Always edit property array + */ private static final QName[] ALWAYS_EDIT_PROPERTIES = new QName[] - { - ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA - }; + { + ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA + }; - /** always edit model URI's */ + /** + * always edit model URI's + */ private List alwaysEditURIs; + /** + * check mandatory properties + */ + private boolean checkMandatoryPropertiesEnabled = true; + /** * @param alwaysEditURIs the alwaysEditURIs to set */ @@ -186,86 +209,140 @@ public class RecordServiceImpl extends BaseBehaviourBean return this.alwaysEditURIs; } - /** record model URI's */ + /** + * record model URI's + */ public static final List RECORD_MODEL_URIS = Collections.unmodifiableList( - Arrays.asList( - RM_URI, - RM_CUSTOM_URI, - ReportModel.RMR_URI, - RecordableVersionModel.RMV_URI, - DOD5015Model.DOD_URI - )); + Arrays.asList( + RM_URI, + RM_CUSTOM_URI, + ReportModel.RMR_URI, + RecordableVersionModel.RMV_URI, + DOD5015Model.DOD_URI + )); - /** non-record model URI's */ + /** + * non-record model URI's + */ private static final String[] NON_RECORD_MODEL_URIS = new String[] - { - NamespaceService.AUDIO_MODEL_1_0_URI, - NamespaceService.CONTENT_MODEL_1_0_URI, - NamespaceService.EMAILSERVER_MODEL_URI, - NamespaceService.EXIF_MODEL_1_0_URI, - NamespaceService.FORUMS_MODEL_1_0_URI, - NamespaceService.LINKS_MODEL_1_0_URI, - NamespaceService.REPOSITORY_VIEW_1_0_URI - }; + { + NamespaceService.AUDIO_MODEL_1_0_URI, + NamespaceService.CONTENT_MODEL_1_0_URI, + NamespaceService.EMAILSERVER_MODEL_URI, + NamespaceService.EXIF_MODEL_1_0_URI, + NamespaceService.FORUMS_MODEL_1_0_URI, + NamespaceService.LINKS_MODEL_1_0_URI, + NamespaceService.REPOSITORY_VIEW_1_0_URI + }; - /** Indentity service */ + /** + * Indentity service + */ private IdentifierService identifierService; - /** Extended permission service */ + /** + * Extended permission service + */ private ExtendedPermissionService extendedPermissionService; - /** Extended security service */ + /** + * Extended security service + */ private ExtendedSecurityService extendedSecurityService; - /** File plan service */ + /** + * File plan service + */ private FilePlanService filePlanService; - /** Records management notification helper */ + /** + * Records management notification helper + */ private RecordsManagementNotificationHelper notificationHelper; - /** Policy component */ + /** + * Policy component + */ private PolicyComponent policyComponent; - /** Ownable service */ + /** + * Ownable service + */ private OwnableService ownableService; - /** Capability service */ + /** + * Capability service + */ private CapabilityService capabilityService; - /** Rule service */ + /** + * Rule service + */ private RuleService ruleService; - /** File folder service */ + /** + * File folder service + */ private FileFolderService fileFolderService; - /** Record folder service */ + /** + * Record folder service + */ private RecordFolderService recordFolderService; - /** File plan role service */ + /** + * File plan role service + */ private FilePlanRoleService filePlanRoleService; - /** Permission service */ + /** + * Permission service + */ private PermissionService permissionService; - /** Version service */ + /** + * Version service + */ private VersionService versionService; - /** Relationship service */ + /** + * Relationship service + */ private RelationshipService relationshipService; - /** Disposition service */ + /** + * Disposition service + */ private DispositionService dispositionService; - /** records management container type */ + /** + * records management container type + */ private RecordsManagementContainerType recordsManagementContainerType; - /** recordable version service */ + /** + * recordable version service + */ private RecordableVersionService recordableVersionService; - /** list of available record meta-data aspects and the file plan types the are applicable to */ + /** + * list of available record meta-data aspects and the file plan types the are applicable to + */ private Map> recordMetaDataAspects; - /** policies */ + /** + * Freeze service + */ + private FreezeService freezeService; + + /** + * Namespace service + */ + private NamespaceService namespaceService; + + /** + * policies + */ private ClassPolicyDelegate beforeFileRecord; private ClassPolicyDelegate onFileRecord; private ClassPolicyDelegate beforeRecordDeclarationDelegate; @@ -292,7 +369,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param extendedSecurityService extended security service + * @param extendedSecurityService extended security service */ public void setExtendedSecurityService(ExtendedSecurityService extendedSecurityService) { @@ -300,7 +377,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param filePlanService file plan service + * @param filePlanService file plan service */ public void setFilePlanService(FilePlanService filePlanService) { @@ -316,7 +393,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param policyComponent policy component + * @param policyComponent policy component */ public void setPolicyComponent(PolicyComponent policyComponent) { @@ -324,7 +401,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param ownableService ownable service + * @param ownableService ownable service */ public void setOwnableService(OwnableService ownableService) { @@ -340,7 +417,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param ruleService rule service + * @param ruleService rule service */ public void setRuleService(RuleService ruleService) { @@ -388,7 +465,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param relationshipService relationship service + * @param relationshipService relationship service */ public void setRelationshipService(RelationshipService relationshipService) { @@ -396,7 +473,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param dispositionService disposition service + * @param dispositionService disposition service */ public void setDispositionService(DispositionService dispositionService) { @@ -404,7 +481,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param recordsManagementContainerType records management container type + * @param recordsManagementContainerType records management container type */ public void setRecordsManagementContainerType(RecordsManagementContainerType recordsManagementContainerType) { @@ -412,7 +489,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param recordableVersionService recordable version service + * @param recordableVersionService recordable version service */ public void setRecordableVersionService(RecordableVersionService recordableVersionService) { @@ -424,6 +501,30 @@ public class RecordServiceImpl extends BaseBehaviourBean this.incompleteNodeTagger = incompleteNodeTagger; } + /** + * @param freezeService freeze service + */ + public void setFreezeService(FreezeService freezeService) + { + this.freezeService = freezeService; + } + + /** + * @param namespaceService namespace service + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * @param checkMandatoryPropertiesEnabled true if check mandatory properties is enabled, false otherwise + */ + public void setCheckMandatoryPropertiesEnabled(boolean checkMandatoryPropertiesEnabled) + { + this.checkMandatoryPropertiesEnabled = checkMandatoryPropertiesEnabled; + } + /** * Init method */ @@ -443,11 +544,11 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - kind = BehaviourKind.CLASS, - type = "rma:record", - notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT - ) + ( + kind = BehaviourKind.CLASS, + type = "rma:record", + notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT + ) public void onAddAspect(NodeRef nodeRef, QName aspect) { authenticationUtil.runAsSystem(new RunAsWork() @@ -470,10 +571,10 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - kind = BehaviourKind.CLASS, - type = "sys:noContent" - ) + ( + kind = BehaviourKind.CLASS, + type = "sys:noContent" + ) public void onRemoveAspect(NodeRef nodeRef, QName aspect) { if (nodeService.hasAspect(nodeRef, ASPECT_RECORD)) @@ -494,11 +595,11 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - kind = ASSOCIATION, - type = "rma:recordFolder", - notificationFrequency = FIRST_EVENT - ) + ( + kind = ASSOCIATION, + type = "rma:recordFolder", + notificationFrequency = FIRST_EVENT + ) public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, final boolean bNew) { AuthenticationUtil.runAs(new RunAsWork() @@ -509,10 +610,10 @@ public class RecordServiceImpl extends BaseBehaviourBean try { NodeRef nodeRef = childAssocRef.getChildRef(); - if (nodeService.exists(nodeRef) && - !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY) && - !nodeService.getType(nodeRef).equals(TYPE_RECORD_FOLDER) && - !nodeService.getType(nodeRef).equals(TYPE_RECORD_CATEGORY)) + if (nodeService.exists(nodeRef) && + !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY) && + !nodeService.getType(nodeRef).equals(TYPE_RECORD_FOLDER) && + !nodeService.getType(nodeRef).equals(TYPE_RECORD_CATEGORY)) { // store information about the 'new' record in the transaction // @since 2.3 @@ -521,8 +622,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { Set newRecords = transactionalResourceHelper.getSet(KEY_NEW_RECORDS); newRecords.add(nodeRef); - } - else + } else { // if we are linking a record NodeRef parentNodeRef = childAssocRef.getParentRef(); @@ -538,13 +638,11 @@ public class RecordServiceImpl extends BaseBehaviourBean // recalculate disposition schedule for the record when linking it dispositionService.recalculateNextDispositionStep(nodeRef); } - } - catch (RecordLinkRuntimeException e) + } catch (RecordLinkRuntimeException e) { // rethrow exception throw e; - } - catch (AlfrescoRuntimeException e) + } catch (AlfrescoRuntimeException e) { // do nothing but log error LOGGER.warn("Unable to file pending record.", e); @@ -597,18 +695,18 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - name = "onUpdateProperties", - kind = BehaviourKind.CLASS, - type= "rma:record" - ) + ( + name = "onUpdateProperties", + kind = BehaviourKind.CLASS, + type = "rma:record" + ) public void onUpdateProperties(final NodeRef nodeRef, final Map before, final Map after) { if (AuthenticationUtil.getFullyAuthenticatedUser() != null && - !AuthenticationUtil.isRunAsUserTheSystemUser() && - nodeService.exists(nodeRef) && - isRecord(nodeRef) && - !transactionalResourceHelper.getSet(KEY_IGNORE_ON_UPDATE).contains(nodeRef)) + !AuthenticationUtil.isRunAsUserTheSystemUser() && + nodeService.exists(nodeRef) && + isRecord(nodeRef) && + !transactionalResourceHelper.getSet(KEY_IGNORE_ON_UPDATE).contains(nodeRef)) { for (Map.Entry entry : after.entrySet()) { @@ -626,34 +724,32 @@ public class RecordServiceImpl extends BaseBehaviourBean // deal with date values, remove the seconds and milliseconds for the // comparison as they are removed from the submitted for data Calendar beforeCal = Calendar.getInstance(); - beforeCal.setTime((Date)beforeValue); + beforeCal.setTime((Date) beforeValue); Calendar afterCal = Calendar.getInstance(); - afterCal.setTime((Date)afterValue); + afterCal.setTime((Date) afterValue); beforeCal.set(Calendar.SECOND, 0); beforeCal.set(Calendar.MILLISECOND, 0); afterCal.set(Calendar.SECOND, 0); afterCal.set(Calendar.MILLISECOND, 0); propertyUnchanged = (beforeCal.compareTo(afterCal) == 0); - } - else if ((afterValue instanceof Boolean) && (beforeValue == null) && (afterValue.equals(Boolean.FALSE))) + } else if ((afterValue instanceof Boolean) && (beforeValue == null) && (afterValue.equals(Boolean.FALSE))) { propertyUnchanged = true; - } - else + } else { // otherwise propertyUnchanged = EqualsHelper.nullSafeEquals(beforeValue, afterValue); } if (!propertyUnchanged && - !(ContentModel.PROP_CONTENT.equals(property) && beforeValue == null) && - !isPropertyEditable(nodeRef, property)) + !(ContentModel.PROP_CONTENT.equals(property) && beforeValue == null) && + !isPropertyEditable(nodeRef, property)) { // the user can't edit the record property throw new ModelAccessDeniedException( "The user " + AuthenticationUtil.getFullyAuthenticatedUser() + - " does not have the permission to edit the record property " + property.toString() + - " on the node " + nodeRef.toString()); + " does not have the permission to edit the record property " + property.toString() + + " on the node " + nodeRef.toString()); } } } @@ -662,8 +758,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Get map containing record metadata aspects. * - * @return {@link Map}<{@link QName}, {@link Set}<{@link QName}>> map containing record metadata aspects - * + * @return {@link Map}<{@link QName}, {@link Set}<{@link QName}>> map containing record metadata aspects * @since 2.2 */ protected Map> getRecordMetadataAspectsMap() @@ -721,8 +816,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { // get the current set of file plan types for this aspect filePlanTypes = getRecordMetadataAspectsMap().get(recordMetadataAspect); - } - else + } else { // create a new set for the file plan type filePlanTypes = new HashSet(1); @@ -744,7 +838,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isRecordMetadataAspect(org.alfresco.service.namespace.QName) + * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isRecordMetadataAspect(org.alfresco.service.namespace.QName) */ @Override public boolean isRecordMetadataAspect(QName aspect) @@ -764,7 +858,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { ClassDefinition classDefinition = propertyDefinition.getContainerClass(); if (classDefinition != null && - getRecordMetadataAspectsMap().containsKey(classDefinition.getName())) + getRecordMetadataAspectsMap().containsKey(classDefinition.getName())) { result = true; } @@ -867,8 +961,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { // move the document into the file plan nodeService.moveNode(nodeRef, newRecordContainer, ContentModel.ASSOC_CONTAINS, parentAssoc.getQName()); - } - finally + } finally { behaviourFilter.enableBehaviour(); } @@ -907,14 +1000,12 @@ public class RecordServiceImpl extends BaseBehaviourBean // set the extended security extendedSecurityService.set(nodeRef, readersAndWriters); - } - finally + } finally { ruleService.enableRules(); } } - } - finally + } finally { ruleService.enableRuleType("outbound"); } @@ -955,8 +1046,7 @@ public class RecordServiceImpl extends BaseBehaviourBean LOGGER.debug(msg); throw new RecordCreationException(msg); } - } - else + } else { // verify that the provided file plan is actually a file plan if (!filePlanService.isFilePlan(filePlan)) @@ -1072,8 +1162,7 @@ public class RecordServiceImpl extends BaseBehaviourBean // create a copy of the original state and add it to the unfiled record container FileInfo recordInfo = fileFolderService.copy(nodeRef, unfiledRecordFolder, null); record = recordInfo.getNodeRef(); - } - finally + } finally { recordsManagementContainerType.enable(); } @@ -1084,8 +1173,7 @@ public class RecordServiceImpl extends BaseBehaviourBean try { nodeService.removeAspect(record, ContentModel.ASPECT_VERSIONABLE); - } - finally + } finally { behaviourFilter.enableBehaviour(ContentModel.ASPECT_VERSIONABLE); } @@ -1108,16 +1196,14 @@ public class RecordServiceImpl extends BaseBehaviourBean if (originalAssocs == null) { nodeService.removeAspect(record, ContentModel.ASPECT_COPIEDFROM); - } - else + } else { for (AssociationRef originalAssoc : originalAssocs) { nodeService.createAssociation(record, originalAssoc.getTargetRef(), ContentModel.ASSOC_ORIGINAL); } } - } - catch (FileNotFoundException e) + } catch (FileNotFoundException e) { throw new AlfrescoRuntimeException("Can't create recorded version, because copy fails.", e); } @@ -1133,7 +1219,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Helper to get the latest version record for a given document (ie non-record) * - * @param nodeRef node reference + * @param nodeRef node reference * @return NodeRef latest version record, null otherwise */ private NodeRef getLatestVersionRecord(NodeRef nodeRef) @@ -1188,8 +1274,7 @@ public class RecordServiceImpl extends BaseBehaviourBean if (type == null) { type = ContentModel.TYPE_CONTENT; - } - else if (!dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) + } else if (!dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) { throw new AlfrescoRuntimeException("Record can only be created from a sub-type of cm:content."); } @@ -1234,8 +1319,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } }); - } - finally + } finally { enablePropertyEditableCheck(); } @@ -1260,7 +1344,7 @@ public class RecordServiceImpl extends BaseBehaviourBean authenticationUtil.runAsSystem(new RunAsWork() { @Override - public Void doWork() throws Exception + public Void doWork() throws Exception { nodeService.addAspect(document, RecordsManagementModel.ASPECT_RECORD, null); @@ -1273,8 +1357,7 @@ public class RecordServiceImpl extends BaseBehaviourBean return null; } }); - } - finally + } finally { ruleService.enableRules(); enablePropertyEditableCheck(); @@ -1308,9 +1391,9 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Helper method to 'file' a new document that arrived in the file plan structure. - * - * TODO atm we only 'file' content as a record .. may need to consider other types if we - * are to support the notion of composite records. + *

+ * TODO atm we only 'file' content as a record .. may need to consider other types if we + * are to support the notion of composite records. * * @param record node reference to record (or soon to be record!) */ @@ -1322,8 +1405,8 @@ public class RecordServiceImpl extends BaseBehaviourBean // we only support filling of content items // TODO composite record support needs to file containers too QName type = nodeService.getType(record); - if (ContentModel.TYPE_CONTENT.equals(type) || - dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) + if (ContentModel.TYPE_CONTENT.equals(type) || + dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) { // fire before file record policy beforeFileRecord.get(getTypeAndApsects(record)).beforeFileRecord(record); @@ -1347,94 +1430,6 @@ public class RecordServiceImpl extends BaseBehaviourBean } } - /** - * Helper method to 'complete' a record. - * - * @param record node reference to record - */ - public void complete(NodeRef record) - { - ParameterCheck.mandatory("item", record); - - // TODO get this from config - boolean checkMandatoryPropertiesEnabled = true; - - if (!checkMandatoryPropertiesEnabled || (isMandatoryPropertiesPopulated(record))) - { - disablePropertyEditableCheck(); - // Add the declared aspect - Map declaredProps = new HashMap<>(2); - declaredProps.put(RecordsManagementModel.PROP_DECLARED_AT, new Date()); - declaredProps.put(RecordsManagementModel.PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); - nodeService.addAspect(record, RecordsManagementModel.ASPECT_DECLARED_RECORD, declaredProps); - enablePropertyEditableCheck(); - } - } - - /** - * Helper method to determine whether a record's mandatory properties are set. - * - * @param nodeRef node reference to record - * @return boolean true if all mandatory metadata properties are set, false otherwise - */ - public boolean isMandatoryPropertiesPopulated(NodeRef nodeRef) - { - boolean result = true; - - // check for missing mandatory metadata from type definitions - Map nodeRefProps = nodeService.getProperties(nodeRef); - QName nodeRefType = nodeService.getType(nodeRef); - - TypeDefinition typeDef = dictionaryService.getType(nodeRefType); - for (PropertyDefinition propDef : typeDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - result = false; - break; - } - } - - // check for missing mandatory metadata from aspect definitions - if (result) - { - // TODO change to aspects = getAspects(nodeRef) ? - Set aspects = nodeService.getAspects(nodeRef); - for (QName aspect : aspects) - { - AspectDefinition aspectDef = dictionaryService.getAspect(aspect); - for (PropertyDefinition propDef : aspectDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - result = false; - break; - } - } - } - } - - // check for missing mandatory metadata from custom aspect definitions - if (result) - { - Collection aspects = dictionaryService.getAspects(RM_CUSTOM_MODEL); - for (QName aspect : aspects) - { - AspectDefinition aspectDef = dictionaryService.getAspect(aspect); - for (PropertyDefinition propDef : aspectDef.getProperties().values()) - { - if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) - { - result = false; - break; - } - } - } - } - - return result; - } - /** * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#rejectRecord(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) */ @@ -1469,10 +1464,10 @@ public class RecordServiceImpl extends BaseBehaviourBean // get record property values final Map properties = nodeService.getProperties(nodeRef); - final String recordId = (String)properties.get(PROP_IDENTIFIER); - final String documentOwner = (String)properties.get(PROP_RECORD_ORIGINATING_USER_ID); - final String originalName = (String)properties.get(PROP_ORIGIONAL_NAME); - final NodeRef originatingLocation = (NodeRef)properties.get(PROP_RECORD_ORIGINATING_LOCATION); + final String recordId = (String) properties.get(PROP_IDENTIFIER); + final String documentOwner = (String) properties.get(PROP_RECORD_ORIGINATING_USER_ID); + final String originalName = (String) properties.get(PROP_ORIGIONAL_NAME); + final NodeRef originatingLocation = (NodeRef) properties.get(PROP_RECORD_ORIGINATING_LOCATION); // we can only reject if the originating location is present if (originatingLocation != null) @@ -1501,7 +1496,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { fileFolderService.rename(nodeRef, originalName); - String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); + String name = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); LOGGER.debug("Rename {} to {}", name, originalName); } @@ -1528,8 +1523,7 @@ public class RecordServiceImpl extends BaseBehaviourBean // send an email to the record creator notificationHelper.recordRejectedEmailNotification(nodeRef, recordId, documentOwner); } - } - finally + } finally { ruleService.enableRules(); } @@ -1546,7 +1540,7 @@ public class RecordServiceImpl extends BaseBehaviourBean for (QName aspect : aspects) { if (RM_URI.equals(aspect.getNamespaceURI()) || - RecordableVersionModel.RMV_URI.equals(aspect.getNamespaceURI())) + RecordableVersionModel.RMV_URI.equals(aspect.getNamespaceURI())) { nodeService.removeAspect(nodeRef, aspect); } @@ -1557,7 +1551,7 @@ public class RecordServiceImpl extends BaseBehaviourBean // Do not attempt to clean up rendition nodes which are not children of their source node. final boolean renditionRequiresCleaning = nodeService.exists(renditionNode) && - renditionAssoc.isPrimary(); + renditionAssoc.isPrimary(); if (renditionRequiresCleaning) { @@ -1613,7 +1607,7 @@ public class RecordServiceImpl extends BaseBehaviourBean for (AccessPermission perm : perms) { if ((perm.getPermission().contains(RMPermissionModel.EDIT_NON_RECORD_METADATA) || - perm.getPermission().contains(RMPermissionModel.EDIT_RECORD_METADATA))) + perm.getPermission().contains(RMPermissionModel.EDIT_RECORD_METADATA))) { LOGGER.debug(" ... " + perm.getAuthority() + " - " + perm.getPermission() + " - " + perm.getAccessStatus().toString()); } @@ -1630,8 +1624,7 @@ public class RecordServiceImpl extends BaseBehaviourBean if (result) { LOGGER.debug(" ... property marked as always editable."); - } - else + } else { boolean allowRecordEdit = false; boolean allowNonRecordEdit = false; @@ -1646,8 +1639,8 @@ public class RecordServiceImpl extends BaseBehaviourBean allowNonRecordEdit = true; } - if (AccessStatus.ALLOWED.equals(accessRecord) || - AccessStatus.ALLOWED.equals(accessDeclaredRecord)) + if (AccessStatus.ALLOWED.equals(accessRecord) || + AccessStatus.ALLOWED.equals(accessDeclaredRecord)) { LOGGER.debug(" ... user has edit record or declared metadata capability"); allowRecordEdit = true; @@ -1657,29 +1650,25 @@ public class RecordServiceImpl extends BaseBehaviourBean { LOGGER.debug(" ... so all properties can be edited."); result = true; - } - else if (allowNonRecordEdit && !allowRecordEdit) + } else if (allowNonRecordEdit && !allowRecordEdit) { // can only edit non record properties if (!isRecordMetadata(filePlan, property)) { LOGGER.debug(" ... property is not considered record metadata so editable."); result = true; - } - else + } else { LOGGER.debug(" ... property is considered record metadata so not editable."); } - } - else if (!allowNonRecordEdit && allowRecordEdit) + } else if (!allowNonRecordEdit && allowRecordEdit) { // can only edit record properties if (isRecordMetadata(filePlan, property)) { LOGGER.debug(" ... property is considered record metadata so editable."); result = true; - } - else + } else { LOGGER.debug(" ... property is not considered record metadata so not editable."); } @@ -1692,7 +1681,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Helper method that indicates whether a property is considered record metadata or not. * - * @param property property + * @param property property * @return boolea true if record metadata, false otherwise */ private boolean isRecordMetadata(NodeRef filePlan, QName property) @@ -1712,8 +1701,7 @@ public class RecordServiceImpl extends BaseBehaviourBean if (parent != null && TYPE_NON_ELECTRONIC_DOCUMENT.equals(parent.getName())) { result = false; - } - else + } else { // check the URI's result = RECORD_MODEL_URIS.contains(property.getNamespaceURI()); @@ -1748,7 +1736,7 @@ public class RecordServiceImpl extends BaseBehaviourBean * Helper method to determine whether a property is protected at a dictionary definition * level. * - * @param property property qualified name + * @param property property qualified name * @return booelan true if protected, false otherwise */ private boolean isProtectedProperty(QName property) @@ -1808,8 +1796,7 @@ public class RecordServiceImpl extends BaseBehaviourBean if (!nodeService.hasAspect(nodeRef, typeQName)) { nodeService.addAspect(nodeRef, typeQName, null); - } - else + } else { LOGGER.info(I18NUtil.getMessage(MSG_NODE_HAS_ASPECT, nodeRef.toString(), typeQName.toString())); } @@ -1825,7 +1812,7 @@ public class RecordServiceImpl extends BaseBehaviourBean ParameterCheck.mandatory("recordFolder", recordFolder); // ensure we are linking a record to a record folder - if(isRecord(record) && isRecordFolder(recordFolder)) + if (isRecord(record) && isRecordFolder(recordFolder)) { // ensure that we are not linking a record to an existing location List parents = nodeService.getParentAssocs(record); @@ -1846,15 +1833,14 @@ public class RecordServiceImpl extends BaseBehaviourBean // create a secondary link to the record folder nodeService.addChild( - recordFolder, - record, - ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name)); + recordFolder, + record, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name)); // recalculate disposition schedule for the record when linking it dispositionService.recalculateNextDispositionStep(record); - } - else + } else { // can only link a record to a record folder throw new RecordLinkRuntimeException("Can only link a record to a record folder."); @@ -1862,7 +1848,6 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * * @param record * @param recordFolder */ @@ -1882,7 +1867,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { // we can't link a record to an incompatible disposition schedule throw new RecordLinkRuntimeException("Cannot link a record to a record folder with an incompatible retention schedule. " - + "They must either both be record level or record folder level retentions."); + + "They must either both be record level or record folder level retentions."); } } } @@ -1898,7 +1883,7 @@ public class RecordServiceImpl extends BaseBehaviourBean ParameterCheck.mandatory("recordFolder", recordFolder); // ensure we are unlinking a record from a record folder - if(isRecord(record) && isRecordFolder(recordFolder)) + if (isRecord(record) && isRecordFolder(recordFolder)) { // check that we are not trying to unlink the primary parent NodeRef primaryParent = nodeService.getPrimaryParent(record).getParentRef(); @@ -1912,8 +1897,7 @@ public class RecordServiceImpl extends BaseBehaviourBean // recalculate disposition schedule for record after unlinking it dispositionService.recalculateNextDispositionStep(record); - } - else + } else { // can only unlink a record from a record folder throw new RecordLinkRuntimeException("Can only unlink a record from a record folder."); @@ -1925,11 +1909,11 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - kind = BehaviourKind.CLASS, - type = "rma:record", - notificationFrequency = TRANSACTION_COMMIT - ) + ( + kind = BehaviourKind.CLASS, + type = "rma:record", + notificationFrequency = TRANSACTION_COMMIT + ) public void onContentUpdate(NodeRef nodeRef, boolean newContent) { if (nodeService.exists(nodeRef) && !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN) && !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE)) @@ -1942,7 +1926,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Invoke invokeBeforeRecordDeclaration policy * - * @param nodeRef node reference + * @param nodeRef node reference */ protected void invokeBeforeRecordDeclaration(NodeRef nodeRef) { @@ -1956,7 +1940,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Invoke invokeOnRecordDeclaration policy * - * @param nodeRef node reference + * @param nodeRef node reference */ protected void invokeOnRecordDeclaration(NodeRef nodeRef) { @@ -1970,7 +1954,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Invoke invokeBeforeRecordRejection policy * - * @param nodeRef node reference + * @param nodeRef node reference */ protected void invokeBeforeRecordRejection(NodeRef nodeRef) { @@ -1984,7 +1968,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Invoke invokeOnRecordRejection policy * - * @param nodeRef node reference + * @param nodeRef node reference */ protected void invokeOnRecordRejection(NodeRef nodeRef) { @@ -1997,19 +1981,185 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * RM-5244 - workaround to make sure the incomplete aspect is removed - * + * * @param nodeRef the node to reevaluate for */ private void reevaluateIncompleteTag(NodeRef nodeRef) { /* * Check if the node has the aspect because the reevaluation is expensive. - * If the node doesn't have the aspect it means IncompleteNodeTagger didn't load before TransactionBehaviourQueue + * If the node doesn't have the aspect it means IncompleteNodeTagger didn't load before TransactionBehaviourQueue * and we don't need to reevaluate. */ - if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_INCOMPLETE)) + if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_INCOMPLETE)) { incompleteNodeTagger.beforeCommit(false); } } + + /** + * Completes a record + * + * @param nodeRef Record node reference + */ + @Override + public void complete(NodeRef nodeRef) + { + if (nodeService.exists(nodeRef) && isRecord(nodeRef) && !freezeService.isFrozen(nodeRef)) + { + if (!isDeclared(nodeRef)) + { + // if the record is newly created make sure the record identifier is set before completing the record + Set newRecords = transactionalResourceHelper.getSet(RecordServiceImpl.KEY_NEW_RECORDS); + if (newRecords.contains(nodeRef)) + { + generateRecordIdentifier(nodeService, identifierService, nodeRef); + } + + List missingProperties = new ArrayList<>(5); + // Aspect not already defined - check mandatory properties then add + if (!checkMandatoryPropertiesEnabled || mandatoryPropertiesSet(nodeRef, missingProperties)) + { + disablePropertyEditableCheck(); + try + { + // Add the declared aspect + Map declaredProps = new HashMap<>(2); + declaredProps.put(PROP_DECLARED_AT, new Date()); + declaredProps.put(PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser()); + nodeService.addAspect(nodeRef, ASPECT_DECLARED_RECORD, declaredProps); + + AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() + { + // remove all owner related rights + ownableService.setOwner(nodeRef, OwnableService.NO_OWNER); + return null; + } + }); + } finally + { + enablePropertyEditableCheck(); + } + } else + { + LOGGER.debug(buildMissingPropertiesErrorString(missingProperties)); + throw new IntegrityException("The record has missing mandatory properties.", null); + } + } else + { + throw new IntegrityException("The record is already completed.", null); + } + } else + { + if (LOGGER.isWarnEnabled()) + { + LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString())); + } + throw new IntegrityException("The record does not exist or is frozen.", null); + } + } + + private String buildMissingPropertiesErrorString(List missingProperties) + { + StringBuilder builder = new StringBuilder(255); + builder.append(I18NUtil.getMessage(MSG_NO_DECLARE_MAND_PROP)); + builder.append(" "); + for (String missingProperty : missingProperties) + { + builder.append(missingProperty).append(", "); + } + return builder.toString(); + } + + /** + * Helper method to check whether all the mandatory properties of the node have been set + * + * @param nodeRef node reference + * @return boolean true if all mandatory properties are set, false otherwise + */ + private boolean mandatoryPropertiesSet(final NodeRef nodeRef, final List missingProperties) + { + Map nodeRefProps = nodeService.getProperties(nodeRef); + QName nodeRefType = nodeService.getType(nodeRef); + + // check for missing mandatory metadata from type definitions + TypeDefinition typeDef = dictionaryService.getType(nodeRefType); + checkDefinitionMandatoryPropsSet(typeDef, nodeRefProps, missingProperties); + + // check for missing mandatory metadata from aspect definitions + Set aspects = nodeService.getAspects(nodeRef); + for (QName aspect : aspects) + { + AspectDefinition aspectDef = dictionaryService.getAspect(aspect); + checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties); + } + + // check for missing mandatory metadata from custom aspect definitions + QName customAspect = getCustomAspectImpl(nodeRefType); + AspectDefinition aspectDef = dictionaryService.getAspect(customAspect); + checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties); + + return missingProperties.isEmpty(); + } + + /** + * Helper method to check whether all the definition mandatory properties of the node have been set + * + * @param classDef the ClassDefinition defining the properties to be checked + * @param nodeRefProps the properties of the node to be checked + * @param missingProperties the list of mandatory properties found to be missing (currently only the first one) + * @return boolean true if all mandatory properties are set, false otherwise + */ + private void checkDefinitionMandatoryPropsSet(final ClassDefinition classDef, final Map nodeRefProps, + final List missingProperties) + { + for (PropertyDefinition propDef : classDef.getProperties().values()) + { + if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null) + { + logMissingProperty(propDef, missingProperties); + ; + } + } + } + + /** + * Log information about missing properties. + * + * @param propDef property definition + * @param missingProperties missing properties + */ + private void logMissingProperty(PropertyDefinition propDef, List missingProperties) + { + if (LOGGER.isWarnEnabled()) + { + StringBuilder msg = new StringBuilder(); + msg.append("Mandatory property missing: ").append(propDef.getName()); + LOGGER.warn(msg.toString()); + } + missingProperties.add(propDef.getName().toString()); + } + + /** + * Helper method to get the custom aspect for a given nodeRef type + * + * @param nodeRefType the node type for which to return custom aspect QName + * @return QName custom aspect + */ + private QName getCustomAspectImpl(QName nodeRefType) + { + QName aspect = ASPECT_RECORD; + if (nodeRefType.equals(TYPE_NON_ELECTRONIC_DOCUMENT)) + { + aspect = TYPE_NON_ELECTRONIC_DOCUMENT; + } + + // get customAspectImpl + String localName = aspect.toPrefixString(namespaceService).replace(":", ""); + localName = MessageFormat.format("{0}CustomProperties", localName); + return QName.createQName(RM_CUSTOM_URI, localName); + } } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java index b73ecc6f78..7642f101bb 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CompleteRecordTest.java @@ -32,8 +32,8 @@ import java.util.HashMap; import java.util.Map; import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionResult; -import org.alfresco.module.org_alfresco_module_rm.action.impl.DeclareRecordAction; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel; +import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; @@ -55,9 +55,9 @@ public class CompleteRecordTest extends BaseRMTestCase private static final boolean OPTIONAL_METADATA = false; /** - * complete record action + * Record service impl */ - private DeclareRecordAction action; + private RecordServiceImpl recordServiceImpl; /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#initServices() @@ -67,8 +67,8 @@ public class CompleteRecordTest extends BaseRMTestCase { super.initServices(); - // get the action - action = (DeclareRecordAction) applicationContext.getBean("declareRecord"); + // get the record service + recordServiceImpl = (RecordServiceImpl) applicationContext.getBean("recordService"); } /** @@ -80,7 +80,7 @@ public class CompleteRecordTest extends BaseRMTestCase super.tearDownImpl(); // ensure action is returned to original state - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); } /** @@ -100,7 +100,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); @@ -140,7 +140,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); @@ -183,7 +183,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that has a mandatory property) for electronic records defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, MANDATORY_METADATA); @@ -229,7 +229,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // define the custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, MANDATORY_METADATA); @@ -279,7 +279,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that has a mandatory property) for non-electronic records defineCustomMetadata(CUSTOM_NON_ELECTRONIC_TEST, TYPE_NON_ELECTRONIC_DOCUMENT, MANDATORY_METADATA); @@ -326,7 +326,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_NON_ELECTRONIC_TEST, TYPE_NON_ELECTRONIC_DOCUMENT, MANDATORY_METADATA); @@ -375,7 +375,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the custom metadata definition (that does not have a mandatory property) defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, OPTIONAL_METADATA); @@ -422,7 +422,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the record custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_ELECTRONIC_TEST, ASPECT_RECORD, MANDATORY_METADATA); @@ -469,7 +469,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() throws Exception { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(true); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(true); // create the non-electronic record custom metadata definition (that has a mandatory property) defineCustomMetadata(CUSTOM_NON_ELECTRONIC_TEST, TYPE_NON_ELECTRONIC_DOCUMENT, MANDATORY_METADATA); @@ -515,7 +515,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // disable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(false); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(false); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); @@ -555,7 +555,7 @@ public class CompleteRecordTest extends BaseRMTestCase public void given() { // enable mandatory parameter check - action.setCheckMandatoryPropertiesEnabled(false); + recordServiceImpl.setCheckMandatoryPropertiesEnabled(false); // create a record record = utils.createRecord(rmFolder, "record.txt", "title"); From 214f5936803953a16747cb63dd8f486622766adf Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Tue, 20 Jun 2017 13:58:19 +0100 Subject: [PATCH 08/18] refactor complete record Rest API --- .../api/records/RecordsEntityResource.java | 45 +------------------ .../main/webapp/definitions/gs-core-api.yaml | 2 +- 2 files changed, 2 insertions(+), 45 deletions(-) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java index 6c437b3951..fe77d89ccc 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java @@ -27,26 +27,13 @@ package org.alfresco.rm.rest.api.records; -import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel.RM_CUSTOM_MODEL; import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank; import static org.alfresco.util.ParameterCheck.mandatory; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.sun.xml.bind.v2.TODO; - import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.repo.activities.ActivityType; import org.alfresco.repo.node.integrity.IntegrityException; -import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.rest.framework.BinaryProperties; import org.alfresco.rest.framework.Operation; @@ -64,23 +51,16 @@ import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils; import org.alfresco.rm.rest.api.model.Record; import org.alfresco.rm.rest.api.model.TargetContainer; import org.alfresco.service.cmr.activities.ActivityPoster; -import org.alfresco.service.cmr.dictionary.AspectDefinition; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ParameterCheck; -import org.opensaml.ws.security.provider.MandatoryAuthenticatedMessageRule; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.ConcurrencyFailureException; -import sun.util.resources.cldr.naq.CalendarData_naq_NA; /** * An implementation of an Entity Resource for a record @@ -103,7 +83,6 @@ public class RecordsEntityResource implements BinaryResourceAction.Read, private RecordService recordService; private NodeService nodeService; private TransactionService transactionService; - private DictionaryService dictionaryService; public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory) { @@ -135,11 +114,6 @@ public class RecordsEntityResource implements BinaryResourceAction.Read, this.transactionService = transactionService; } - public void setDictionaryService(DictionaryService dictionaryService) - { - this.dictionaryService = dictionaryService; - } - /** * Download content * @@ -267,24 +241,7 @@ public class RecordsEntityResource implements BinaryResourceAction.Read, NodeRef record = apiUtils.validateRecord(recordId); // Complete the record - if (!recordService.isDeclared(record)) - { - //TODO: move this to appropriate place when resolved - boolean checkMandatoryPropertiesEnabled = true; // TODO - if (checkMandatoryPropertiesEnabled && (!recordService.isMandatoryPropertiesPopulated(record))) - { - throw new IntegrityException("Model integrity exception: the record has missing mandatory meta-data.", - null); - } - else - { - recordService.complete(record); - } - } - else - { - throw new IntegrityException("Model integrity exception: the record is frozen or already completed.", null); - } + recordService.complete(record); // return record state FileInfo info = fileFolderService.getFileInfo(record); diff --git a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml index 1c80b65973..af99534fa8 100644 --- a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml +++ b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml @@ -1835,7 +1835,7 @@ paths: **recordIdParam** does not exist '422': description: | - Model integrity exception: the record is frozen or already completed + Model integrity exception: the action breaks system's integrity restrictions default: description: Unexpected error schema: From 6b3c140bdd07df442ea29228f629cf458a4b4a7a Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Tue, 20 Jun 2017 15:48:25 +0100 Subject: [PATCH 09/18] correct message for Share --- .../action/impl/DeclareRecordAction.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java index fe21ae45cd..a1332ec08c 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java @@ -74,7 +74,10 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase recordService.complete(actionedUponNodeRef); } catch (IntegrityException e) { - action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, e.getMessage()); + if (e.getMessage().contains("missing")) + { + action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, "missingProperties"); + } } } From f9c4ef0f419b9a78ab15610fc387956569ecaf72 Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Wed, 21 Jun 2017 15:34:00 +0100 Subject: [PATCH 10/18] fixing tests --- .../rm/community/records/CompleteRecordTests.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java index f683dcf6fa..631c2daf16 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java @@ -57,6 +57,8 @@ public class CompleteRecordTests extends BaseRMRestTest private static final Boolean COMPLETE = true; private static final Boolean INCOMPLETE = false; private static final String parameters = "include=isCompleted"; + //private static final boolean MANDATORY_METADATA = true; + //private static final QName ASPECT_TEST = QName.createQName("http://www.alfresco.org/model/rmtest/1.0", "recordMetaDataWithProperty"); /** * Incomplete records with mandatory meta-data present @@ -76,7 +78,7 @@ public class CompleteRecordTests extends BaseRMRestTest getFile(IMAGE_FILE)); assertStatusCode(CREATED); setMandatoryMetadata(electronicRecord); - // TODO verfiy mandatory metadata is present + // TODO verfiy mandatory metadata is present? //create non-electronic record in record folder Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); @@ -97,7 +99,7 @@ public class CompleteRecordTests extends BaseRMRestTest public Object[][] getIncompleteRecordsMandatoryMetadataMissing() throws Exception { createRMSiteIfNotExists(); - createMandatoryMetadata(); + //createMandatoryMetadata(); String recordFolderId = createCategoryFolderInFilePlan().getId(); RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); @@ -106,6 +108,7 @@ public class CompleteRecordTests extends BaseRMRestTest Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, getFile(IMAGE_FILE)); assertStatusCode(CREATED); + createMissingMandatoryMetadata(electronicRecord); //create non-electronic record in record folder Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); @@ -322,12 +325,13 @@ public class CompleteRecordTests extends BaseRMRestTest } - private void createMandatoryMetadata() + private void createMissingMandatoryMetadata(Record record) { - + nodeService.addAspect(record, ASPECT_TEST, null); } private void setMandatoryMetadata(Record record) { + nodeService.addAspect(record, ASPECT_TEST, "SomeTextValue"); } } From 1400d3f657e300c30a6284208470ff163a6a9992 Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Fri, 23 Jun 2017 11:54:40 +0100 Subject: [PATCH 11/18] tidied up REST tests --- .../records/CompleteRecordTests.java | 286 ++++++++---------- .../action/impl/DeclareRecordAction.java | 3 +- 2 files changed, 128 insertions(+), 161 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java index 631c2daf16..8964357053 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java @@ -30,6 +30,8 @@ import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.IMAGE_ import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createElectronicRecordModel; import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createNonElectronicRecordModel; import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.getFile; +import static org.alfresco.rest.rm.community.utils.RMSiteUtil.createDOD5015RMSiteModel; +import static org.alfresco.rest.rm.community.utils.RMSiteUtil.createStandardRMSiteModel; import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.CREATED; import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; @@ -39,6 +41,7 @@ import java.util.Arrays; import org.alfresco.rest.rm.community.base.BaseRMRestTest; import org.alfresco.rest.rm.community.model.record.Record; +import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI; import org.alfresco.test.AlfrescoTest; @@ -57,40 +60,6 @@ public class CompleteRecordTests extends BaseRMRestTest private static final Boolean COMPLETE = true; private static final Boolean INCOMPLETE = false; private static final String parameters = "include=isCompleted"; - //private static final boolean MANDATORY_METADATA = true; - //private static final QName ASPECT_TEST = QName.createQName("http://www.alfresco.org/model/rmtest/1.0", "recordMetaDataWithProperty"); - - /** - * Incomplete records with mandatory meta-data present - */ - @DataProvider (name = "IncompleteRecordsMandatoryMetadataPresent") - public Object[][] getIncompleteRecordsMandatoryMetadataPresent() throws Exception - { - createRMSiteIfNotExists(); - createMandatoryMetadata(); - - // create record folder - String recordFolderId = createCategoryFolderInFilePlan().getId(); - RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); - - //create electronic record in record folder - Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, - getFile(IMAGE_FILE)); - assertStatusCode(CREATED); - setMandatoryMetadata(electronicRecord); - // TODO verfiy mandatory metadata is present? - - //create non-electronic record in record folder - Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); - assertStatusCode(CREATED); - setMandatoryMetadata(nonElectronicRecord); - - return new String[][] - { - // an arbitrary record folder - { electronicRecord.getId(), nonElectronicRecord.getId() }, - }; - } /** * Incomplete records with mandatory meta-data missing @@ -98,21 +67,17 @@ public class CompleteRecordTests extends BaseRMRestTest @DataProvider (name = "IncompleteRecordsMandatoryMetadataMissing") public Object[][] getIncompleteRecordsMandatoryMetadataMissing() throws Exception { - createRMSiteIfNotExists(); - //createMandatoryMetadata(); + //create RM site + RMSiteAPI rmSiteAPI = getRestAPIFactory().getRMSiteAPI(); + rmSiteAPI.deleteRMSite(); + rmSiteAPI.createRMSite(createDOD5015RMSiteModel()); + assertStatusCode(CREATED); + // create record folder String recordFolderId = createCategoryFolderInFilePlan().getId(); - RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); - //create electronic record in record folder - Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, - getFile(IMAGE_FILE)); - assertStatusCode(CREATED); - createMissingMandatoryMetadata(electronicRecord); - - //create non-electronic record in record folder - Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); - assertStatusCode(CREATED); + Record electronicRecord = createAndVerifyElectronicRecord(recordFolderId); + Record nonElectronicRecord = createAndVerifyNonElectronicRecord(recordFolderId); return new String[][] { @@ -121,27 +86,38 @@ public class CompleteRecordTests extends BaseRMRestTest }; } - // TODO repeat previous 2 providers but with config set to not chk for mandatory data + /** + * Incomplete records with mandatory meta-data present + */ + @DataProvider (name = "IncompleteRecordsMandatoryMetadataPresent") + public Object[][] getIncompleteRecordsMandatoryMetadataPresent() throws Exception + { + //create RM site + RMSiteAPI rmSiteAPI = getRestAPIFactory().getRMSiteAPI(); + rmSiteAPI.deleteRMSite(); + rmSiteAPI.createRMSite(createStandardRMSiteModel()); + assertStatusCode(CREATED); + + // create record folder + String recordFolderId = createCategoryFolderInFilePlan().getId(); + + Record electronicRecord = createAndVerifyElectronicRecord(recordFolderId); + Record nonElectronicRecord = createAndVerifyNonElectronicRecord(recordFolderId); + + return new String[][] + { + // an arbitrary record folder + { electronicRecord.getId(), nonElectronicRecord.getId() }, + }; + } /** * Document to be completed is not a record */ @DataProvider (name = "Supplied node is not a record") - // TODO include is a document but not a record - public Object[][] getNodesWhichAreNotRecords() throws Exception { - //create record folder - String recordFolderId = createCategoryFolderInFilePlan().getId(); - RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); - Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, - getFile(IMAGE_FILE)); - assertStatusCode(CREATED); - - //create non-electronic record in record folder - Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); - assertStatusCode(CREATED); - + createRMSiteIfNotExists(); return new String[][] { { createCategoryFolderInFilePlan().getId() }, @@ -149,75 +125,6 @@ public class CompleteRecordTests extends BaseRMRestTest }; } - /** - * Record to be completed is frozen - */ - @DataProvider (name = "FrozenRecords") - public Object[][] getFrozenRecords() throws Exception - { - // TODO consider adding method to BaseRMRestTest eg. createRMSiteIfNotExists(DOD5015); - createRMSiteIfNotExists(); - - // TODO add custom metadata to record model, and do not populate it - //create electronic record in record folder - String recordFolderId = createCategoryFolderInFilePlan().getId(); - RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); - Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, - getFile(IMAGE_FILE)); - assertStatusCode(CREATED); - - //create non-electronic record in record folder - Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); - assertStatusCode(CREATED); - - return new String[][] - { - // an arbitrary record folder - { electronicRecord.getId(), nonElectronicRecord.getId() }, - }; - } - - // TODO Add test for authentication fails (see yaml file) - // TODO Add test for user does not have permission to complete record - - /** - *

-     * Given the repository is configured to check mandatory data before completing a record
-     * And an incomplete record with all mandatory meta-data present
-     * When I complete the record
-     * Then the record is successfully completed
-     * 
- */ - @Test - ( - dataProvider = "IncompleteRecordsMandatoryMetadataPresent", - description = "Can complete electronic and non-electronic records with mandatory metadata present" - ) - @AlfrescoTest (jira = "RM-4431") - public void completeRecordWithMandatoryMetadataPresent(String electronicRecordId, String nonElectronicRecordId) - throws Exception - { - // Get the recordsAPI - RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); - Record electronicRecord = recordsAPI.getRecord(electronicRecordId); - Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); - - for (Record record : Arrays.asList(electronicRecord, nonElectronicRecord)) - { - Record recordModel; - // Verify the record is incomplete - recordModel = recordsAPI.getRecord(record.getId(), parameters); - assertEquals(recordModel.getIsCompleted(), INCOMPLETE); - - // Complete record - recordModel = recordsAPI.completeRecord(record.getId(), parameters); - assertStatusCode(CREATED); - - // Verify the record has been completed - assertEquals(recordModel.getIsCompleted(), COMPLETE); - } - } - /** *
      * Given the repository is configured to check mandatory data before completing a record
@@ -241,23 +148,49 @@ public class CompleteRecordTests extends BaseRMRestTest
         Record electronicRecord = recordsAPI.getRecord(electronicRecordId);
         Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId);
 
-        for (Record record : Arrays.asList(nonElectronicRecord))
+        for (Record record : Arrays.asList(electronicRecord, nonElectronicRecord))
         {
-            Record recordModel;
-            // Verify the record is incomplete
-            recordModel = recordsAPI.getRecord(record.getId(), parameters);
-            assertEquals(recordModel.getIsCompleted(), INCOMPLETE);
-
-            //Verify the record has missing mandatory metadata
-            // TODO change next line to get custom metadata and check not populated
-            //assertEquals(recordModel.  .getProperties()  .getTitle(), INCOMPLETE);
+            verifyRecordIsIncomplete(record);
 
             // Complete record
-            recordModel = recordsAPI.completeRecord(record.getId(), parameters);
+            recordsAPI.completeRecord(record.getId(), parameters);
             assertStatusCode(UNPROCESSABLE_ENTITY);
 
-            // Verify the record has not been completed
-            assertEquals(recordModel.getIsCompleted(), INCOMPLETE);
+            verifyRecordIsIncomplete(record);
+        }
+    }
+
+    /**
+     * 
+     * Given the repository is configured to check mandatory data before completing a record
+     * And an incomplete record with all mandatory meta-data present
+     * When I complete the record
+     * Then the record is successfully completed
+     * 
+ */ + @Test + ( + dataProvider = "IncompleteRecordsMandatoryMetadataPresent", + description = "Can complete electronic and non-electronic records with mandatory metadata present" + ) + @AlfrescoTest (jira = "RM-4431") + public void completeRecordWithMandatoryMetadataPresent(String electronicRecordId, String nonElectronicRecordId) + throws Exception + { + // Get the recordsAPI + RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); + Record electronicRecord = recordsAPI.getRecord(electronicRecordId); + Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); + + for (Record record : Arrays.asList(electronicRecord, nonElectronicRecord)) + { + verifyRecordIsIncomplete(record); + + // Complete record + recordsAPI.completeRecord(record.getId(), parameters); + assertStatusCode(CREATED); + + verifyRecordIsComplete(record); } } @@ -279,8 +212,7 @@ public class CompleteRecordTests extends BaseRMRestTest { // Get the recordsAPI RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); - Record recordModel; - recordModel = recordsAPI.completeRecord(nonRecordId, parameters); + recordsAPI.completeRecord(nonRecordId, parameters); assertStatusCode(BAD_REQUEST); } @@ -305,33 +237,67 @@ public class CompleteRecordTests extends BaseRMRestTest Record electronicRecord = recordsAPI.getRecord(electronicRecordId); Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); - for (Record record : Arrays.asList(nonElectronicRecord)) + for (Record record : Arrays.asList(electronicRecord, nonElectronicRecord)) { - Record recordModel; - // If the record is incomplete, complete it - recordModel = recordsAPI.getRecord(record.getId(), parameters); - if (recordModel.getIsCompleted().equals(INCOMPLETE)) - { - recordModel = recordsAPI.completeRecord(record.getId(), parameters); - } - - // Verify the record is already completed - assertEquals(recordModel.getIsCompleted(), COMPLETE); + verifyRecordIsIncomplete(record); // Complete record - recordModel = recordsAPI.completeRecord(record.getId(), parameters); + recordsAPI.completeRecord(record.getId(), parameters); + assertStatusCode(CREATED); + + verifyRecordIsComplete(record); + + // Complete record + recordsAPI.completeRecord(record.getId(), parameters); assertStatusCode(UNPROCESSABLE_ENTITY); } } - - private void createMissingMandatoryMetadata(Record record) + /** + * Helper method to create an electronic record and and assert successfully creation + */ + private Record createAndVerifyElectronicRecord(String recordFolderId) throws Exception { - nodeService.addAspect(record, ASPECT_TEST, null); + //create electronic record in record folder + RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); + Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, + getFile(IMAGE_FILE)); + assertStatusCode(CREATED); + + return electronicRecord; } - private void setMandatoryMetadata(Record record) + /** + * Helper method to create a non-electronic record and and assert successfully creation + */ + private Record createAndVerifyNonElectronicRecord(String recordFolderId) throws Exception { - nodeService.addAspect(record, ASPECT_TEST, "SomeTextValue"); + //create non-electronic record in record folder + RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); + Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); + assertStatusCode(CREATED); + + return nonElectronicRecord; } + + /** + * Helper method to verify that a record is not complete + */ + private void verifyRecordIsIncomplete(Record record) + { + RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); + Record recordModel = recordsAPI.getRecord(record.getId(), parameters); + assertEquals(recordModel.getIsCompleted(), INCOMPLETE); + } + + /** + * Helper method to verify that a record is completed + */ + private void verifyRecordIsComplete(Record record) + { + RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); + Record recordModel = recordsAPI.getRecord(record.getId(), parameters); + assertEquals(recordModel.getIsCompleted(), COMPLETE); + } + } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java index a1332ec08c..fcf1925d5f 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java @@ -72,7 +72,8 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase try { recordService.complete(actionedUponNodeRef); - } catch (IntegrityException e) + } + catch (IntegrityException e) { if (e.getMessage().contains("missing")) { From bf06f075d4bf7e4043ccca4bd2ad13c6ff709111 Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Fri, 23 Jun 2017 16:24:47 +0100 Subject: [PATCH 12/18] corrected comment --- .../rest/rm/community/requests/gscore/api/RecordsAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java index 27e7faf5c6..a2e58dcf6a 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java @@ -148,7 +148,7 @@ public class RecordsAPI extends RMModelRequest *
    *
  • Invalid parameter: {@code recordBodyFile} is not a valid format,{@code recordId} is not a record
  • *
  • authentication fails
  • - *
  • current user does not have permission to file to {@code fileplanComponentId}
  • + *
  • current user does not have permission to complete {@code recordId}
  • *
  • {@code recordId} does not exist
  • *
  • model integrity exception: the record is already complete
  • *
  • model integrity exception: the record has missing meta-data
  • From 822f046e0d12d5f91c99a3183f3fa366289d8108 Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Fri, 23 Jun 2017 18:16:38 +0100 Subject: [PATCH 13/18] changes following review --- .../rest/rm/community/requests/gscore/api/RecordsAPI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java index a2e58dcf6a..2825dab997 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java @@ -143,10 +143,10 @@ public class RecordsAPI extends RMModelRequest * Complete the record recordId * * @param recordId The id of the record to complete - * @return The {@link Record} with the given properties + * @return The completed {@link Record} with the given properties * @throws Exception for the following cases: *
      - *
    • Invalid parameter: {@code recordBodyFile} is not a valid format,{@code recordId} is not a record
    • + *
    • Invalid parameter: {@code recordId} is not a record
    • *
    • authentication fails
    • *
    • current user does not have permission to complete {@code recordId}
    • *
    • {@code recordId} does not exist
    • From fb215876b82053e06907b5e8b10a3ce75db2bf5c Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Sat, 24 Jun 2017 22:49:27 +0100 Subject: [PATCH 14/18] fixing IDE whitespaces --- .../requests/gscore/api/RecordsAPI.java | 6 +- .../records/CompleteRecordTests.java | 7 +- .../rm-service-context.xml | 1986 ++++++++--------- .../action/impl/DeclareRecordAction.java | 8 +- .../record/RecordService.java | 350 +-- .../record/RecordServiceImpl.java | 429 ++-- .../rule/FilePlanRuleInheritanceTest.java | 103 +- 7 files changed, 1411 insertions(+), 1478 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java index 2825dab997..e39c8034be 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java @@ -149,8 +149,8 @@ public class RecordsAPI extends RMModelRequest *
    • Invalid parameter: {@code recordId} is not a record
    • *
    • authentication fails
    • *
    • current user does not have permission to complete {@code recordId}
    • - *
    • {@code recordId} does not exist
    • - *
    • model integrity exception: the record is already complete
    • + *
    • {@code recordId} does not exist or is frozen
    • + *
    • model integrity exception: the record is already completed
    • *
    • model integrity exception: the record has missing meta-data
    • *
    */ @@ -242,7 +242,7 @@ public class RecordsAPI extends RMModelRequest * @param recordModel The record model which holds the information * @param recordId The identifier of a record * @param parameters The URL parameters to add - * @param returns The updated {@link Record} + * @return The updated {@link Record} * @throws Exception for the following cases: *
      *
    • the update request is invalid or {@code recordId} is not a valid format or {@code recordModel} is invalid
    • diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java index 8964357053..e099fd9afb 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java @@ -207,8 +207,7 @@ public class CompleteRecordTests extends BaseRMRestTest description = "Cannot complete a document that is not a record" ) @AlfrescoTest (jira = "RM-4431") - public void completeNonRecord(String nonRecordId) - throws Exception + public void completeNonRecord(String nonRecordId) throws Exception { // Get the recordsAPI RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); @@ -254,7 +253,7 @@ public class CompleteRecordTests extends BaseRMRestTest } /** - * Helper method to create an electronic record and and assert successfully creation + * Helper method to create an electronic record and and assert successful creation */ private Record createAndVerifyElectronicRecord(String recordFolderId) throws Exception { @@ -268,7 +267,7 @@ public class CompleteRecordTests extends BaseRMRestTest } /** - * Helper method to create a non-electronic record and and assert successfully creation + * Helper method to create a non-electronic record and and assert successful creation */ private Record createAndVerifyNonElectronicRecord(String recordFolderId) throws Exception { 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 2a9b9accf5..6916b0bd36 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 @@ -1,10 +1,10 @@ - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - + + + + + + + - + - + - + - - - + + + - - - org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService - - - - - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService + + + + + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - - - - - - - - - - - + + + + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.transfer.TransferService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.transfer.TransferService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - + + - - - org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - + + + + + + + - - - + + + - - - org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - + class="org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanServiceImpl"> + + - - - org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService - - - - - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService + + + + + + + + + + + + + + + + - + - - - - + + + - - - + + + - - - - - - - - + class="org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionServiceImpl" + init-method="init"> + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - + + + + + + + + - + - - - org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService + + + + + + + + + + + + - + - - - - + + + - - - + + + - + - - - - - + + + + + - - - org.alfresco.module.org_alfresco_module_rm.model.security.ModelSecurityService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.model.security.ModelSecurityService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - + + + + - - - org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - + + + + - - - org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEventService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEventService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - - - - - - + + + + + + - + - + rma:recordCategory @@ -817,39 +798,38 @@ - - - org.alfresco.module.org_alfresco_module_rm.admin.RecordsManagementAdminService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.admin.RecordsManagementAdminService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - - - - - - - - cm:lastThumbnailModification - cm:autoVersion - cm:autoVersionOnUpdateProps - cm:initialVersion - - - + + + + + + + + + + + + + + + cm:lastThumbnailModification + cm:autoVersion + cm:autoVersionOnUpdateProps + cm:initialVersion + + + - - - org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1118,48 +1093,46 @@ http://www.alfresco.org/model/rendition/1.0 - - - - + + + + - - - org.alfresco.module.org_alfresco_module_rm.record.RecordService - - - - - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.record.RecordService + + + + + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - + @@ -1205,23 +1177,22 @@ - + - - - + + + - + - + @@ -1244,25 +1215,25 @@ + class="org.alfresco.module.org_alfresco_module_rm.security.FilePlanAuthenticationServiceImpl" /> org.alfresco.module.org_alfresco_module_rm.security.FilePlanAuthenticationService - + - - - + + + - + @@ -1274,18 +1245,16 @@ - - + + - + - - - + Thread-Index @@ -1298,112 +1267,110 @@ - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - - - - org.alfresco.module.org_alfresco_module_rm.email.CustomEmailMappingService - - - - customEmailMappingService - - - - - - - - - + + + + org.alfresco.module.org_alfresco_module_rm.email.CustomEmailMappingService + + + + customEmailMappingService + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + - + - + - + - - - - - - org.alfresco.caveatConfigTransactionalCache - - - - - + + + + + + org.alfresco.caveatConfigTransactionalCache + + + + + - + {http://www.alfresco.org/model/recordsmanagement/1.0}recordComponentIdentifier @@ -1411,7 +1378,7 @@ - + {http://www.alfresco.org/model/rmcustom/1.0}rmcustom @@ -1419,15 +1386,14 @@ - - - + + + - - - - + + + - - - + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - org.alfresco.module.org_alfresco_module_rm.caveat.RMCaveatConfigService - - - - caveatConfigService - - - - - - - - - + + + + org.alfresco.module.org_alfresco_module_rm.caveat.RMCaveatConfigService + + + + caveatConfigService + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - org.alfresco.module.org_alfresco_module_rm.dataset.DataSetService - - - - - - - - - - - - + + + org.alfresco.module.org_alfresco_module_rm.dataset.DataSetService + + + + + + + + + + + + - - - - - - - ${server.transaction.mode.default} - - - + + + + + + + ${server.transaction.mode.default} + + + - - - - + + + - - - + + + - + - - - + + + - - - - + + + + @@ -1567,7 +1530,7 @@ - + @@ -1577,13 +1540,13 @@ org.alfresco.module.org_alfresco_module_rm.hold.HoldService - + - - - + + + @@ -1616,10 +1579,8 @@ - - + + @@ -1627,21 +1588,20 @@ org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService - + - - - + + + - + - + @@ -1672,9 +1632,8 @@ - - + + @@ -1682,21 +1641,20 @@ org.alfresco.module.org_alfresco_module_rm.recordableversion.RecordableVersionConfigService - + - - - + + + - + - + diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java index fcf1925d5f..7c8c6ba1df 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java @@ -42,14 +42,10 @@ import org.alfresco.util.ParameterCheck; */ public class DeclareRecordAction extends RMActionExecuterAbstractBase { - /** - * action name - */ + /** action name */ public static final String NAME = "declareRecord"; - /** - * Record service - */ + /** Record service */ private RecordService recordService; /** diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java index f9cfaf2255..a54119ffe9 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java @@ -55,8 +55,9 @@ public interface RecordService * A record metadata aspect can be registered more than once if it applies to more than one * file plan type. * - * @param recordMetadataAspect record metadata aspect qualified name - * @param filePlanType file plan type + * @param recordMetadataAspect record metadata aspect qualified name + * @param filePlanType file plan type + * * @since 2.2 */ void registerRecordMetadataAspect(QName recordMetadataAspect, QName filePlanType); @@ -71,7 +72,8 @@ public interface RecordService /** * Disables the property editable check for a given node in this transaction only. * - * @param nodeRef node reference + * @param nodeRef node reference + * * @since 2.2 */ void disablePropertyEditableCheck(NodeRef nodeRef); @@ -82,194 +84,200 @@ public interface RecordService void enablePropertyEditableCheck(); /** - * Gets a list of all the record meta-data aspects - * - * @return {@link Set}<{@link QName}> list of record meta-data aspects - * @deprecated since 2.2, file plan component required to provide context - */ - @Deprecated - Set getRecordMetaDataAspects(); + * Gets a list of all the record meta-data aspects + * + * @return {@link Set}<{@link QName}> list of record meta-data aspects + * + * @deprecated since 2.2, file plan component required to provide context + */ + @Deprecated + Set getRecordMetaDataAspects(); - /** - * Indicates whether the provided aspect is a registered record meta-data - * aspect. - * - * @param aspect aspect {@link QName} - * @return boolean true if the aspect is a registered record meta-data aspect, false otherwise - * @since 2.3 - */ - boolean isRecordMetadataAspect(QName aspect); + /** + * Indicates whether the provided aspect is a registered record meta-data + * aspect. + * + * @param aspect aspect {@link QName} + * @return boolean true if the aspect is a registered record meta-data aspect, false otherwise + * + * @since 2.3 + */ + boolean isRecordMetadataAspect(QName aspect); - /** - * Indicates whther the provided property is declared on a registered record - * meta-data aspect. - * - * @param property property {@link QName} - * @return boolean true if the property is declared on a registered record meta-data aspect, - * false otherwise - * @since 2.3 - */ - boolean isRecordMetadataProperty(QName property); + /** + * Indicates whther the provided property is declared on a registered record + * meta-data aspect. + * + * @param property property {@link QName} + * @return boolean true if the property is declared on a registered record meta-data aspect, + * false otherwise + * + * @since 2.3 + */ + boolean isRecordMetadataProperty(QName property); - /** - * Gets a list of all the record metadata aspects relevant to the file plan type of the - * file plan component provided. - *

      - * If a null context is provided all record meta-data aspects are returned, but this is not - * recommended. - * - * @param nodeRef node reference to file plan component providing context - * @return {@link Set}<{@link QName}> list of record meta-data aspects - * @since 2.2 - */ - Set getRecordMetadataAspects(NodeRef nodeRef); + /** + * Gets a list of all the record metadata aspects relevant to the file plan type of the + * file plan component provided. + *

      + * If a null context is provided all record meta-data aspects are returned, but this is not + * recommended. + * + * @param nodeRef node reference to file plan component providing context + * @return {@link Set}<{@link QName}> list of record meta-data aspects + * + * @since 2.2 + */ + Set getRecordMetadataAspects(NodeRef nodeRef); - /** - * Gets a list of all the record metadata aspect that relate to the provided file plan type. - *

      - * If null is provided for the file plan type then record metadata aspects for the default - * file plan type (rma:filePlan) are returned. - * - * @param filePlanType file plan type - * @return{@link Set}<{@link QName}> list of record meta-data aspects - * @since 2.2 - */ - Set getRecordMetadataAspects(QName filePlanType); + /** + * Gets a list of all the record metadata aspect that relate to the provided file plan type. + *

      + * If null is provided for the file plan type then record metadata aspects for the default + * file plan type (rma:filePlan) are returned. + * + * @param filePlanType file plan type + * @return{@link Set}<{@link QName}> list of record meta-data aspects + * + * @since 2.2 + */ + Set getRecordMetadataAspects(QName filePlanType); - /** - * Checks whether if the given node reference is a record or not - * - * @param nodeRef node reference to be checked - * @return boolean true if the node reference is a record, false otherwise - */ - boolean isRecord(NodeRef nodeRef); + /** + * Checks whether if the given node reference is a record or not + * + * @param nodeRef node reference to be checked + * @return boolean true if the node reference is a record, false otherwise + */ + boolean isRecord(NodeRef nodeRef); - /** - * Indicates whether the record is declared - * - * @param nodeRef node reference of the record for which the check would be performed - * @return boolean true if record is declared, false otherwise - */ - boolean isDeclared(NodeRef nodeRef); + /** + * Indicates whether the record is declared + * + * @param nodeRef node reference of the record for which the check would be performed + * @return boolean true if record is declared, false otherwise + */ + boolean isDeclared(NodeRef nodeRef); - /** - * Creates a new unfiled record from an existing node. - *

      - * Note that the node reference of the record will be the same as the original - * document. - * - * @param filePlan The filePlan in which the record should be placed. filePlan can be null in this case the default RM site will be used. - * @param nodeRef The node from which the record will be created - * @param isLinked indicates if the newly created record is linked to it's original location or not. - */ - void createRecord(NodeRef filePlan, NodeRef nodeRef, boolean isLinked); + /** + * Creates a new unfiled record from an existing node. + *

      + * Note that the node reference of the record will be the same as the original + * document. + * + * @param filePlan The filePlan in which the record should be placed. filePlan can be null in this case the default RM site will be used. + * @param nodeRef The node from which the record will be created + * @param isLinked indicates if the newly created record is linked to it's original location or not. + */ + void createRecord(NodeRef filePlan, NodeRef nodeRef, boolean isLinked); - /** - * Links the newly created record to it's original location. - * - * @see #createRecord(NodeRef, NodeRef, boolean) - */ - void createRecord(NodeRef filePlan, NodeRef nodeRef); + /** + * Links the newly created record to it's original location. + * + * @see #createRecord(NodeRef, NodeRef, boolean) + */ + void createRecord(NodeRef filePlan, NodeRef nodeRef); - /** - * Creates a record from a copy of the node reference provided. - * - * @param filePlan file plan - * @param nodeRef node reference - */ - NodeRef createRecordFromCopy(NodeRef filePlan, NodeRef nodeRef); + /** + * Creates a record from a copy of the node reference provided. + * + * @param filePlan file plan + * @param nodeRef node reference + */ + NodeRef createRecordFromCopy(NodeRef filePlan, NodeRef nodeRef); - /** - * Creates a new document in the unfiled records container if the given node reference is a file plan - * node reference otherwise the node reference will be used as the destination for the new record. - * - * @param parent parent node reference - * @param name name of the new record - * @param type content type, cm:content if null - * @param properties properties - * @param reader content reader - */ - NodeRef createRecordFromContent(NodeRef parent, String name, QName type, Map properties, ContentReader reader); + /** + * Creates a new document in the unfiled records container if the given node reference is a file plan + * node reference otherwise the node reference will be used as the destination for the new record. + * + * @param parent parent node reference + * @param name name of the new record + * @param type content type, cm:content if null + * @param properties properties + * @param reader content reader + */ + NodeRef createRecordFromContent(NodeRef parent, String name, QName type, Map properties, ContentReader reader); - /** - * Indicates whether the record is filed or not - * - * @param record Record node reference - * @return boolean true if filed, false otherwise - */ - boolean isFiled(NodeRef record); + /** + * Indicates whether the record is filed or not + * + * @param record nodeRef of record + * @return boolean true if filed, false otherwise + */ + boolean isFiled(NodeRef record); - /** - * 'File' a new document that arrived in the file plan structure. - * - * @param record Record node reference - */ - void file(NodeRef record); + /** + * 'File' a new document that arrived in the file plan structure. + * + * @param record noderef of record + */ + void file(NodeRef record); - /** - * Rejects a record with the provided reason - * - * @param nodeRef The record which will be rejected - * @param reason The reason for rejection - */ - void rejectRecord(NodeRef nodeRef, String reason); + /** + * Rejects a record with the provided reason + * + * @param nodeRef The record which will be rejected + * @param reason The reason for rejection + */ + void rejectRecord(NodeRef nodeRef, String reason); - /** - * Indicates whether a property of a record is editable for the current user or not. - * - * @param record record - * @param property property - * @return boolean true if editable, false otherwise. - */ - boolean isPropertyEditable(NodeRef record, QName property); + /** + * Indicates whether a property of a record is editable for the current user or not. + * + * @param record record + * @param property property + * @return boolean true if editable, false otherwise. + */ + boolean isPropertyEditable(NodeRef record, QName property); - /** - * Indicates whether the given node (record or record folder) is a metadata stub or not. - * - * @param nodeRef node reference - * @return boolean true if a metadata stub, false otherwise - */ - boolean isMetadataStub(NodeRef nodeRef); + /** + * Indicates whether the given node (record or record folder) is a metadata stub or not. + * + * @param nodeRef node reference + * @return boolean true if a metadata stub, false otherwise + */ + boolean isMetadataStub(NodeRef nodeRef); - /** - * Gets a list of all the records within a record folder - * - * @param recordFolder record folder - * @return List list of records in the record folder - */ - List getRecords(NodeRef recordFolder); + /** + * Gets a list of all the records within a record folder + * + * @param recordFolder record folder + * @return List list of records in the record folder + */ + List getRecords(NodeRef recordFolder); - /** - * Adds the specified type to the record - * - * @param nodeRef Record node reference - * @param typeQName Type to add - */ - void addRecordType(NodeRef nodeRef, QName typeQName); + /** + * Adds the specified type to the record + * + * @param nodeRef Record node reference + * @param typeQName Type to add + */ + void addRecordType(NodeRef nodeRef, QName typeQName); - /** - * Creates a record from the given document - * - * @param nodeRef The document node reference from which a record will be created - */ - void makeRecord(NodeRef nodeRef); + /** + * Creates a record from the given document + * + * @param nodeRef The document node reference from which a record will be created + */ + void makeRecord(NodeRef nodeRef); - /** - * Links a record to a record folder - * - * @param record the record to link - * @param recordFolder the record folder to link it to - */ - void link(NodeRef record, NodeRef recordFolder); + /** + * Links a record to a record folder + * + * @param record the record to link + * @param recordFolder the record folder to link it to + */ + void link(NodeRef record, NodeRef recordFolder); - /** - * Unlinks a record from a specified record folder. - * - * @param record the record to unlink - * @param recordFolder the record folder to unlink it from - * @since 2.3 - */ - void unlink(NodeRef record, NodeRef recordFolder); + /** + * Unlinks a record from a specified record folder. + * + * @param record the record to unlink + * @param recordFolder the record folder to unlink it from + * + * @since 2.3 + */ + void unlink(NodeRef record, NodeRef recordFolder); /** * Completes a record 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 fc9b8af4b3..b614ab292a 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 @@ -136,56 +136,42 @@ import org.springframework.extensions.surf.util.I18NUtil; */ @BehaviourBean public class RecordServiceImpl extends BaseBehaviourBean - implements RecordService, - RecordsManagementModel, - RecordsManagementCustomModel, - NodeServicePolicies.OnAddAspectPolicy, - NodeServicePolicies.OnCreateChildAssociationPolicy, - NodeServicePolicies.OnRemoveAspectPolicy, - NodeServicePolicies.OnUpdatePropertiesPolicy, - ContentServicePolicies.OnContentUpdatePolicy + implements RecordService, + RecordsManagementModel, + RecordsManagementCustomModel, + NodeServicePolicies.OnAddAspectPolicy, + NodeServicePolicies.OnCreateChildAssociationPolicy, + NodeServicePolicies.OnRemoveAspectPolicy, + NodeServicePolicies.OnUpdatePropertiesPolicy, + ContentServicePolicies.OnContentUpdatePolicy { - /** - * Logger - */ + /** Logger */ private static final Logger LOGGER = LoggerFactory.getLogger(RecordServiceImpl.class); - /** - * Sync Model URI - */ + /** Sync Model URI */ private static final String SYNC_MODEL_1_0_URI = "http://www.alfresco.org/model/sync/1.0"; - /** - * Synced aspect - */ + /** Synced aspect */ private static final QName ASPECT_SYNCED = QName.createQName(SYNC_MODEL_1_0_URI, "synced"); - /** - * transation data key - */ + /** transation data key */ private static final String KEY_IGNORE_ON_UPDATE = "ignoreOnUpdate"; public static final String KEY_NEW_RECORDS = "newRecords"; - /** - * I18N - */ + /** I18N */ private static final String MSG_NODE_HAS_ASPECT = "rm.service.node-has-aspect"; private static final String FINAL_VERSION = "rm.service.final-version"; private static final String FINAL_DESCRIPTION = "rm.service.final-version-description"; private static final String MSG_UNDECLARED_ONLY_RECORDS = "rm.action.undeclared-only-records"; private static final String MSG_NO_DECLARE_MAND_PROP = "rm.action.no-declare-mand-prop"; - /** - * Always edit property array - */ + /** Always edit property array */ private static final QName[] ALWAYS_EDIT_PROPERTIES = new QName[] - { - ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA - }; + { + ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA + }; - /** - * always edit model URI's - */ + /** always edit model URI's */ private List alwaysEditURIs; /** @@ -209,140 +195,92 @@ public class RecordServiceImpl extends BaseBehaviourBean return this.alwaysEditURIs; } - /** - * record model URI's - */ + /** record model URI's */ public static final List RECORD_MODEL_URIS = Collections.unmodifiableList( - Arrays.asList( - RM_URI, - RM_CUSTOM_URI, - ReportModel.RMR_URI, - RecordableVersionModel.RMV_URI, - DOD5015Model.DOD_URI - )); + Arrays.asList( + RM_URI, + RM_CUSTOM_URI, + ReportModel.RMR_URI, + RecordableVersionModel.RMV_URI, + DOD5015Model.DOD_URI + )); - /** - * non-record model URI's - */ + /** non-record model URI's */ private static final String[] NON_RECORD_MODEL_URIS = new String[] - { - NamespaceService.AUDIO_MODEL_1_0_URI, - NamespaceService.CONTENT_MODEL_1_0_URI, - NamespaceService.EMAILSERVER_MODEL_URI, - NamespaceService.EXIF_MODEL_1_0_URI, - NamespaceService.FORUMS_MODEL_1_0_URI, - NamespaceService.LINKS_MODEL_1_0_URI, - NamespaceService.REPOSITORY_VIEW_1_0_URI - }; + { + NamespaceService.AUDIO_MODEL_1_0_URI, + NamespaceService.CONTENT_MODEL_1_0_URI, + NamespaceService.EMAILSERVER_MODEL_URI, + NamespaceService.EXIF_MODEL_1_0_URI, + NamespaceService.FORUMS_MODEL_1_0_URI, + NamespaceService.LINKS_MODEL_1_0_URI, + NamespaceService.REPOSITORY_VIEW_1_0_URI + }; - /** - * Indentity service - */ + /** Indentity service */ private IdentifierService identifierService; - /** - * Extended permission service - */ + /** Extended permission service */ private ExtendedPermissionService extendedPermissionService; - /** - * Extended security service - */ + /** Extended security service */ private ExtendedSecurityService extendedSecurityService; - /** - * File plan service - */ + /** File plan service */ private FilePlanService filePlanService; - /** - * Records management notification helper - */ + /** Records management notification helper */ private RecordsManagementNotificationHelper notificationHelper; - /** - * Policy component - */ + /** Policy component */ private PolicyComponent policyComponent; - /** - * Ownable service - */ + /** Ownable service */ private OwnableService ownableService; - /** - * Capability service - */ + /** Capability service */ private CapabilityService capabilityService; - /** - * Rule service - */ + /** Rule service */ private RuleService ruleService; - /** - * File folder service - */ + /** File folder service */ private FileFolderService fileFolderService; - /** - * Record folder service - */ + /** Record folder service */ private RecordFolderService recordFolderService; - /** - * File plan role service - */ + /** File plan role service */ private FilePlanRoleService filePlanRoleService; - /** - * Permission service - */ + /** Permission service */ private PermissionService permissionService; - /** - * Version service - */ + /** Version service */ private VersionService versionService; - /** - * Relationship service - */ + /** Relationship service */ private RelationshipService relationshipService; - /** - * Disposition service - */ + /** Disposition service */ private DispositionService dispositionService; - /** - * records management container type - */ + /** records management container type */ private RecordsManagementContainerType recordsManagementContainerType; - /** - * recordable version service - */ + /** recordable version service */ private RecordableVersionService recordableVersionService; - /** - * list of available record meta-data aspects and the file plan types the are applicable to - */ + /** list of available record meta-data aspects and the file plan types the are applicable to */ private Map> recordMetaDataAspects; - /** - * Freeze service - */ + /** Freeze service */ private FreezeService freezeService; - /** - * Namespace service - */ + /** Namespace service */ private NamespaceService namespaceService; - /** - * policies - */ + /** policies */ private ClassPolicyDelegate beforeFileRecord; private ClassPolicyDelegate onFileRecord; private ClassPolicyDelegate beforeRecordDeclarationDelegate; @@ -369,7 +307,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param extendedSecurityService extended security service + * @param extendedSecurityService extended security service */ public void setExtendedSecurityService(ExtendedSecurityService extendedSecurityService) { @@ -377,7 +315,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param filePlanService file plan service + * @param filePlanService file plan service */ public void setFilePlanService(FilePlanService filePlanService) { @@ -393,7 +331,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param policyComponent policy component + * @param policyComponent policy component */ public void setPolicyComponent(PolicyComponent policyComponent) { @@ -401,7 +339,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param ownableService ownable service + * @param ownableService ownable service */ public void setOwnableService(OwnableService ownableService) { @@ -417,7 +355,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param ruleService rule service + * @param ruleService rule service */ public void setRuleService(RuleService ruleService) { @@ -465,7 +403,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param relationshipService relationship service + * @param relationshipService relationship service */ public void setRelationshipService(RelationshipService relationshipService) { @@ -473,7 +411,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param dispositionService disposition service + * @param dispositionService disposition service */ public void setDispositionService(DispositionService dispositionService) { @@ -481,7 +419,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param recordsManagementContainerType records management container type + * @param recordsManagementContainerType records management container type */ public void setRecordsManagementContainerType(RecordsManagementContainerType recordsManagementContainerType) { @@ -489,7 +427,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @param recordableVersionService recordable version service + * @param recordableVersionService recordable version service */ public void setRecordableVersionService(RecordableVersionService recordableVersionService) { @@ -544,11 +482,11 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - kind = BehaviourKind.CLASS, - type = "rma:record", - notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT - ) + ( + kind = BehaviourKind.CLASS, + type = "rma:record", + notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT + ) public void onAddAspect(NodeRef nodeRef, QName aspect) { authenticationUtil.runAsSystem(new RunAsWork() @@ -571,10 +509,10 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - kind = BehaviourKind.CLASS, - type = "sys:noContent" - ) + ( + kind = BehaviourKind.CLASS, + type = "sys:noContent" + ) public void onRemoveAspect(NodeRef nodeRef, QName aspect) { if (nodeService.hasAspect(nodeRef, ASPECT_RECORD)) @@ -595,11 +533,11 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - kind = ASSOCIATION, - type = "rma:recordFolder", - notificationFrequency = FIRST_EVENT - ) + ( + kind = ASSOCIATION, + type = "rma:recordFolder", + notificationFrequency = FIRST_EVENT + ) public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, final boolean bNew) { AuthenticationUtil.runAs(new RunAsWork() @@ -610,10 +548,10 @@ public class RecordServiceImpl extends BaseBehaviourBean try { NodeRef nodeRef = childAssocRef.getChildRef(); - if (nodeService.exists(nodeRef) && - !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY) && - !nodeService.getType(nodeRef).equals(TYPE_RECORD_FOLDER) && - !nodeService.getType(nodeRef).equals(TYPE_RECORD_CATEGORY)) + if (nodeService.exists(nodeRef) && + !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY) && + !nodeService.getType(nodeRef).equals(TYPE_RECORD_FOLDER) && + !nodeService.getType(nodeRef).equals(TYPE_RECORD_CATEGORY)) { // store information about the 'new' record in the transaction // @since 2.3 @@ -622,7 +560,8 @@ public class RecordServiceImpl extends BaseBehaviourBean { Set newRecords = transactionalResourceHelper.getSet(KEY_NEW_RECORDS); newRecords.add(nodeRef); - } else + } + else { // if we are linking a record NodeRef parentNodeRef = childAssocRef.getParentRef(); @@ -638,11 +577,13 @@ public class RecordServiceImpl extends BaseBehaviourBean // recalculate disposition schedule for the record when linking it dispositionService.recalculateNextDispositionStep(nodeRef); } - } catch (RecordLinkRuntimeException e) + } + catch (RecordLinkRuntimeException e) { // rethrow exception throw e; - } catch (AlfrescoRuntimeException e) + } + catch (AlfrescoRuntimeException e) { // do nothing but log error LOGGER.warn("Unable to file pending record.", e); @@ -695,18 +636,18 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - name = "onUpdateProperties", - kind = BehaviourKind.CLASS, - type = "rma:record" - ) + ( + name = "onUpdateProperties", + kind = BehaviourKind.CLASS, + type= "rma:record" + ) public void onUpdateProperties(final NodeRef nodeRef, final Map before, final Map after) { if (AuthenticationUtil.getFullyAuthenticatedUser() != null && - !AuthenticationUtil.isRunAsUserTheSystemUser() && - nodeService.exists(nodeRef) && - isRecord(nodeRef) && - !transactionalResourceHelper.getSet(KEY_IGNORE_ON_UPDATE).contains(nodeRef)) + !AuthenticationUtil.isRunAsUserTheSystemUser() && + nodeService.exists(nodeRef) && + isRecord(nodeRef) && + !transactionalResourceHelper.getSet(KEY_IGNORE_ON_UPDATE).contains(nodeRef)) { for (Map.Entry entry : after.entrySet()) { @@ -724,32 +665,34 @@ public class RecordServiceImpl extends BaseBehaviourBean // deal with date values, remove the seconds and milliseconds for the // comparison as they are removed from the submitted for data Calendar beforeCal = Calendar.getInstance(); - beforeCal.setTime((Date) beforeValue); + beforeCal.setTime((Date)beforeValue); Calendar afterCal = Calendar.getInstance(); - afterCal.setTime((Date) afterValue); + afterCal.setTime((Date)afterValue); beforeCal.set(Calendar.SECOND, 0); beforeCal.set(Calendar.MILLISECOND, 0); afterCal.set(Calendar.SECOND, 0); afterCal.set(Calendar.MILLISECOND, 0); propertyUnchanged = (beforeCal.compareTo(afterCal) == 0); - } else if ((afterValue instanceof Boolean) && (beforeValue == null) && (afterValue.equals(Boolean.FALSE))) + } + else if ((afterValue instanceof Boolean) && (beforeValue == null) && (afterValue.equals(Boolean.FALSE))) { propertyUnchanged = true; - } else + } + else { // otherwise propertyUnchanged = EqualsHelper.nullSafeEquals(beforeValue, afterValue); } if (!propertyUnchanged && - !(ContentModel.PROP_CONTENT.equals(property) && beforeValue == null) && - !isPropertyEditable(nodeRef, property)) + !(ContentModel.PROP_CONTENT.equals(property) && beforeValue == null) && + !isPropertyEditable(nodeRef, property)) { // the user can't edit the record property throw new ModelAccessDeniedException( "The user " + AuthenticationUtil.getFullyAuthenticatedUser() + - " does not have the permission to edit the record property " + property.toString() + - " on the node " + nodeRef.toString()); + " does not have the permission to edit the record property " + property.toString() + + " on the node " + nodeRef.toString()); } } } @@ -758,7 +701,8 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Get map containing record metadata aspects. * - * @return {@link Map}<{@link QName}, {@link Set}<{@link QName}>> map containing record metadata aspects + * @return {@link Map}<{@link QName}, {@link Set}<{@link QName}>> map containing record metadata aspects + * * @since 2.2 */ protected Map> getRecordMetadataAspectsMap() @@ -816,7 +760,8 @@ public class RecordServiceImpl extends BaseBehaviourBean { // get the current set of file plan types for this aspect filePlanTypes = getRecordMetadataAspectsMap().get(recordMetadataAspect); - } else + } + else { // create a new set for the file plan type filePlanTypes = new HashSet(1); @@ -838,7 +783,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isRecordMetadataAspect(org.alfresco.service.namespace.QName) + * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isRecordMetadataAspect(org.alfresco.service.namespace.QName) */ @Override public boolean isRecordMetadataAspect(QName aspect) @@ -858,7 +803,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { ClassDefinition classDefinition = propertyDefinition.getContainerClass(); if (classDefinition != null && - getRecordMetadataAspectsMap().containsKey(classDefinition.getName())) + getRecordMetadataAspectsMap().containsKey(classDefinition.getName())) { result = true; } @@ -961,7 +906,8 @@ public class RecordServiceImpl extends BaseBehaviourBean { // move the document into the file plan nodeService.moveNode(nodeRef, newRecordContainer, ContentModel.ASSOC_CONTAINS, parentAssoc.getQName()); - } finally + } + finally { behaviourFilter.enableBehaviour(); } @@ -1000,12 +946,14 @@ public class RecordServiceImpl extends BaseBehaviourBean // set the extended security extendedSecurityService.set(nodeRef, readersAndWriters); - } finally + } + finally { ruleService.enableRules(); } } - } finally + } + finally { ruleService.enableRuleType("outbound"); } @@ -1046,7 +994,8 @@ public class RecordServiceImpl extends BaseBehaviourBean LOGGER.debug(msg); throw new RecordCreationException(msg); } - } else + } + else { // verify that the provided file plan is actually a file plan if (!filePlanService.isFilePlan(filePlan)) @@ -1162,7 +1111,8 @@ public class RecordServiceImpl extends BaseBehaviourBean // create a copy of the original state and add it to the unfiled record container FileInfo recordInfo = fileFolderService.copy(nodeRef, unfiledRecordFolder, null); record = recordInfo.getNodeRef(); - } finally + } + finally { recordsManagementContainerType.enable(); } @@ -1173,7 +1123,8 @@ public class RecordServiceImpl extends BaseBehaviourBean try { nodeService.removeAspect(record, ContentModel.ASPECT_VERSIONABLE); - } finally + } + finally { behaviourFilter.enableBehaviour(ContentModel.ASPECT_VERSIONABLE); } @@ -1196,14 +1147,16 @@ public class RecordServiceImpl extends BaseBehaviourBean if (originalAssocs == null) { nodeService.removeAspect(record, ContentModel.ASPECT_COPIEDFROM); - } else + } + else { for (AssociationRef originalAssoc : originalAssocs) { nodeService.createAssociation(record, originalAssoc.getTargetRef(), ContentModel.ASSOC_ORIGINAL); } } - } catch (FileNotFoundException e) + } + catch (FileNotFoundException e) { throw new AlfrescoRuntimeException("Can't create recorded version, because copy fails.", e); } @@ -1219,7 +1172,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Helper to get the latest version record for a given document (ie non-record) * - * @param nodeRef node reference + * @param nodeRef node reference * @return NodeRef latest version record, null otherwise */ private NodeRef getLatestVersionRecord(NodeRef nodeRef) @@ -1274,7 +1227,8 @@ public class RecordServiceImpl extends BaseBehaviourBean if (type == null) { type = ContentModel.TYPE_CONTENT; - } else if (!dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) + } + else if (!dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) { throw new AlfrescoRuntimeException("Record can only be created from a sub-type of cm:content."); } @@ -1319,7 +1273,8 @@ public class RecordServiceImpl extends BaseBehaviourBean } }); - } finally + } + finally { enablePropertyEditableCheck(); } @@ -1344,7 +1299,7 @@ public class RecordServiceImpl extends BaseBehaviourBean authenticationUtil.runAsSystem(new RunAsWork() { @Override - public Void doWork() throws Exception + public Void doWork() throws Exception { nodeService.addAspect(document, RecordsManagementModel.ASPECT_RECORD, null); @@ -1357,7 +1312,8 @@ public class RecordServiceImpl extends BaseBehaviourBean return null; } }); - } finally + } + finally { ruleService.enableRules(); enablePropertyEditableCheck(); @@ -1391,9 +1347,9 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Helper method to 'file' a new document that arrived in the file plan structure. - *

      - * TODO atm we only 'file' content as a record .. may need to consider other types if we - * are to support the notion of composite records. + * + * TODO atm we only 'file' content as a record .. may need to consider other types if we + * are to support the notion of composite records. * * @param record node reference to record (or soon to be record!) */ @@ -1405,8 +1361,8 @@ public class RecordServiceImpl extends BaseBehaviourBean // we only support filling of content items // TODO composite record support needs to file containers too QName type = nodeService.getType(record); - if (ContentModel.TYPE_CONTENT.equals(type) || - dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) + if (ContentModel.TYPE_CONTENT.equals(type) || + dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) { // fire before file record policy beforeFileRecord.get(getTypeAndApsects(record)).beforeFileRecord(record); @@ -1464,10 +1420,10 @@ public class RecordServiceImpl extends BaseBehaviourBean // get record property values final Map properties = nodeService.getProperties(nodeRef); - final String recordId = (String) properties.get(PROP_IDENTIFIER); - final String documentOwner = (String) properties.get(PROP_RECORD_ORIGINATING_USER_ID); - final String originalName = (String) properties.get(PROP_ORIGIONAL_NAME); - final NodeRef originatingLocation = (NodeRef) properties.get(PROP_RECORD_ORIGINATING_LOCATION); + final String recordId = (String)properties.get(PROP_IDENTIFIER); + final String documentOwner = (String)properties.get(PROP_RECORD_ORIGINATING_USER_ID); + final String originalName = (String)properties.get(PROP_ORIGIONAL_NAME); + final NodeRef originatingLocation = (NodeRef)properties.get(PROP_RECORD_ORIGINATING_LOCATION); // we can only reject if the originating location is present if (originatingLocation != null) @@ -1496,7 +1452,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { fileFolderService.rename(nodeRef, originalName); - String name = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); + String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); LOGGER.debug("Rename {} to {}", name, originalName); } @@ -1523,7 +1479,8 @@ public class RecordServiceImpl extends BaseBehaviourBean // send an email to the record creator notificationHelper.recordRejectedEmailNotification(nodeRef, recordId, documentOwner); } - } finally + } + finally { ruleService.enableRules(); } @@ -1540,7 +1497,7 @@ public class RecordServiceImpl extends BaseBehaviourBean for (QName aspect : aspects) { if (RM_URI.equals(aspect.getNamespaceURI()) || - RecordableVersionModel.RMV_URI.equals(aspect.getNamespaceURI())) + RecordableVersionModel.RMV_URI.equals(aspect.getNamespaceURI())) { nodeService.removeAspect(nodeRef, aspect); } @@ -1551,7 +1508,7 @@ public class RecordServiceImpl extends BaseBehaviourBean // Do not attempt to clean up rendition nodes which are not children of their source node. final boolean renditionRequiresCleaning = nodeService.exists(renditionNode) && - renditionAssoc.isPrimary(); + renditionAssoc.isPrimary(); if (renditionRequiresCleaning) { @@ -1607,7 +1564,7 @@ public class RecordServiceImpl extends BaseBehaviourBean for (AccessPermission perm : perms) { if ((perm.getPermission().contains(RMPermissionModel.EDIT_NON_RECORD_METADATA) || - perm.getPermission().contains(RMPermissionModel.EDIT_RECORD_METADATA))) + perm.getPermission().contains(RMPermissionModel.EDIT_RECORD_METADATA))) { LOGGER.debug(" ... " + perm.getAuthority() + " - " + perm.getPermission() + " - " + perm.getAccessStatus().toString()); } @@ -1624,7 +1581,8 @@ public class RecordServiceImpl extends BaseBehaviourBean if (result) { LOGGER.debug(" ... property marked as always editable."); - } else + } + else { boolean allowRecordEdit = false; boolean allowNonRecordEdit = false; @@ -1639,8 +1597,8 @@ public class RecordServiceImpl extends BaseBehaviourBean allowNonRecordEdit = true; } - if (AccessStatus.ALLOWED.equals(accessRecord) || - AccessStatus.ALLOWED.equals(accessDeclaredRecord)) + if (AccessStatus.ALLOWED.equals(accessRecord) || + AccessStatus.ALLOWED.equals(accessDeclaredRecord)) { LOGGER.debug(" ... user has edit record or declared metadata capability"); allowRecordEdit = true; @@ -1650,25 +1608,29 @@ public class RecordServiceImpl extends BaseBehaviourBean { LOGGER.debug(" ... so all properties can be edited."); result = true; - } else if (allowNonRecordEdit && !allowRecordEdit) + } + else if (allowNonRecordEdit && !allowRecordEdit) { // can only edit non record properties if (!isRecordMetadata(filePlan, property)) { LOGGER.debug(" ... property is not considered record metadata so editable."); result = true; - } else + } + else { LOGGER.debug(" ... property is considered record metadata so not editable."); } - } else if (!allowNonRecordEdit && allowRecordEdit) + } + else if (!allowNonRecordEdit && allowRecordEdit) { // can only edit record properties if (isRecordMetadata(filePlan, property)) { LOGGER.debug(" ... property is considered record metadata so editable."); result = true; - } else + } + else { LOGGER.debug(" ... property is not considered record metadata so not editable."); } @@ -1681,7 +1643,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Helper method that indicates whether a property is considered record metadata or not. * - * @param property property + * @param property property * @return boolea true if record metadata, false otherwise */ private boolean isRecordMetadata(NodeRef filePlan, QName property) @@ -1701,7 +1663,8 @@ public class RecordServiceImpl extends BaseBehaviourBean if (parent != null && TYPE_NON_ELECTRONIC_DOCUMENT.equals(parent.getName())) { result = false; - } else + } + else { // check the URI's result = RECORD_MODEL_URIS.contains(property.getNamespaceURI()); @@ -1736,7 +1699,7 @@ public class RecordServiceImpl extends BaseBehaviourBean * Helper method to determine whether a property is protected at a dictionary definition * level. * - * @param property property qualified name + * @param property property qualified name * @return booelan true if protected, false otherwise */ private boolean isProtectedProperty(QName property) @@ -1796,7 +1759,8 @@ public class RecordServiceImpl extends BaseBehaviourBean if (!nodeService.hasAspect(nodeRef, typeQName)) { nodeService.addAspect(nodeRef, typeQName, null); - } else + } + else { LOGGER.info(I18NUtil.getMessage(MSG_NODE_HAS_ASPECT, nodeRef.toString(), typeQName.toString())); } @@ -1812,7 +1776,7 @@ public class RecordServiceImpl extends BaseBehaviourBean ParameterCheck.mandatory("recordFolder", recordFolder); // ensure we are linking a record to a record folder - if (isRecord(record) && isRecordFolder(recordFolder)) + if(isRecord(record) && isRecordFolder(recordFolder)) { // ensure that we are not linking a record to an existing location List parents = nodeService.getParentAssocs(record); @@ -1833,14 +1797,15 @@ public class RecordServiceImpl extends BaseBehaviourBean // create a secondary link to the record folder nodeService.addChild( - recordFolder, - record, - ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name)); + recordFolder, + record, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name)); // recalculate disposition schedule for the record when linking it dispositionService.recalculateNextDispositionStep(record); - } else + } + else { // can only link a record to a record folder throw new RecordLinkRuntimeException("Can only link a record to a record folder."); @@ -1848,6 +1813,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** + * * @param record * @param recordFolder */ @@ -1867,7 +1833,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { // we can't link a record to an incompatible disposition schedule throw new RecordLinkRuntimeException("Cannot link a record to a record folder with an incompatible retention schedule. " - + "They must either both be record level or record folder level retentions."); + + "They must either both be record level or record folder level retentions."); } } } @@ -1883,7 +1849,7 @@ public class RecordServiceImpl extends BaseBehaviourBean ParameterCheck.mandatory("recordFolder", recordFolder); // ensure we are unlinking a record from a record folder - if (isRecord(record) && isRecordFolder(recordFolder)) + if(isRecord(record) && isRecordFolder(recordFolder)) { // check that we are not trying to unlink the primary parent NodeRef primaryParent = nodeService.getPrimaryParent(record).getParentRef(); @@ -1897,7 +1863,8 @@ public class RecordServiceImpl extends BaseBehaviourBean // recalculate disposition schedule for record after unlinking it dispositionService.recalculateNextDispositionStep(record); - } else + } + else { // can only unlink a record from a record folder throw new RecordLinkRuntimeException("Can only unlink a record from a record folder."); @@ -1909,11 +1876,11 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override @Behaviour - ( - kind = BehaviourKind.CLASS, - type = "rma:record", - notificationFrequency = TRANSACTION_COMMIT - ) + ( + kind = BehaviourKind.CLASS, + type = "rma:record", + notificationFrequency = TRANSACTION_COMMIT + ) public void onContentUpdate(NodeRef nodeRef, boolean newContent) { if (nodeService.exists(nodeRef) && !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN) && !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE)) @@ -1926,7 +1893,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Invoke invokeBeforeRecordDeclaration policy * - * @param nodeRef node reference + * @param nodeRef node reference */ protected void invokeBeforeRecordDeclaration(NodeRef nodeRef) { @@ -1940,7 +1907,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Invoke invokeOnRecordDeclaration policy * - * @param nodeRef node reference + * @param nodeRef node reference */ protected void invokeOnRecordDeclaration(NodeRef nodeRef) { @@ -1954,7 +1921,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Invoke invokeBeforeRecordRejection policy * - * @param nodeRef node reference + * @param nodeRef node reference */ protected void invokeBeforeRecordRejection(NodeRef nodeRef) { @@ -1968,7 +1935,7 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * Invoke invokeOnRecordRejection policy * - * @param nodeRef node reference + * @param nodeRef node reference */ protected void invokeOnRecordRejection(NodeRef nodeRef) { @@ -1981,17 +1948,17 @@ public class RecordServiceImpl extends BaseBehaviourBean /** * RM-5244 - workaround to make sure the incomplete aspect is removed - * + * * @param nodeRef the node to reevaluate for */ private void reevaluateIncompleteTag(NodeRef nodeRef) { /* * Check if the node has the aspect because the reevaluation is expensive. - * If the node doesn't have the aspect it means IncompleteNodeTagger didn't load before TransactionBehaviourQueue + * If the node doesn't have the aspect it means IncompleteNodeTagger didn't load before TransactionBehaviourQueue * and we don't need to reevaluate. */ - if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_INCOMPLETE)) + if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_INCOMPLETE)) { incompleteNodeTagger.beforeCommit(false); } @@ -2162,4 +2129,4 @@ public class RecordServiceImpl extends BaseBehaviourBean localName = MessageFormat.format("{0}CustomProperties", localName); return QName.createQName(RM_CUSTOM_URI, localName); } -} +} \ No newline at end of file diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/rule/FilePlanRuleInheritanceTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/rule/FilePlanRuleInheritanceTest.java index b465953eae..857310927d 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/rule/FilePlanRuleInheritanceTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/rule/FilePlanRuleInheritanceTest.java @@ -76,6 +76,7 @@ public class FilePlanRuleInheritanceTest extends BaseRMTestCase doBehaviourDrivenTest(new BehaviourDrivenTest() { private NodeRef filePlan = null; + private Rule rule = null; private List rules = null; public void given() @@ -83,24 +84,24 @@ public class FilePlanRuleInheritanceTest extends BaseRMTestCase filePlan = createFilePlan(); // create a rule that applies to childre - Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); - Rule rule = new Rule(); + Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); + rule = new Rule(); rule.setRuleType("inbound"); rule.setAction(completeRecordAction); rule.applyToChildren(true); - + } + + public void when() + { // save rule on file plan root parent folder ruleService.saveRule(folder, rule); } - - public void when() + + public void then() { // get rules, including those inherited rules = ruleService.getRules(filePlan, true); - } - - public void then() - { + // rules aren't inhreited from file plan root parent folder assertEquals(0, rules.size()); } @@ -121,31 +122,32 @@ public class FilePlanRuleInheritanceTest extends BaseRMTestCase { private NodeRef filePlan = null; private List rules = null; - + private Rule rule = null; + public void given() { filePlan = createFilePlan(); // create a rule that applies to childre - Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); - Rule rule = new Rule(); + Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); + rule = new Rule(); rule.setRuleType("inbound"); rule.setAction(completeRecordAction); rule.applyToChildren(true); - + } + + public void when() + { // save rule on file plan root ruleService.saveRule(filePlan, rule); } - - public void when() + + public void then() { // get rules, including those inherited NodeRef unfiledRecordContainer = filePlanService.getUnfiledContainer(filePlan); rules = ruleService.getRules(unfiledRecordContainer, true); - } - - public void then() - { + // rules aren't inhreited from file plan root assertEquals(0, rules.size()); } @@ -164,31 +166,32 @@ public class FilePlanRuleInheritanceTest extends BaseRMTestCase { private NodeRef filePlan = null; private List rules = null; - + private Rule rule = null; + public void given() { filePlan = createFilePlan(); // create a rule that applies to childre - Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); - Rule rule = new Rule(); + Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); + rule = new Rule(); rule.setRuleType("inbound"); rule.setAction(completeRecordAction); rule.applyToChildren(true); - + } + + public void when() + { // save rule on file plan root ruleService.saveRule(filePlan, rule); } - - public void when() + + public void then() { // get rules, including those inherited NodeRef container = filePlanService.getHoldContainer(filePlan); rules = ruleService.getRules(container, true); - } - - public void then() - { + // rules aren't inhreited from file plan root assertEquals(0, rules.size()); } @@ -207,31 +210,32 @@ public class FilePlanRuleInheritanceTest extends BaseRMTestCase { private NodeRef filePlan = null; private List rules = null; - + private Rule rule = null; + public void given() { filePlan = createFilePlan(); // create a rule that applies to childre - Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); - Rule rule = new Rule(); + Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); + rule = new Rule(); rule.setRuleType("inbound"); rule.setAction(completeRecordAction); rule.applyToChildren(true); - + } + + public void when() + { // save rule on file plan root ruleService.saveRule(filePlan, rule); } - - public void when() + + public void then() { // get rules, including those inherited NodeRef container = filePlanService.getTransferContainer(filePlan); rules = ruleService.getRules(container, true); - } - - public void then() - { + // rules aren't inhreited from file plan root assertEquals(0, rules.size()); } @@ -251,31 +255,32 @@ public class FilePlanRuleInheritanceTest extends BaseRMTestCase private NodeRef filePlan = null; private NodeRef recordCategory = null; private List rules = null; - + private Rule rule = null; + public void given() { filePlan = createFilePlan(); recordCategory = filePlanService.createRecordCategory(filePlan, GUID.generate()); // create a rule that applies to childre - Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); - Rule rule = new Rule(); + Action completeRecordAction = actionService.createAction(DeclareRecordAction.NAME); + rule = new Rule(); rule.setRuleType("inbound"); rule.setAction(completeRecordAction); rule.applyToChildren(true); - + } + + public void when() + { // save rule on file plan root ruleService.saveRule(filePlan, rule); } - - public void when() + + public void then() { // get rules, including those inherited rules = ruleService.getRules(recordCategory, true); - } - - public void then() - { + // rules aren't inhreited from file plan root assertEquals(1, rules.size()); } From 5d02384f246eb01c5881254286f73f6de799acbc Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Sun, 25 Jun 2017 11:01:11 +0100 Subject: [PATCH 15/18] tidy up --- .../records/CompleteRecordTests.java | 142 ++++++++---------- 1 file changed, 66 insertions(+), 76 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java index e099fd9afb..d2d241e02f 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java @@ -38,9 +38,11 @@ import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; import static org.testng.Assert.assertEquals; import java.util.Arrays; +import java.util.List; import org.alfresco.rest.rm.community.base.BaseRMRestTest; import org.alfresco.rest.rm.community.model.record.Record; +import org.alfresco.rest.rm.community.model.site.RMSite; import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI; @@ -68,22 +70,10 @@ public class CompleteRecordTests extends BaseRMRestTest public Object[][] getIncompleteRecordsMandatoryMetadataMissing() throws Exception { //create RM site - RMSiteAPI rmSiteAPI = getRestAPIFactory().getRMSiteAPI(); - rmSiteAPI.deleteRMSite(); - rmSiteAPI.createRMSite(createDOD5015RMSiteModel()); - assertStatusCode(CREATED); + createRMSite(createDOD5015RMSiteModel()); - // create record folder - String recordFolderId = createCategoryFolderInFilePlan().getId(); - - Record electronicRecord = createAndVerifyElectronicRecord(recordFolderId); - Record nonElectronicRecord = createAndVerifyNonElectronicRecord(recordFolderId); - - return new String[][] - { - // an arbitrary record folder - { electronicRecord.getId(), nonElectronicRecord.getId() }, - }; + // create electronic and non-electronic records + return createAndVerifyRecordsInFolder(); } /** @@ -93,22 +83,10 @@ public class CompleteRecordTests extends BaseRMRestTest public Object[][] getIncompleteRecordsMandatoryMetadataPresent() throws Exception { //create RM site - RMSiteAPI rmSiteAPI = getRestAPIFactory().getRMSiteAPI(); - rmSiteAPI.deleteRMSite(); - rmSiteAPI.createRMSite(createStandardRMSiteModel()); - assertStatusCode(CREATED); + createRMSite(createStandardRMSiteModel()); - // create record folder - String recordFolderId = createCategoryFolderInFilePlan().getId(); - - Record electronicRecord = createAndVerifyElectronicRecord(recordFolderId); - Record nonElectronicRecord = createAndVerifyNonElectronicRecord(recordFolderId); - - return new String[][] - { - // an arbitrary record folder - { electronicRecord.getId(), nonElectronicRecord.getId() }, - }; + // create electronic and non-electronic records + return createAndVerifyRecordsInFolder(); } /** @@ -143,20 +121,17 @@ public class CompleteRecordTests extends BaseRMRestTest public void completeRecordWithMandatoryMetadataMissing(String electronicRecordId, String nonElectronicRecordId) throws Exception { - // Get the recordsAPI - RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); - Record electronicRecord = recordsAPI.getRecord(electronicRecordId); - Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); + List records = getRecordsList(electronicRecordId, nonElectronicRecordId); - for (Record record : Arrays.asList(electronicRecord, nonElectronicRecord)) + for (Record record : records) { - verifyRecordIsIncomplete(record); + verifyRecordCompletionStatus(record, INCOMPLETE); // Complete record - recordsAPI.completeRecord(record.getId(), parameters); + completeRecord(record); assertStatusCode(UNPROCESSABLE_ENTITY); - verifyRecordIsIncomplete(record); + verifyRecordCompletionStatus(record, INCOMPLETE); } } @@ -177,20 +152,17 @@ public class CompleteRecordTests extends BaseRMRestTest public void completeRecordWithMandatoryMetadataPresent(String electronicRecordId, String nonElectronicRecordId) throws Exception { - // Get the recordsAPI - RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); - Record electronicRecord = recordsAPI.getRecord(electronicRecordId); - Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); + List records = getRecordsList(electronicRecordId, nonElectronicRecordId); - for (Record record : Arrays.asList(electronicRecord, nonElectronicRecord)) + for (Record record : records) { - verifyRecordIsIncomplete(record); + verifyRecordCompletionStatus(record, INCOMPLETE); // Complete record - recordsAPI.completeRecord(record.getId(), parameters); + completeRecord(record); assertStatusCode(CREATED); - verifyRecordIsComplete(record); + verifyRecordCompletionStatus(record, COMPLETE); } } @@ -231,72 +203,90 @@ public class CompleteRecordTests extends BaseRMRestTest public void completeAlreadyCompletedRecord(String electronicRecordId, String nonElectronicRecordId) throws Exception { - // Get the recordsAPI - RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); - Record electronicRecord = recordsAPI.getRecord(electronicRecordId); - Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); + List records = getRecordsList(electronicRecordId, nonElectronicRecordId); - for (Record record : Arrays.asList(electronicRecord, nonElectronicRecord)) + for (Record record : records) { - verifyRecordIsIncomplete(record); + verifyRecordCompletionStatus(record, INCOMPLETE); // Complete record - recordsAPI.completeRecord(record.getId(), parameters); + completeRecord(record); assertStatusCode(CREATED); - verifyRecordIsComplete(record); + verifyRecordCompletionStatus(record, COMPLETE); // Complete record - recordsAPI.completeRecord(record.getId(), parameters); + completeRecord(record); assertStatusCode(UNPROCESSABLE_ENTITY); } } /** - * Helper method to create an electronic record and and assert successful creation + * Helper method to create an RM site and assert successful creation */ - private Record createAndVerifyElectronicRecord(String recordFolderId) throws Exception + private void createRMSite(RMSite rmSiteModel) throws Exception + { + RMSiteAPI rmSiteAPI = getRestAPIFactory().getRMSiteAPI(); + rmSiteAPI.deleteRMSite(); + rmSiteAPI.createRMSite(rmSiteModel); + assertStatusCode(CREATED); + } + + /** + * Helper method to create records and and assert successful creation + */ + private String[][] createAndVerifyRecordsInFolder() throws Exception { - //create electronic record in record folder RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); + + // create record folder + String recordFolderId = createCategoryFolderInFilePlan().getId(); + + // create electronic record in record folder Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolderId, getFile(IMAGE_FILE)); assertStatusCode(CREATED); - return electronicRecord; - } - - /** - * Helper method to create a non-electronic record and and assert successful creation - */ - private Record createAndVerifyNonElectronicRecord(String recordFolderId) throws Exception - { - //create non-electronic record in record folder - RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); + // create non-electronic record in record folder Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(), recordFolderId); assertStatusCode(CREATED); - return nonElectronicRecord; + return new String[][] + { + { electronicRecord.getId(), nonElectronicRecord.getId() }, + }; } /** - * Helper method to verify that a record is not complete + * Helper method to provide list of records from record Ids */ - private void verifyRecordIsIncomplete(Record record) + private List getRecordsList(String electronicRecordId, String nonElectronicRecordId) { + // Get the recordsAPI RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); - Record recordModel = recordsAPI.getRecord(record.getId(), parameters); - assertEquals(recordModel.getIsCompleted(), INCOMPLETE); + + Record electronicRecord = recordsAPI.getRecord(electronicRecordId); + Record nonElectronicRecord = recordsAPI.getRecord(nonElectronicRecordId); + + return Arrays.asList(electronicRecord,nonElectronicRecord); } /** - * Helper method to verify that a record is completed + * Helper method to verify record is complete or incomplete */ - private void verifyRecordIsComplete(Record record) + private void verifyRecordCompletionStatus(Record record, Boolean completionStatus) { RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); Record recordModel = recordsAPI.getRecord(record.getId(), parameters); - assertEquals(recordModel.getIsCompleted(), COMPLETE); + assertEquals(recordModel.getIsCompleted(), completionStatus); } + /** + * Helper method to complete a record + */ + private void completeRecord(Record record) throws Exception + { + RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); + recordsAPI.completeRecord(record.getId(), parameters); + } } From 7269b33c65af915d5a60096aadabc0567eee1fe6 Mon Sep 17 00:00:00 2001 From: Sara Aspery Date: Mon, 26 Jun 2017 12:41:02 +0100 Subject: [PATCH 16/18] changes following review --- .../records/CompleteRecordTests.java | 10 +-- .../action/impl/DeclareRecordAction.java | 23 ++++- .../record/RecordServiceImpl.java | 89 +++++++++---------- 3 files changed, 68 insertions(+), 54 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java index d2d241e02f..a46a3dd5bf 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java @@ -61,7 +61,7 @@ public class CompleteRecordTests extends BaseRMRestTest { private static final Boolean COMPLETE = true; private static final Boolean INCOMPLETE = false; - private static final String parameters = "include=isCompleted"; + private static final String PARAMETERS = "include=isCompleted"; /** * Incomplete records with mandatory meta-data missing @@ -106,7 +106,7 @@ public class CompleteRecordTests extends BaseRMRestTest /** *

            * Given the repository is configured to check mandatory data before completing a record
      -     * And an incomplete record with missing mandatory meta-data
      +     * And an incomplete record with its mandatory meta-data missing
            * When I complete the record
            * Then I receive an error indicating that I can't complete the operation,
            * because some of the mandatory meta-data of the record is missing
      @@ -183,7 +183,7 @@ public class CompleteRecordTests extends BaseRMRestTest
           {
               // Get the recordsAPI
               RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI();
      -        recordsAPI.completeRecord(nonRecordId, parameters);
      +        recordsAPI.completeRecord(nonRecordId, PARAMETERS);
               assertStatusCode(BAD_REQUEST);
           }
       
      @@ -277,7 +277,7 @@ public class CompleteRecordTests extends BaseRMRestTest
           private void verifyRecordCompletionStatus(Record record, Boolean completionStatus)
           {
               RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI();
      -        Record recordModel = recordsAPI.getRecord(record.getId(), parameters);
      +        Record recordModel = recordsAPI.getRecord(record.getId(), PARAMETERS);
               assertEquals(recordModel.getIsCompleted(), completionStatus);
           }
       
      @@ -287,6 +287,6 @@ public class CompleteRecordTests extends BaseRMRestTest
           private void completeRecord(Record record) throws Exception
           {
               RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI();
      -        recordsAPI.completeRecord(record.getId(), parameters);
      +        recordsAPI.completeRecord(record.getId(), PARAMETERS);
           }
       }
      diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java
      index 7c8c6ba1df..c468f109ac 100644
      --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java
      +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java
      @@ -27,6 +27,9 @@
       
       package org.alfresco.module.org_alfresco_module_rm.action.impl;
       
      +import java.util.HashMap;
      +import java.util.Map;
      +
       import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase;
       import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
       import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
      @@ -42,6 +45,8 @@ import org.alfresco.util.ParameterCheck;
        */
       public class DeclareRecordAction extends RMActionExecuterAbstractBase
       {
      +    private static final String MISSING_PROPERTIES = "missingProperties";
      +    
           /** action name */
           public static final String NAME = "declareRecord";
       
      @@ -71,11 +76,25 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase
               }
               catch (IntegrityException e)
               {
      -            if (e.getMessage().contains("missing"))
      +            Map errorMap = getErrorMessageMap();
      +            if (e.getMsgId().equals(errorMap.get(MISSING_PROPERTIES)))
                   {
      -                action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, "missingProperties");
      +                action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, MISSING_PROPERTIES);
                   }
               }
       
           }
      +
      +    /**
      +     * TODO: needs to be properties file
      +     * Temporary Helper method to get the map of complete record error message keys with associated message text
      +     * @return errorMap
      +     */
      +    private Map getErrorMessageMap() {
      +        Map errorMap = new HashMap<>();
      +        errorMap.put("missingProperties", "The record has missing mandatory properties.");
      +        errorMap.put("alreadyCompleted", "The record is already completed.");
      +        errorMap.put("unsuitableNode", "The node is not a record or the record does not exist or is frozen.");
      +        return errorMap;
      +    }
       }
      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 b614ab292a..3dc1c547b9 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
      @@ -1972,6 +1972,39 @@ public class RecordServiceImpl extends BaseBehaviourBean
           @Override
           public void complete(NodeRef nodeRef)
           {
      +        validateForCompletion(nodeRef);
      +        disablePropertyEditableCheck();
      +        try
      +        {
      +            // Add the declared aspect
      +            Map declaredProps = new HashMap<>(2);
      +            declaredProps.put(PROP_DECLARED_AT, new Date());
      +            declaredProps.put(PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser());
      +            nodeService.addAspect(nodeRef, ASPECT_DECLARED_RECORD, declaredProps);
      +
      +            AuthenticationUtil.runAsSystem(new RunAsWork()
      +            {
      +                @Override
      +                public Void doWork()
      +                {
      +                    // remove all owner related rights
      +                    ownableService.setOwner(nodeRef, OwnableService.NO_OWNER);
      +                    return null;
      +                }
      +            });
      +        } finally
      +        {
      +            enablePropertyEditableCheck();
      +        }
      +    }
      +
      +    /**
      +     * Helper method to validate whether the node is in a state suitable for completion
      +     *
      +     * @param nodeRef node reference
      +     * @throws Exception if node not valid for completion
      +     */
      +    private void validateForCompletion(NodeRef nodeRef) {
               if (nodeService.exists(nodeRef) && isRecord(nodeRef) && !freezeService.isFrozen(nodeRef))
               {
                   if (!isDeclared(nodeRef))
      @@ -1985,32 +2018,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
       
                       List missingProperties = new ArrayList<>(5);
                       // Aspect not already defined - check mandatory properties then add
      -                if (!checkMandatoryPropertiesEnabled || mandatoryPropertiesSet(nodeRef, missingProperties))
      -                {
      -                    disablePropertyEditableCheck();
      -                    try
      -                    {
      -                        // Add the declared aspect
      -                        Map declaredProps = new HashMap<>(2);
      -                        declaredProps.put(PROP_DECLARED_AT, new Date());
      -                        declaredProps.put(PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser());
      -                        nodeService.addAspect(nodeRef, ASPECT_DECLARED_RECORD, declaredProps);
      -
      -                        AuthenticationUtil.runAsSystem(new RunAsWork()
      -                        {
      -                            @Override
      -                            public Void doWork()
      -                            {
      -                                // remove all owner related rights
      -                                ownableService.setOwner(nodeRef, OwnableService.NO_OWNER);
      -                                return null;
      -                            }
      -                        });
      -                    } finally
      -                    {
      -                        enablePropertyEditableCheck();
      -                    }
      -                } else
      +                if (checkMandatoryPropertiesEnabled && !mandatoryPropertiesSet(nodeRef, missingProperties))
                       {
                           LOGGER.debug(buildMissingPropertiesErrorString(missingProperties));
                           throw new IntegrityException("The record has missing mandatory properties.", null);
      @@ -2025,10 +2033,9 @@ public class RecordServiceImpl extends BaseBehaviourBean
                   {
                       LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString()));
                   }
      -            throw new IntegrityException("The record does not exist or is frozen.", null);
      +            throw new IntegrityException("The node is not a record or the record does not exist or is frozen.", null);
               }
           }
      -
           private String buildMissingPropertiesErrorString(List missingProperties)
           {
               StringBuilder builder = new StringBuilder(255);
      @@ -2087,29 +2094,17 @@ public class RecordServiceImpl extends BaseBehaviourBean
               {
                   if (propDef.isMandatory() && nodeRefProps.get(propDef.getName()) == null)
                   {
      -                logMissingProperty(propDef, missingProperties);
      -                ;
      +                if (LOGGER.isWarnEnabled())
      +                {
      +                    StringBuilder msg = new StringBuilder();
      +                    msg.append("Mandatory property missing: ").append(propDef.getName());
      +                    LOGGER.warn(msg.toString());
      +                }
      +                missingProperties.add(propDef.getName().toString());
                   }
               }
           }
       
      -    /**
      -     * Log information about missing properties.
      -     *
      -     * @param propDef           property definition
      -     * @param missingProperties missing properties
      -     */
      -    private void logMissingProperty(PropertyDefinition propDef, List missingProperties)
      -    {
      -        if (LOGGER.isWarnEnabled())
      -        {
      -            StringBuilder msg = new StringBuilder();
      -            msg.append("Mandatory property missing: ").append(propDef.getName());
      -            LOGGER.warn(msg.toString());
      -        }
      -        missingProperties.add(propDef.getName().toString());
      -    }
      -
           /**
            * Helper method to get the custom aspect for a given nodeRef type
            *
      
      From cbabf8e5455fe77c494ecfa2a3394a378b02ac55 Mon Sep 17 00:00:00 2001
      From: Sara Aspery 
      Date: Tue, 27 Jun 2017 12:48:59 +0100
      Subject: [PATCH 17/18] updated serialId in new RecordMissingMetadataException
      
      ---
       .../requests/gscore/api/RecordsAPI.java       |  10 ++
       .../action/impl/DeclareRecordAction.java      |  28 +---
       .../RecordMissingMetadataException.java       |  63 +++++++++
       .../record/RecordServiceImpl.java             | 132 ++++++++++--------
       .../api/records/RecordsEntityResource.java    |  10 +-
       5 files changed, 165 insertions(+), 78 deletions(-)
       create mode 100644 rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordMissingMetadataException.java
      
      diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java
      index e39c8034be..6864754edb 100644
      --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java
      +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java
      @@ -139,6 +139,16 @@ public class RecordsAPI extends RMModelRequest
               ));
           }
       
      +    /**
      +     * see {@link #completeRecord(String, String)
      +     */
      +    public Record completeRecord(String recordId) throws Exception
      +    {
      +        mandatoryString("recordId", recordId);
      +
      +        return completeRecord(recordId, EMPTY);
      +    }
      +
           /**
            * Complete the record recordId
            *
      diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java
      index c468f109ac..2042701e27 100644
      --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java
      +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java
      @@ -27,10 +27,8 @@
       
       package org.alfresco.module.org_alfresco_module_rm.action.impl;
       
      -import java.util.HashMap;
      -import java.util.Map;
      -
       import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase;
      +import org.alfresco.module.org_alfresco_module_rm.record.RecordMissingMetadataException;
       import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
       import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
       import org.alfresco.repo.node.integrity.IntegrityException;
      @@ -74,27 +72,15 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase
               {
                   recordService.complete(actionedUponNodeRef);
               }
      +        catch (RecordMissingMetadataException e)
      +        {
      +            action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, MISSING_PROPERTIES);
      +        }
               catch (IntegrityException e)
               {
      -            Map errorMap = getErrorMessageMap();
      -            if (e.getMsgId().equals(errorMap.get(MISSING_PROPERTIES)))
      -            {
      -                action.setParameterValue(ActionExecuterAbstractBase.PARAM_RESULT, MISSING_PROPERTIES);
      -            }
      +            // IntegrityException is deliberately ignored here, there should be no action taken
               }
       
           }
      -
      -    /**
      -     * TODO: needs to be properties file
      -     * Temporary Helper method to get the map of complete record error message keys with associated message text
      -     * @return errorMap
      -     */
      -    private Map getErrorMessageMap() {
      -        Map errorMap = new HashMap<>();
      -        errorMap.put("missingProperties", "The record has missing mandatory properties.");
      -        errorMap.put("alreadyCompleted", "The record is already completed.");
      -        errorMap.put("unsuitableNode", "The node is not a record or the record does not exist or is frozen.");
      -        return errorMap;
      -    }
      +    
       }
      diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordMissingMetadataException.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordMissingMetadataException.java
      new file mode 100644
      index 0000000000..74fbacd567
      --- /dev/null
      +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordMissingMetadataException.java
      @@ -0,0 +1,63 @@
      +/*
      + * #%L
      + * Alfresco Records Management Module
      + * %%
      + * Copyright (C) 2005 - 2017 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.record;
      +
      +import java.io.Serializable;
      +
      +import org.alfresco.error.AlfrescoRuntimeException;
      +
      +/**
      + * Record missing metadata exception class
      + *
      + * @author Sara Aspery
      + * @since 2.6
      + */
      +public class RecordMissingMetadataException extends AlfrescoRuntimeException
      +{
      +    private static final long serialVersionUID = 3437687270967611234L;
      +
      +    public RecordMissingMetadataException(String msgId, Throwable cause)
      +    {
      +        super(msgId, cause);
      +    }
      +
      +    public RecordMissingMetadataException(String msgId, Object[] msgParams, Throwable cause)
      +    {
      +        super(msgId, msgParams, cause);
      +    }
      +
      +    public RecordMissingMetadataException(String msgId, Object[] msgParams)
      +    {
      +        super(msgId, msgParams);
      +    }
      +
      +    public RecordMissingMetadataException(String msgId)
      +    {
      +        super(msgId);
      +    }
      +}
      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 3dc1c547b9..f6c42d8f85 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
      @@ -1992,7 +1992,8 @@ public class RecordServiceImpl extends BaseBehaviourBean
                           return null;
                       }
                   });
      -        } finally
      +        }
      +        finally
               {
                   enablePropertyEditableCheck();
               }
      @@ -2005,37 +2006,87 @@ public class RecordServiceImpl extends BaseBehaviourBean
            * @throws Exception if node not valid for completion
            */
           private void validateForCompletion(NodeRef nodeRef) {
      -        if (nodeService.exists(nodeRef) && isRecord(nodeRef) && !freezeService.isFrozen(nodeRef))
      +        if (!nodeService.exists(nodeRef))
               {
      -            if (!isDeclared(nodeRef))
      -            {
      -                // if the record is newly created make sure the record identifier is set before completing the record
      -                Set newRecords = transactionalResourceHelper.getSet(RecordServiceImpl.KEY_NEW_RECORDS);
      -                if (newRecords.contains(nodeRef))
      -                {
      -                    generateRecordIdentifier(nodeService, identifierService, nodeRef);
      -                }
      +            logError(nodeRef);
      +            throw new IntegrityException("The record does not exist.", null);
      +        }
      +        
      +        if (!isRecord(nodeRef))
      +        {
      +            logError(nodeRef);
      +            throw new IntegrityException("The node is not a record.", null);
      +        }
      +        
      +        if (freezeService.isFrozen(nodeRef))
      +        {
      +            logError(nodeRef);
      +            throw new IntegrityException("The record is frozen.", null);
      +        }
       
      -                List missingProperties = new ArrayList<>(5);
      -                // Aspect not already defined - check mandatory properties then add
      -                if (checkMandatoryPropertiesEnabled && !mandatoryPropertiesSet(nodeRef, missingProperties))
      -                {
      -                    LOGGER.debug(buildMissingPropertiesErrorString(missingProperties));
      -                    throw new IntegrityException("The record has missing mandatory properties.", null);
      -                }
      -            } else
      -            {
      -                throw new IntegrityException("The record is already completed.", null);
      -            }
      -        } else
      +        if (isDeclared(nodeRef))
               {
      -            if (LOGGER.isWarnEnabled())
      +            throw new IntegrityException("The record is already completed.", null);
      +        }
      +
      +        // if the record is newly created make sure the record identifier is set before completing the record
      +        Set newRecords = transactionalResourceHelper.getSet(RecordServiceImpl.KEY_NEW_RECORDS);
      +        if (newRecords.contains(nodeRef))
      +        {
      +            generateRecordIdentifier(nodeService, identifierService, nodeRef);
      +        }
      +
      +        // Validate that all mandatory properties, if any, are present
      +        List missingProperties = new ArrayList<>(5);
      +        // Aspect not already defined - check mandatory properties then add
      +        if (checkMandatoryPropertiesEnabled)
      +        {
      +            Map nodeRefProps = nodeService.getProperties(nodeRef);
      +            QName nodeRefType = nodeService.getType(nodeRef);
      +
      +            // check for missing mandatory metadata from type definitions
      +            TypeDefinition typeDef = dictionaryService.getType(nodeRefType);
      +            checkDefinitionMandatoryPropsSet(typeDef, nodeRefProps, missingProperties);
      +
      +            // check for missing mandatory metadata from aspect definitions
      +            Set aspects = nodeService.getAspects(nodeRef);
      +            for (QName aspect : aspects)
                   {
      -                LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString()));
      +                AspectDefinition aspectDef = dictionaryService.getAspect(aspect);
      +                checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties);
      +            }
      +
      +            // check for missing mandatory metadata from custom aspect definitions
      +            QName customAspect = getCustomAspectImpl(nodeRefType);
      +            AspectDefinition aspectDef = dictionaryService.getAspect(customAspect);
      +            checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties);
      +
      +            if (!missingProperties.isEmpty())
      +            {
      +                LOGGER.debug(buildMissingPropertiesErrorString(missingProperties));
      +                throw new RecordMissingMetadataException("The record has missing mandatory properties.");
                   }
      -            throw new IntegrityException("The node is not a record or the record does not exist or is frozen.", null);
               }
           }
      +
      +    /**
      +     * Helper method to log a warning to the log file
      +     *
      +     * @param nodeRef           node for which error occurred
      +     */
      +    private void logError(NodeRef nodeRef) {
      +        if (LOGGER.isWarnEnabled())
      +        {
      +            LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString()));
      +        }
      +    }
      +
      +    /**
      +     * Helper method to build single string containing list of missing properties 
      +     *
      +     * @param missingProperties list of missing properties
      +     * @return String of missing properties
      +     */
           private String buildMissingPropertiesErrorString(List missingProperties)
           {
               StringBuilder builder = new StringBuilder(255);
      @@ -2048,37 +2099,6 @@ public class RecordServiceImpl extends BaseBehaviourBean
               return builder.toString();
           }
       
      -    /**
      -     * Helper method to check whether all the mandatory properties of the node have been set
      -     *
      -     * @param nodeRef node reference
      -     * @return boolean true if all mandatory properties are set, false otherwise
      -     */
      -    private boolean mandatoryPropertiesSet(final NodeRef nodeRef, final List missingProperties)
      -    {
      -        Map nodeRefProps = nodeService.getProperties(nodeRef);
      -        QName nodeRefType = nodeService.getType(nodeRef);
      -
      -        // check for missing mandatory metadata from type definitions
      -        TypeDefinition typeDef = dictionaryService.getType(nodeRefType);
      -        checkDefinitionMandatoryPropsSet(typeDef, nodeRefProps, missingProperties);
      -
      -        // check for missing mandatory metadata from aspect definitions
      -        Set aspects = nodeService.getAspects(nodeRef);
      -        for (QName aspect : aspects)
      -        {
      -            AspectDefinition aspectDef = dictionaryService.getAspect(aspect);
      -            checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties);
      -        }
      -
      -        // check for missing mandatory metadata from custom aspect definitions
      -        QName customAspect = getCustomAspectImpl(nodeRefType);
      -        AspectDefinition aspectDef = dictionaryService.getAspect(customAspect);
      -        checkDefinitionMandatoryPropsSet(aspectDef, nodeRefProps, missingProperties);
      -
      -        return missingProperties.isEmpty();
      -    }
      -
           /**
            * Helper method to check whether all the definition mandatory properties of the node have been set
            *
      diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java
      index fe77d89ccc..daf676ecdb 100644
      --- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java
      +++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/records/RecordsEntityResource.java
      @@ -31,6 +31,7 @@ import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.c
       import static org.alfresco.util.ParameterCheck.mandatory;
       
       import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
      +import org.alfresco.module.org_alfresco_module_rm.record.RecordMissingMetadataException;
       import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
       import org.alfresco.repo.activities.ActivityType;
       import org.alfresco.repo.node.integrity.IntegrityException;
      @@ -241,7 +242,14 @@ public class RecordsEntityResource implements BinaryResourceAction.Read,
               NodeRef record = apiUtils.validateRecord(recordId);
       
               // Complete the record
      -        recordService.complete(record);
      +        try
      +        {
      +            recordService.complete(record);
      +        }
      +        catch (RecordMissingMetadataException e)
      +        {
      +            throw new IntegrityException("The record has missing mandatory properties.", null); 
      +        }
       
               // return record state
               FileInfo info = fileFolderService.getFileInfo(record);
      
      From 29517c366c9f6b945ddb8c8a88a99ae1a8f980e8 Mon Sep 17 00:00:00 2001
      From: Sara Aspery 
      Date: Tue, 27 Jun 2017 15:12:22 +0100
      Subject: [PATCH 18/18] final change after review - replace logger method
      
      ---
       .../record/RecordServiceImpl.java              | 18 +++---------------
       1 file changed, 3 insertions(+), 15 deletions(-)
      
      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 f6c42d8f85..8da0e40161 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
      @@ -2008,19 +2008,19 @@ public class RecordServiceImpl extends BaseBehaviourBean
           private void validateForCompletion(NodeRef nodeRef) {
               if (!nodeService.exists(nodeRef))
               {
      -            logError(nodeRef);
      +            LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString()));
                   throw new IntegrityException("The record does not exist.", null);
               }
               
               if (!isRecord(nodeRef))
               {
      -            logError(nodeRef);
      +            LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString()));
                   throw new IntegrityException("The node is not a record.", null);
               }
               
               if (freezeService.isFrozen(nodeRef))
               {
      -            logError(nodeRef);
      +            LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString()));
                   throw new IntegrityException("The record is frozen.", null);
               }
       
      @@ -2069,18 +2069,6 @@ public class RecordServiceImpl extends BaseBehaviourBean
               }
           }
       
      -    /**
      -     * Helper method to log a warning to the log file
      -     *
      -     * @param nodeRef           node for which error occurred
      -     */
      -    private void logError(NodeRef nodeRef) {
      -        if (LOGGER.isWarnEnabled())
      -        {
      -            LOGGER.warn(I18NUtil.getMessage(MSG_UNDECLARED_ONLY_RECORDS, nodeRef.toString()));
      -        }
      -    }
      -
           /**
            * Helper method to build single string containing list of missing properties 
            *