From 46ef31e9266cb0df3af9437dcfdd87d5e4c94afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BC?= Date: Fri, 5 Aug 2011 13:58:17 +0000 Subject: [PATCH] OpenCMIS server performance improvements git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@29571 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../opencmis/AlfrescoCmisService.java | 155 ++++++++++++------ .../org/alfresco/opencmis/CMISConnector.java | 2 +- .../alfresco/opencmis/CMISNodeInfoImpl.java | 25 +++ .../mapping/ParentActionEvaluator.java | 14 +- .../opencmis/mapping/ParentProperty.java | 8 +- .../RuntimePropertyAccessorMapping.java | 12 +- 6 files changed, 143 insertions(+), 73 deletions(-) diff --git a/source/java/org/alfresco/opencmis/AlfrescoCmisService.java b/source/java/org/alfresco/opencmis/AlfrescoCmisService.java index be8d27ed25..d756cdac31 100644 --- a/source/java/org/alfresco/opencmis/AlfrescoCmisService.java +++ b/source/java/org/alfresco/opencmis/AlfrescoCmisService.java @@ -146,12 +146,14 @@ public class AlfrescoCmisService extends AbstractCmisService private CMISConnector connector; private CallContext context; private UserTransaction txn; - private Map nodeInfoMap; + private Map nodeInfoMap; + private Map objectInfoMap; public AlfrescoCmisService(CMISConnector connector) { this.connector = connector; - nodeInfoMap = new HashMap(); + nodeInfoMap = new HashMap(); + objectInfoMap = new HashMap(); } public void beginCall(CallContext context) @@ -228,8 +230,7 @@ public class AlfrescoCmisService extends AbstractCmisService AuthenticationUtil.popAuthentication(); context = null; nodeInfoMap.clear(); - - super.close(); + objectInfoMap.clear(); } } @@ -291,9 +292,9 @@ public class AlfrescoCmisService extends AbstractCmisService return result; } - protected CMISNodeInfoImpl getOrCreateNodeInfo(String objectId) + protected CMISNodeInfo getOrCreateNodeInfo(String objectId) { - CMISNodeInfoImpl result = nodeInfoMap.get(objectId); + CMISNodeInfo result = nodeInfoMap.get(objectId); if (result == null) { result = connector.createNodeInfo(objectId); @@ -303,22 +304,33 @@ public class AlfrescoCmisService extends AbstractCmisService return result; } - protected CMISNodeInfoImpl getOrCreateNodeInfo(String objectId, String what) + protected CMISNodeInfo getOrCreateNodeInfo(String objectId, String what) { - CMISNodeInfoImpl result = getOrCreateNodeInfo(objectId); - result.checkIfUseful(what); + CMISNodeInfo result = getOrCreateNodeInfo(objectId); + if (result instanceof CMISNodeInfoImpl) + { + ((CMISNodeInfoImpl) result).checkIfUseful(what); + } return result; } - protected CMISNodeInfoImpl getOrCreateFolderInfo(String folderId, String what) + protected CMISNodeInfo getOrCreateFolderInfo(String folderId, String what) { - CMISNodeInfoImpl result = getOrCreateNodeInfo(folderId); - result.checkIfFolder(what); + CMISNodeInfo result = getOrCreateNodeInfo(folderId); + if (result instanceof CMISNodeInfoImpl) + { + ((CMISNodeInfoImpl) result).checkIfFolder(what); + } return result; } + protected void addNodeInfo(CMISNodeInfo info) + { + nodeInfoMap.put(info.getObjectId(), info); + } + // --- repository service --- @Override @@ -810,15 +822,16 @@ public class AlfrescoCmisService extends AbstractCmisService } // get the parent - ChildAssociationRef parent = connector.getNodeService().getPrimaryParent(info.getNodeRef()); - if (parent == null) + List parentInfos = info.getParents(); + if (parentInfos.isEmpty()) { throw new CmisRuntimeException("Folder has no parent and is not the root folder?!"); } - // create parent object - CMISNodeInfo ni = createNodeInfo(parent.getParentRef()); - ObjectData result = connector.createCMISObject(ni, filter, false, IncludeRelationships.NONE, + CMISNodeInfo parentInfo = parentInfos.get(0); + addNodeInfo(parentInfo); + + ObjectData result = connector.createCMISObject(parentInfo, filter, false, IncludeRelationships.NONE, CMISConnector.RENDITION_NONE, false, false); if (context.isObjectInfoRequired()) { @@ -848,11 +861,13 @@ public class AlfrescoCmisService extends AbstractCmisService if (info.isFolder() && !info.isRootFolder()) { - ChildAssociationRef parent = connector.getNodeService().getPrimaryParent(info.getNodeRef()); - if (parent != null) + List parentInfos = info.getParents(); + if (!parentInfos.isEmpty()) { - CMISNodeInfo ni = createNodeInfo(parent.getParentRef()); - ObjectData object = connector.createCMISObject(ni, filter, includeAllowableActions, + CMISNodeInfo parentInfo = parentInfos.get(0); + addNodeInfo(parentInfo); + + ObjectData object = connector.createCMISObject(parentInfo, filter, includeAllowableActions, includeRelationships, renditionFilter, false, false); if (context.isObjectInfoRequired()) { @@ -872,31 +887,28 @@ public class AlfrescoCmisService extends AbstractCmisService } } else if (info.isCurrentVersion() || info.isPWC()) { - List parents = connector.getNodeService().getParentAssocs(info.getNodeRef(), - ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); - if (parents != null) + List parentInfos = info.getParents(); + for (CMISNodeInfo parentInfo : parentInfos) { - for (ChildAssociationRef parent : parents) + addNodeInfo(parentInfo); + + ObjectData object = connector.createCMISObject(parentInfo, filter, includeAllowableActions, + includeRelationships, renditionFilter, false, false); + if (context.isObjectInfoRequired()) { - CMISNodeInfo ni = createNodeInfo(parent.getParentRef()); - ObjectData object = connector.createCMISObject(ni, filter, includeAllowableActions, - includeRelationships, renditionFilter, false, false); - if (context.isObjectInfoRequired()) - { - getObjectInfo(repositoryId, object.getId()); - } - - ObjectParentDataImpl objectParent = new ObjectParentDataImpl(); - objectParent.setObject(object); - - // include relative path segment - if (includeRelativePathSegment) - { - objectParent.setRelativePathSegment(info.getName()); - } - - result.add(objectParent); + getObjectInfo(repositoryId, object.getId()); } + + ObjectParentDataImpl objectParent = new ObjectParentDataImpl(); + objectParent.setObject(object); + + // include relative path segment + if (includeRelativePathSegment) + { + objectParent.setRelativePathSegment(info.getName()); + } + + result.add(objectParent); } } @@ -1507,7 +1519,7 @@ public class AlfrescoCmisService extends AbstractCmisService checkRepositoryId(repositoryId); // what kind of object is it? - final CMISNodeInfoImpl info = getOrCreateNodeInfo(objectId, "Object"); + final CMISNodeInfo info = getOrCreateNodeInfo(objectId, "Object"); // run transaction endReadOnlyTransaction(); @@ -1559,7 +1571,7 @@ public class AlfrescoCmisService extends AbstractCmisService } } else if (info.isVariant(CMISObjectVariant.VERSION)) { - Version version = info.getVersion(); + Version version = ((CMISNodeInfoImpl) info).getVersion(); connector.getVersionService().deleteVersion(nodeRef, version); return true; } @@ -1757,7 +1769,7 @@ public class AlfrescoCmisService extends AbstractCmisService checkRepositoryId(repositoryId); // what kind of object is it? - CMISNodeInfoImpl info = getOrCreateNodeInfo(objectId, "Object"); + CMISNodeInfo info = getOrCreateNodeInfo(objectId, "Object"); // relationships cannot have content if (info.isVariant(CMISObjectVariant.ASSOC)) @@ -2051,10 +2063,12 @@ public class AlfrescoCmisService extends AbstractCmisService } // what kind of object is it? - CMISNodeInfoImpl info = getOrCreateNodeInfo(versionSeriesId, "Version Series"); + CMISNodeInfo info = getOrCreateNodeInfo(versionSeriesId, "Version Series"); + CMISNodeInfo versionInfo = createNodeInfo(((CMISNodeInfoImpl) info).getLatestVersionNodeRef(major)); + addNodeInfo(versionInfo); - return connector.createCMISObject(createNodeInfo(info.getLatestVersionNodeRef(major)), filter, - includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeAcl); + return connector.createCMISObject(versionInfo, filter, includeAllowableActions, includeRelationships, + renditionFilter, includePolicyIds, includeAcl); } @Override @@ -2070,14 +2084,16 @@ public class AlfrescoCmisService extends AbstractCmisService } // what kind of object is it? - CMISNodeInfoImpl info = getOrCreateNodeInfo(versionSeriesId, "Version Series"); + CMISNodeInfo info = getOrCreateNodeInfo(versionSeriesId, "Version Series"); if (info.isVariant(CMISObjectVariant.ASSOC)) { return connector.getAssocProperties(info, filter); } else { - return connector.getNodeProperties(createNodeInfo(info.getLatestVersionNodeRef(major)), filter); + CMISNodeInfo versionInfo = createNodeInfo(((CMISNodeInfoImpl) info).getLatestVersionNodeRef(major)); + addNodeInfo(versionInfo); + return connector.getNodeProperties(versionInfo, filter); } } @@ -2420,6 +2436,39 @@ public class AlfrescoCmisService extends AbstractCmisService // -------------------------------------------------------- + /** + * Collects the {@link ObjectInfo} about an object. + * + * (Provided by OpenCMIS, but optimized for Alfresco.) + */ + @Override + public ObjectInfo getObjectInfo(String repositoryId, String objectId) + { + ObjectInfo info = objectInfoMap.get(objectId); + if (info == null) + { + CMISNodeInfo nodeInfo = getOrCreateNodeInfo(objectId); + + // object info has not been found -> create one + try + { + // get the object and its info + ObjectData object = connector.createCMISObject(nodeInfo, null, false, IncludeRelationships.BOTH, null, + false, false); + + info = getObjectInfoIntern(repositoryId, object); + + // add object info + objectInfoMap.put(objectId, info); + } catch (Exception e) + { + e.printStackTrace(); + info = null; + } + } + return info; + } + /** * Collects the {@link ObjectInfo} about an object. * @@ -2499,7 +2548,7 @@ public class AlfrescoCmisService extends AbstractCmisService info.setFileName(null); // parent - info.setHasParent(!connector.getRootNodeRef().equals(object.getId())); + info.setHasParent(!ni.isRootFolder()); // policies and relationships info.setSupportsRelationships(true); @@ -2563,7 +2612,7 @@ public class AlfrescoCmisService extends AbstractCmisService } // parent - info.setHasParent(true); + info.setHasParent(ni.isCurrentVersion() || ni.isPWC()); // policies and relationships info.setSupportsRelationships(true); diff --git a/source/java/org/alfresco/opencmis/CMISConnector.java b/source/java/org/alfresco/opencmis/CMISConnector.java index b19922cbd5..a30e3c0317 100644 --- a/source/java/org/alfresco/opencmis/CMISConnector.java +++ b/source/java/org/alfresco/opencmis/CMISConnector.java @@ -1018,7 +1018,7 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen /** * Gets the content from the repository. */ - public ContentStream getContentStream(CMISNodeInfoImpl info, String streamId, BigInteger offset, BigInteger length) + public ContentStream getContentStream(CMISNodeInfo info, String streamId, BigInteger offset, BigInteger length) { // get the type and check if the object can have content TypeDefinitionWrapper type = info.getType(); diff --git a/source/java/org/alfresco/opencmis/CMISNodeInfoImpl.java b/source/java/org/alfresco/opencmis/CMISNodeInfoImpl.java index 3e82a9983e..65d3b0cc7d 100644 --- a/source/java/org/alfresco/opencmis/CMISNodeInfoImpl.java +++ b/source/java/org/alfresco/opencmis/CMISNodeInfoImpl.java @@ -19,8 +19,10 @@ package org.alfresco.opencmis; import java.io.Serializable; +import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.alfresco.model.ContentModel; @@ -43,6 +45,7 @@ import org.alfresco.service.cmr.version.VersionDoesNotExistException; import org.alfresco.service.cmr.version.VersionHistory; import org.alfresco.service.cmr.version.VersionType; import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException; import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException; import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException; @@ -68,6 +71,7 @@ public class CMISNodeInfoImpl implements CMISNodeInfo private Version version; private Boolean isLatestMajorVersion; private Map properties; + private List parents; public CMISNodeInfoImpl(CMISConnector connector, String objectId) { @@ -766,4 +770,25 @@ public class CMISNodeInfoImpl implements CMISNodeInfo { return getObjectId() + " (" + getNodeRef() + ")"; } + + @Override + public List getParents() + { + if (parents == null) + { + parents = new ArrayList(); + + List nodeParents = connector.getNodeService().getParentAssocs(nodeRef, + ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); + if (nodeParents != null) + { + for (ChildAssociationRef parent : nodeParents) + { + parents.add(new CMISNodeInfoImpl(connector, parent.getParentRef())); + } + } + } + + return parents; + } } diff --git a/source/java/org/alfresco/opencmis/mapping/ParentActionEvaluator.java b/source/java/org/alfresco/opencmis/mapping/ParentActionEvaluator.java index 29753aa5cf..d711aa9d8e 100644 --- a/source/java/org/alfresco/opencmis/mapping/ParentActionEvaluator.java +++ b/source/java/org/alfresco/opencmis/mapping/ParentActionEvaluator.java @@ -18,9 +18,9 @@ */ package org.alfresco.opencmis.mapping; -import org.alfresco.opencmis.CMISConnector; +import java.util.List; + import org.alfresco.opencmis.dictionary.CMISNodeInfo; -import org.alfresco.service.cmr.repository.ChildAssociationRef; /** * Action Evaluator whose evaluation takes place on parent @@ -30,7 +30,6 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; public class ParentActionEvaluator extends AbstractActionEvaluator { private AbstractActionEvaluator evaluator; - private CMISConnector cmisConnector; /** * Construct @@ -38,11 +37,10 @@ public class ParentActionEvaluator extends AbstractActionEvaluator * @param serviceRegistry * @param action */ - protected ParentActionEvaluator(CMISConnector cmisConnector, AbstractActionEvaluator evaluator) + protected ParentActionEvaluator(AbstractActionEvaluator evaluator) { super(evaluator.getServiceRegistry(), evaluator.getAction()); this.evaluator = evaluator; - this.cmisConnector = cmisConnector; } public boolean isAllowed(CMISNodeInfo nodeInfo) @@ -52,10 +50,10 @@ public class ParentActionEvaluator extends AbstractActionEvaluator return false; } - ChildAssociationRef car = getServiceRegistry().getNodeService().getPrimaryParent(nodeInfo.getNodeRef()); - if ((car != null) && (car.getParentRef() != null)) + List parents = nodeInfo.getParents(); + if (!parents.isEmpty()) { - return evaluator.isAllowed(cmisConnector.createNodeInfo(car.getParentRef())); + return evaluator.isAllowed(parents.get(0)); } return false; diff --git a/source/java/org/alfresco/opencmis/mapping/ParentProperty.java b/source/java/org/alfresco/opencmis/mapping/ParentProperty.java index 29279c1ce3..bc45599dff 100644 --- a/source/java/org/alfresco/opencmis/mapping/ParentProperty.java +++ b/source/java/org/alfresco/opencmis/mapping/ParentProperty.java @@ -19,11 +19,11 @@ package org.alfresco.opencmis.mapping; import java.io.Serializable; +import java.util.List; import org.alfresco.opencmis.CMISConnector; import org.alfresco.opencmis.dictionary.CMISNodeInfo; import org.alfresco.service.ServiceRegistry; -import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.apache.chemistry.opencmis.commons.PropertyIds; /** @@ -51,10 +51,10 @@ public class ParentProperty extends AbstractProperty return null; } - ChildAssociationRef car = getServiceRegistry().getNodeService().getPrimaryParent(nodeInfo.getNodeRef()); - if ((car != null) && (car.getParentRef() != null)) + List parents = nodeInfo.getParents(); + if (!parents.isEmpty()) { - return car.getParentRef().toString(); + return parents.get(0).getObjectId(); } return null; diff --git a/source/java/org/alfresco/opencmis/mapping/RuntimePropertyAccessorMapping.java b/source/java/org/alfresco/opencmis/mapping/RuntimePropertyAccessorMapping.java index 2b45f23cb7..dba52075af 100644 --- a/source/java/org/alfresco/opencmis/mapping/RuntimePropertyAccessorMapping.java +++ b/source/java/org/alfresco/opencmis/mapping/RuntimePropertyAccessorMapping.java @@ -159,9 +159,8 @@ public class RuntimePropertyAccessorMapping implements PropertyAccessorMapping, Action.CAN_GET_PROPERTIES, PermissionService.READ_PROPERTIES)); registerEvaluator(BaseTypeId.CMIS_DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, Action.CAN_GET_OBJECT_RELATIONSHIPS, true)); - registerEvaluator(BaseTypeId.CMIS_DOCUMENT, new ParentActionEvaluator(cmisConnector, - new PermissionActionEvaluator(serviceRegistry, Action.CAN_GET_OBJECT_PARENTS, - PermissionService.READ_PERMISSIONS))); + registerEvaluator(BaseTypeId.CMIS_DOCUMENT, new ParentActionEvaluator(new PermissionActionEvaluator( + serviceRegistry, Action.CAN_GET_OBJECT_PARENTS, PermissionService.READ_PERMISSIONS))); // Is CAN_MOVE correct mapping? registerEvaluator(BaseTypeId.CMIS_DOCUMENT, new CurrentVersionEvaluator(serviceRegistry, new PermissionActionEvaluator(serviceRegistry, Action.CAN_MOVE_OBJECT, PermissionService.DELETE_NODE), @@ -213,11 +212,10 @@ public class RuntimePropertyAccessorMapping implements PropertyAccessorMapping, Action.CAN_GET_PROPERTIES, PermissionService.READ_PROPERTIES)); registerEvaluator(BaseTypeId.CMIS_FOLDER, new FixedValueActionEvaluator(serviceRegistry, Action.CAN_GET_OBJECT_RELATIONSHIPS, true)); - registerEvaluator(BaseTypeId.CMIS_FOLDER, new ParentActionEvaluator(cmisConnector, - new PermissionActionEvaluator(serviceRegistry, Action.CAN_GET_OBJECT_PARENTS, - PermissionService.READ_PERMISSIONS))); + registerEvaluator(BaseTypeId.CMIS_FOLDER, new ParentActionEvaluator(new PermissionActionEvaluator( + serviceRegistry, Action.CAN_GET_OBJECT_PARENTS, PermissionService.READ_PERMISSIONS))); registerEvaluator(BaseTypeId.CMIS_FOLDER, new RootFolderEvaluator(serviceRegistry, new ParentActionEvaluator( - cmisConnector, new PermissionActionEvaluator(serviceRegistry, Action.CAN_GET_FOLDER_PARENT, + new PermissionActionEvaluator(serviceRegistry, Action.CAN_GET_FOLDER_PARENT, PermissionService.READ_PERMISSIONS)), false)); registerEvaluator(BaseTypeId.CMIS_FOLDER, new PermissionActionEvaluator(serviceRegistry, Action.CAN_GET_DESCENDANTS, PermissionService.READ_CHILDREN));