You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by je...@apache.org on 2010/03/22 17:31:34 UTC

svn commit: r926164 - /incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-support/src/main/java/org/apache/opencmis/server/support/ObjectInfoHelper.java

Author: jens
Date: Mon Mar 22 16:31:33 2010
New Revision: 926164

URL: http://svn.apache.org/viewvc?rev=926164&view=rev
Log:
Add helper class for easier implementatiion of AtomPub protocol binding.

Added:
    incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-support/src/main/java/org/apache/opencmis/server/support/ObjectInfoHelper.java

Added: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-support/src/main/java/org/apache/opencmis/server/support/ObjectInfoHelper.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-support/src/main/java/org/apache/opencmis/server/support/ObjectInfoHelper.java?rev=926164&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-support/src/main/java/org/apache/opencmis/server/support/ObjectInfoHelper.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-support/src/main/java/org/apache/opencmis/server/support/ObjectInfoHelper.java Mon Mar 22 16:31:33 2010
@@ -0,0 +1,507 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.server.support;
+
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.opencmis.commons.PropertyIds;
+import org.apache.opencmis.commons.api.TypeDefinition;
+import org.apache.opencmis.commons.api.TypeDefinitionList;
+import org.apache.opencmis.commons.enums.BaseObjectTypeIds;
+import org.apache.opencmis.commons.enums.CapabilityAcl;
+import org.apache.opencmis.commons.enums.IncludeRelationships;
+import org.apache.opencmis.commons.provider.ObjectData;
+import org.apache.opencmis.commons.provider.ObjectInFolderContainer;
+import org.apache.opencmis.commons.provider.ObjectInFolderData;
+import org.apache.opencmis.commons.provider.ObjectInFolderList;
+import org.apache.opencmis.commons.provider.ObjectList;
+import org.apache.opencmis.commons.provider.ObjectParentData;
+import org.apache.opencmis.commons.provider.PropertyData;
+import org.apache.opencmis.commons.provider.RenditionData;
+import org.apache.opencmis.commons.provider.RepositoryCapabilitiesData;
+import org.apache.opencmis.commons.provider.RepositoryInfoData;
+import org.apache.opencmis.server.spi.CallContext;
+import org.apache.opencmis.server.spi.CmisObjectService;
+import org.apache.opencmis.server.spi.CmisRepositoryService;
+import org.apache.opencmis.server.spi.CmisNavigationService;
+import org.apache.opencmis.server.spi.ObjectInfoHolder;
+import org.apache.opencmis.server.spi.ObjectInfoImpl;
+import org.apache.opencmis.server.spi.RenditionInfo;
+import org.apache.opencmis.server.spi.RenditionInfosImpl;
+
+
+/**
+ * A helper class used from various methods to fill the ObjectInfoHolder structure with 
+ * the required information to generate all the links in the AtomPub binding. Use this 
+ * class as a convenience class for starting the implementation. For productive use it
+ * is highly recommended that a server implementation replaces this implementation by
+ * a more efficient one. This default implementation can only rely on the services and
+ * therefore requires a round-trip for each object to the server once again. This can 
+ * be avoided in a repository specific implementation.
+ * 
+ */
+
+public class ObjectInfoHelper
+{
+    private CmisObjectService _objSvc;
+    private CmisRepositoryService _repSvc;
+    private CmisNavigationService _navSvc;
+    
+    private Map<String, RepositoryCapabilitiesData > _repos = new HashMap<String, RepositoryCapabilitiesData >();
+    private Map<String, Boolean > _mapPolicies = new HashMap<String, Boolean >();
+    private Map<String, Boolean > _mapRelationships = new HashMap<String, Boolean >();
+    
+    public ObjectInfoHelper(CmisRepositoryService repSvc, CmisObjectService objSvc, CmisNavigationService navSvc) {
+        _objSvc = objSvc;
+        _repSvc = repSvc;
+        _navSvc = navSvc;
+    }
+    
+    /**
+     * fill an ObjectInfoHolder object with required information needed for Atom binding 
+     * to be able to generate the necessary links in AtomPub
+     * 
+     * @param context
+     *          call context of the current request
+     * @param repositoryId
+     *          id of repository 
+     * @param objectId
+     *          object to retrieve information for
+     * @param objectInfos
+     *          Holder to fill with information
+     */
+    public ObjectData fillObjectInfoHolder(CallContext context, String repositoryId, String objectId,
+        ObjectInfoHolder objectInfos) {
+        
+      if (null == objectInfos || null == objectId)
+        return null;
+      
+      // call getObject to get the required information to fill ObjectInfoHolder
+      ObjectData objData = getObject(context, repositoryId, objectId);
+      fillObjectInfoHolder(context, repositoryId, objData, objectInfos);
+      
+      return objData; // might be useful as return value in some service methods
+    }
+    
+    /**
+     * Fill object in
+     * @param context
+     * @param repositoryId
+     * @param objData
+     * @param filter
+     * @param objectInfos
+     */
+    public void fillObjectInfoHolder(CallContext context, String repositoryId, ObjectData objData,
+        String filter, ObjectInfoHolder objectInfos) {
+        // fill objectInfos
+        if (filterContainsRequiredProperties(filter))
+            fillObjectInfoHolder(context, repositoryId, objData, objectInfos);
+        else // get object again as we need almost all system properties
+            fillObjectInfoHolder(context, repositoryId, objData.getId(), objectInfos);        
+    }
+    
+    public boolean filterContainsRequiredProperties(String filter) {
+        if (filter==null)
+            return false;
+        if (filter.equals("*"))
+            return true;
+        if (!filter.contains(PropertyIds.CMIS_NAME))
+            return false;
+        if (!filter.contains(PropertyIds.CMIS_CREATED_BY))
+            return false;
+        if (!filter.contains(PropertyIds.CMIS_CREATION_DATE))
+            return false;
+        if (!filter.contains(PropertyIds.CMIS_LAST_MODIFICATION_DATE))
+            return false;
+        if (!filter.contains(PropertyIds.CMIS_OBJECT_TYPE_ID))
+            return false;
+        if (!filter.contains(PropertyIds.CMIS_BASE_TYPE_ID))
+            return false;
+        if (!filter.contains(PropertyIds.CMIS_CONTENT_STREAM_FILE_NAME))
+            return false;
+        if (!filter.contains(PropertyIds.CMIS_CONTENT_STREAM_MIME_TYPE))
+            return false;
+        if (!filter.contains(PropertyIds.CMIS_CONTENT_STREAM_ID))
+            return false;
+        return true;
+        
+    }
+    /**
+     * fill an ObjectInfoHolder object with required information needed for Atom binding 
+     * to be able to generate the necessary links in AtomPub
+     * 
+     * @param context
+     *          call context of the current request
+     * @param repositoryId
+     *          id of repository 
+     * @param objData
+     *          object data to grab information from
+     * @param objectInfos
+     *          Holder to fill with information
+     */
+    public void fillObjectInfoHolder(CallContext context, String repositoryId, ObjectData objData,
+        ObjectInfoHolder objectInfos) {
+        
+        if (null==objData || null==objectInfos)
+            return;
+                
+        // Get required information about the repository and cache it for later use:
+        
+        Map<String, PropertyData<?>> properties = objData.getProperties().getProperties();
+        RepositoryCapabilitiesData repoCaps = _repos.get(repositoryId);
+        if (null == repoCaps) {
+            RepositoryInfoData repoInfo = _repSvc.getRepositoryInfo(null, repositoryId, null);
+            repoCaps = repoInfo.getRepositoryCapabilities();
+            _repos.put(repositoryId, repoCaps);          
+        }
+        
+        Boolean supportsRelationships = _mapRelationships.get(repositoryId);
+        Boolean supportsPolicies = _mapPolicies.get(repositoryId);
+        if (null == supportsRelationships || null == supportsPolicies) {
+            supportsPolicies = supportsRelationships = false;
+            TypeDefinitionList children = _repSvc.getTypeChildren(context, repositoryId, null, false,
+                BigInteger.valueOf(100), BigInteger.ZERO, null);
+            for (TypeDefinition typeDefinition : children.getList()) {
+                if (typeDefinition.getId().equals(BaseObjectTypeIds.CMIS_RELATIONSHIP))
+                    supportsRelationships = true;
+                if (typeDefinition.getId().equals(BaseObjectTypeIds.CMIS_POLICY))
+                    supportsPolicies = true;
+            }
+            _mapRelationships.put(repositoryId, supportsRelationships);
+            _mapPolicies.put(repositoryId, supportsPolicies);
+        }
+        
+        ObjectInfoImpl objInfo = new ObjectInfoImpl();
+       // Fill all setters:
+        objInfo.setId(objData.getId());
+        objInfo.setName(getStringProperty(properties, PropertyIds.CMIS_NAME));
+        objInfo.setCreatedBy(getStringProperty(properties, PropertyIds.CMIS_CREATED_BY)); 
+        objInfo.setCreationDate(getDateProperty(properties, PropertyIds.CMIS_CREATION_DATE)); 
+        objInfo.setLastModificationDate(getDateProperty(properties, PropertyIds.CMIS_LAST_MODIFICATION_DATE));
+        objInfo.setTypeId(getStringProperty(properties, PropertyIds.CMIS_OBJECT_TYPE_ID));
+        String baseId = getStringProperty(properties, PropertyIds.CMIS_BASE_TYPE_ID);
+        objInfo.setBaseType(BaseObjectTypeIds.fromValue(baseId));
+        
+        boolean isVersioned = getStringProperty(properties, PropertyIds.CMIS_VERSION_SERIES_ID) != null;
+        // versioning information: 
+        if (isVersioned) {          
+          objInfo.setIsCurrentVersion(getBooleanProperty(properties, PropertyIds.CMIS_IS_LATEST_VERSION)); 
+          objInfo.setHasVersionHistory(true);
+          objInfo.setWorkingCopyId(getStringProperty(properties, PropertyIds.CMIS_VERSION_SERIES_CHECKED_OUT_ID));
+          objInfo.setWorkingCopyOriginalId(getStringProperty(properties, PropertyIds.CMIS_VERSION_SERIES_CHECKED_OUT_ID));
+        } else { // unversioned document
+          objInfo.setIsCurrentVersion (true); 
+          objInfo.setHasVersionHistory(false);
+          objInfo.setWorkingCopyId(null);
+          objInfo.setWorkingCopyOriginalId(null);
+        }
+        
+        String fileName = getStringProperty(properties, PropertyIds.CMIS_CONTENT_STREAM_FILE_NAME);
+        String mimeType = getStringProperty(properties, PropertyIds.CMIS_CONTENT_STREAM_MIME_TYPE);
+        String streamId = getStringProperty(properties, PropertyIds.CMIS_CONTENT_STREAM_ID);
+        BigInteger length = getIntegerProperty(properties, PropertyIds.CMIS_CONTENT_STREAM_LENGTH);
+        boolean hasContent = fileName != null || mimeType != null || streamId != null || length != null;
+        if (hasContent) {
+          objInfo.setHasContent(hasContent);
+          objInfo.setContentType(mimeType);
+          objInfo.setFileName(fileName);
+        } else {
+          objInfo.setHasContent(false);
+          objInfo.setContentType(null);
+          objInfo.setFileName(null);
+        }
+        
+        if (objInfo.getBaseType() == BaseObjectTypeIds.CMIS_FOLDER)
+            objInfo.setHasParent(getStringProperty(properties, PropertyIds.CMIS_PARENT_ID) != null);
+        else if (objInfo.getBaseType() == BaseObjectTypeIds.CMIS_DOCUMENT) {
+            if (repoCaps.supportsUnfiling())
+                objInfo.setHasParent(documentHasParent(context, repositoryId, objData.getId()));
+            else
+                objInfo.setHasParent(true);
+        } else
+            objInfo.setHasParent(false);            
+        
+        // Renditions, currently not supported by in-memory provider
+        objInfo.setRenditionInfos(convertRenditions(objData.getRenditions()));
+        
+        List<String> sourceIds = new ArrayList<String>();
+        List<String> targetIds = new ArrayList<String>();
+        getRelationshipIds(objData, sourceIds, targetIds);
+        
+        // Relationships, currently not supported by in-memory provider
+        objInfo.setSupportsRelationships(supportsRelationships);
+        objInfo.setRelationshipSourceIds(sourceIds);
+        objInfo.setRelationshipTargetIds(targetIds);
+        
+        objInfo.setSupportsPolicies(supportsPolicies);
+        
+        objInfo.setHasAcl(repoCaps.getCapabilityAcl() != CapabilityAcl.NONE);
+        
+        String baseTypeId = getStringProperty(properties, PropertyIds.CMIS_BASE_TYPE_ID);
+        boolean isFolder = baseTypeId != null && baseTypeId.equals(BaseObjectTypeIds.CMIS_FOLDER.value());
+        
+        objInfo.setSupportsDescendants(isFolder && repoCaps.supportsGetDescendants());;
+        objInfo.setSupportsFolderTree(isFolder && repoCaps.supportsGetFolderTree());
+        
+        objectInfos.addObjectInfo(objInfo);
+    }
+
+        
+        
+
+    /**
+     * fill an ObjectInfoHolder object with required information needed for Atom binding 
+     * to be able to generate the necessary links in AtomPub
+     * 
+     * @param context
+     *          call context of the current request
+     * @param repositoryId
+     *          id of repository 
+     * @param objList
+     *          object list, fill information for each element
+     * @param objectInfos
+     *          Holder to fill with information
+     */
+    public void fillObjectInfoHolder(
+        CallContext context,
+        String repositoryId,
+        ObjectList objList,
+        ObjectInfoHolder objectInfos)
+    {
+          
+        if (null != objectInfos && null != objList && null != objList.getObjects()) {
+            // Fill object information for all children in result list
+            List<ObjectData> listObjects = objList.getObjects();
+            if (null != listObjects)
+                for (ObjectData object : listObjects) {
+                    fillObjectInfoHolder(context, repositoryId, object.getId(), objectInfos);
+                }    
+        }
+    }
+
+    /**
+     * fill an ObjectInfoHolder object with required information needed for Atom binding 
+     * to be able to generate the necessary links in AtomPub
+     * 
+     * @param context
+     *          call context of the current request
+     * @param repositoryId
+     *          id of repository 
+     * @param objList
+     *          object list, fill information for each element
+     * @param objectInfos
+     *          Holder to fill with information
+     */
+    public void fillObjectInfoHolder(
+        CallContext context,
+        String repositoryId,
+        List<ObjectData> objList,
+        ObjectInfoHolder objectInfos)
+    {
+        if (null == objectInfos || null == objList)
+            return;
+
+        // Fill object information for all children in result list
+        for (ObjectData object : objList) {
+            fillObjectInfoHolder(context, repositoryId, object.getId(), objectInfos);
+        }
+    }
+
+    /**
+     * fill an ObjectInfoHolder object with required information needed for Atom binding 
+     * to be able to generate the necessary links in AtomPub
+     * 
+     * @param context
+     *          call context of the current request
+     * @param repositoryId
+     *          id of repository 
+     * @param objList
+     *          object list, fill information for each element
+     * @param objectInfos
+     *          Holder to fill with information
+     */
+    public void fillObjectInfoHolder(
+        CallContext context,
+        String repositoryId,
+        ObjectInFolderList objList,
+        ObjectInfoHolder objectInfos)
+    {
+        if (null == objectInfos || null == objList)
+            return;
+
+        // Fill object information for all children in result list
+        for (ObjectInFolderData object : objList.getObjects()) {
+            fillObjectInfoHolder(context, repositoryId, object.getObject().getId(), objectInfos);
+        }
+    }
+
+    /**
+     * fill an ObjectInfoHolder object with required information needed for Atom binding 
+     * to be able to generate the necessary links in AtomPub
+     * 
+     * @param context
+     *          call context of the current request
+     * @param repositoryId
+     *          id of repository 
+     * @param objList
+     *          object list, fill information for each element
+     * @param objectInfos
+     *          Holder to fill with information
+     */
+    public void fillObjectInfoHolderObjectParentData(
+        CallContext context,
+        String repositoryId,
+        List<ObjectParentData> objParents,
+        ObjectInfoHolder objectInfos)
+    {
+        if (null == objectInfos || null == objParents)
+            return;
+
+        for (ObjectParentData object : objParents) {
+            fillObjectInfoHolder(context, repositoryId, object.getObject().getId(), objectInfos);
+        }        
+    }
+        
+    /**
+     * fill an ObjectInfoHolder object with required information needed for Atom binding 
+     * to be able to generate the necessary links in AtomPub
+     * 
+     * @param context
+     *          call context of the current request
+     * @param repositoryId
+     *          id of repository 
+     * @param objList
+     *          object list, fill information for each element recursively
+     * @param objectInfos
+     *          Holder to fill with information
+     */
+    public void fillObjectInfoHolderFolderContainer(
+        CallContext context,
+        String repositoryId,
+        List<ObjectInFolderContainer> oifcList,
+        ObjectInfoHolder objectInfos)
+    {
+        if (null == objectInfos || null == oifcList)
+            return;
+
+          
+        for (ObjectInFolderContainer object : oifcList) {
+            fillObjectInfoHolderFolderContainer(context, repositoryId, object, objectInfos);
+        }    
+    }
+    
+    private void fillObjectInfoHolderFolderContainer(
+        CallContext context,
+        String repositoryId,
+        ObjectInFolderContainer oifc,
+        ObjectInfoHolder objectInfos)
+    {
+        if (null == objectInfos || null == oifc)
+            return;
+
+        fillObjectInfoHolder(context, repositoryId, oifc.getObject().getObject(), objectInfos);
+
+        if (null!=oifc.getChildren())
+            for (ObjectInFolderContainer object : oifc.getChildren()) {
+                // call recursively
+                fillObjectInfoHolderFolderContainer(context, repositoryId, object, objectInfos);
+            }    
+    }
+
+    private Boolean getBooleanProperty(Map<String, PropertyData<?>> props, String key) {
+        PropertyData<?> pdVal = props.get(key);
+        Boolean val = null==pdVal ? null : (Boolean) pdVal.getFirstValue();
+        return val;
+    }
+
+    private String getStringProperty(Map<String, PropertyData<?>> props, String key) {
+        PropertyData<?> pdVal = props.get(key);
+        String val = null==pdVal ? null : (String) pdVal.getFirstValue();
+        return val;
+    }
+    
+    private GregorianCalendar getDateProperty(Map<String, PropertyData<?>> props, String key) {
+        PropertyData<?> pdVal = props.get(key);
+        GregorianCalendar val = null==pdVal ? null : (GregorianCalendar) pdVal.getFirstValue();
+        return val;
+    }
+
+    private BigInteger getIntegerProperty(Map<String, PropertyData<?>> props, String key) {
+        PropertyData<?> pdVal = props.get(key);
+        BigInteger val = null==pdVal ? null : (BigInteger) pdVal.getFirstValue();
+        return val;
+    }
+
+    private ObjectData getObject(CallContext context, String repositoryId, String objectId) {
+        
+        ObjectData od = _objSvc.getObject(context, repositoryId, objectId, null, false, 
+            IncludeRelationships.BOTH, "*", true, true, null, null);
+        return od;
+    }
+
+    private List<RenditionInfo> convertRenditions(List<RenditionData> renditions) {
+        
+        if (null==renditions)
+            return null;
+        
+        List<RenditionInfo> rendInfos = new ArrayList<RenditionInfo>(renditions.size());
+        RenditionInfosImpl ri = new RenditionInfosImpl();
+        for (RenditionData rd : renditions) {
+            ri.setContentType(rd.getMimeType());
+            ri.setId(rd.getStreamId());
+            ri.setKind(rd.getKind());
+            ri.setLength(rd.getLength());
+            ri.setTitle(rd.getTitle());
+            rendInfos.add(ri);            
+        }
+        return rendInfos;
+    }
+    
+    private void getRelationshipIds(ObjectData objData, List<String> sourceIds, List<String> targetIds) {
+        if (null==objData || null == objData.getRelationships())
+            return;
+        
+        String objectId = objData.getId();
+        for (ObjectData rel : objData.getRelationships()) {
+            String relId = getStringProperty(rel.getProperties().getProperties(), PropertyIds.CMIS_OBJECT_ID);
+            String sourceId = getStringProperty(rel.getProperties().getProperties(), PropertyIds.CMIS_SOURCE_ID);
+            String targetId = getStringProperty(rel.getProperties().getProperties(), PropertyIds.CMIS_TARGET_ID);
+            if (objectId.equals(sourceId))
+                sourceIds.add(relId);
+            if (objectId.equals(targetId))
+                targetIds.add(relId);
+        }
+    }
+
+    private boolean documentHasParent(CallContext context, String repositoryId, String objectId)
+    {
+        List<ObjectParentData> opd = _navSvc.getObjectParents(context, repositoryId, objectId, null, false, IncludeRelationships.NONE, 
+            null, false, null, null);
+
+        return opd!= null && opd.size()>0;
+    }
+
+}
+