RM-1098: Refactor RM model behavior into a more maintainable structure

* added behaviour bean and method annotations .. allows the simple defintion of methods as behaviours, simplifies code and provides a way to report on the registered behaviours in the future
  * moved and consolidated some of the behaviours into classes based on the RM object model .. with behaviours in one logical place it should reduce issues with unpredictable behaviours and help maintenance
  * TODO more consolidate still needed



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@58120 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2013-11-22 06:16:51 +00:00
parent 1abda8f161
commit 06bc92f0b6
23 changed files with 1217 additions and 305 deletions

View File

@@ -28,12 +28,10 @@ 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.disposition.DispositionService;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanComponentKind;
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.model.RecordsManagementCustomModel;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
@@ -45,7 +43,6 @@ import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
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.ScriptService;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -61,12 +58,11 @@ import org.springframework.extensions.surf.util.I18NUtil;
*/
public class RecordsManagementServiceImpl extends ServiceBaseImpl
implements RecordsManagementService,
RecordsManagementModel,
RecordsManagementPolicies.OnCreateReference,
RecordsManagementPolicies.OnRemoveReference
RecordsManagementModel //,
//RecordsManagementPolicies.OnCreateReference,
//RecordsManagementPolicies.OnRemoveReference
{
/** I18N */
private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container";
private final static String MSG_UPDATE_DISP_ACT_DEF = "rm.service.update-disposition-action-def";
private final static String MSG_SET_ID = "rm.service.set-id";
@@ -81,7 +77,7 @@ public class RecordsManagementServiceImpl extends ServiceBaseImpl
/** Policy component */
private PolicyComponent policyComponent;
/** Well-known location of the scripts folder. */
///** Well-known location of the scripts folder. */
private NodeRef scriptsFolderNodeRef = new NodeRef("workspace", "SpacesStore", "rm_behavior_scripts");
/** Java behaviour */
@@ -196,26 +192,6 @@ public class RecordsManagementServiceImpl extends ServiceBaseImpl
*/
public void init()
{
// Register the association behaviours
policyComponent.bindAssociationBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateChildAssociation"),
TYPE_FILE_PLAN,
ContentModel.ASSOC_CONTAINS,
new JavaBehaviour(this, "onAddContentToContainer", NotificationFrequency.EVERY_EVENT));
policyComponent.bindAssociationBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateChildAssociation"),
TYPE_RECORD_CATEGORY,
ContentModel.ASSOC_CONTAINS,
new JavaBehaviour(this, "onAddContentToContainer", NotificationFrequency.EVERY_EVENT));
// TODO move this into the record service
policyComponent.bindAssociationBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateChildAssociation"),
ASPECT_RECORD,
RenditionModel.ASSOC_RENDITION,
new JavaBehaviour(this, "onAddRecordThumbnail", NotificationFrequency.TRANSACTION_COMMIT)
);
// Register script execution behaviour on RM property update.
policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
ASPECT_FILE_PLAN_COMPONENT,
@@ -227,81 +203,12 @@ public class RecordsManagementServiceImpl extends ServiceBaseImpl
TYPE_DISPOSITION_ACTION_DEFINITION,
onChangeToDispositionActionDefinition);
// Reference behaviours
policyComponent.bindClassBehaviour(RecordsManagementPolicies.ON_CREATE_REFERENCE,
ASPECT_RECORD,
new JavaBehaviour(this, "onCreateReference", NotificationFrequency.TRANSACTION_COMMIT));
policyComponent.bindClassBehaviour(RecordsManagementPolicies.ON_REMOVE_REFERENCE,
ASPECT_RECORD,
new JavaBehaviour(this, "onRemoveReference", NotificationFrequency.TRANSACTION_COMMIT));
// Identifier behaviours
policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
ASPECT_RECORD_COMPONENT_ID,
new JavaBehaviour(this, "onIdentifierUpdate", NotificationFrequency.TRANSACTION_COMMIT));
}
/**
* On add content to container
*
* Prevents content nodes being added to record series and record category folders
* by imap, cifs etc.
*
* @param childAssocRef
* @param bNew
*/
public void onAddContentToContainer(ChildAssociationRef childAssocRef, boolean bNew)
{
NodeRef parent = childAssocRef.getParentRef();
NodeRef nodeRef = childAssocRef.getChildRef();
if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true)
{
throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER));
}
if (isFilePlan(parent) == true && isRecordFolder(nodeRef) == true)
{
throw new AlfrescoRuntimeException("Operation failed, because you can not place a record folder in the root of the file plan.");
}
}
/**
* Make sure the thumbnails of records are marked as file plan components as are therefore subject to the same
* permission restrictions.
*
* @param childAssocRef
* @param bNew
*/
public void onAddRecordThumbnail(final ChildAssociationRef childAssocRef, final boolean bNew)
{
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
{
@Override
public Void doWork() throws Exception
{
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
NodeRef parent = childAssocRef.getParentRef();
ExtendedSecurityService extendedSecurityService = getExtendedSecurityService();
Set<String> readers = extendedSecurityService.getExtendedReaders(parent);
Set<String> writers = extendedSecurityService.getExtendedWriters(parent);
if (readers != null && readers.size() != 0)
{
extendedSecurityService.addExtendedSecurity(thumbnail, readers, writers, false);
}
}
return null;
}
});
}
/**
* Called after a DispositionActionDefinition property has been updated.
*/
@@ -483,67 +390,6 @@ public class RecordsManagementServiceImpl extends ServiceBaseImpl
}
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnCreateReference#onCreateReference(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
*/
public void onCreateReference(NodeRef fromNodeRef, NodeRef toNodeRef, QName reference)
{
// Deal with versioned records
if (reference.equals(QName.createQName(RecordsManagementCustomModel.RM_CUSTOM_URI, "versions")) == true)
{
// Apply the versioned aspect to the from node
this.nodeService.addAspect(fromNodeRef, ASPECT_VERSIONED_RECORD, null);
}
// Execute script if for the reference event
executeReferenceScript("onCreate", reference, fromNodeRef, toNodeRef);
}
/**
* Executes a reference script if present
*
* @param policy
* @param reference
* @param from
* @param to
*/
private void executeReferenceScript(String policy, QName reference, NodeRef from, NodeRef to)
{
String referenceId = reference.getLocalName();
// This is the filename pattern which is assumed.
// e.g. a script file onCreate_superceded.js for the creation of a superseded reference
String expectedScriptName = policy + "_" + referenceId + ".js";
NodeRef scriptNodeRef = nodeService.getChildByName(scriptsFolderNodeRef, ContentModel.ASSOC_CONTAINS, expectedScriptName);
if (scriptNodeRef != null)
{
Map<String, Object> objectModel = new HashMap<String, Object>(1);
objectModel.put("node", from);
objectModel.put("toNode", to);
objectModel.put("policy", policy);
objectModel.put("reference", referenceId);
getScriptService().executeScript(scriptNodeRef, null, objectModel);
}
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnRemoveReference#onRemoveReference(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
*/
public void onRemoveReference(NodeRef fromNodeRef, NodeRef toNodeRef, QName reference)
{
// Deal with versioned records
if (reference.equals(QName.createQName(RecordsManagementCustomModel.RM_CUSTOM_URI, "versions")) == true)
{
// Apply the versioned aspect to the from node
this.nodeService.removeAspect(fromNodeRef, ASPECT_VERSIONED_RECORD);
}
// Execute script if for the reference event
executeReferenceScript("onRemove", reference, fromNodeRef, toNodeRef);
}
/**
* @deprecated As of 2.1, see {@link FilePlanService#isFilePlanComponent(NodeRef)}
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
* Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -26,8 +26,10 @@ import org.alfresco.service.namespace.QName;
/**
* Bootstrap bean that indicates that the specified types or aspects are
* customizable.
*
* @author Roy Wetherall
* @since 2.0
*/
public class CustomisableTypesBootstrap
{

View File

@@ -143,10 +143,6 @@ public class RecordCopyBehaviours implements RecordsManagementModel
QName.createQName(NamespaceService.ALFRESCO_URI, "getCopyCallback"),
RecordsManagementModel.TYPE_RECORD_FOLDER,
new JavaBehaviour(this, "onCopyRecordFolderNode"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "getCopyCallback"),
RecordsManagementModel.TYPE_RECORD_CATEGORY,
new JavaBehaviour(this, "onCopyRecordCategoryNode"));
}
/**
@@ -330,36 +326,6 @@ public class RecordCopyBehaviours implements RecordsManagementModel
};
}
/**
* Record Category Copy Behaviour
*
* <li> Do not allow copy of record category into a record folder</li>
*
* @param classRef
* @param copyDetails
* @return
*/
public CopyBehaviourCallback onCopyRecordCategoryNode(final QName classRef, final CopyDetails copyDetails)
{
return new DefaultCopyBehaviourCallback()
{
final NodeService nodeService = rmServiceRegistry.getNodeService();
/**
* If the targets parent is a Record Folder -- Do Not Allow Copy
*
* @param classQName
* @param copyDetails
* @return boolean
*/
@Override
public boolean getMustCopy(QName classQName, CopyDetails copyDetails)
{
return nodeService.getType(copyDetails.getTargetParentNodeRef()).equals(TYPE_RECORD_FOLDER) ? false : true;
}
};
}
/**
* Removes unwanted aspects
*

View File

@@ -0,0 +1,80 @@
/**
*
*/
package org.alfresco.module.org_alfresco_module_rm.model.rma;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Convenient base class for behaviour beans.
*
* @author Roy Wetherall
* @since 2.2
*/
public abstract class BaseBehaviourBean implements RecordsManagementModel
{
/** Logger */
protected static Log logger = LogFactory.getLog(BaseBehaviourBean.class);
/** node service */
protected NodeService nodeService;
/** dictionary service */
protected DictionaryService dictionaryService;
/** behaviour filter */
protected BehaviourFilter behaviourFilter;
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param dictionaryService dictionary service
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* @param behaviourFilter behaviour filter
*/
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
{
this.behaviourFilter = behaviourFilter;
}
/**
* Utility method to safely and quickly determine if a node is a type (or sub-type) of the one specified.
*
* @param nodeRef node reference
* @param ofClassName class name to check
*/
protected boolean instanceOf(NodeRef nodeRef, QName ofClassName)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
ParameterCheck.mandatory("ofClassName", ofClassName);
boolean result = false;
if (nodeService.exists(nodeRef) == true &&
(ofClassName.equals(nodeService.getType(nodeRef)) == true ||
dictionaryService.isSubClass(nodeService.getType(nodeRef), ofClassName) == true))
{
result = true;
}
return result;
}
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.model.rma;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
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.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* rma:filePlan behaviour bean
*
* @author Roy Wetherall
* @since 2.2
*/
@BehaviourBean
(
defaultType = "rma:filePlan"
)
public class FilePlanType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnCreateNodePolicy,
NodeServicePolicies.OnDeleteNodePolicy
{
/** file plan service */
protected FilePlanService filePlanService;
/** record folder service */
protected RecordFolderService recordFolderService;
/** identifier service */
protected IdentifierService identifierService;
/** file plan role service */
protected FilePlanRoleService filePlanRoleService;
/**
* @param filePlanService file plan service
*/
public void setFilePlanService(FilePlanService filePlanService)
{
this.filePlanService = filePlanService;
}
/**
* @param recordFolderService record folder service
*/
public void setRecordFolderService(RecordFolderService recordFolderService)
{
this.recordFolderService = recordFolderService;
}
/**
* @param identifierService identifier service
*/
public void setIdentifierService(IdentifierService identifierService)
{
this.identifierService = identifierService;
}
/**
* @param filePlanRoleService file plan role service
*/
public void setFilePlanRoleService(FilePlanRoleService filePlanRoleService)
{
this.filePlanRoleService = filePlanRoleService;
}
/**
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/
@Behaviour
(
kind = BehaviourKind.ASSOCIATION
)
@Override
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew)
{
// ensure we are not trying to put content in the file plan root node
NodeRef nodeRef = childAssocRef.getChildRef();
if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true)
{
throw new AlfrescoRuntimeException("Operation failed, because you can't place content in the root of the file plan.");
}
// ensure we are not trying to put a record folder in the root of the file plan
NodeRef parent = childAssocRef.getParentRef();
if (filePlanService.isFilePlan(parent) == true && recordFolderService.isRecordFolder(nodeRef) == true)
{
throw new AlfrescoRuntimeException("Operation failed, because you can not place a record folder in the root of the file plan.");
}
}
/**
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy#onCreateNode(org.alfresco.service.cmr.repository.ChildAssociationRef)
*/
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
@Override
public void onCreateNode(final ChildAssociationRef childAssocRef)
{
final NodeRef filePlan = childAssocRef.getChildRef();
AuthenticationUtil.runAsSystem(new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
if (nodeService.hasAspect(filePlan, ASPECT_FILE_PLAN_COMPONENT) == true &&
nodeService.getProperty(filePlan, PROP_IDENTIFIER) == null)
{
String id = identifierService.generateIdentifier(filePlan);
nodeService.setProperty(filePlan, RecordsManagementModel.PROP_IDENTIFIER, id);
}
return null;
}
});
// setup the file plan roles
filePlanRoleService.setupFilePlanRoles(filePlan);
}
/**
* @see org.alfresco.repo.node.NodeServicePolicies.OnDeleteNodePolicy#onDeleteNode(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
@Override
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean archived)
{
// tear down the file plan roles
filePlanRoleService.tearDownFilePlanRoles(childAssocRef.getChildRef());
}
}

View File

@@ -0,0 +1,195 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.model.rma;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.namespace.QName;
/**
* rma:record behaviour bean
*
* @author Roy Wetherall
* @since 2.2
*/
@BehaviourBean
(
defaultType = "rma:record"
)
public class RecordAspect extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy,
RecordsManagementPolicies.OnCreateReference,
RecordsManagementPolicies.OnRemoveReference
{
/** Well-known location of the scripts folder. */
// TODO make configurable
private NodeRef scriptsFolderNodeRef = new NodeRef("workspace", "SpacesStore", "rm_behavior_scripts");
/** extended security service */
protected ExtendedSecurityService extendedSecurityService;
/** script service */
protected ScriptService scriptService;
/**
* @param extendedSecurityService extended security service
*/
public void setExtendedSecurityService(ExtendedSecurityService extendedSecurityService)
{
this.extendedSecurityService = extendedSecurityService;
}
/**
* @param scriptService script service
*/
public void setScriptService(ScriptService scriptService)
{
this.scriptService = scriptService;
}
/**
* Behaviour to ensure renditions have the appropriate extended security.
*
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/
@Override
@Behaviour
(
kind = BehaviourKind.ASSOCIATION,
assocType = "rn:rendition",
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, boolean bNew)
{
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
{
@Override
public Void doWork() throws Exception
{
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
NodeRef parent = childAssocRef.getParentRef();
Set<String> readers = extendedSecurityService.getExtendedReaders(parent);
Set<String> writers = extendedSecurityService.getExtendedWriters(parent);
if (readers != null && readers.size() != 0)
{
extendedSecurityService.addExtendedSecurity(thumbnail, readers, writers, false);
}
}
return null;
}
});
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnCreateReference#onCreateReference(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
*/
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
public void onCreateReference(NodeRef fromNodeRef, NodeRef toNodeRef, QName reference)
{
// Deal with versioned records
if (reference.equals(QName.createQName(RecordsManagementCustomModel.RM_CUSTOM_URI, "versions")) == true)
{
// Apply the versioned aspect to the from node
nodeService.addAspect(fromNodeRef, ASPECT_VERSIONED_RECORD, null);
}
// Execute script if for the reference event
executeReferenceScript("onCreate", reference, fromNodeRef, toNodeRef);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnRemoveReference#onRemoveReference(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
*/
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
public void onRemoveReference(NodeRef fromNodeRef, NodeRef toNodeRef, QName reference)
{
// Deal with versioned records
if (reference.equals(QName.createQName(RecordsManagementCustomModel.RM_CUSTOM_URI, "versions")) == true)
{
// Apply the versioned aspect to the from node
nodeService.removeAspect(fromNodeRef, ASPECT_VERSIONED_RECORD);
}
// Execute script if for the reference event
executeReferenceScript("onRemove", reference, fromNodeRef, toNodeRef);
}
/**
* Executes a reference script if present
*
* @param policy
* @param reference
* @param from
* @param to
*/
private void executeReferenceScript(String policy, QName reference, NodeRef from, NodeRef to)
{
String referenceId = reference.getLocalName();
// This is the filename pattern which is assumed.
// e.g. a script file onCreate_superceded.js for the creation of a superseded reference
String expectedScriptName = policy + "_" + referenceId + ".js";
NodeRef scriptNodeRef = nodeService.getChildByName(scriptsFolderNodeRef, ContentModel.ASSOC_CONTAINS, expectedScriptName);
if (scriptNodeRef != null)
{
Map<String, Object> objectModel = new HashMap<String, Object>(1);
objectModel.put("node", from);
objectModel.put("toNode", to);
objectModel.put("policy", policy);
objectModel.put("reference", referenceId);
scriptService.executeScript(scriptNodeRef, null, objectModel);
}
}
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.model.rma;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService;
import org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService;
import org.alfresco.repo.copy.CopyBehaviourCallback;
import org.alfresco.repo.copy.CopyDetails;
import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* rma:recordCategory behaviour bean
*
* @author Roy Wetherall
* @since 2.2
*/
@BehaviourBean
(
defaultType = "rma:recordCategory"
)
public class RecordCategoryType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnCreateNodePolicy
{
/** vital record service */
protected VitalRecordService vitalRecordService;
/** file plan permission service */
protected FilePlanPermissionService filePlanPermissionService;
/**
* @param vitalRecordService vital record service
*/
public void setVitalRecordService(VitalRecordService vitalRecordService)
{
this.vitalRecordService = vitalRecordService;
}
/**
* @param filePlanPermissionService file plan permission service
*/
public void setFilePlanPermissionService(FilePlanPermissionService filePlanPermissionService)
{
this.filePlanPermissionService = filePlanPermissionService;
}
/**
* On every event
*
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/
@Override
@Behaviour
(
kind = BehaviourKind.ASSOCIATION
)
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew)
{
// ensure content is not placed directly into a record category
NodeRef nodeRef = childAssocRef.getChildRef();
if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true)
{
throw new AlfrescoRuntimeException("Operation failed, because you can't place content directly into a record category.");
}
}
/**
* On transaction commit
*
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/
@Behaviour
(
kind = BehaviourKind.ASSOCIATION,
policy = "alf:onCreateChildAssociation",
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
public void onCreateChildAssociationOnCommit(ChildAssociationRef childAssocRef, boolean bNew)
{
final NodeRef recordCategory = childAssocRef.getChildRef();
behaviourFilter.disableBehaviour();
try
{
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
{
@Override
public Void doWork() throws Exception
{
// setup vital record definition
vitalRecordService.setupVitalRecordDefinition(recordCategory);
return null;
}
});
}
finally
{
behaviourFilter.enableBehaviour();
}
}
/**
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy#onCreateNode(org.alfresco.service.cmr.repository.ChildAssociationRef)
*/
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
public void onCreateNode(ChildAssociationRef childAssocRef)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("rma:recordCategory|alf:onCreateNode|this.onCreateNode()|TRANSATION_COMMIT");
}
// setup record category permissions
filePlanPermissionService.setupRecordCategoryPermissions(childAssocRef.getChildRef());
}
/**
* Copy callback for record category
*/
@Behaviour
(
kind = BehaviourKind.CLASS,
policy = "alf:getCopyCallback"
)
public CopyBehaviourCallback onCopyRecordCategory(final QName classRef, final CopyDetails copyDetails)
{
return new DefaultCopyBehaviourCallback()
{
/**
* If the targets parent is a Record Folder -- Do Not Allow Copy
*
* @param classQName
* @param copyDetails
* @return boolean
*/
@Override
public boolean getMustCopy(QName classQName, CopyDetails copyDetails)
{
return nodeService.getType(copyDetails.getTargetParentNodeRef()).equals(TYPE_RECORD_FOLDER) ? false : true;
}
};
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.model.rma;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* rma:recordsManagementContainer behaviour bean.
*
* @author Roy Wetherall
* @since 2.2
*/
@BehaviourBean
(
defaultType = "rma:recordsManagementContainer"
)
public class RecordsManagementContainerType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy
{
/** identifier service */
protected IdentifierService identifierService;
/**
* @param identifierService identifier service
*/
public void setIdentifierService(IdentifierService identifierService)
{
this.identifierService = identifierService;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.model.BaseTypeBehaviour#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/
@Behaviour
(
kind = BehaviourKind.ASSOCIATION,
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, boolean isNewNode)
{
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
{
@Override
public Void doWork() throws Exception
{
// Get the elements of the created association
final NodeRef child = childAssocRef.getChildRef();
if (nodeService.exists(child) == true)
{
QName childType = nodeService.getType(child);
// We only care about "folder" or sub-types
if (dictionaryService.isSubClass(childType, ContentModel.TYPE_FOLDER) == true)
{
if (dictionaryService.isSubClass(childType, ContentModel.TYPE_SYSTEM_FOLDER) == true)
{
// this is a rule container, make sure it is an file plan component
nodeService.addAspect(child, ASPECT_FILE_PLAN_COMPONENT, null);
}
else
{
// We need to automatically cast the created folder to RM type if it is a plain folder
// This occurs if the RM folder has been created via IMap, WebDav, etc
if (nodeService.hasAspect(child, ASPECT_FILE_PLAN_COMPONENT) == false)
{
// TODO it may not always be a record folder ... perhaps if the current user is a admin it would be a record category??
// Assume any created folder is a rma:recordFolder
nodeService.setType(child, TYPE_RECORD_FOLDER);
}
// Catch all to generate the rm id (assuming it doesn't already have one!)
setIdenifierProperty(child);
}
}
}
return null;
}
});
}
/**
*
* @param nodeRef
*/
protected void setIdenifierProperty(final NodeRef nodeRef)
{
AuthenticationUtil.runAsSystem(new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
if (nodeService.hasAspect(nodeRef, ASPECT_FILE_PLAN_COMPONENT) == true &&
nodeService.getProperty(nodeRef, PROP_IDENTIFIER) == null)
{
String id = identifierService.generateIdentifier(nodeRef);
nodeService.setProperty(nodeRef, RecordsManagementModel.PROP_IDENTIFIER, id);
}
return null;
}
});
}
}

