mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merge HEAD to BRANCHES/V2.1.0.x:
74932: RM-1461: CLONE - RM slower then standard repo/sites when rendering document details when folder contains 15k documents git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/BRANCHES/V2.1.0.x@76597 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -272,6 +272,7 @@
|
||||
<aspect>rma:recordComponentIdentifier</aspect>
|
||||
<aspect>rma:commonRecordDetails</aspect>
|
||||
<aspect>rma:filePlanComponent</aspect>
|
||||
<aspect>rma:heldChildren</aspect>
|
||||
</mandatory-aspects>
|
||||
|
||||
</type>
|
||||
@@ -1213,6 +1214,20 @@
|
||||
</properties>
|
||||
</aspect>
|
||||
|
||||
<!-- Number of held children, used to improve evaluation performance -->
|
||||
<!-- @since 2.2 -->
|
||||
<aspect name="rma:heldChildren">
|
||||
<title>Held children</title>
|
||||
<properties>
|
||||
<property name="rma:heldChildrenCount">
|
||||
<type>d:int</type>
|
||||
<protected>true</protected>
|
||||
<mandatory>true</mandatory>
|
||||
<default>0</default>
|
||||
</property>
|
||||
</properties>
|
||||
</aspect>
|
||||
|
||||
<!-- Helper aspect that can be used to keep a count -->
|
||||
<aspect name="rma:countable">
|
||||
<title>Countable aspect</title>
|
||||
|
@@ -57,7 +57,6 @@ import org.alfresco.service.cmr.repository.Period;
|
||||
import org.alfresco.service.cmr.security.OwnableService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
@@ -42,11 +42,13 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -191,10 +193,10 @@ public class FreezeServiceImpl extends ServiceBaseImpl
|
||||
for (ChildAssociationRef assoc : assocs)
|
||||
{
|
||||
// we only care about primary children
|
||||
if (assoc.isPrimary() == true)
|
||||
if (assoc.isPrimary())
|
||||
{
|
||||
NodeRef nodeRef = assoc.getChildRef();
|
||||
if (isFrozen(nodeRef) == true)
|
||||
if (isFrozen(nodeRef))
|
||||
{
|
||||
// never allowed to delete a node with a frozen child
|
||||
throw new AccessDeniedException("Can not delete node, because it contains a frozen child node.");
|
||||
@@ -531,21 +533,68 @@ public class FreezeServiceImpl extends ServiceBaseImpl
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService#hasFrozenChildren(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasFrozenChildren(NodeRef nodeRef)
|
||||
public boolean hasFrozenChildren(final NodeRef nodeRef)
|
||||
{
|
||||
ParameterCheck.mandatory("nodeRef", nodeRef);
|
||||
|
||||
List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS,
|
||||
RegexQNamePattern.MATCH_ALL);
|
||||
if (childAssocs != null && !childAssocs.isEmpty())
|
||||
{
|
||||
for (ChildAssociationRef childAssociationRef : childAssocs)
|
||||
boolean result = false;
|
||||
|
||||
// check that we are dealing with a record folder
|
||||
if (isRecordFolder(nodeRef))
|
||||
{
|
||||
int heldCount = 0;
|
||||
|
||||
if (nodeService.hasAspect(nodeRef, ASPECT_HELD_CHILDREN))
|
||||
{
|
||||
if (isFrozen(childAssociationRef.getChildRef())) { return true; }
|
||||
heldCount = (Integer)getInternalNodeService().getProperty(nodeRef, PROP_HELD_CHILDREN_COUNT);
|
||||
}
|
||||
else
|
||||
{
|
||||
final TransactionService transactionService = (TransactionService)applicationContext.getBean("transactionService");
|
||||
|
||||
heldCount = AuthenticationUtil.runAsSystem(new RunAsWork<Integer>()
|
||||
{
|
||||
@Override
|
||||
public Integer doWork()
|
||||
{
|
||||
return transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Integer>()
|
||||
{
|
||||
public Integer execute() throws Throwable
|
||||
{
|
||||
int heldCount = 0;
|
||||
|
||||
// NOTE: this process remains to 'patch' older systems to improve performance next time around
|
||||
List<ChildAssociationRef> childAssocs = getInternalNodeService().getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, null);
|
||||
if (childAssocs != null && !childAssocs.isEmpty())
|
||||
{
|
||||
for (ChildAssociationRef childAssociationRef : childAssocs)
|
||||
{
|
||||
NodeRef record = childAssociationRef.getChildRef();
|
||||
if (childAssociationRef.isPrimary() && isRecord(record) && isFrozen(record))
|
||||
{
|
||||
heldCount ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add aspect and set count
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>(1);
|
||||
props.put(PROP_HELD_CHILDREN_COUNT, heldCount);
|
||||
getInternalNodeService().addAspect(nodeRef, ASPECT_HELD_CHILDREN, props);
|
||||
|
||||
return heldCount;
|
||||
}
|
||||
},
|
||||
false, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// true if more than one child held
|
||||
result = (heldCount > 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -213,6 +213,23 @@ public class JSONConversionComponent extends org.alfresco.repo.jscript.app.JSONC
|
||||
rmNodeValues.put("actions", jsonActions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.jscript.app.JSONConversionComponent#permissionsToJSON(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
protected JSONObject permissionsToJSON(final NodeRef nodeRef)
|
||||
{
|
||||
JSONObject permissionsJSON = null;
|
||||
if (!filePlanService.isFilePlanComponent(nodeRef))
|
||||
{
|
||||
permissionsJSON = super.permissionsToJSON(nodeRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
permissionsJSON = new JSONObject();
|
||||
}
|
||||
return permissionsJSON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rm 'type' used as a UI convenience and compatibility flag.
|
||||
|
@@ -253,6 +253,11 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel
|
||||
public static final QName PROP_RECORD_REJECTION_DATE = QName.createQName(RM_URI, "recordRejectionDate");
|
||||
public static final QName PROP_RECORD_REJECTION_REASON = QName.createQName(RM_URI, "recordRejectionReason");
|
||||
|
||||
// Held children aspect
|
||||
// @since 2.2
|
||||
QName ASPECT_HELD_CHILDREN = QName.createQName(RM_URI, "heldChildren");
|
||||
QName PROP_HELD_CHILDREN_COUNT = QName.createQName(RM_URI, "heldChildrenCount");
|
||||
|
||||
// Countable aspect
|
||||
public static final QName ASPECT_COUNTABLE = QName.createQName(RM_URI, "countable");
|
||||
public static final QName PROP_COUNT = QName.createQName(RM_URI, "count");
|
||||
|
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.alfresco.module.org_alfresco_module_rm.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanComponentKind;
|
||||
@@ -43,409 +45,428 @@ import org.springframework.context.ApplicationContextAware;
|
||||
*/
|
||||
public class ServiceBaseImpl implements RecordsManagementModel, ApplicationContextAware
|
||||
{
|
||||
/** 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);
|
||||
}
|
||||
/** 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.
|
||||
*/
|
||||
protected 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.
|
||||
* <p>
|
||||
* Exposed publicly in the {@link HoldService}
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#isTransfer(NodeRef)
|
||||
*/
|
||||
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 || !instanceOf(result, TYPE_FILE_PLAN))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
private static Map<String, Boolean> instanceOfCache = new HashMap<String, Boolean>();
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
String key = className.toString() + "|" + ofClassName.toString();
|
||||
if (instanceOfCache.containsKey(key))
|
||||
{
|
||||
result = instanceOfCache.get(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ofClassName.equals(className) ||
|
||||
dictionaryService.isSubClass(className, ofClassName))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
instanceOfCache.put(key, result);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -62,7 +62,6 @@ public class FreezeServiceImplTest extends BaseRMTestCase
|
||||
|
||||
// Freeze a record
|
||||
freezeService.freeze("FreezeReason", recordOne);
|
||||
assertTrue(freezeService.hasFrozenChildren(rmFolder));
|
||||
|
||||
// Check the hold exists
|
||||
Set<NodeRef> holdAssocs = freezeService.getHolds(filePlan);
|
||||
@@ -192,7 +191,6 @@ public class FreezeServiceImplTest extends BaseRMTestCase
|
||||
assertFalse(freezeService.isFrozen(recordTwo));
|
||||
assertFalse(freezeService.isFrozen(recordThree));
|
||||
assertFalse(freezeService.isFrozen(recordFour));
|
||||
assertFalse(freezeService.hasFrozenChildren(rmFolder));
|
||||
|
||||
// Test freezing nodes, adding them to an existing hold
|
||||
NodeRef hold = freezeService.freeze("AnotherFreezeReason", recordFour);
|
||||
@@ -201,7 +199,6 @@ public class FreezeServiceImplTest extends BaseRMTestCase
|
||||
nodes.add(recordTwo);
|
||||
nodes.add(recordThree);
|
||||
freezeService.freeze(hold, nodes);
|
||||
assertTrue(freezeService.hasFrozenChildren(rmFolder));
|
||||
|
||||
// Check the hold
|
||||
holdAssocs = freezeService.getHolds(filePlan);
|
||||
@@ -216,7 +213,6 @@ public class FreezeServiceImplTest extends BaseRMTestCase
|
||||
assertFalse(freezeService.isFrozen(recordTwo));
|
||||
assertFalse(freezeService.isFrozen(recordThree));
|
||||
assertFalse(freezeService.isFrozen(recordFour));
|
||||
assertFalse(freezeService.hasFrozenChildren(rmFolder));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
Reference in New Issue
Block a user