Merge HEAD to BRANCHES/V2.1.0.x:

* 74458 - RM Performance Improvements
              * general file plan browse rendering in around half the previously recorded times for around 500 records (need to scale up)
	      * unessesary bottle neck removed from record detail page rendering (see RM-1461)
              * other general improvements
              * TODO .. hasFrozenChildren, getNextDisposition, TransferNodeIndicator, HeldBy .. all traverse up or down record/record folder hierarchy in ways that don't scale
              * fix to disposition lifecycle job that failed all when one failed .. this explains why the job appeared not to work on occasion

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/BRANCHES/V2.1.0.x@76475 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2014-07-15 00:48:34 +00:00
parent 458cc51bb4
commit 558399aa2b
12 changed files with 447 additions and 342 deletions

View File

@@ -8,8 +8,8 @@
<bean id="capabilityCondition.base"
abstract="true">
<property name="recordsManagementService" ref="recordsManagementService" />
<property name="permissionService" ref="PermissionService" />
<property name="nodeService" ref="NodeService" />
<property name="permissionService" ref="permissionService" /> <!-- user lower case service to enhance performance -->
<property name="nodeService" ref="nodeService" /> <!-- user lower case service to enhance performance -->
<property name="freezeService" ref="FreezeService" />
<property name="recordService" ref="recordService" />
<property name="filePlanService" ref="FilePlanService" />

View File

@@ -1130,9 +1130,7 @@
<!-- Record Service -->
<bean id="recordService" class="org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl" init-method="init">
<property name="nodeService" ref="NodeService"/>
<property name="dictionaryService" ref="DictionaryService"/>
<bean id="recordService" class="org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl" parent="baseService" init-method="init">
<property name="identifierService" ref="recordsManagementIdentifierService"/>
<property name="permissionService" ref="ExtendedPermissionService"/>
<property name="extendedSecurityService" ref="ExtendedSecurityService" />

View File

