mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
RM performance enhancements
* serach improvements * in-place record browse improvements * saved search via file plan browse improvements git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/BRANCHES/V2.1.0.x@76850 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.alfresco.module.org_alfresco_module_rm.capability;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.acegisecurity.vote.AccessDecisionVoter;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
@@ -27,6 +29,7 @@ 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.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.TransactionalResourceHelper;
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -34,6 +37,7 @@ import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -192,48 +196,82 @@ public class RMSecurityCommon
|
||||
}
|
||||
|
||||
/**
|
||||
* Core RM read check
|
||||
*
|
||||
* @param nodeRef
|
||||
* @return
|
||||
* @param nodeRef node reference
|
||||
* @return int see {@link AccessDecisionVoter}
|
||||
*/
|
||||
public int checkRmRead(NodeRef nodeRef)
|
||||
{
|
||||
int result = getTransactionCache("checkRmRead", nodeRef);
|
||||
if (result != NOSET_VALUE)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (permissionService.hasPermission(nodeRef, RMPermissionModel.READ_RECORDS) == AccessStatus.DENIED)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\t\tUser does not have read record permission on node, access denied. (nodeRef=" + nodeRef.toString() + ", user=" + AuthenticationUtil.getRunAsUser() + ")");
|
||||
}
|
||||
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())
|
||||
{
|
||||
logger.debug("\t\tUser does not have view records capability permission on node, access denied. (filePlan=" + filePlan.toString() + ", user=" + AuthenticationUtil.getRunAsUser() + ")");
|
||||
}
|
||||
return setTransactionCache("checkRmRead", nodeRef, AccessDecisionVoter.ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if (caveatConfigComponent.hasAccess(nodeRef))
|
||||
{
|
||||
return setTransactionCache("checkRmRead", nodeRef, AccessDecisionVoter.ACCESS_GRANTED);
|
||||
}
|
||||
else
|
||||
{
|
||||
return setTransactionCache("checkRmRead", nodeRef, AccessDecisionVoter.ACCESS_DENIED);
|
||||
}
|
||||
|
||||
{
|
||||
int result = AccessDecisionVoter.ACCESS_ABSTAIN;
|
||||
|
||||
Map<Pair<String, NodeRef>, Integer> transactionCache = TransactionalResourceHelper.getMap("rm.security.checkRMRead");
|
||||
Pair<String, NodeRef> key = new Pair<String, NodeRef>(AuthenticationUtil.getRunAsUser(), nodeRef);
|
||||
|
||||
if (transactionCache.containsKey(key))
|
||||
{
|
||||
result = transactionCache.get(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (permissionService.hasPermission(nodeRef, RMPermissionModel.READ_RECORDS) == AccessStatus.DENIED)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\t\tUser does not have read record permission on node, access denied. (nodeRef=" + nodeRef.toString() + ", user=" + AuthenticationUtil.getRunAsUser() + ")");
|
||||
}
|
||||
result = AccessDecisionVoter.ACCESS_DENIED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the file plan for the node
|
||||
NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
|
||||
if (hasViewCapability(filePlan) == AccessStatus.DENIED)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\t\tUser does not have view records capability permission on node, access denied. (filePlan=" + filePlan.toString() + ", user=" + AuthenticationUtil.getRunAsUser() + ")");
|
||||
}
|
||||
result = AccessDecisionVoter.ACCESS_DENIED;
|
||||
}
|
||||
else if (!caveatConfigComponent.hasAccess(nodeRef))
|
||||
{
|
||||
result = AccessDecisionVoter.ACCESS_DENIED;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = AccessDecisionVoter.ACCESS_GRANTED;
|
||||
}
|
||||
}
|
||||
|
||||
// cache result
|
||||
transactionCache.put(key, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine whether the current user has view capability on the file plan
|
||||
*
|
||||
* @param filePlan file plan
|
||||
* @return {@link AccessStatus}
|
||||
*/
|
||||
private AccessStatus hasViewCapability(NodeRef filePlan)
|
||||
{
|
||||
Map<Pair<String, NodeRef>, AccessStatus> transactionCache = TransactionalResourceHelper.getMap("rm.security.hasViewCapability");
|
||||
Pair<String, NodeRef> key = new Pair<String, NodeRef>(AuthenticationUtil.getRunAsUser(), filePlan);
|
||||
|
||||
if (transactionCache.containsKey(key))
|
||||
{
|
||||
return transactionCache.get(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
AccessStatus result = permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS);
|
||||
transactionCache.put(key, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
@@ -33,9 +33,7 @@ import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearch
|
||||
import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.search.SavedSearchDetailsCompatibility;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
@@ -44,6 +42,7 @@ import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.extensions.webscripts.Cache;
|
||||
@@ -199,20 +198,20 @@ public class RMSearchGet extends DeclarativeWebScript
|
||||
}
|
||||
|
||||
// Execute search
|
||||
List<NodeRef> results = recordsManagementSearchService.search(siteId, query, searchParameters);
|
||||
List<Pair<NodeRef, NodeRef>> results = recordsManagementSearchService.search(siteId, query, searchParameters);
|
||||
|
||||
// Reset person data cache
|
||||
personDataCache = new HashMap<String, String>(57);
|
||||
|
||||
// Process the result items
|
||||
List<Item> items = new ArrayList<Item>(results.size());
|
||||
for (NodeRef nodeRef : results)
|
||||
for (Pair<NodeRef, NodeRef> pair : results)
|
||||
{
|
||||
// FIXME: This is a workaround for DOD Recert
|
||||
// TC 3-3 Create User Groups
|
||||
try
|
||||
{
|
||||
Item item = new Item(nodeRef);
|
||||
Item item = new Item(pair.getFirst(), pair.getSecond());
|
||||
items.add(item);
|
||||
}
|
||||
catch(Exception e) {}
|
||||
@@ -245,7 +244,7 @@ public class RMSearchGet extends DeclarativeWebScript
|
||||
private Map<QName, Serializable> nodeProperties;
|
||||
private Map<String, Serializable> properties;
|
||||
|
||||
public Item(NodeRef nodeRef)
|
||||
public Item(NodeRef parent, NodeRef nodeRef)
|
||||
{
|
||||
// Set node ref
|
||||
this.nodeRef = nodeRef;
|
||||
@@ -265,12 +264,12 @@ public class RMSearchGet extends DeclarativeWebScript
|
||||
}
|
||||
|
||||
// Get parent node reference
|
||||
NodeRef parent = null;
|
||||
ChildAssociationRef assoc = nodeService.getPrimaryParent(nodeRef);
|
||||
if (assoc != null)
|
||||
{
|
||||
parent = assoc.getParentRef();
|
||||
}
|
||||
// NodeRef parent = null;
|
||||
// ChildAssociationRef assoc = nodeService.getPrimaryParent(nodeRef);
|
||||
// if (assoc != null)
|
||||
// {
|
||||
// parent = assoc.getParentRef();
|
||||
// }
|
||||
|
||||
if (isContainer == true)
|
||||
{
|
||||
@@ -334,16 +333,6 @@ public class RMSearchGet extends DeclarativeWebScript
|
||||
if (NamespaceService.SYSTEM_MODEL_1_0_URI.equals(qName.getNamespaceURI()) == false)
|
||||
{
|
||||
String prefixName = qName.getPrefixString().replace(":", "_");
|
||||
Serializable value = entry.getValue();
|
||||
if (value instanceof NodeRef)
|
||||
{
|
||||
value = value.toString();
|
||||
}
|
||||
else if (value instanceof ContentData)
|
||||
{
|
||||
ContentReader contentReader = contentService.getReader(nodeRef, qName);
|
||||
value = contentReader.getContentString();
|
||||
}
|
||||
properties.put(prefixName, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ package org.alfresco.module.org_alfresco_module_rm.search;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.util.Pair;
|
||||
|
||||
/**
|
||||
* Records management search service.
|
||||
@@ -33,10 +34,10 @@ public interface RecordsManagementSearchService
|
||||
* Execute a records management search
|
||||
* @param siteId the id of the rm site to query
|
||||
* @param query search query string
|
||||
* @param searchParameters search parameters
|
||||
* @return {@link List}<{@link NodeRef}> search results
|
||||
* @param searchParameters search parameters
|
||||
* @return {@link List}<{@link Pair}<{@link NodeRef}, {@link NodeRef}> search results as pairs for parent and child nodes
|
||||
*/
|
||||
List<NodeRef> search(String siteId, String query, RecordsManagementSearchParameters searchParameters);
|
||||
List<Pair<NodeRef, NodeRef>> search(String siteId, String query, RecordsManagementSearchParameters searchParameters);
|
||||
|
||||
/**
|
||||
* Get all the searches saved on the given records management site.
|
||||
|
@@ -30,6 +30,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -41,6 +42,7 @@ import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.ISO9075;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@@ -173,7 +175,7 @@ public class RecordsManagementSearchServiceImpl implements RecordsManagementSear
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService#search(java.lang.String, java.lang.String, org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchParameters)
|
||||
*/
|
||||
@Override
|
||||
public List<NodeRef> search(String siteId, String query, RecordsManagementSearchParameters rmSearchParameters)
|
||||
public List<Pair<NodeRef, NodeRef>> search(String siteId, String query, RecordsManagementSearchParameters rmSearchParameters)
|
||||
{
|
||||
// build the full RM query
|
||||
StringBuilder fullQuery = new StringBuilder(1024);
|
||||
@@ -206,9 +208,16 @@ public class RecordsManagementSearchServiceImpl implements RecordsManagementSear
|
||||
|
||||
// execute query
|
||||
ResultSet resultSet = searchService.query(searchParameters);
|
||||
|
||||
// process results
|
||||
List<Pair<NodeRef, NodeRef>> result = new ArrayList<Pair<NodeRef, NodeRef>>(resultSet.length());
|
||||
for (ChildAssociationRef childAssoc : resultSet.getChildAssocRefs())
|
||||
{
|
||||
result.add(new Pair<NodeRef, NodeRef>(childAssoc.getParentRef(), childAssoc.getChildRef()));
|
||||
}
|
||||
|
||||
// return results
|
||||
return resultSet.getNodeRefs();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -49,4 +49,13 @@ public class ExtendedReaderDynamicAuthority extends ExtendedSecurityBaseDynamicA
|
||||
{
|
||||
return getExtendedSecurityService().getExtendedReaders(nodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityBaseDynamicAuthority#getTransactionCacheName()
|
||||
*/
|
||||
@Override
|
||||
protected String getTransactionCacheName()
|
||||
{
|
||||
return "rm.extendedreaderdynamicauthority";
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ import org.alfresco.repo.transaction.TransactionalResourceHelper;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.AuthorityService;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -42,9 +43,6 @@ public abstract class ExtendedSecurityBaseDynamicAuthority implements DynamicAut
|
||||
RecordsManagementModel,
|
||||
ApplicationContextAware
|
||||
{
|
||||
/** transaction cache key */
|
||||
private static final String KEY_HAS_AUTHORITY_CACHE = "rm.transaction.hasAuthority";
|
||||
|
||||
/** Authority service */
|
||||
private AuthorityService authorityService;
|
||||
|
||||
@@ -95,6 +93,11 @@ public abstract class ExtendedSecurityBaseDynamicAuthority implements DynamicAut
|
||||
}
|
||||
return nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String transaction cache name
|
||||
*/
|
||||
protected abstract String getTransactionCacheName();
|
||||
|
||||
/**
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
@@ -122,51 +125,38 @@ public abstract class ExtendedSecurityBaseDynamicAuthority implements DynamicAut
|
||||
{
|
||||
boolean result = false;
|
||||
|
||||
if (getNodeService().hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY) == true)
|
||||
Map<Pair<NodeRef, String>, Boolean> transactionCache = TransactionalResourceHelper.getMap(getTransactionCacheName());
|
||||
Pair<NodeRef, String> key = new Pair<NodeRef, String>(nodeRef, userName);
|
||||
|
||||
if (transactionCache.containsKey(key))
|
||||
{
|
||||
Set<String> authorities = getAuthorites(nodeRef);
|
||||
if (authorities != null)
|
||||
{
|
||||
for (String authority : authorities)
|
||||
{
|
||||
if ("GROUP_EVERYONE".equals(authority) == true)
|
||||
{
|
||||
// 'eveyone' is there so break
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
else if (authority.startsWith("GROUP_") == true)
|
||||
{
|
||||
Map<String, Boolean> transactionCache = TransactionalResourceHelper.getMap(KEY_HAS_AUTHORITY_CACHE);
|
||||
String key = authority + "|" + userName;
|
||||
if (transactionCache.containsKey(key))
|
||||
|
||||
{
|
||||
result = transactionCache.get(key);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Set<String> contained = getAuthorityService().getAuthoritiesForUser(userName);
|
||||
if (contained.contains(authority))
|
||||
{
|
||||
result = true;
|
||||
transactionCache.put(key, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// presume we have a user
|
||||
if (authority.equals(userName) == true)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = transactionCache.get(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getNodeService().hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY) == true)
|
||||
{
|
||||
Set<String> authorities = getAuthorites(nodeRef);
|
||||
if (authorities != null)
|
||||
{
|
||||
// check for everyone or the user
|
||||
if (authorities.contains("GROUP_EVEYONE") ||
|
||||
authorities.contains(userName))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// determine whether any of the users groups are in the extended security
|
||||
Set<String> contained = getAuthorityService().getAuthoritiesForUser(userName);
|
||||
authorities.retainAll(contained);
|
||||
result = (authorities.size() != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cache result
|
||||
transactionCache.put(key, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@@ -48,5 +48,14 @@ public class ExtendedWriterDynamicAuthority extends ExtendedSecurityBaseDynamicA
|
||||
protected Set<String> getAuthorites(NodeRef nodeRef)
|
||||
{
|
||||
return getExtendedSecurityService().getExtendedWriters(nodeRef);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityBaseDynamicAuthority#getTransactionCacheName()
|
||||
*/
|
||||
@Override
|
||||
protected String getTransactionCacheName()
|
||||
{
|
||||
return "rm.extendedwriterdynamicauthority";
|
||||
}
|
||||
}
|
||||
|
@@ -338,24 +338,35 @@ public class ServiceBaseImpl implements RecordsManagementModel, ApplicationConte
|
||||
public NodeRef getFilePlan(final NodeRef nodeRef)
|
||||
{
|
||||
NodeRef result = null;
|
||||
if (nodeRef != 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<NodeRef, NodeRef> transactionCache = TransactionalResourceHelper.getMap("rm.servicebase.getFilePlan");
|
||||
if (transactionCache.containsKey(nodeRef))
|
||||
{
|
||||
result = transactionCache.get(nodeRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cache result in transaction
|
||||
transactionCache.put(nodeRef, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
Reference in New Issue
Block a user