diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-fileplan-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-fileplan-context.xml index 95ad0bf90e..898b546ea9 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-fileplan-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-fileplan-context.xml @@ -12,13 +12,13 @@ - + + - @@ -62,5 +62,21 @@ + + + + + + + UNFILED_RECORD_CONTAINER + + + + + + + + \ No newline at end of file diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml index 0c76022945..8fa9c83db3 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml @@ -88,6 +88,11 @@ rma:recordsManagementRoot + + + + Unfiled Record Container + rma:recordsManagementContainer @@ -618,6 +623,19 @@ true + + + Unfiled Records + + true + false + + + rma:unfiledRecordContainer + true + true + + @@ -708,7 +726,6 @@ Date Filed d:date - true @@ -824,6 +841,16 @@ rma:filePlanComponent + + + + + + + + d:any + + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 1bc9237751..eb95219e78 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -67,6 +67,7 @@ org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isFilePlanComponent=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.getFilePlanComponentKind=ACL_NODE.0.sys:base.ReadProperties, RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.getFilePlanComponentKindFromType=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordsManagementContainer=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isFilePlan=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordCategory=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordFolder=RM.Read.0 @@ -89,9 +90,9 @@ org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordFolderClosed=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.createRecordFolder=RM.Write.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.getRecords=RM.Read.0,AFTER_RM.FilterNode + org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.getRecordFolders=RM.Read.0,AFTER_RM.FilterNode org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.getRecordMetaDataAspects=RM_ALLOW - org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.getRecordFolders=RM.Read.0,AFTER_RM.FilterNode - org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordDeclared=RM.Read.0 + org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordDeclared=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.*=RM_DENY ]]> @@ -480,7 +481,13 @@ org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.createRole=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.updateRole=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.deleteRole=RM_ALLOW - org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.assignRoleToAuthority=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.assignRoleToAuthority=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.hasExtendedReaders=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.getExtendedReaders=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.setExtendedReaders=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.removeExtendedReaders=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.removeAllExtendedReaders=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.*=RM_DENY ]]> @@ -787,6 +794,68 @@ + + + + + + + + + + + + + + + org.alfresco.module.org_alfresco_module_rm.record.RecordService + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + + + + + + + + + + + + + list of record meta-data aspects - */ - Set getRecordMetaDataAspects(); - /** * Get all the record folders that a record is filed into. * @@ -463,12 +463,27 @@ public interface RecordsManagementService */ // TODO rename to List getParentRecordFolders(NodeRef record); List getRecordFolders(NodeRef record); - + + /********** Deprecated **********/ + + /** + * Get a list of all the record meta-data aspects + * + * @return {@link Set}<{@link QName}> list of record meta-data aspects + * + * @deprecated As of 2.1, replaced by {@link RecordService#getRecordMetaDataAspects()} + */ + @Deprecated + Set getRecordMetaDataAspects(); + /** * Indicates whether the record is declared - * + * * @param nodeRef node reference (record) * @return boolean true if record is declared, false otherwise + * + * @deprecated As of 2.1, replaced by {@link RecordsService#isDeclared()} */ - boolean isRecordDeclared(NodeRef nodeRef); + @Deprecated + boolean isRecordDeclared(NodeRef nodeRef); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceImpl.java index 8a25859fdd..49fa37e409 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceImpl.java @@ -20,7 +20,6 @@ package org.alfresco.module.org_alfresco_module_rm; import java.io.Serializable; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; @@ -34,11 +33,11 @@ import org.alfresco.model.RenditionModel; import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService; import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; -import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -77,7 +76,6 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, private final static String MSG_PARENT_RECORD_FOLDER_ROOT = "rm.service.parent-record-folder-root"; private final static String MSG_PARENT_RECORD_FOLDER_TYPE = "rm.service.parent-record-folder-type"; private final static String MSG_RECORD_FOLDER_TYPE = "rm.service.record-folder-type"; - private final static String MSG_NOT_RECORD = "rm.service.not-record"; /** Store that the RM roots are contained within */ @SuppressWarnings("unused") @@ -105,9 +103,6 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, /** Well-known location of the scripts folder. */ private NodeRef scriptsFolderNodeRef = new NodeRef("workspace", "SpacesStore", "rm_scripts"); - /** List of available record meta-data aspects */ - private Set recordMetaDataAspects; - /** Java behaviour */ private JavaBehaviour onChangeToDispositionActionDefinition; @@ -253,7 +248,7 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, throw new AlfrescoRuntimeException("Unable to complete operation, because only content can be filed within a record folder."); } } - } + } /** * On add content to container @@ -290,7 +285,17 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, NodeRef thumbnail = childAssocRef.getChildRef(); if (nodeService.exists(thumbnail) == true) { + // apply file plan component aspect to thumbnail nodeService.addAspect(thumbnail, ASPECT_FILE_PLAN_COMPONENT, null); + + // manage any extended readers + RecordsManagementSecurityService securityService = serviceRegistry.getRecordsManagementSecurityService(); + NodeRef parent = childAssocRef.getParentRef(); + Set readers = securityService.getExtendedReaders(parent); + if (readers != null && readers.size() != 0) + { + securityService.setExtendedReaders(thumbnail, readers, false); + } } } @@ -442,6 +447,15 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, return instanceOf(nodeRef, TYPE_FILE_PLAN); } + /** + * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementService#isRecordsManagementContainer(org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public boolean isRecordsManagementContainer(NodeRef nodeRef) + { + return instanceOf(nodeRef, TYPE_RECORDS_MANAGEMENT_CONTAINER); + } + /** * Utility method to safely and quickly determine if a node is a type (or sub-type) of the one specified. */ @@ -512,6 +526,10 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, { result = FilePlanComponentKind.DISPOSITION_SCHEDULE; } + else if (instanceOf(nodeRef, TYPE_UNFILED_RECORD_CONTAINER) == true) + { + result = FilePlanComponentKind.UNFILED_RECORD_CONTAINER; + } } return result; @@ -1001,7 +1019,7 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, List records = getRecords(recordFolder); for (NodeRef record : records) { - if (isRecordDeclared(record) == false) + if (serviceRegistry.getRecordService().isDeclared(record) == false) { result = false; break; @@ -1120,31 +1138,6 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, return createRecordFolder(parent, name, type, null); } - /** - * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementService#getRecordMetaDataAspects() - */ - public Set getRecordMetaDataAspects() - { - if (recordMetaDataAspects == null) - { - recordMetaDataAspects = new HashSet(7); - Collection aspects = dictionaryService.getAllAspects(); - for (QName aspect : aspects) - { - AspectDefinition def = dictionaryService.getAspect(aspect); - if (def != null) - { - QName parent = def.getParentName(); - if (parent != null && ASPECT_RECORD_META_DATA.equals(parent) == true) - { - recordMetaDataAspects.add(aspect); - } - } - } - } - return recordMetaDataAspects; - } - /** * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementService#getRecords(org.alfresco.service.cmr.repository.NodeRef) */ @@ -1164,21 +1157,7 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, } } return result; - } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementService#isRecord(org.alfresco.service.cmr.repository.NodeRef, boolean) - */ - public boolean isRecordDeclared(NodeRef record) - { - if (isRecord(record) == false) - { - throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NOT_RECORD, record.toString())); - } - return (this.nodeService.hasAspect(record, ASPECT_DECLARED_RECORD)); - } - - + } /** * This method examines the old and new property sets and for those properties which @@ -1271,4 +1250,24 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, return result; } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementService#getRecordMetaDataAspects() + */ + @Override + @Deprecated + public Set getRecordMetaDataAspects() + { + return serviceRegistry.getRecordService().getRecordMetaDataAspects(); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementService#isRecordDeclared(org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + @Deprecated + public boolean isRecordDeclared(NodeRef nodeRef) + { + return serviceRegistry.getRecordService().isDeclared(nodeRef); + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceRegistry.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceRegistry.java index ae6ba63928..551d1d406c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceRegistry.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceRegistry.java @@ -23,6 +23,7 @@ import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditSe import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; import org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEventService; +import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService; import org.alfresco.service.NotAuditable; import org.alfresco.service.ServiceRegistry; @@ -45,6 +46,7 @@ public interface RecordsManagementServiceRegistry extends ServiceRegistry static final QName RECORDS_MANAGEMENT_SECURITY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "RecordsManagementSecurityService"); static final QName RECORDS_MANAGEMENT_AUDIT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "RecordsManagementAuditService"); static final QName CAPABILITY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CapabilityService"); + static final QName RECORD_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "RecordService"); /** * @return records management service @@ -52,6 +54,12 @@ public interface RecordsManagementServiceRegistry extends ServiceRegistry @NotAuditable RecordsManagementService getRecordsManagementService(); + /** + * @return record service + */ + @NotAuditable + RecordService getRecordService(); + /** * @return disposition service */ diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceRegistryImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceRegistryImpl.java index b27d6c86fc..d340b0190f 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceRegistryImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceRegistryImpl.java @@ -23,6 +23,7 @@ import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditSe import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; import org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEventService; +import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService; import org.alfresco.repo.service.ServiceDescriptorRegistry; @@ -65,6 +66,14 @@ public class RecordsManagementServiceRegistryImpl extends ServiceDescriptorRegis { return (RecordsManagementService)getService(RECORDS_MANAGEMENT_SERVICE); } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry#getRecordService() + */ + public RecordService getRecordService() + { + return (RecordService)getService(RECORD_SERVICE); + } /** * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry#getRecordsManagementSecurityService() @@ -74,7 +83,7 @@ public class RecordsManagementServiceRegistryImpl extends ServiceDescriptorRegis return (RecordsManagementSecurityService)getService(RECORDS_MANAGEMENT_SECURITY_SERVICE); } - /* + /** * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry#getRecordsManagementAuditService() */ public RecordsManagementAuditService getRecordsManagementAuditService() diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java index b7cad234b4..e8e3111ea2 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java @@ -57,6 +57,9 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel // Records management root container public static final QName TYPE_FILE_PLAN = QName.createQName(RM_URI, "filePlan"); + // Unfiled record container + public static final QName TYPE_UNFILED_RECORD_CONTAINER = QName.createQName(RM_URI, "unfiledRecordContainer"); + // Disposition instructions aspect public static final QName ASPECT_SCHEDULED = QName.createQName(RM_URI, "scheduled"); public static final QName ASSOC_DISPOSITION_SCHEDULE = QName.createQName(RM_URI, "dispositionSchedule"); @@ -167,6 +170,7 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel public static final QName ASPECT_RECORDS_MANAGEMENT_ROOT = QName.createQName(RM_URI, "recordsManagementRoot"); public static final QName ASSOC_HOLDS = QName.createQName(RM_URI, "holds"); public static final QName ASSOC_TRANSFERS = QName.createQName(RM_URI, "transfers"); + public static final QName ASSOC_UNFILED_RECORDS = QName.createQName(RM_URI, "unfiledRecords"); // Hold type public static final QName TYPE_HOLD = QName.createQName(RM_URI, "hold"); @@ -223,4 +227,8 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel // Loaded Data Set Ids public static final QName ASPECT_LOADED_DATA_SET_ID = QName.createQName(RM_URI, "loadedDataSetId"); public static final QName PROP_LOADED_DATA_SET_IDS = QName.createQName(RM_URI, "loadedDataSetIds"); + + // Extended readers aspect + public static final QName ASPECT_EXTENDED_READERS = QName.createQName(RM_URI, "extendedReaders"); + public static final QName PROP_READERS = QName.createQName(RM_URI, "readers"); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java new file mode 100644 index 0000000000..037dd56ae9 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +package org.alfresco.module.org_alfresco_module_rm.record; + +import java.util.Set; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; + +/** + * Record Service Interface. + * + * @author Roy Wetherall + * @since 2.1 + */ +public interface RecordService +{ + /** + * Get a list of all the record meta-data aspects + * + * @return {@link Set}<{@link QName}> list of record meta-data aspects + */ + Set getRecordMetaDataAspects(); + + /** + * Indicates whether the record is declared + * + * @param nodeRef node reference (record) + * @return boolean true if record is declared, false otherwise + */ + boolean isDeclared(NodeRef nodeRef); + + /** + * Create a new record from an existing document. + * + * @param filePlan + * @param document + */ + void createRecordFromDocument(NodeRef filePlan, NodeRef document); + + // TODO boolean isRecordFiled(NodeRef record); + // TODO boolean isRecordClassified(NodeRef record); + + // NodeRef getNewRecordContainer(NodeRef filePlan); + + //NodeRef createRecord(NodeRef filePlan, NodeRef document); + + // TODO NodeRef createAndFileRecord(NodeRef recordFolder, NodeRef document); + + // TODO void fileRecord(NodeRef recordFolder, NodeRef record); + + public NodeRef getUnfiledRecordContainer(NodeRef filePlan); +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java new file mode 100644 index 0000000000..dc53ecf1c9 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.record; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService; +import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; +import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; + +/** + * Record service implementation + * + * @author Roy Wetherall + * @since 2.1 + */ +public class RecordServiceImpl implements RecordService, RecordsManagementModel +{ + /** Node service **/ + private NodeService nodeService; + + /** Indentiy service */ + private IdentifierService identifierService; + + /** Records management service */ + private RecordsManagementService recordsManagementService; + + /** Dictionary service */ + private DictionaryService dictionaryService; + + /** Policy component */ + private PolicyComponent policyComponent; + + /** Permission service */ + private PermissionService permissionService; + + /** Records management security service */ + private RecordsManagementSecurityService recordsManagementSecurityService; + + /** List of available record meta-data aspects */ + private Set recordMetaDataAspects; + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setIdentifierService(IdentifierService identifierService) + { + this.identifierService = identifierService; + } + + public void setRecordsManagementService(RecordsManagementService recordsManagementService) + { + this.recordsManagementService = recordsManagementService; + } + + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + public void setPermissionService(PermissionService permissionService) + { + this.permissionService = permissionService; + } + + public void setRecordsManagementSecurityService(RecordsManagementSecurityService recordsManagementSecurityService) + { + this.recordsManagementSecurityService = recordsManagementSecurityService; + } + + public void init() + { + // policyComponent.bindAssociationBehaviour( + // QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateChildAssociation"), + // TYPE_UNFILED_RECORD_CONTAINER, + // ContentModel.ASSOC_CONTAINS, + // new JavaBehaviour(this, "onCreateNewRecord", NotificationFrequency.TRANSACTION_COMMIT)); + } + +// public void onCreateNewRecord(final ChildAssociationRef childAssocRef, boolean bNew) +// { +// AuthenticationUtil.runAsSystem(new RunAsWork() +// { +// @Override +// public Void doWork() throws Exception +// { +// NodeRef nodeRef = childAssocRef.getChildRef(); +// if (nodeService.exists(nodeRef) == true) +// { +// QName type = nodeService.getType(nodeRef); +// if (ContentModel.TYPE_CONTENT.equals(type) == true || +// dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) == true) +// { +// makeRecord(nodeRef); +// } +// else +// { +// throw new AlfrescoRuntimeException("Only content can be created as a record."); +// } +// } +// +// return null; +// } +// }); +// } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#getRecordMetaDataAspects() + */ + public Set getRecordMetaDataAspects() + { + if (recordMetaDataAspects == null) + { + recordMetaDataAspects = new HashSet(7); + Collection aspects = dictionaryService.getAllAspects(); + for (QName aspect : aspects) + { + AspectDefinition def = dictionaryService.getAspect(aspect); + if (def != null) + { + QName parent = def.getParentName(); + if (parent != null && ASPECT_RECORD_META_DATA.equals(parent) == true) + { + recordMetaDataAspects.add(aspect); + } + } + } + } + return recordMetaDataAspects; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isDeclared(org.alfresco.service.cmr.repository.NodeRef) + */ + public boolean isDeclared(NodeRef record) + { + return (nodeService.hasAspect(record, ASPECT_DECLARED_RECORD)); + } + + @Override + public void createRecordFromDocument(NodeRef filePlan, NodeRef document) + { + // skip everything if the document is already a record + if (nodeService.hasAspect(document, ASPECT_RECORD) == false) + { + // get the documents readers + Long aclId = nodeService.getNodeAclId(document); + Set readers = permissionService.getReaders(aclId); + + // get the documents primary parent assoc + ChildAssociationRef parentAssoc = nodeService.getPrimaryParent(document); + + /// get the new record container for the file plan + NodeRef newRecordContainer = getUnfiledRecordContainer(filePlan); + if (newRecordContainer == null) + { + throw new AlfrescoRuntimeException("Unable to create record, because new record container could not be found."); + } + + // move the document into the file plan + nodeService.moveNode(document, newRecordContainer, ContentModel.ASSOC_CONTAINS, parentAssoc.getQName()); + + // maintain the original primary location + nodeService.addChild(parentAssoc.getParentRef(), document, parentAssoc.getTypeQName(), parentAssoc.getQName()); + + // make the document a record + makeRecord(document); + + // set the readers + recordsManagementSecurityService.setExtendedReaders(document, readers); + } + } + + /** + * + * @param document + */ + private void makeRecord(NodeRef document) + { + nodeService.addAspect(document, RecordsManagementModel.ASPECT_RECORD, null); + + String recordId = identifierService.generateIdentifier(ASPECT_RECORD, nodeService.getPrimaryParent(document).getParentRef()); + nodeService.setProperty(document, PROP_IDENTIFIER, recordId); + } + + /** + * + * @param filePlan + * @return + */ + public NodeRef getUnfiledRecordContainer(NodeRef filePlan) + { + List assocs = nodeService.getChildAssocs(filePlan, ASSOC_UNFILED_RECORDS, RegexQNamePattern.MATCH_ALL); + if (assocs.size() != 1) + { + throw new AlfrescoRuntimeException("Error getting the unfiled container, because the container cannot be indentified."); + } + return assocs.get(0).getChildRef(); + } + +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/admin/RmRolesGet.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/admin/RmRolesGet.java index 71f004e46b..1255120eb3 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/admin/RmRolesGet.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/admin/RmRolesGet.java @@ -19,6 +19,7 @@ package org.alfresco.module.org_alfresco_module_rm.script.admin; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -65,19 +66,26 @@ public class RmRolesGet extends DeclarativeWebScript // TODO should be passed List roots = rmService.getFilePlans(); - NodeRef root = roots.get(0); - - // Get the user filter - String user = req.getParameter("user"); - if (user != null && user.length() != 0) + if (roots != null && roots.size() > 0) { - roles = rmSecurityService.getRolesByUser(root, user); + NodeRef root = roots.get(0); + + // Get the user filter + String user = req.getParameter("user"); + if (user != null && user.length() != 0) + { + roles = rmSecurityService.getRolesByUser(root, user); + } + else + { + roles = rmSecurityService.getRoles(root); + } } else { - roles = rmSecurityService.getRoles(root); + roles = new HashSet(1); } - + model.put("roles", roles); return model; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java new file mode 100644 index 0000000000..8eaf471512 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java @@ -0,0 +1,173 @@ +/* +` * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.security; + +import java.util.Set; + +import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.repo.security.permissions.DynamicAuthority; +import org.alfresco.repo.security.permissions.PermissionReference; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.namespace.QName; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * Extended readers dynamic authority implementation. + * + * @author Roy Wetherall + * @since 2.1 + */ +public class ExtendedReaderDynamicAuthority implements DynamicAuthority, + RecordsManagementModel, + ApplicationContextAware +{ + /** Extended reader role */ + public static final String EXTENDED_READER = "ROLE_EXTENDED_READER"; + + /** Authority service */ + private AuthorityService authorityService; + + /** Records management security service */ + private RecordsManagementSecurityService recordsManagementSecurityService; + + /** Node service */ + private NodeService nodeService; + + /** Application context */ + private ApplicationContext applicationContext; + + // NOTE: we get the services directly from the application context in this way to avoid + // cyclic relationships and issues when loading the application context + + /** + * @return authority service + */ + private AuthorityService getAuthorityService() + { + if (authorityService == null) + { + authorityService = (AuthorityService)applicationContext.getBean("authorityService"); + } + return authorityService; + } + + /** + * @return records management security service + */ + public RecordsManagementSecurityService getRecordsManagementSecurityService() + { + if (recordsManagementSecurityService == null) + { + recordsManagementSecurityService = (RecordsManagementSecurityService)applicationContext.getBean("recordsManagementSecurityService"); + } + return recordsManagementSecurityService; + } + + /** + * @return node service + */ + public NodeService getNodeService() + { + if (nodeService == null) + { + nodeService = (NodeService)applicationContext.getBean("nodeService"); + } + return nodeService; + } + + /** + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + } + + /** + * @see org.alfresco.repo.security.permissions.DynamicAuthority#getAuthority() + */ + @Override + public String getAuthority() + { + return EXTENDED_READER; + } + + /** + * @see org.alfresco.repo.security.permissions.DynamicAuthority#hasAuthority(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) + */ + @Override + public boolean hasAuthority(NodeRef nodeRef, String userName) + { + boolean result = false; + + if (getNodeService().hasAspect(nodeRef, ASPECT_EXTENDED_READERS) == true) + { + Set readers = getRecordsManagementSecurityService().getExtendedReaders(nodeRef); + if (readers != null) + { + for (String reader : readers) + { + if ("GROUP_EVERYONE".equals(reader) == true) + { + // 'eveyone' has read + result = true; + break; + } + else if (reader.startsWith("GROUP_") == true) + { + // check group to see if the user is contained + Set contained = getAuthorityService().getContainedAuthorities(AuthorityType.USER, reader, false); + if (contained.isEmpty() == false && + contained.contains(userName) == true) + { + result = true; + break; + } + } + else + { + // presume we have a user + if (reader.equals(userName) == true) + { + result = true; + break; + } + } + } + } + } + + return result; + } + + /** + * @see org.alfresco.repo.security.permissions.DynamicAuthority#requiredFor() + */ + @Override + public Set requiredFor() + { + return null; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityService.java index 7cb8b18895..3eba852122 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityService.java @@ -152,4 +152,56 @@ public interface RecordsManagementSecurityService * @param permission permission */ void deletePermission(NodeRef nodeRef, String authority, String permission); + + /** + * Indicates whether the node has any extended readers set or not. + * + * @param nodeRef node reference + * @return boolean true if the node has extended readers set, false otherwise + * @since 2.1 + */ + boolean hasExtendedReaders(NodeRef nodeRef); + + /** + * Gets the set authorities that are extended readers for the given node. + * + * @param nodeRef node reference + * @return {@link Set}<{@link String}> extended readers + * @since 2.1 + */ + Set getExtendedReaders(NodeRef nodeRef); + + /** + * Set the authorities that are extended readers on the node. Applies extended readers to + * file plan parent hierarchy. + * + * @param nodeRef node reference + * @param readers extended readers + * @since 2.1 + */ + void setExtendedReaders(NodeRef nodeRef, Set readers); + + /** + * + * @param nodeRef + * @param readers + * @param applyToParents + * @since 2.1 + */ + void setExtendedReaders(NodeRef nodeRef, Set readers, boolean applyToParents); + + /** + * + * @param nodeRef + * @param readers + * @since 2.1 + */ + void removeExtendedReaders(NodeRef nodeRef, Set readers); + + /** + * + * @param nodeRef + * @since 2.1 + */ + void removeAllExtendedReaders(NodeRef nodeRef); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityServiceImpl.java index 9ae1855e1e..a397570951 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityServiceImpl.java @@ -22,12 +22,16 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.Serializable; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.model.RenditionModel; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService; import org.alfresco.module.org_alfresco_module_rm.capability.Capability; import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; @@ -39,6 +43,7 @@ import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -56,6 +61,9 @@ import org.apache.commons.logging.LogFactory; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; /** * Records management permission service implementation @@ -63,7 +71,9 @@ import org.json.JSONObject; * @author Roy Wetherall */ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSecurityService, - RecordsManagementModel + RecordsManagementModel, + ApplicationContextAware, + NodeServicePolicies.OnMoveNodePolicy { /** Capability service */ @@ -90,9 +100,24 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe /** Records management role zone */ public static final String RM_ROLE_ZONE_PREFIX = "rmRoleZone"; + /** Unfiled record container name */ + private static final String NAME_UNFILED_CONTAINER = "Unfiled Records"; + /** Logger */ private static Log logger = LogFactory.getLog(RecordsManagementSecurityServiceImpl.class); + /** Application context */ + private ApplicationContext applicationContext; + + /** + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + } + /** * Set the capability service * @@ -183,7 +208,12 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe policyComponent.bindClassBehaviour( NodeServicePolicies.OnCreateNodePolicy.QNAME, TYPE_RECORD_FOLDER, - new JavaBehaviour(this, "onCreateRecordFolder", NotificationFrequency.TRANSACTION_COMMIT)); + new JavaBehaviour(this, "onCreateRecordFolder", NotificationFrequency.TRANSACTION_COMMIT)); + + policyComponent.bindClassBehaviour( + NodeServicePolicies.OnMoveNodePolicy.QNAME, + ASPECT_RECORD, + new JavaBehaviour(this, "onMoveNode", NotificationFrequency.TRANSACTION_COMMIT)); } /** @@ -204,9 +234,9 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe if (nodeService.exists(rmRootNode) == true) { - AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + NodeRef unfiledContainer = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { - public Object doWork() + public NodeRef doWork() { // Create "all" role group for root node String allRoles = authorityService.createAuthority(AuthorityType.GROUP, getAllRolesGroupShortName(rmRootNode), "All Roles", null); @@ -214,16 +244,47 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe // Set the permissions permissionService.setInheritParentPermissions(rmRootNode, false); permissionService.setPermission(rmRootNode, allRoles, RMPermissionModel.READ_RECORDS, true); - - return null; + permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true); + permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.VIEW_RECORDS, true); + + // Create the unfiled record container + return createUnfiledContainer(rmRootNode, allRoles); } }, AuthenticationUtil.getSystemUserName()); // Bootstrap in the default set of roles for the newly created root node - bootstrapDefaultRoles(rmRootNode); + bootstrapDefaultRoles(rmRootNode, unfiledContainer); } } + /** + * Creates unfiled container node and sets up permissions + * + * @param rmRootNode + * @param allRoles + */ + private NodeRef createUnfiledContainer(NodeRef rmRootNode, String allRoles) + { + // create the properties map + Map properties = new HashMap(1); + properties.put(ContentModel.PROP_NAME, NAME_UNFILED_CONTAINER); + + // create the unfiled container + NodeRef container = nodeService.createNode( + rmRootNode, + ASSOC_UNFILED_RECORDS, + QName.createQName(RM_URI, NAME_UNFILED_CONTAINER), + TYPE_UNFILED_RECORD_CONTAINER, + properties).getChildRef(); + + // set inheritance to false + permissionService.setInheritParentPermissions(container, false); + permissionService.setPermission(container, allRoles, RMPermissionModel.READ_RECORDS, true); + permissionService.setPermission(container, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true); + + return container; + } + /** * Delete root node behaviour * @@ -279,36 +340,39 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe */ public void onCreateRecordFolder(ChildAssociationRef childAssocRef) { - final NodeRef folderNodeRef = childAssocRef.getChildRef(); + final NodeRef folderNodeRef = childAssocRef.getChildRef(); setUpPermissions(folderNodeRef); // Pull any permissions found on the parent (ie the record category) final NodeRef catNodeRef = childAssocRef.getParentRef(); if (nodeService.exists(catNodeRef) == true) { - AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { public Object doWork() { - Set perms = permissionService.getAllSetPermissions(catNodeRef); - for (AccessPermission perm : perms) - { - AccessStatus accessStatus = perm.getAccessStatus(); - boolean allow = false; - if (AccessStatus.ALLOWED.equals(accessStatus) == true) - { - allow = true; - } - permissionService.setPermission( - folderNodeRef, - perm.getAuthority(), - perm.getPermission(), - allow); - } - + Set perms = permissionService.getAllSetPermissions(catNodeRef); + for (AccessPermission perm : perms) + { + if (ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(perm.getAuthority()) == false) + { + AccessStatus accessStatus = perm.getAccessStatus(); + boolean allow = false; + if (AccessStatus.ALLOWED.equals(accessStatus) == true) + { + allow = true; + } + permissionService.setPermission( + folderNodeRef, + perm.getAuthority(), + perm.getPermission(), + allow); + } + } + return null; } - }, AuthenticationUtil.getSystemUserName()); + }, AuthenticationUtil.getSystemUserName()); } } @@ -324,8 +388,11 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe { public Object doWork() { - // Break inheritance + // break inheritance permissionService.setInheritParentPermissions(nodeRef, false); + + // set extended reader permissions + permissionService.setPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true); return null; } @@ -352,7 +419,12 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe /** * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#bootstrapDefaultRoles(org.alfresco.service.cmr.repository.NodeRef) */ - public void bootstrapDefaultRoles(final NodeRef rmRootNode) + public void bootstrapDefaultRoles(NodeRef rmRootNode) + { + bootstrapDefaultRoles(rmRootNode, null); + } + + private void bootstrapDefaultRoles(final NodeRef rmRootNode, final NodeRef unfiledContainer) { AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { @@ -434,7 +506,12 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe // Add any additional admin permissions if (isAdmin == true) { + // Admin has filing permissionService.setPermission(rmRootNode, role.getRoleGroupName(), RMPermissionModel.FILING, true); + if (unfiledContainer != null) + { + permissionService.setPermission(unfiledContainer, role.getRoleGroupName(), RMPermissionModel.FILING, true); + } // Add the creating user to the administration group String user = AuthenticationUtil.getFullyAuthenticatedUser(); @@ -597,6 +674,12 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe }, AuthenticationUtil.getSystemUserName()); } + /** + * + * @param rmRootNode + * @param roleAuthority + * @return + */ private Set getCapabilitiesImpl(NodeRef rmRootNode, String roleAuthority) { Set permissions = permissionService.getAllSetPermissions(rmRootNode); @@ -636,7 +719,7 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe }, AuthenticationUtil.getSystemUserName()).booleanValue(); } - /* + /** * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#hasRMAdminRole(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) */ public boolean hasRMAdminRole(NodeRef rmRootNode, String user) @@ -791,7 +874,7 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe public Boolean doWork() throws Exception { if (recordsManagementService.isFilePlan(nodeRef) == false && - recordsManagementService.isRecordCategory(nodeRef) == true) + recordsManagementService.isRecordsManagementContainer(nodeRef) == true) { setReadPermissionUp(nodeRef, authority); setPermissionDown(nodeRef, authority, permission); @@ -841,13 +924,13 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe private void setPermissionDown(NodeRef nodeRef, String authority, String permission) { setPermissionImpl(nodeRef, authority, permission); - if (recordsManagementService.isRecordCategory(nodeRef) == true) + if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true) { List assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); for (ChildAssociationRef assoc : assocs) { NodeRef child = assoc.getChildRef(); - if (recordsManagementService.isRecordCategory(child) == true || + if (recordsManagementService.isRecordsManagementContainer(child) == true || recordsManagementService.isRecordFolder(child) == true) { setPermissionDown(child, authority, permission); @@ -886,13 +969,13 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe // Delete permission on this node permissionService.deletePermission(nodeRef, authority, permission); - if (recordsManagementService.isRecordCategory(nodeRef) == true) + if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true) { List assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); for (ChildAssociationRef assoc : assocs) { NodeRef child = assoc.getChildRef(); - if (recordsManagementService.isRecordCategory(child) == true || + if (recordsManagementService.isRecordsManagementContainer(child) == true || recordsManagementService.isRecordFolder(child) == true) { deletePermission(child, authority, permission); @@ -904,4 +987,163 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe } }, AuthenticationUtil.getSystemUserName()); } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#hasExtendedReaders(org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public boolean hasExtendedReaders(NodeRef nodeRef) + { + boolean result = false; + Set extendedReaders = getExtendedReaders(nodeRef); + if (extendedReaders != null && extendedReaders.size() != 0) + { + result = true; + } + return result; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#getExtendedReaders(org.alfresco.service.cmr.repository.NodeRef) + */ + @SuppressWarnings("unchecked") + @Override + public Set getExtendedReaders(NodeRef nodeRef) + { + NodeService nodeService = (NodeService)applicationContext.getBean("nodeService"); + Set result = null; + + Map readerMap = (Map)nodeService.getProperty(nodeRef, PROP_READERS); + if (readerMap != null) + { + result = readerMap.keySet(); + } + + return result; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#setExtendedReaders(org.alfresco.service.cmr.repository.NodeRef, java.util.Set) + */ + @Override + public void setExtendedReaders(NodeRef nodeRef, Set readers) + { + setExtendedReaders(nodeRef, readers, true); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#setExtendedReaders(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, boolean) + */ + @SuppressWarnings("unchecked") + @Override + public void setExtendedReaders(NodeRef nodeRef, java.util.Set readers, boolean applyToParents) + { + ParameterCheck.mandatory("nodeRef", nodeRef); + ParameterCheck.mandatory("readers", readers); + + NodeService nodeService = (NodeService)applicationContext.getBean("nodeService"); + RecordsManagementService recordsManagementService = (RecordsManagementService)applicationContext.getBean("recordsManagementService"); + + if (nodeRef != null && + readers.isEmpty() == false) + { + // add the aspect if missing + if (nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_READERS) == false) + { + nodeService.addAspect(nodeRef, ASPECT_EXTENDED_READERS, null); + } + + // get reader map + Map readersMap = (Map)nodeService.getProperty(nodeRef, PROP_READERS); + if (readersMap == null) + { + // create reader map + readersMap = new HashMap(7); + } + + for (String reader : readers) + { + if (readersMap.containsKey(reader) == true) + { + // increment reference count + Integer count = readersMap.get(reader); + readersMap.put(reader, Integer.valueOf(count.intValue()+1)); + } + else + { + // add reader with initial count + readersMap.put(reader, Integer.valueOf(1)); + } + } + + // set the readers property (this will in turn apply the aspect if required) + nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)readersMap); + + // apply the readers to any renditions of the content + if (recordsManagementService.isRecord(nodeRef) == true) + { + List assocs = nodeService.getChildAssocs(nodeRef, RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL); + for (ChildAssociationRef assoc : assocs) + { + NodeRef child = assoc.getChildRef(); + setExtendedReaders(child, readers, false); + } + } + + if (applyToParents == true) + { + // apply the extended readers up the file plan primary hierarchy + NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef(); + if (parent != null && + recordsManagementService.isFilePlanComponent(parent) == true) + { + setExtendedReaders(parent, readers); + } + } + } + } + + @Override + public void removeExtendedReaders(NodeRef nodeRef, Set readers) + { + // TODO Auto-generated method stub + + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#removeAllExtendedReaders(org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public void removeAllExtendedReaders(NodeRef nodeRef) + { + // TODO Auto-generated method stub + + } + + @Override + public void onMoveNode(final ChildAssociationRef origAssoc, final ChildAssociationRef newAssoc) + { + // TODO temp solution for demo + + AuthenticationUtil.runAsSystem(new RunAsWork() + { + + @Override + public Void doWork() throws Exception + { + NodeRef record = newAssoc.getChildRef(); + NodeRef parent = newAssoc.getParentRef(); + + Set readers = getExtendedReaders(record); + if (readers != null && readers.size() != 0) + { + setExtendedReaders(parent, readers); + } + + return null; + }}); + + + + } }