View File

@@ -84,6 +84,7 @@ public class RecordFolderServiceImpl extends ServiceBaseImpl
= new JavaBehaviour(this,
"onCreateChildAssociation",
NotificationFrequency.FIRST_EVENT);
private JavaBehaviour onCreateChildAssociationInRecordFolderFolder
= new JavaBehaviour(this,
"onCreateChildAssociationInRecordFolder",
@@ -126,6 +127,7 @@ public class RecordFolderServiceImpl extends ServiceBaseImpl
*/
public void init()
{
policyComponent.bindAssociationBehaviour(
NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME,
TYPE_RECORD_CATEGORY,

View File

@@ -47,7 +47,21 @@ public interface FilePlanRoleService
ROLE_EXTENDED_READERS,
ROLE_EXTENDED_WRITERS
);
/**
* Sets up the roles on a new file plan.
*
* @param filePlan file plan
*/
void setupFilePlanRoles(NodeRef filePlan);
/**
* Tears down the roles on a file plan.
*
* @param filePlan file plan
*/
void tearDownFilePlanRoles(NodeRef filePlan);
/**
* Returns the name of the container group for all roles of a specified file
* plan.

View File

@@ -42,13 +42,8 @@ import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.FilePlanAuthenticationService;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authority.RMAuthority;
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.repository.StoreRef;
@@ -95,9 +90,6 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
/** Permission service */
private PermissionService permissionService;
/** Policy component */
private PolicyComponent policyComponent;
/** File plan service */
private FilePlanService filePlanService;
@@ -150,14 +142,6 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
this.permissionService = permissionService;
}
/**
* @param policyComponent policy component
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* @param nodeService node service
*/
@@ -208,39 +192,21 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
}
/**
* Initialisation method
* @see org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService#initialiseFilePlan(org.alfresco.service.cmr.repository.NodeRef)
*/
public void init()
@Override
public void setupFilePlanRoles(final NodeRef filePlan)
{
policyComponent.bindClassBehaviour(
NodeServicePolicies.OnCreateNodePolicy.QNAME,
TYPE_FILE_PLAN,
new JavaBehaviour(this, "onCreateRootNode", NotificationFrequency.TRANSACTION_COMMIT));
policyComponent.bindClassBehaviour(
NodeServicePolicies.OnDeleteNodePolicy.QNAME,
TYPE_FILE_PLAN,
new JavaBehaviour(this, "onDeleteRootNode", NotificationFrequency.TRANSACTION_COMMIT));
}
/**
* Create root node behaviour
*
* @param childAssocRef
*/
public void onCreateRootNode(ChildAssociationRef childAssocRef)
{
final NodeRef rmRootNode = childAssocRef.getChildRef();
// Do not execute behaviour if this has been created in the archive store
if(rmRootNode.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE) == true)
if(filePlan.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE) == true)
{
// This is not the spaces store - probably the archive store
return;
}
if (nodeService.exists(rmRootNode) == true)
if (nodeService.exists(filePlan) == true)
{
List<NodeRef> systemContainers = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<List<NodeRef>>()
List<NodeRef> systemContainers = AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<List<NodeRef>>()
{
public List<NodeRef> doWork()
{
@@ -256,50 +222,44 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
// Create "all" role group for root node
String allRoles = authorityService.createAuthority(
AuthorityType.GROUP,
getAllRolesGroupShortName(rmRootNode),
getAllRolesGroupShortName(filePlan),
I18NUtil.getMessage(MSG_ALL_ROLES),
new HashSet<String>(Arrays.asList(RMAuthority.ZONE_APP_RM)));
// Set the permissions
permissionService.setInheritParentPermissions(rmRootNode, false);
permissionService.setPermission(rmRootNode, allRoles, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(rmRootNode, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
permissionService.setInheritParentPermissions(filePlan, false);
permissionService.setPermission(filePlan, allRoles, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(filePlan, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(filePlan, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
// Create the transfer and hold containers
systemContainers.add(filePlanService.createHoldContainer(rmRootNode));
systemContainers.add(filePlanService.createTransferContainer(rmRootNode));
systemContainers.add(filePlanService.createHoldContainer(filePlan));
systemContainers.add(filePlanService.createTransferContainer(filePlan));
// Create the unfiled record container
systemContainers.add(filePlanService.createUnfiledContainer(rmRootNode));
systemContainers.add(filePlanService.createUnfiledContainer(filePlan));
return systemContainers;
}
}, AuthenticationUtil.getSystemUserName());
});
// Bootstrap in the default set of roles for the newly created root node
bootstrapDefaultRoles(rmRootNode, systemContainers);
bootstrapDefaultRoles(filePlan, systemContainers);
}
}
/**
* Delete root node behaviour
*
* @param childAssocRef
* @see org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService#tearDownFilePlanRoles(org.alfresco.service.cmr.repository.NodeRef)
*/
public void onDeleteRootNode(ChildAssociationRef childAssocRef, boolean isNodeArchived)
@Override
public void tearDownFilePlanRoles(final NodeRef filePlan)
{
logger.debug("onDeleteRootNode called");
// get the deleted node
final NodeRef rmRootNode = childAssocRef.getChildRef();
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork()
{
// cascade delete the 'all' roles group for the site
String allRolesGroup = authorityService.getName(AuthorityType.GROUP, getAllRolesGroupShortName(rmRootNode));
String allRolesGroup = authorityService.getName(AuthorityType.GROUP, getAllRolesGroupShortName(filePlan));
Set<String> groups = authorityService.getContainedAuthorities(AuthorityType.GROUP, allRolesGroup, true);
for (String group : groups)
{
@@ -310,7 +270,7 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
return null;
}
}, AuthenticationUtil.getSystemUserName());
});
}
/**

View File

@@ -28,6 +28,12 @@ import org.alfresco.service.cmr.repository.NodeRef;
*/
public interface FilePlanPermissionService
{
/**
*
* @param nodeRef
*/
void setupRecordCategoryPermissions(NodeRef recordCategory);
/**
* Sets a permission on a file plan object. Assumes allow is true. Cascades permission down to record folder.
* Cascades ReadRecord up to file plan.

View File

@@ -22,6 +22,7 @@ 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.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
@@ -79,10 +80,6 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
*/
public void init()
{
policyComponent.bindClassBehaviour(
NodeServicePolicies.OnCreateNodePolicy.QNAME,
TYPE_RECORD_CATEGORY,
new JavaBehaviour(this, "onCreateRMContainer", NotificationFrequency.TRANSACTION_COMMIT));
policyComponent.bindClassBehaviour(
NodeServicePolicies.OnCreateNodePolicy.QNAME,
TYPE_RECORD_FOLDER,
@@ -152,28 +149,33 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
{
this.recordFolderService = recordFolderService;
}
/**
* @param childAssocRef
* @see org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService#setupRecordCategoryPermissions(org.alfresco.service.cmr.repository.NodeRef)
*/
public void onCreateRMContainer(ChildAssociationRef childAssocRef)
@Override
public void setupRecordCategoryPermissions(final NodeRef recordCategory)
{
final NodeRef recordCategory = childAssocRef.getChildRef();
setUpPermissions(recordCategory);
ParameterCheck.mandatory("recordCategory", recordCategory);
// assert that we have a record category in our hands
if (instanceOf(recordCategory, TYPE_RECORD_CATEGORY) == false)
{
throw new AlfrescoRuntimeException("Unable to setup record category permissions, because node is not a record category.");
}
// init permissions
initPermissions(recordCategory);
// Pull any permissions found on the parent (ie the record category)
final NodeRef parentNodeRef = childAssocRef.getParentRef();
final NodeRef parentNodeRef = nodeService.getPrimaryParent(recordCategory).getParentRef();
if (parentNodeRef != null && nodeService.exists(parentNodeRef) == true)
{
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork()
{
boolean fillingOnly = false;
if (filePlanService.isFilePlan(parentNodeRef) == true)
{
fillingOnly = true;
}
boolean fillingOnly = filePlanService.isFilePlan(parentNodeRef);
// since this is not a root category, inherit from parent
Set<AccessPermission> perms = permissionService.getAllSetPermissions(parentNodeRef);
@@ -198,7 +200,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
return null;
}
}, AuthenticationUtil.getSystemUserName());
});
}
}
@@ -210,7 +212,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
final NodeRef folderNodeRef = childAssocRef.getChildRef();
// initialise the permissions
setUpPermissions(folderNodeRef);
initPermissions(folderNodeRef);
// Pull any permissions found on the parent (ie the record category)
final NodeRef catNodeRef = childAssocRef.getParentRef();
@@ -285,7 +287,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
NodeRef nodeRef = childAssocRef.getChildRef();
if (nodeService.exists(nodeRef) == true)
{
setUpPermissions(nodeRef);
initPermissions(nodeRef);
NodeRef parent = childAssocRef.getParentRef();
Set<AccessPermission> perms = permissionService.getAllSetPermissions(parent);
@@ -324,7 +326,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
*/
public void initialiseRecordPermissions(NodeRef record, NodeRef parent)
{
setUpPermissions(record);
initPermissions(record);
Set<AccessPermission> perms = permissionService.getAllSetPermissions(parent);
for (AccessPermission perm : perms)
@@ -402,10 +404,11 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
}
/**
*
* @param nodeRef
* Initiliase the permissions for the given node.
*
* @param nodeRef node reference
*/
public void setUpPermissions(final NodeRef nodeRef)
private void initPermissions(final NodeRef nodeRef)
{
if (nodeService.exists(nodeRef) == true)
{

View File

@@ -33,8 +33,15 @@ public interface VitalRecordService
static final Period PERIOD_NONE = new Period("none|0");
/**
* Gets the vital record definition details for the node.
*
* Setup the vital record definition for the given node.
*
* @param nodeRef node reference
*/
void setupVitalRecordDefinition(NodeRef nodeRef);
/**
* Gets the vital record definition details for the node.
*
* @param nodeRef node reference
* @return VitalRecordDefinition vital record definition details
*/

View File

@@ -129,11 +129,6 @@ public class VitalRecordServiceImpl implements VitalRecordService,
TYPE_RECORD_FOLDER,
ContentModel.ASSOC_CONTAINS,
onCreateChildAssociation);
policyComponent.bindAssociationBehaviour(
NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME,
TYPE_RECORD_CATEGORY,
ContentModel.ASSOC_CONTAINS,
onCreateChildAssociation);
}
/**
@@ -185,7 +180,7 @@ public class VitalRecordServiceImpl implements VitalRecordService,
if (filePlanService.isRecordCategory(nodeRef) == true ||
recordFolderService.isRecordFolder(nodeRef) == true)
{
inheritVitalRecordDefinition(nodeRef);
setupVitalRecordDefinition(nodeRef);
}
return null;
@@ -202,11 +197,10 @@ public class VitalRecordServiceImpl implements VitalRecordService,
}
/**
* Helper method to set the inherited vital record definition details.
*
* @param nodeRef node reference
* @see org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService#setupVitalRecordDefinition(org.alfresco.service.cmr.repository.NodeRef)
*/
private void inheritVitalRecordDefinition(NodeRef nodeRef)
@Override
public void setupVitalRecordDefinition(NodeRef nodeRef)
{
// get the current review period value
Period currentReviewPeriod = (Period)nodeService.getProperty(nodeRef, PROP_REVIEW_PERIOD);

View File

@@ -0,0 +1,210 @@
/*
* Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.policy.annotation;
import java.lang.reflect.Method;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* Annotated behaviour bean post processor.
* <p>
* Registers the annotated methods on behaviour beans with the policy component.
*
* @author Roy Wetherall
*/
public class AnnotatedBehaviourPostProcessor implements BeanPostProcessor
{
/** logger */
private static Log logger = LogFactory.getLog(AnnotatedBehaviourPostProcessor.class);
/** policy component */
private PolicyComponent policyComponent;
/** namespace service */
private NamespaceService namespaceService;
/**
* @param policyComponent policy component
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* @param namespaceService namespace service
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
// register annotated behavior methods
registerBehaviours(bean, beanName);
return bean;
}
/**
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
// do nothing
return bean;
}
/**
*
* @param bean
* @param beanName
*/
private void registerBehaviours(Object bean, String beanName)
{
if (bean.getClass().isAnnotationPresent(BehaviourBean.class) == true)
{
BehaviourBean behaviourBean = bean.getClass().getAnnotation(BehaviourBean.class);
if (logger.isDebugEnabled() == true)
{
logger.debug("Annotated behaviour post processing for " + beanName);
}
Method[] methods = bean.getClass().getMethods();
for (Method method : methods)
{
if (method.isAnnotationPresent(Behaviour.class) == true)
{
registerBehaviour(behaviourBean, bean, beanName, method);
}
}
}
}
/**
*
* @param bean
* @param beanName
* @param method
* @param classBehaviour
*/
private void registerBehaviour(BehaviourBean behaviourBean, Object bean, String beanName, Method method)
{
Behaviour behaviour = method.getAnnotation(Behaviour.class);
QName policy = resolvePolicy(behaviour.policy(), method);
QName type = resolveType(behaviourBean, behaviour.type());
// assert that the policy and type have been set!!
ParameterCheck.mandatory("policy", policy);
ParameterCheck.mandatory("type", type);
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... registering " + behaviour.kind() + " behaviour for " + beanName + "." + method.getName() +
" for policy " + policy.toString() +
" and type " + type.toString());
}
JavaBehaviour javaBehaviour = new JavaBehaviour(bean, method.getName(), behaviour.notificationFrequency());
if (BehaviourKind.CLASS.equals(behaviour.kind()) == true)
{
policyComponent.bindClassBehaviour(policy,
type,
javaBehaviour);
}
else if (BehaviourKind.ASSOCIATION.equals(behaviour.kind()) == true)
{
policyComponent.bindAssociationBehaviour(policy,
type,
toQName(behaviour.assocType()),
javaBehaviour);
}
}
/**
*
* @param policyName
* @param method
* @return
*/
private QName resolvePolicy(String policyName, Method method)
{
QName policy = null;
if (policyName.isEmpty() == true)
{
policy = QName.createQName(NamespaceService.ALFRESCO_URI, method.getName());
}
else
{
policy = toQName(policyName);
}
return policy;
}
/**
*
* @param behaviourBean
* @param typeName
* @return
*/
private QName resolveType(BehaviourBean behaviourBean, String typeName)
{
QName type = null;
if (typeName.isEmpty() == true)
{
// get default
type = toQName(behaviourBean.defaultType());
}
else
{
// convert set
type = toQName(typeName);
}
return type;
}
/**
*
* @param name
* @return
*/
private QName toQName(String name)
{
return QName.createQName(name, namespaceService);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.policy.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
/**
* Behaviour method annotation.
*
* @author Roy Wetherall
*/
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Behaviour
{
/** kind of behaviour */
BehaviourKind kind();
/** qualified name of policy */
String policy() default "";
/** qualified name of type/aspect */
String type() default "";
/** qualified name of association */
String assocType() default "cm:contains";
/** notification frequency */
NotificationFrequency notificationFrequency() default NotificationFrequency.EVERY_EVENT;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.policy.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Roy Wetherall
*/
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface BehaviourBean
{
/** qualified name of type/aspect */
String defaultType() default "";
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.policy.annotation;
/**
* Enumeration describing the different kinds of behaviour.
*
* @author Roy Wetherall
* @since 2.2
*/
public enum BehaviourKind
{
CLASS,
ASSOCIATION
}