@@ -48,9 +48,6 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyMap;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.extensions.surf.util.I18NUtil;
/**
@@ -62,8 +59,7 @@ public class RecordsManagementServiceImpl extends ServiceBaseImpl
implements RecordsManagementService,
RecordsManagementModel,
RecordsManagementPolicies.OnCreateReference,
RecordsManagementPolicies.OnRemoveReference,
ApplicationContextAware
RecordsManagementPolicies.OnRemoveReference
{
/** I18N */
private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container";
@@ -91,18 +87,6 @@ public class RecordsManagementServiceImpl extends ServiceBaseImpl
/** Java behaviour */
private JavaBehaviour onChangeToDispositionActionDefinition;
/** 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 service registry service
*

View File

@@ -489,7 +489,7 @@ public abstract class RMActionExecuterAbstractBase extends PropertySubActionExe
NodeRef currentDispositionAction = null;
if (this.nodeService.hasAspect(nodeRef, ASPECT_DISPOSITION_LIFECYCLE) == true)
{
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(nodeRef, ASSOC_NEXT_DISPOSITION_ACTION, RegexQNamePattern.MATCH_ALL);
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(nodeRef, ASSOC_NEXT_DISPOSITION_ACTION, ASSOC_NEXT_DISPOSITION_ACTION);
if (assocs.size() > 0)
{
currentDispositionAction = assocs.get(0).getChildRef();

View File

@@ -55,10 +55,10 @@ import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.dictionary.M2Namespace;
import org.alfresco.repo.dictionary.M2Property;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.ClassPolicyDelegate;
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.dictionary.AspectDefinition;
@@ -80,7 +80,6 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -1155,8 +1154,7 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin
*/
public List<AssociationRef> getCustomReferencesFrom(NodeRef node)
{
List<AssociationRef> retrievedAssocs = nodeService.getTargetAssocs(node, RegexQNamePattern.MATCH_ALL);
return retrievedAssocs;
return nodeService.getTargetAssocs(node, null);
}
/**
@@ -1173,8 +1171,7 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin
*/
public List<AssociationRef> getCustomReferencesTo(NodeRef node)
{
List<AssociationRef> retrievedAssocs = nodeService.getSourceAssocs(node, RegexQNamePattern.MATCH_ALL);
return retrievedAssocs;
return nodeService.getSourceAssocs(node, null);
}
/**

View File

@@ -204,19 +204,6 @@ public class RMSecurityCommon
return result;
}
// Get the file plan for the node
NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
// Admin role
//if (permissionService.hasPermission(filePlan, RMPermissionModel.ROLE_ADMINISTRATOR) == AccessStatus.ALLOWED)
//{
// if (logger.isDebugEnabled())
// {
// logger.debug("\t\tAdmin user, access granted. (nodeRef=" + nodeRef.toString() + ", user=" + AuthenticationUtil.getRunAsUser() + ")");
// }
// return setTransactionCache("checkRmRead", nodeRef, AccessDecisionVoter.ACCESS_GRANTED);
// }
if (permissionService.hasPermission(nodeRef, RMPermissionModel.READ_RECORDS) == AccessStatus.DENIED)
{
if (logger.isDebugEnabled())
@@ -226,6 +213,9 @@ public class RMSecurityCommon
return setTransactionCache("checkRmRead", nodeRef, AccessDecisionVoter.ACCESS_DENIED);
}
// Get the file plan for the node
NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
if (permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS) == AccessStatus.DENIED)
{
if (logger.isDebugEnabled())

View File

@@ -796,7 +796,7 @@ public class DispositionServiceImpl implements
private NodeRef getNextDispositionActionNodeRef(NodeRef nodeRef)
{
NodeRef result = null;
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ASSOC_NEXT_DISPOSITION_ACTION, RegexQNamePattern.MATCH_ALL);
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ASSOC_NEXT_DISPOSITION_ACTION, ASSOC_NEXT_DISPOSITION_ACTION, 1, true);
if (assocs.size() != 0)
{
result = assocs.get(0).getChildRef();

View File

@@ -52,9 +52,6 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.extensions.surf.util.I18NUtil;
/**
@@ -65,8 +62,7 @@ import org.springframework.extensions.surf.util.I18NUtil;
*/
public class FilePlanServiceImpl extends ServiceBaseImpl
implements FilePlanService,
RecordsManagementModel,
ApplicationContextAware
RecordsManagementModel
{
/** I18N */
private final static String MSG_DUP_ROOT = "rm.service.dup-root";
@@ -86,18 +82,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
/** RM site file plan container */
private static final String FILE_PLAN_CONTAINER = "documentLibrary";
/** 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;
}
/**
* NOTE: for some reason spring couldn't cope with the circular references between these two
* beans so we need to grab this one manually.
@@ -173,121 +157,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
return (RecordsManagementService)applicationContext.getBean("RecordsManagementService");
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isFilePlanComponent(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlanComponent(NodeRef nodeRef)
{
boolean result = false;
if (getInternalNodeService().exists(nodeRef) == true &&
getInternalNodeService().hasAspect(nodeRef, ASPECT_FILE_PLAN_COMPONENT) == true)
{
result = true;
}
return result;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlanComponentKind(org.alfresco.service.cmr.repository.NodeRef)
*/
public FilePlanComponentKind getFilePlanComponentKind(NodeRef nodeRef)
{
FilePlanComponentKind result = null;
if (isFilePlanComponent(nodeRef) == true)
{
result = FilePlanComponentKind.FILE_PLAN_COMPONENT;
if (isFilePlan(nodeRef) == true)
{
result = FilePlanComponentKind.FILE_PLAN;
}
else if (isRecordCategory(nodeRef) == true)
{
result = FilePlanComponentKind.RECORD_CATEGORY;
}
else if (getRecordsManagementService().isRecordFolder(nodeRef) == true)
{
result = FilePlanComponentKind.RECORD_FOLDER;
}
else if (getRecordService().isRecord(nodeRef) == true)
{
result = FilePlanComponentKind.RECORD;
}
else if (getFreezeService().isHold(nodeRef) == true)
{
result = FilePlanComponentKind.HOLD;
}
else if (getRecordsManagementService().isTransfer(nodeRef) == true)
{
result = FilePlanComponentKind.TRANSFER;
}
else if (instanceOf(nodeRef, TYPE_DISPOSITION_SCHEDULE) == true || instanceOf(nodeRef, TYPE_DISPOSITION_ACTION_DEFINITION) == true)
{
result = FilePlanComponentKind.DISPOSITION_SCHEDULE;
}
else if (instanceOf(nodeRef, TYPE_UNFILED_RECORD_CONTAINER) == true)
{
result = FilePlanComponentKind.UNFILED_RECORD_CONTAINER;
}
}
return result;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementService#getFilePlanComponentKindFromType(org.alfresco.service.namespace.QName)
*/
@Override
public FilePlanComponentKind getFilePlanComponentKindFromType(QName type)
{
FilePlanComponentKind result = null;
if (ASPECT_FILE_PLAN_COMPONENT.equals(type) == true)
{
result = FilePlanComponentKind.FILE_PLAN_COMPONENT;
}
else if (dictionaryService.isSubClass(type, ASPECT_RECORD) == true)
{
result = FilePlanComponentKind.RECORD;
}
else if (dictionaryService.isSubClass(type, TYPE_FILE_PLAN) == true)
{
result = FilePlanComponentKind.FILE_PLAN;
}
else if (dictionaryService.isSubClass(type, TYPE_RECORD_CATEGORY) == true)
{
result = FilePlanComponentKind.RECORD_CATEGORY;
}
else if (dictionaryService.isSubClass(type, TYPE_RECORD_FOLDER) == true)
{
result = FilePlanComponentKind.RECORD_FOLDER;
}
else if (dictionaryService.isSubClass(type, TYPE_HOLD) == true)
{
result = FilePlanComponentKind.HOLD;
}
else if (dictionaryService.isSubClass(type, TYPE_TRANSFER) == true)
{
result = FilePlanComponentKind.TRANSFER;
}
else if (dictionaryService.isSubClass(type, TYPE_DISPOSITION_SCHEDULE) == true ||
dictionaryService.isSubClass(type, TYPE_DISPOSITION_ACTION_DEFINITION) == true)
{
result = FilePlanComponentKind.DISPOSITION_SCHEDULE;
}
return result;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isFilePlan(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlan(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_FILE_PLAN);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlans()
*/
@@ -325,36 +194,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
return results;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlan(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public NodeRef getFilePlan(NodeRef nodeRef)
{
NodeRef result = null;
if (nodeRef != null)
{
result = (NodeRef)getInternalNodeService().getProperty(nodeRef, PROP_ROOT_NODEREF);
if (result == null)
{
if (instanceOf(nodeRef, TYPE_FILE_PLAN) == true)
{
result = nodeRef;
}
else
{
ChildAssociationRef parentAssocRef = getInternalNodeService().getPrimaryParent(nodeRef);
if (parentAssocRef != null)
{
result = getFilePlan(parentAssocRef.getParentRef());
}
}
}
}
return result;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlanBySiteId(java.lang.String)
*/
@@ -640,23 +479,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
}
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isFilePlanContainer(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public boolean isFilePlanContainer(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_RECORDS_MANAGEMENT_CONTAINER);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isRecordCategory(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isRecordCategory(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_RECORD_CATEGORY);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#createRecordCategory(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, org.alfresco.service.namespace.QName, java.util.Map)
*/

View File

@@ -164,7 +164,7 @@ public class FreezeServiceImpl extends ServiceBaseImpl
public Void doWork() throws Exception
{
if (nodeService.exists(nodeRef) == true &&
filePlanService.isFilePlanComponent(nodeRef) == true)
nodeService.hasAspect(nodeRef, ASPECT_FILE_PLAN_COMPONENT) == true)
{
if (isFrozen(nodeRef) == true)
{

View File

@@ -186,12 +186,22 @@ public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecute
Map<String, Serializable> props = new HashMap<String, Serializable>(1);
props.put(RMDispositionActionExecuterAbstractBase.PARAM_NO_ERROR_CHECK, Boolean.FALSE);
// execute disposition action
recordsManagementActionService.executeRecordsManagementAction(parent.getParentRef(), dispAction, props);
if (logger.isDebugEnabled())
try
{
logger.debug("Processed action: " + dispAction + "on" + parent);
// execute disposition action
recordsManagementActionService.executeRecordsManagementAction(parent.getParentRef(), dispAction, props);
if (logger.isDebugEnabled())
{
logger.debug("Processed action: " + dispAction + "on" + parent);
}
}
catch (AlfrescoRuntimeException exception)
{
if (logger.isDebugEnabled())
{
logger.debug(exception);
}
}
}
}

View File

@@ -46,6 +46,7 @@ import org.alfresco.module.org_alfresco_module_rm.notification.RecordsManagement
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.role.Role;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordServiceImpl;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
@@ -84,9 +85,6 @@ import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Record service implementation.
@@ -94,12 +92,12 @@ import org.springframework.context.ApplicationContextAware;
* @author Roy Wetherall
* @since 2.1
*/
public class RecordServiceImpl implements RecordService,
public class RecordServiceImpl extends ServiceBaseImpl
implements RecordService,
RecordsManagementModel,
RecordsManagementCustomModel,
NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnUpdatePropertiesPolicy,
ApplicationContextAware,
NodeServicePolicies.OnAddAspectPolicy,
NodeServicePolicies.OnRemoveAspectPolicy
{
@@ -142,9 +140,6 @@ public class RecordServiceImpl implements RecordService,
NamespaceService.REPOSITORY_VIEW_1_0_URI
};
/** Application context */
private ApplicationContext applicationContext;
/** Node service **/
private NodeService nodeService;
@@ -209,12 +204,6 @@ public class RecordServiceImpl implements RecordService,
"onDeleteDeclaredRecordLink",
NotificationFrequency.FIRST_EVENT);
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
/**
* @param nodeService node service
*/
@@ -624,28 +613,6 @@ public class RecordServiceImpl implements RecordService,
return recordMetaDataAspects;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isRecord(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public boolean isRecord(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
return nodeService.hasAspect(nodeRef, ASPECT_RECORD);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isDeclared(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public boolean isDeclared(NodeRef record)
{
ParameterCheck.mandatory("record", record);
return nodeService.hasAspect(record, ASPECT_DECLARED_RECORD);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createRecord(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef)
*/

View File

@@ -18,13 +18,22 @@
*/
package org.alfresco.module.org_alfresco_module_rm.util;
import java.util.Set;
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.model.RecordsManagementModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
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.namespace.QName;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyMap;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Helper base class for service implementations.
@@ -32,83 +41,411 @@ import org.alfresco.util.PropertyMap;
* @author Roy Wetherall
* @since 2.1
*/
public class ServiceBaseImpl implements RecordsManagementModel
public class ServiceBaseImpl implements RecordsManagementModel, ApplicationContextAware
{
/** Node service */
protected NodeService nodeService;
/** Dictionary service */
protected DictionaryService dictionaryService;
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param dictionaryService dictionary service
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* 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;
}
/**
* Utility method to get the next counter for a node.
* <p>
* If the node is not already countable, then rma:countable is added and 0 returned.
*
* @param nodeRef node reference
* @return int next counter value
*/
protected int getNextCount(NodeRef nodeRef)
{
int counter = 0;
if (nodeService.hasAspect(nodeRef, ASPECT_COUNTABLE) == false)
{
PropertyMap props = new PropertyMap(1);
props.put(PROP_COUNT, 1);
nodeService.addAspect(nodeRef, ASPECT_COUNTABLE, props);
counter = 1;
}
else
{
Integer value = (Integer)this.nodeService.getProperty(nodeRef, PROP_COUNT);
if (value != null)
{
counter = value.intValue() + 1;
}
else
{
counter = 1;
}
nodeService.setProperty(nodeRef, PROP_COUNT, counter);
}
return counter;
}
/** Node service */
protected NodeService nodeService;
/** Dictionary service */
protected DictionaryService dictionaryService;
/** Application context */
protected ApplicationContext applicationContext;
/** internal node service */
private NodeService internalNodeService;
/**
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext)
{
this.applicationContext = applicationContext;
}
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param dictionaryService dictionary service
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* Helper to get internal node service.
* <p>
* Used for performance reasons.
*/
private NodeService getInternalNodeService()
{
if (internalNodeService == null)
{
internalNodeService = (NodeService)applicationContext.getBean("dbNodeService");
}
return internalNodeService;
}
/**
* Gets the file plan component kind from the given node reference
*
* @see FilePlanService#getFilePlanComponentKind(org.alfresco.service.cmr.repository.NodeRef)
*/
public FilePlanComponentKind getFilePlanComponentKind(NodeRef nodeRef)
{
FilePlanComponentKind result = null;
if (isFilePlanComponent(nodeRef))
{
result = FilePlanComponentKind.FILE_PLAN_COMPONENT;
if (isFilePlan(nodeRef))
{
result = FilePlanComponentKind.FILE_PLAN;
}
else if (isRecordCategory(nodeRef))
{
result = FilePlanComponentKind.RECORD_CATEGORY;
}
else if (isRecordFolder(nodeRef))
{
result = FilePlanComponentKind.RECORD_FOLDER;
}
else if (isRecord(nodeRef))
{
result = FilePlanComponentKind.RECORD;
}
else if (isHold(nodeRef))
{
result = FilePlanComponentKind.HOLD;
}
else if (isTransfer(nodeRef))
{
result = FilePlanComponentKind.TRANSFER;
}
else if (instanceOf(nodeRef, TYPE_DISPOSITION_SCHEDULE) || instanceOf(nodeRef, TYPE_DISPOSITION_ACTION_DEFINITION))
{
result = FilePlanComponentKind.DISPOSITION_SCHEDULE;
}
else if (instanceOf(nodeRef, TYPE_UNFILED_RECORD_CONTAINER))
{
result = FilePlanComponentKind.UNFILED_RECORD_CONTAINER;
}
}
return result;
}
/**
* Gets the file plan component kind from the given type.
*
* @see FilePlanService#getFilePlanComponentKindFromType(QName)
*/
public FilePlanComponentKind getFilePlanComponentKindFromType(QName type)
{
FilePlanComponentKind result = null;
if (ASPECT_FILE_PLAN_COMPONENT.equals(type))
{
result = FilePlanComponentKind.FILE_PLAN_COMPONENT;
}
else if (instanceOf(type, ASPECT_RECORD))
{
result = FilePlanComponentKind.RECORD;
}
else if (instanceOf(type, TYPE_FILE_PLAN))
{
result = FilePlanComponentKind.FILE_PLAN;
}
else if (instanceOf(type, TYPE_RECORD_CATEGORY))
{
result = FilePlanComponentKind.RECORD_CATEGORY;
}
else if (instanceOf(type, TYPE_RECORD_FOLDER))
{
result = FilePlanComponentKind.RECORD_FOLDER;
}
else if (instanceOf(type, TYPE_HOLD))
{
result = FilePlanComponentKind.HOLD;
}
else if (instanceOf(type, TYPE_TRANSFER))
{
result = FilePlanComponentKind.TRANSFER;
}
else if (instanceOf(type, TYPE_DISPOSITION_SCHEDULE) ||
instanceOf(type, TYPE_DISPOSITION_ACTION_DEFINITION))
{
result = FilePlanComponentKind.DISPOSITION_SCHEDULE;
}
return result;
}
/**
* Indicates whether the given node is a file plan component or not.
* <p>
* Exposed in the FilePlan service.
*
* @see FilePlanService#isFilePlanComponent(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlanComponent(NodeRef nodeRef)
{
boolean result = false;
if (getInternalNodeService().exists(nodeRef) &&
getInternalNodeService().hasAspect(nodeRef, ASPECT_FILE_PLAN_COMPONENT))
{
result = true;
}
return result;
}
/**
* Indicates whether the given node is a file plan or not.
* <p>
* Exposed in the FilePlan service.
*
* @see FilePlanService#isFilePlan(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlan(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_FILE_PLAN);
}
/**
* Indicates whether the given node is a file plan container or not.
*
* @see FilePlanService#isFilePlanContainer(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlanContainer(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_RECORDS_MANAGEMENT_CONTAINER);
}
/**
* Indicates whether the given node is a record category or not.
*
* @see FilePlanService#isRecordCategory(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isRecordCategory(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_RECORD_CATEGORY);
}
/**
* Indicates whether the given node is a record folder or not.
* <p>
* Exposed in the RecordFolder service.
*
* @param nodeRef node reference
* @return boolean true if record folder, false otherwise
*/
public boolean isRecordFolder(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
return instanceOf(nodeRef, TYPE_RECORD_FOLDER);
}
/**
* Indicates whether the given node reference is a record or not.
*
* @param nodeRef node reference
* @return boolean true if node reference is a record, false otherwise
*/
public boolean isRecord(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
return getInternalNodeService().hasAspect(nodeRef, ASPECT_RECORD);
}
/**
* Indicates whether the given node reference is a hold or not.
*
* @param nodeRef node reference
* @return boolean true if rma:hold or sub-type, false otherwise
*/
public boolean isHold(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
boolean isHold = false;
if (getInternalNodeService().exists(nodeRef) &&
instanceOf(nodeRef, TYPE_HOLD))
{
isHold = true;
}
return isHold;
}
/**
* Indicates whether the given node reference is a transfer or not.
*/
public boolean isTransfer(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
return instanceOf(nodeRef, TYPE_TRANSFER);
}
/**
* Indicates whether a record is complete or not.
*
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isDeclared(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isDeclared(NodeRef record)
{
ParameterCheck.mandatory("record", record);
return getInternalNodeService().hasAspect(record, ASPECT_DECLARED_RECORD);
}
/**
* Gets the file plan that a given file plan component resides within.
*
* @param nodeRef node reference
* @return {@link NodeRef} file plan, null if none
*/
public NodeRef getFilePlan(final NodeRef nodeRef)
{
NodeRef result = null;
if (nodeRef != null)
{
result = (NodeRef)getInternalNodeService().getProperty(nodeRef, PROP_ROOT_NODEREF);
if (result == null)
{
if (instanceOf(nodeRef, TYPE_FILE_PLAN))
{
result = nodeRef;
}
else
{
ChildAssociationRef parentAssocRef = getInternalNodeService().getPrimaryParent(nodeRef);
if (parentAssocRef != null)
{
result = getFilePlan(parentAssocRef.getParentRef());
}
}
}
}
return result;
}
/**
* 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);
QName className = getInternalNodeService().getType(nodeRef);
return instanceOf(className, ofClassName);
}
/**
* Utility method to quickly determine whether one class is equal to or sub of another.
*
* @param className class name
* @param ofClassName class name to check against
* @return boolean true if equal to or sub, false otherwise
*/
protected boolean instanceOf(QName className, QName ofClassName)
{
ParameterCheck.mandatory("className", className);
ParameterCheck.mandatory("ofClassName", ofClassName);
boolean result = false;
if (ofClassName.equals(className) ||
dictionaryService.isSubClass(className, ofClassName))
{
result = true;
}
return result;
}
/**
* Utility method to get the next counter for a node.
* <p>
* If the node is not already countable, then rma:countable is added and 0 returned.
*
* @param nodeRef node reference
* @return int next counter value
*/
protected int getNextCount(NodeRef nodeRef)
{
int counter = 0;
if (!nodeService.hasAspect(nodeRef, ASPECT_COUNTABLE))
{
PropertyMap props = new PropertyMap(1);
props.put(PROP_COUNT, 1);
nodeService.addAspect(nodeRef, ASPECT_COUNTABLE, props);
counter = 1;
}
else
{
Integer value = (Integer)this.nodeService.getProperty(nodeRef, PROP_COUNT);
if (value != null)
{
counter = value.intValue() + 1;
}
else
{
counter = 1;
}
nodeService.setProperty(nodeRef, PROP_COUNT, counter);
}
return counter;
}
/**
* Helper method to get a set containing the node's type and all it's aspects
*
* @param nodeRef nodeRef
* @return Set<QName> set of qname's
*/
protected Set<QName> getTypeAndApsects(NodeRef nodeRef)
{
Set<QName> result = nodeService.getAspects(nodeRef);
result.add(nodeService.getType(nodeRef));
return result;
}
/**
* Helper method that executed work as system user.
* <p>
* Useful when testing using mocks.
*
* @param runAsWork work to execute as system user
* @return
*/
public <R> R runAsSystem(RunAsWork<R> runAsWork)
{
return AuthenticationUtil.runAsSystem(runAsWork);
}
/**
* Helper method that executed work as given user.
* <p>
* Useful when testing using mocks.
*
* @param runAsWork work to execute as given user
* @return
*/
public <R> R runAs(RunAsWork<R> runAsWork, String uid)
{
return AuthenticationUtil.runAs(runAsWork, uid);
}
}