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/01 18:20:17 UTC

svn commit: r917600 [2/3] - in /incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src: main/java/org/apache/opencmis/inmemory/ main/java/org/apache/opencmis/inmemory/clientprovider/ main/java/org/apache/opencmis/inmemory/serve...

Added: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryNavigationServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryNavigationServiceImpl.java?rev=917600&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryNavigationServiceImpl.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryNavigationServiceImpl.java Mon Mar  1 17:20:16 2010
@@ -0,0 +1,416 @@
+/*
+ * 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.inmemory.server;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.opencmis.commons.PropertyIds;
+import org.apache.opencmis.commons.api.ExtensionsData;
+import org.apache.opencmis.commons.enums.IncludeRelationships;
+import org.apache.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.opencmis.commons.impl.dataobjects.ObjectDataImpl;
+import org.apache.opencmis.commons.impl.dataobjects.ObjectInFolderContainerImpl;
+import org.apache.opencmis.commons.impl.dataobjects.ObjectInFolderDataImpl;
+import org.apache.opencmis.commons.impl.dataobjects.ObjectInFolderListImpl;
+import org.apache.opencmis.commons.impl.dataobjects.ObjectListImpl;
+import org.apache.opencmis.commons.impl.dataobjects.ObjectParentDataImpl;
+import org.apache.opencmis.commons.provider.AllowableActionsData;
+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.PropertiesData;
+import org.apache.opencmis.inmemory.DataObjectCreator;
+import org.apache.opencmis.inmemory.FilterParser;
+import org.apache.opencmis.inmemory.storedobj.api.Children;
+import org.apache.opencmis.inmemory.storedobj.api.DocumentVersion;
+import org.apache.opencmis.inmemory.storedobj.api.Filing;
+import org.apache.opencmis.inmemory.storedobj.api.Folder;
+import org.apache.opencmis.inmemory.storedobj.api.MultiFiling;
+import org.apache.opencmis.inmemory.storedobj.api.ObjectStore;
+import org.apache.opencmis.inmemory.storedobj.api.SingleFiling;
+import org.apache.opencmis.inmemory.storedobj.api.StoreManager;
+import org.apache.opencmis.inmemory.storedobj.api.StoredObject;
+import org.apache.opencmis.inmemory.storedobj.api.VersionedDocument;
+import org.apache.opencmis.inmemory.types.PropertyCreationHelper;
+import org.apache.opencmis.server.spi.CallContext;
+import org.apache.opencmis.server.spi.CmisNavigationService;
+import org.apache.opencmis.server.spi.ObjectInfoHolder;
+
+public class InMemoryNavigationServiceImpl extends AbstractServiceImpl implements
+    CmisNavigationService {
+
+  private static Log LOG = LogFactory.getLog(InMemoryNavigationServiceImpl.class);
+
+  AtomLinkInfoProvider fAtomLinkProvider;
+
+  public InMemoryNavigationServiceImpl(StoreManager storeManager) {
+    super(storeManager);
+    fAtomLinkProvider = new AtomLinkInfoProvider(fStoreManager);
+  }
+
+  public ObjectList getCheckedOutDocs(CallContext context, String repositoryId, String folderId,
+      String filter, String orderBy, Boolean includeAllowableActions,
+      IncludeRelationships includeRelationships, String renditionFilter, BigInteger maxItems,
+      BigInteger skipCount, ExtensionsData extension, ObjectInfoHolder objectInfos) {
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    ObjectListImpl res = new ObjectListImpl();
+    List<ObjectData> odList = new ArrayList<ObjectData>();
+
+    LOG.debug("start getCheckedOutDocs()");
+    if (null != folderId)
+      checkStandardParameters(repositoryId, folderId);
+    else
+      checkRepositoryId(repositoryId);
+
+    if (null == folderId) {
+      List<VersionedDocument> checkedOuts = fStoreManager.getObjectStore(repositoryId)
+          .getCheckedOutDocuments(orderBy);
+      for (VersionedDocument checkedOut : checkedOuts) {
+        ObjectData od = PropertyCreationHelper
+            .getObjectData(fStoreManager, checkedOut, filter, includeAllowableActions,
+                includeRelationships, renditionFilter, false, false, extension);
+        fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, checkedOut, objectInfos);
+        odList.add(od);
+      }
+    }
+    else {
+      ObjectInFolderList children = getChildrenIntern(repositoryId, folderId, filter, orderBy,
+          includeAllowableActions, includeRelationships, renditionFilter, false, -1, -1, false,
+          objectInfos);
+      for (ObjectInFolderData child : children.getObjects()) {
+        ObjectData obj = child.getObject();
+        StoredObject so = fStoreManager.getObjectStore(repositoryId).getObjectById(obj.getId());
+        LOG.info("Checked out: children:" + obj.getId());
+        if (so instanceof DocumentVersion
+            && ((DocumentVersion) so).getParentDocument().isCheckedOut()) {
+          odList.add(obj);
+          fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+        }
+      }
+    }
+    res.setObjects(odList);
+    res.setNumItems(BigInteger.valueOf(odList.size()));
+
+    LOG.debug("end getCheckedOutDocs()");
+    return res;
+  }
+
+  public ObjectInFolderList getChildren(CallContext context, String repositoryId, String folderId,
+      String filter, String orderBy, Boolean includeAllowableActions,
+      IncludeRelationships includeRelationships, String renditionFilter,
+      Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount,
+      ExtensionsData extension, ObjectInfoHolder objectInfos) {
+
+    LOG.debug("start getChildren()");
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    checkStandardParameters(repositoryId, folderId);
+
+    int maxItemsInt = maxItems == null ? -1 : maxItems.intValue();
+    int skipCountInt = skipCount == null ? -1 : skipCount.intValue();
+    ObjectInFolderList res = getChildrenIntern(repositoryId, folderId, filter, orderBy,
+        includeAllowableActions, includeRelationships, renditionFilter, includePathSegment,
+        maxItemsInt, skipCountInt, false, objectInfos);
+    LOG.debug("stop getChildren()");
+    return res;
+  }
+
+  public List<ObjectInFolderContainer> getDescendants(CallContext context, String repositoryId,
+      String folderId, BigInteger depth, String filter, Boolean includeAllowableActions,
+      IncludeRelationships includeRelationships, String renditionFilter,
+      Boolean includePathSegment, ExtensionsData extension, ObjectInfoHolder objectInfos) {
+
+    LOG.debug("start getDescendants()");
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    checkStandardParameters(repositoryId, folderId);
+
+    int levels;
+    if (depth == null)
+      levels = 2; // one of the recommended defaults (should it be -1?)
+    else if (depth.intValue() == 0)
+      throw new CmisInvalidArgumentException("A zero depth is not allowed for getDescendants().");
+    else
+      levels = depth.intValue();
+
+    int level = 0;
+    List<ObjectInFolderContainer> result = getDescendantsIntern(repositoryId, folderId, filter,
+        includeAllowableActions, includeRelationships, renditionFilter, includePathSegment, level,
+        levels, false, objectInfos);
+
+    LOG.debug("stop getDescendants()");
+    return result;
+  }
+
+  public ObjectData getFolderParent(CallContext context, String repositoryId, String folderId,
+      String filter, ExtensionsData extension, ObjectInfoHolder objectInfos) {
+
+    LOG.debug("start getFolderParent()");
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = checkStandardParameters(repositoryId, folderId);
+
+    Folder folder = null;
+    if (so instanceof Folder)
+      folder = (Folder) so;
+    else
+      throw new CmisInvalidArgumentException(
+          "Can't get folder parent, id does not refer to a folder: " + folderId);
+
+    ObjectData res = getFolderParentIntern(repositoryId, folder, filter, objectInfos);
+
+    // To be able to provide all Atom links in the response we need additional information:
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+
+    LOG.debug("stop getFolderParent()");
+    return res;
+  }
+
+  public List<ObjectInFolderContainer> getFolderTree(CallContext context, String repositoryId,
+      String folderId, BigInteger depth, String filter, Boolean includeAllowableActions,
+      IncludeRelationships includeRelationships, String renditionFilter,
+      Boolean includePathSegment, ExtensionsData extension, ObjectInfoHolder objectInfos) {
+
+    LOG.debug("start getFolderTree()");
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    checkStandardParameters(repositoryId, folderId);
+
+    if (depth != null && depth.intValue() == 0)
+      throw new CmisInvalidArgumentException("A zero depth is not allowed for getFolderTree().");
+
+    int levels = depth == null ? 2 : depth.intValue();
+    int level = 0;
+    List<ObjectInFolderContainer> result = getDescendantsIntern(repositoryId, folderId, filter,
+        includeAllowableActions, includeRelationships, renditionFilter, includePathSegment, level,
+        levels, true, objectInfos);
+
+    LOG.debug("stop getFolderTree()");
+    return result;
+  }
+
+  public List<ObjectParentData> getObjectParents(CallContext context, String repositoryId,
+      String objectId, String filter, Boolean includeAllowableActions,
+      IncludeRelationships includeRelationships, String renditionFilter,
+      Boolean includeRelativePathSegment, ExtensionsData extension, ObjectInfoHolder objectInfos) {
+    
+    LOG.debug("start getObjectParents()");
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = checkStandardParameters(repositoryId, objectId);
+
+    // for now we have only folders that have a parent and the in-memory provider only has one
+    // parent for each object (no multi-filing)
+    List<ObjectParentData> result = null;
+
+    Filing spo = null;
+    if (so instanceof Filing)
+      spo = (Filing) so;
+    else
+      throw new CmisInvalidArgumentException(
+          "Can't get object parent, id does not refer to a folder or document: " + objectId);
+
+    result = getObjectParentsIntern(repositoryId, spo, filter, objectInfos);
+
+    // To be able to provide all Atom links in the response we need additional information:
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+
+
+    LOG.debug("stop getObjectParents()");
+    return result;
+  }
+
+  // private helpers
+
+  private ObjectInFolderList getChildrenIntern(String repositoryId, String folderId, String filter,
+      String orderBy, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
+      String renditionFilter, Boolean includePathSegments, int maxItems, int skipCount,
+      boolean folderOnly, ObjectInfoHolder objectInfos) {
+
+    ObjectInFolderListImpl result = new ObjectInFolderListImpl();
+    List<ObjectInFolderData> folderList = new ArrayList<ObjectInFolderData>();
+    ObjectStore fs = fStoreManager.getObjectStore(repositoryId);
+    StoredObject so = fs.getObjectById(folderId);
+    Folder folder = null;
+
+    if (so == null)
+      throw new CmisObjectNotFoundException("Unknown object id: " + folderId);
+
+    if (so instanceof Folder)
+      folder = (Folder) so;
+    else
+      return null; // it is a document and has no children
+
+    List<? extends StoredObject> children = folderOnly ? folder.getFolderChildren(maxItems,
+        skipCount) : folder.getChildren(maxItems, skipCount);
+
+    List<String> requestedIds = FilterParser.getRequestedIdsFromFilter(filter);
+
+    for (StoredObject spo : children) {
+      ObjectInFolderDataImpl oifd = new ObjectInFolderDataImpl();
+      ObjectDataImpl objectData = new ObjectDataImpl();
+      if (includePathSegments != null && includePathSegments)
+        oifd.setPathSegment(spo.getName());
+      if (includeAllowableActions != null && includeAllowableActions) {
+        AllowableActionsData allowableActions = DataObjectCreator.fillAllowableActions(fs, spo);
+        objectData.setAllowableActions(allowableActions);
+      }
+      if (includeRelationships != null && includeRelationships != IncludeRelationships.NONE) {
+        objectData.setRelationships(null /* f.getRelationships() */);
+      }
+      if (renditionFilter != null && renditionFilter.length() > 0) {
+        objectData.setRelationships(null /* f.getRenditions(renditionFilter) */);
+      }
+
+      PropertiesData props = PropertyCreationHelper.getPropertiesFromObject(repositoryId, spo,
+          fStoreManager, requestedIds);
+      objectData.setProperties(props);
+
+      oifd.setObject(objectData);
+      folderList.add(oifd);
+      // add additional information for Atom
+      fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, spo, objectInfos);
+
+    }
+    result.setObjects(folderList);
+    return result;
+  }
+
+  private List<ObjectInFolderContainer> getDescendantsIntern(String repositoryId, String folderId,
+      String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
+      String renditionFilter, Boolean includePathSegments, int level, int maxLevels,
+      boolean folderOnly, ObjectInfoHolder objectInfos) {
+
+    // log.info("getDescendantsIntern: " + folderId + ", in level " + level
+    // + ", max levels " + maxLevels);
+
+    List<ObjectInFolderContainer> childrenOfFolderId = null;
+    if (maxLevels == -1 || level < maxLevels) {
+      String orderBy = PropertyIds.CMIS_NAME;
+      ObjectInFolderList children = getChildrenIntern(repositoryId, folderId, filter, orderBy,
+          includeAllowableActions, includeRelationships, renditionFilter, includePathSegments,
+          1000, 0, folderOnly, objectInfos);
+
+      childrenOfFolderId = new ArrayList<ObjectInFolderContainer>();
+      if (null != children) {
+
+        for (ObjectInFolderData child : children.getObjects()) {
+          ObjectInFolderContainerImpl oifc = new ObjectInFolderContainerImpl();
+          String childId = child.getObject().getId();
+          List<ObjectInFolderContainer> subChildren = getDescendantsIntern(repositoryId, childId,
+              filter, includeAllowableActions, includeRelationships, renditionFilter,
+              includePathSegments, level + 1, maxLevels, folderOnly, objectInfos);
+
+          oifc.setObject(child);
+          if (null != subChildren)
+            oifc.setChildren(subChildren);
+          childrenOfFolderId.add(oifc);
+        }
+      }
+    }
+    return childrenOfFolderId;
+  }
+
+  private List<ObjectParentData> getObjectParentsIntern(String repositoryId, Filing sop,
+      String filter, ObjectInfoHolder objectInfos) {
+
+    List<ObjectParentData> result = null;
+    if (sop instanceof SingleFiling) {
+      ObjectData parent = getFolderParentIntern(repositoryId, (SingleFiling) sop, filter, objectInfos);
+      if (null != parent) {
+        ObjectParentDataImpl parentData = new ObjectParentDataImpl();
+        parentData.setObject(parent);
+        String path = ((SingleFiling) sop).getPath();
+        int beginIndex = path.lastIndexOf(Filing.PATH_SEPARATOR) + 1; // Note: if / not found
+                                                                      // results in 0
+        String relPathSeg = path.substring(beginIndex, path.length());
+        parentData.setRelativePathSegment(relPathSeg);
+        result = Collections.singletonList((ObjectParentData) parentData);
+      }
+      else
+        result = Collections.emptyList();
+    }
+    else if (sop instanceof MultiFiling) {
+      result = new ArrayList<ObjectParentData>();
+      MultiFiling multiParentObj = (MultiFiling) sop;
+      List<Folder> parents = multiParentObj.getParents();
+      if (null != parents)
+        for (Folder parent : parents) {
+          ObjectParentDataImpl parentData = new ObjectParentDataImpl();
+          ObjectDataImpl objData = new ObjectDataImpl();
+          copyFilteredProperties(repositoryId, parent, filter, objData);
+          parentData.setObject(objData);
+          parentData.setRelativePathSegment(multiParentObj.getPathSegment());
+          result.add(parentData);
+          fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, parent, objectInfos);
+        }
+    }
+    return result;
+  }
+
+  private ObjectData getFolderParentIntern(String repositoryId, SingleFiling sop, String filter, ObjectInfoHolder objectInfos) {
+
+    ObjectDataImpl parent = new ObjectDataImpl();
+
+    Folder parentFolder = sop.getParent();
+
+    if (null == parentFolder) {
+      if (sop instanceof Children) // a folder without a parent
+        throw new CmisInvalidArgumentException("Cannot get parent of a root folder");
+      else
+        return null; // an unfiled document
+    }
+
+    copyFilteredProperties(repositoryId, parentFolder, filter, parent);
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, parentFolder, objectInfos);
+
+    return parent;
+  }
+
+  void copyFilteredProperties(String repositoryId, StoredObject so, String filter,
+      ObjectDataImpl objData) {
+    List<String> requestedIds = FilterParser.getRequestedIdsFromFilter(filter);
+    PropertiesData props = PropertyCreationHelper.getPropertiesFromObject(repositoryId, so,
+        fStoreManager, requestedIds);
+    objData.setProperties(props);
+  }
+
+}

Added: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryObjectServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryObjectServiceImpl.java?rev=917600&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryObjectServiceImpl.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryObjectServiceImpl.java Mon Mar  1 17:20:16 2010
@@ -0,0 +1,884 @@
+/*
+ * 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.inmemory.server;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.opencmis.commons.PropertyIds;
+import org.apache.opencmis.commons.api.DocumentTypeDefinition;
+import org.apache.opencmis.commons.api.ExtensionsData;
+import org.apache.opencmis.commons.api.PropertyDefinition;
+import org.apache.opencmis.commons.api.TypeDefinition;
+import org.apache.opencmis.commons.api.TypeDefinitionContainer;
+import org.apache.opencmis.commons.enums.BaseObjectTypeIds;
+import org.apache.opencmis.commons.enums.IncludeRelationships;
+import org.apache.opencmis.commons.enums.UnfileObjects;
+import org.apache.opencmis.commons.enums.Updatability;
+import org.apache.opencmis.commons.enums.VersioningState;
+import org.apache.opencmis.commons.exceptions.CmisConstraintException;
+import org.apache.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.opencmis.commons.exceptions.CmisNotSupportedException;
+import org.apache.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.opencmis.commons.exceptions.CmisUpdateConflictException;
+import org.apache.opencmis.commons.impl.dataobjects.FailedToDeleteDataImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertiesDataImpl;
+import org.apache.opencmis.commons.provider.AccessControlList;
+import org.apache.opencmis.commons.provider.AllowableActionsData;
+import org.apache.opencmis.commons.provider.ContentStreamData;
+import org.apache.opencmis.commons.provider.FailedToDeleteData;
+import org.apache.opencmis.commons.provider.Holder;
+import org.apache.opencmis.commons.provider.ObjectData;
+import org.apache.opencmis.commons.provider.PropertiesData;
+import org.apache.opencmis.commons.provider.PropertyData;
+import org.apache.opencmis.commons.provider.RenditionData;
+import org.apache.opencmis.inmemory.DataObjectCreator;
+import org.apache.opencmis.inmemory.FilterParser;
+import org.apache.opencmis.inmemory.TypeValidator;
+import org.apache.opencmis.inmemory.storedobj.api.Content;
+import org.apache.opencmis.inmemory.storedobj.api.Document;
+import org.apache.opencmis.inmemory.storedobj.api.DocumentVersion;
+import org.apache.opencmis.inmemory.storedobj.api.Filing;
+import org.apache.opencmis.inmemory.storedobj.api.Folder;
+import org.apache.opencmis.inmemory.storedobj.api.ObjectStore;
+import org.apache.opencmis.inmemory.storedobj.api.StoreManager;
+import org.apache.opencmis.inmemory.storedobj.api.StoredObject;
+import org.apache.opencmis.inmemory.storedobj.api.VersionedDocument;
+import org.apache.opencmis.inmemory.types.InMemoryDocumentTypeDefinition;
+import org.apache.opencmis.inmemory.types.InMemoryFolderTypeDefinition;
+import org.apache.opencmis.inmemory.types.InMemoryPolicyTypeDefinition;
+import org.apache.opencmis.inmemory.types.InMemoryRelationshipTypeDefinition;
+import org.apache.opencmis.inmemory.types.PropertyCreationHelper;
+import org.apache.opencmis.server.spi.CallContext;
+import org.apache.opencmis.server.spi.CmisObjectService;
+import org.apache.opencmis.server.spi.ObjectInfoHolder;
+
+public class InMemoryObjectServiceImpl extends AbstractServiceImpl implements CmisObjectService {
+  private static final Log LOG = LogFactory.getLog(ServiceFactory.class.getName());
+
+  AtomLinkInfoProvider fAtomLinkProvider;
+
+  public InMemoryObjectServiceImpl(StoreManager storeManager) {
+    super(storeManager);
+    fAtomLinkProvider = new AtomLinkInfoProvider(fStoreManager);
+  }
+  
+  public String createDocument(CallContext context, String repositoryId, PropertiesData properties,
+      String folderId, ContentStreamData contentStream, VersioningState versioningState,
+      List<String> policies, AccessControlList addAces, AccessControlList removeAces,
+      ExtensionsData extension) {
+
+    LOG.debug("start createDocument()");
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = createDocumentIntern(repositoryId, properties, folderId, contentStream,
+        versioningState, policies, addAces, removeAces, extension);
+    LOG.debug("stop createDocument()");
+
+    return so.getId();
+  }
+
+  public String createDocumentFromSource(CallContext context, String repositoryId, String sourceId,
+      PropertiesData properties, String folderId, VersioningState versioningState,
+      List<String> policies, AccessControlList addAces, AccessControlList removeAces,
+      ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start createDocumentFromSource()");
+
+    StoredObject so = checkStandardParameters(repositoryId, sourceId);
+
+    ContentStreamData content = getContentStream(context, repositoryId, sourceId, null, BigInteger
+        .valueOf(-1), BigInteger.valueOf(-1), null);
+
+    if (so == null)
+      throw new CmisObjectNotFoundException("Unknown object id: " + sourceId);
+
+    // build properties collection
+    List<String> requestedIds = FilterParser.getRequestedIdsFromFilter("*");
+
+    PropertiesData existingProps = PropertyCreationHelper.getPropertiesFromObject(repositoryId, so,
+        fStoreManager, requestedIds);
+
+    PropertiesDataImpl newPD = new PropertiesDataImpl();
+    // copy all existing properties
+    for (PropertyData<?> prop : existingProps.getProperties().values()) {
+      newPD.addProperty(prop);
+    }
+    // overwrite all new properties
+    for (PropertyData<?> prop : properties.getProperties().values()) {
+      newPD.addProperty(prop);
+    }
+
+    String res = createDocument(context, repositoryId, newPD, folderId, content, versioningState, policies,
+        addAces, removeAces, null);
+    LOG.debug("stop createDocumentFromSource()");
+    return res;
+  }
+
+  public String createFolder(CallContext context, String repositoryId, PropertiesData properties,
+      String folderId, List<String> policies, AccessControlList addAces,
+      AccessControlList removeAces, ExtensionsData extension) {
+    LOG.debug("start createFolder()");
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+    
+    Folder folder = createFolderIntern(repositoryId, properties, folderId, policies,
+        addAces, removeAces, extension);
+    LOG.debug("stop createFolder()");
+    return folder.getId();
+  }
+
+  public String createPolicy(CallContext context, String repositoryId, PropertiesData properties,
+      String folderId, List<String> policies, AccessControlList addAces,
+      AccessControlList removeAces, ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    // TODO to be completed if ACLs are implemented
+    LOG.debug("start createPolicy()");
+    checkStandardParameters(repositoryId, folderId);
+    StoredObject so = createPolicyIntern(repositoryId, properties, folderId, policies, addAces, removeAces, extension);
+    LOG.debug("stop createPolicy()");
+    return so==null ? null : so.getId();
+  }
+  
+  public String createRelationship(CallContext context, String repositoryId,
+      PropertiesData properties, List<String> policies, AccessControlList addAces,
+      AccessControlList removeAces, ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    // TODO to be completed if relationships are implemented
+    LOG.debug("start createRelationship()");
+    checkRepositoryId(repositoryId);
+    StoredObject so = createRelationshipIntern(repositoryId, properties, policies,
+        addAces, removeAces, extension);
+    LOG.debug("stop createRelationship()");
+    return so==null ? null : so.getId();
+  }
+
+  /* (non-Javadoc)
+   * @see org.opencmis.server.spi.CmisObjectService#create(org.opencmis.server.spi.CallContext, java.lang.String, org.opencmis.client.provider.PropertiesData, java.lang.String, org.opencmis.client.provider.ContentStreamData, org.opencmis.commons.enums.VersioningState, org.opencmis.client.provider.ExtensionsData, org.opencmis.server.spi.ObjectInfoHolder)
+   * 
+   * An additional create call compared to the ObjectService from the CMIS spec.
+   * This one is needed because the Atom binding in the server implementation does 
+   * not know what kind of object needs to be created. Also the ObjectInfoHolder needs
+   * to be filled.
+   * 
+   */
+  @SuppressWarnings("unchecked")
+  public ObjectData create(CallContext context, String repositoryId, PropertiesData properties,
+      String folderId, ContentStreamData contentStream, VersioningState versioningState, List<String> policies,
+      ExtensionsData extension, ObjectInfoHolder objectInfos) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+    
+    if (null==properties || null==properties.getProperties())
+        throw new RuntimeException("Cannot create object, without properties.");
+
+    // Find out what kind of object needs to be created
+    PropertyData<String> pd = (PropertyData<String>) properties.getProperties().get(PropertyIds.CMIS_OBJECT_TYPE_ID);
+    String typeId = pd==null ? null : pd.getFirstValue(); 
+    if (null==typeId)
+      throw new RuntimeException("Cannot create object, without a type (no property with id CMIS_OBJECT_TYPE_ID).");
+    
+    TypeDefinitionContainer typeDefC = fStoreManager.getTypeById(repositoryId, typeId);
+    if (typeDefC == null)
+      throw new RuntimeException("Cannot create object, a type with id " + typeId + " is unknown");
+
+    // check if the given type is a document type
+    BaseObjectTypeIds typeBaseId = typeDefC.getTypeDefinition().getBaseId();
+    StoredObject so= null;
+    if (typeBaseId.equals(InMemoryDocumentTypeDefinition.getRootDocumentType().getBaseId())) {
+      so = createDocumentIntern(repositoryId, properties, folderId, contentStream, versioningState, 
+          null, null, null, null);
+    } else if (typeBaseId.equals(InMemoryFolderTypeDefinition.getRootFolderType().getBaseId())) {
+      so = createFolderIntern(repositoryId, properties, folderId, null, null, null, null);
+    } else if (typeBaseId.equals(InMemoryPolicyTypeDefinition.getRootPolicyType().getBaseId())) {
+      so = createPolicyIntern(repositoryId, properties, folderId, null, null, null, null);
+    } else if (typeBaseId.equals(InMemoryRelationshipTypeDefinition.getRootRelationshipType().getBaseId())) {
+      so = createRelationshipIntern(repositoryId, properties,  null, null, null, null);
+    } else
+      LOG.error("The type contains an unknown base object id, object can't be created");
+
+    // Make a call to getObject to convert the resulting id into an ObjectData
+    ObjectData od = PropertyCreationHelper.getObjectData(fStoreManager, so, null, false,
+        IncludeRelationships.NONE, null, false, false, extension);    
+    
+    return od;
+  }
+  
+  public void deleteContentStream(CallContext context, String repositoryId,
+      Holder<String> objectId, Holder<String> changeToken, ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start deleteContentStream()");
+    StoredObject so = checkStandardParameters(repositoryId, objectId.getValue());
+    
+    if (so == null)
+      throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
+
+    if (!(so instanceof Content))
+      throw new CmisObjectNotFoundException("Id" + objectId
+          + " does not refer to a document, but only documents can have content");
+
+    ((Content) so).setContent(null, true);
+    LOG.debug("stop deleteContentStream()");
+  }
+
+  public void deleteObjectOrCancelCheckOut(CallContext context, String repositoryId, String objectId,
+      Boolean allVersions, ExtensionsData extension) {
+
+    LOG.debug("start deleteObject()");
+    checkStandardParameters(repositoryId, objectId);
+    ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
+    LOG.info("delete object for id: " + objectId);
+
+    // check if it is the root folder
+    if (objectId.equals(objectStore.getRootFolder().getId()))
+      throw new CmisNotSupportedException("You can't delete a root folder");
+
+    objectStore.deleteObject(objectId);
+    LOG.debug("stop deleteObject()");
+  }
+
+  public FailedToDeleteData deleteTree(CallContext context, String repositoryId, String folderId,
+      Boolean allVersions, UnfileObjects unfileObjects, Boolean continueOnFailure,
+      ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start deleteTree()");
+    StoredObject so = checkStandardParameters(repositoryId, folderId);
+    List<String> failedToDeleteIds = new ArrayList<String>();
+    FailedToDeleteDataImpl result = new FailedToDeleteDataImpl();
+
+    if (null == allVersions)
+      allVersions = true;
+    if (null == unfileObjects)
+      unfileObjects = UnfileObjects.DELETE;
+    if (null == continueOnFailure)
+      continueOnFailure = false;
+    
+    ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
+
+    if (null == so)
+      throw new RuntimeException("Cannot delete object with id  " + folderId
+          + ". Object does not exist.");
+
+    if (!(so instanceof Folder))
+      throw new RuntimeException("deleteTree can only be invoked on a folder, but id " + folderId
+          + " does not refer to a folder");
+
+    if (unfileObjects == UnfileObjects.UNFILE)
+      throw new CmisNotSupportedException("This repository does not support unfile operations.");
+
+    // check if it is the root folder
+    if (folderId.equals(objectStore.getRootFolder().getId()))
+      throw new CmisNotSupportedException("You can't delete a root folder");
+
+    // recursively delete folder
+    deleteRecursive(objectStore, (Folder) so, continueOnFailure, allVersions, failedToDeleteIds);
+
+    result.setIds(failedToDeleteIds);
+    LOG.debug("stop deleteTree()");
+    return result;
+  }
+
+  public AllowableActionsData getAllowableActions(CallContext context, String repositoryId,
+      String objectId, ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start getAllowableActions()");
+    StoredObject so = checkStandardParameters(repositoryId, objectId);
+    ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
+
+    if (so == null)
+      throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
+
+    AllowableActionsData allowableActions = DataObjectCreator.fillAllowableActions(objectStore, so);
+    LOG.debug("stop getAllowableActions()");
+    return allowableActions;
+ }
+
+  public ContentStreamData getContentStream(CallContext context, String repositoryId,
+      String objectId, String streamId, BigInteger offset, BigInteger length,
+      ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start getContentStream()");
+    StoredObject so = checkStandardParameters(repositoryId, objectId);
+
+    if (so == null)
+      throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
+
+    if (!(so instanceof Content))
+      throw new CmisObjectNotFoundException("Id" + objectId
+          + " does not refer to a document or version, but only those can have content");
+
+    ContentStreamData csd = getContentStream(so, streamId, offset, length);
+    LOG.debug("stop getContentStream()");
+    return csd;
+ }
+
+  public ObjectData getObject(CallContext context, String repositoryId, String objectId,
+      String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
+      String renditionFilter, Boolean includePolicyIds, Boolean includeAcl,
+      ExtensionsData extension, ObjectInfoHolder objectInfos) {
+
+    LOG.debug("start getObject()");
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = checkStandardParameters(repositoryId, objectId);
+
+    if (so == null)
+      throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
+
+    ObjectData od = PropertyCreationHelper.getObjectData(fStoreManager, so, filter,
+        includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds,
+        includeAcl, extension);
+    
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+    
+    LOG.debug("stop getObject()");
+ 
+   return od;
+ }
+
+  public ObjectData getObjectByPath(CallContext context, String repositoryId, String path,
+      String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
+      String renditionFilter, Boolean includePolicyIds, Boolean includeAcl,
+      ExtensionsData extension, ObjectInfoHolder objectInfos) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start getObjectByPath()");
+    checkRepositoryId(repositoryId);
+    ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
+    StoredObject so = objectStore.getObjectByPath(path);
+
+    if (so == null)
+      throw new CmisObjectNotFoundException("Unknown path: " + path);
+
+    ObjectData od = PropertyCreationHelper.getObjectData(fStoreManager, so, filter,
+        includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds,
+        includeAcl, extension);
+    
+    LOG.debug("stop getObjectByPath()");
+
+    // To be able to provide all Atom links in the response we need additional information:
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+
+    return od;
+  }
+
+  public PropertiesData getProperties(CallContext context, String repositoryId, String objectId,
+      String filter, ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start getProperties()");
+    StoredObject so = checkStandardParameters(repositoryId, objectId);
+
+    if (so == null)
+      throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
+
+    // build properties collection
+    List<String> requestedIds = FilterParser.getRequestedIdsFromFilter(filter);
+    PropertiesData props = PropertyCreationHelper.getPropertiesFromObject(repositoryId, so,
+        fStoreManager, requestedIds);
+    LOG.debug("stop getProperties()");
+    return props;
+  }
+
+  public List<RenditionData> getRenditions(CallContext context, String repositoryId,
+      String objectId, String renditionFilter, BigInteger maxItems, BigInteger skipCount,
+      ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    // TODO to be completed if renditions are implemented
+    LOG.debug("start getRenditions()");
+    checkStandardParameters(repositoryId, objectId);
+    LOG.debug("stop getRenditions()");
+    return null;
+  }
+
+  public ObjectData moveObject(CallContext context, String repositoryId, Holder<String> objectId,
+      String targetFolderId, String sourceFolderId, ExtensionsData extension,
+      ObjectInfoHolder objectInfos) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start moveObject()");
+    StoredObject so = checkStandardParameters(repositoryId, objectId.getValue());
+    Folder targetFolder = null;
+    Folder sourceFolder = null;
+    ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
+    Filing spo = null;
+
+    if (null == so)
+      throw new CmisObjectNotFoundException("Unknown object: " + objectId.getValue());
+    else if (so instanceof Filing)
+      spo = (Filing) so;
+    else
+      throw new CmisInvalidArgumentException("Object must be folder or document: "
+          + objectId.getValue());
+
+    StoredObject soTarget = objectStore.getObjectById(targetFolderId);
+    if (null == soTarget)
+      throw new CmisObjectNotFoundException("Unknown target folder: " + targetFolderId);
+    else if (soTarget instanceof Folder)
+      targetFolder = (Folder) soTarget;
+    else
+      throw new CmisNotSupportedException("Destination " + targetFolderId + " of a move operation must be a folder");
+
+    StoredObject soSource = objectStore.getObjectById(sourceFolderId);
+    if (null == soSource)
+      throw new CmisObjectNotFoundException("Unknown source folder: " + sourceFolderId);
+    else if (soSource instanceof Folder)
+      sourceFolder = (Folder) soSource;
+    else
+      throw new CmisNotSupportedException("Source " + sourceFolderId + " of a move operation must be a folder");
+
+    boolean foundOldParent = false;
+    for (Folder parent: spo.getParents()) {
+      if (parent.getId().equals(soSource.getId())) {
+        foundOldParent = true;
+        break;
+      }
+    }
+    if (!foundOldParent)
+      throw new CmisNotSupportedException("Cannot move object, source folder " + sourceFolderId + "is not a parent of object " + objectId.getValue());
+    
+    if (so instanceof Folder && hasDescendant((Folder) so, targetFolder)) {
+      throw new CmisNotSupportedException(
+          "Destination of a move cannot be a subfolder of the source");
+    }
+    
+    spo.move(sourceFolder, targetFolder);
+    objectId.setValue(so.getId());
+    LOG.debug("stop moveObject()");
+
+    // To be able to provide all Atom links in the response we need additional information:
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+  
+    ObjectData od = PropertyCreationHelper.getObjectData(fStoreManager, so, null, false,
+        IncludeRelationships.NONE, null, false, false, extension);
+    
+    return od;
+  }
+
+  public void setContentStream(CallContext context, String repositoryId, Holder<String> objectId,
+      Boolean overwriteFlag, Holder<String> changeToken, ContentStreamData contentStream,
+      ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start setContentStream()");
+    checkStandardParameters(repositoryId, objectId.getValue());
+
+    ObjectStore folderStore = fStoreManager.getObjectStore(repositoryId);
+    StoredObject so = folderStore.getObjectById(objectId.getValue());
+    Content content;
+
+    if (!(so instanceof Document || so instanceof VersionedDocument || so instanceof DocumentVersion))
+      throw new CmisObjectNotFoundException("Id" + objectId
+          + " does not refer to a document, but only documents can have content");
+    
+    if (so instanceof Document) 
+      content = ((Document) so);
+    else if (so instanceof DocumentVersion) {
+      // something that is versionable check the proper status of the object
+      String user = RuntimeContext.getRuntimeConfigValue(CallContext.USERNAME);
+      testHasProperCheckedOutStatus(so, user);
+      content = (DocumentVersion) so;
+    } else
+      throw new IllegalArgumentException("Content cannot be set on this object (must be document or version)");
+
+    if (!overwriteFlag && content.getContent(0, -1) != null)
+      throw new CmisConstraintException(
+          "cannot overwrite existing content if overwrite flag is not set");
+
+    content.setContent(contentStream, true);
+    LOG.debug("stop setContentStream()");
+  }
+
+  public ObjectData updateProperties(CallContext context, String repositoryId, Holder<String> objectId,
+      Holder<String> changeToken, PropertiesData properties, AccessControlList acl, ExtensionsData extension,
+      ObjectInfoHolder objectInfos) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    LOG.debug("start updateProperties()");
+    StoredObject so = checkStandardParameters(repositoryId, objectId.getValue());
+    
+    // Validation
+    TypeDefinition typeDef = getTypeDefinition(repositoryId, so);
+    boolean isCheckedOut = false;
+    
+    // if the object is a versionable object it must be checked-out
+    if (so instanceof VersionedDocument || so instanceof DocumentVersion) {
+      String user = RuntimeContext.getRuntimeConfigValue(CallContext.USERNAME);
+      //VersionedDocument verDoc = testIsNotCheckedOutBySomeoneElse(so, user); 
+      testHasProperCheckedOutStatus(so, user);
+      isCheckedOut = true;
+    }
+
+    Map<String, PropertyData<?>> oldProperties = so.getProperties();
+
+    // check properties for validity
+    TypeValidator.validateProperties(typeDef, properties, false);
+
+    if (changeToken != null && changeToken.getValue() != null
+        && Long.valueOf(so.getChangeToken()) > Long.valueOf(changeToken.getValue()))
+      throw new CmisUpdateConflictException(" updateProperties failed: outdated changeToken");
+
+    // update properties
+    boolean hasUpdatedName = false;
+    boolean hasUpdatedOtherProps = false;
+
+    for (String key : properties.getProperties().keySet()) {
+      if (key.equals(PropertyIds.CMIS_NAME))
+        continue; // ignore here
+
+      PropertyData<?> value = properties.getProperties().get(key);
+      PropertyDefinition<?> propDef = typeDef.getPropertyDefinitions().get(key);
+      if (value.getValues() == null || value.getFirstValue() == null) {
+        // delete property
+        // check if a required a property
+        if (propDef.isRequired())
+          throw new CmisConstraintException(
+              "updateProperties failed, following property can't be deleted, because it is required: "
+                  + key);
+        oldProperties.remove(key);
+        hasUpdatedOtherProps = true;
+      } else {
+        if (propDef.getUpdatability().equals(Updatability.WHENCHECKEDOUT) && !isCheckedOut)
+          throw new CmisConstraintException(
+              "updateProperties failed, following property can't be updated, because it is not checked-out: "
+                  + key);
+        else if (!propDef.getUpdatability().equals(Updatability.READWRITE) )
+          throw new CmisConstraintException(
+              "updateProperties failed, following property can't be updated, because it is not writable: "
+                  + key);
+        oldProperties.put(key, value);
+        hasUpdatedOtherProps = true;
+      }
+    }
+
+    // get name from properties and perform special rename to check if path
+    // already exists
+    PropertyData<?> pd = properties.getProperties().get(PropertyIds.CMIS_NAME);
+    if (pd != null && so instanceof Filing) {
+      String newName = (String) pd.getFirstValue();
+      List<Folder> parents = ((Filing) so).getParents();
+      if (so instanceof Folder && parents.isEmpty())
+        throw new CmisConstraintException(
+            "updateProperties failed, you cannot rename the root folder");
+      for (Folder parent : parents) {
+        if (parent.hasChild(newName))
+          throw new CmisConstraintException(
+              "updateProperties failed, cannot rename because path already exists.");
+      }
+      so.rename((String) pd.getFirstValue()); // note: this does persist
+      hasUpdatedName = true;
+    }
+
+    if (hasUpdatedOtherProps) {
+      // set user, creation date, etc.
+      String user = RuntimeContext.getRuntimeConfigValue(CallContext.USERNAME);
+
+      if (user == null)
+        user = "unknown";
+      so.updateSystemBasePropertiesWhenModified(properties.getProperties(), user);
+      // set changeToken
+      so.persist();
+    }
+
+    if (hasUpdatedName || hasUpdatedOtherProps) {
+      objectId.setValue(so.getId()); // might have a new id
+      if (null != changeToken) {
+        String changeTokenVal = so.getChangeToken();
+        LOG.info("updateProperties(), new change token is: " + changeTokenVal);
+        changeToken.setValue(changeTokenVal);
+      }
+    }
+     
+    if (null != acl) {
+      LOG.warn("Setting ACLs is currently not supported by this implementation, acl is ignored");
+      // if implemented add this call:
+      // fAclService.appyAcl(context, repositoryId, acl, null, AclPropagation.OBJECTONLY, extension);
+    }
+
+    // To be able to provide all Atom links in the response we need additional information:
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+
+    ObjectData od = PropertyCreationHelper.getObjectData(fStoreManager, so, null, false,
+        IncludeRelationships.NONE, null, false, false, extension);
+
+    LOG.debug("stop updateProperties()");
+    
+    return od;
+  }
+  // ///////////////////////////////////////////////////////
+  // private helper methods
+
+  private StoredObject createDocumentIntern(String repositoryId, PropertiesData properties,
+      String folderId, ContentStreamData contentStream, VersioningState versioningState,
+      List<String> policies, AccessControlList addACEs, AccessControlList removeACEs,
+      ExtensionsData extension) {
+    checkRepositoryId(repositoryId);
+
+    ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
+
+    // get name from properties
+    PropertyData<?> pd = properties.getProperties().get(PropertyIds.CMIS_NAME);
+    String name = (String) pd.getFirstValue();
+
+    // Validation stuff
+    TypeValidator.validateRequiredSystemProperties(properties);
+    TypeDefinition typeDef = getTypeDefinition(repositoryId, properties);
+
+    Folder folder = null;
+    if (null != folderId) {
+      StoredObject so = objectStore.getObjectById(folderId);
+
+      if (null == so)
+        throw new CmisInvalidArgumentException(" Cannot create document, folderId: " + folderId
+            + " is invalid");
+
+      if (so instanceof Folder)
+        folder = (Folder) so;
+      else
+        throw new CmisInvalidArgumentException(
+            "Can't creat document, folderId does not refer to a folder: " + folderId);
+
+      TypeValidator.validateAllowedChildObjectTypes(typeDef, folder.getAllowedChildObjectTypeIds());
+    }
+
+    // check if the given type is a document type
+    if (!typeDef.getBaseId().equals(
+        InMemoryDocumentTypeDefinition.getRootDocumentType().getBaseId()))
+      throw new RuntimeException("Cannot create a document, with a non-document type: "
+          + typeDef.getId());
+
+    TypeValidator.validateVersionStateForCreate((DocumentTypeDefinition) typeDef, versioningState);
+    TypeValidator.validateProperties(typeDef, properties, true);
+
+    // set user, creation date, etc.
+    String user = RuntimeContext.getRuntimeConfigValue(CallContext.USERNAME);
+    if (user == null)
+      user = "unknown";
+
+    StoredObject so = null;
+
+    // Now we are sure to have document type definition:
+    if (((DocumentTypeDefinition) typeDef).isVersionable()) {
+      VersionedDocument verDoc = fStoreManager.getObjectStore(repositoryId)
+          .createVersionedDocument(name);
+      verDoc.createSystemBasePropertiesWhenCreated(properties.getProperties(), user);
+      verDoc.setCustomProperties(properties.getProperties());
+      DocumentVersion version = verDoc.addVersion(contentStream, versioningState, user);
+      if (null != folder)
+        folder.addChildDocument(verDoc); // add document to folder and set parent in doc
+      else
+        verDoc.persist();
+      version.createSystemBasePropertiesWhenCreated(properties.getProperties(), user);
+      version.setCustomProperties(properties.getProperties());
+      version.persist();
+      so = version; // return the version and not the version series to caller
+    }
+    else {
+      Document doc = fStoreManager.getObjectStore(repositoryId).createDocument(name);
+      doc.setContent(contentStream, false);
+      // add document to folder
+      doc.createSystemBasePropertiesWhenCreated(properties.getProperties(), user);
+      doc.setCustomProperties(properties.getProperties());
+      if (null != folder)
+        folder.addChildDocument(doc); // add document to folder and set parent in doc
+      else
+        doc.persist();
+      so = doc;
+    }
+
+    // policies, addACEs, removeACEs, extension are ignored for
+    // now.
+    return so;
+  }
+
+  private Folder createFolderIntern(String repositoryId, PropertiesData properties,
+      String folderId, List<String> policies, AccessControlList addAces,
+      AccessControlList removeAces, ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+     checkStandardParameters(repositoryId, folderId);
+
+    ObjectStore fs = fStoreManager.getObjectStore(repositoryId);
+    StoredObject so = null;
+    Folder parent = null;
+
+    // get required properties
+    PropertyData<?> pd = properties.getProperties().get(PropertyIds.CMIS_NAME);
+    String folderName = (String) pd.getFirstValue();
+    if (null == folderName || folderName.length() == 0)
+      throw new CmisInvalidArgumentException("Cannot create a folder without a name.");
+
+    TypeValidator.validateRequiredSystemProperties(properties);
+
+    TypeDefinition typeDef = getTypeDefinition(repositoryId, properties);
+
+        // check if the given type is a folder type
+    if (!typeDef.getBaseId().equals(
+        InMemoryFolderTypeDefinition.getRootFolderType().getBaseId()))
+      throw new RuntimeException("Cannot create a folder, with a non-folder type: " + typeDef.getId());
+
+    TypeValidator.validateProperties(typeDef, properties, true);
+
+    // create folder
+    try {
+      LOG.info("get folder for id: " + folderId);
+      so = fs.getObjectById(folderId);
+    } catch (Exception e) {
+      throw new CmisObjectNotFoundException("Failed to retrieve folder.", e);
+    }
+
+    if (so instanceof Folder)
+      parent = (Folder) so;
+    else
+      throw new CmisInvalidArgumentException(
+          "Can't create folder, folderId does not refer to a folder: " + folderId);
+    try {
+      ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
+      Folder newFolder = objStore.createFolder(folderName);
+      // set default system attributes
+      String user = RuntimeContext.getRuntimeConfigValue(CallContext.USERNAME);
+      if (user == null)
+        user = "unknown";
+      newFolder.createSystemBasePropertiesWhenCreated(properties.getProperties(), user);
+      newFolder.setCustomProperties(properties.getProperties());
+      parent.addChildFolder(newFolder);
+      LOG.debug("stop createFolder()");
+      return newFolder;
+    } catch (Exception e) {
+      throw new CmisInvalidArgumentException("Failed to create child folder.", e);
+    }
+  }
+
+  private StoredObject createPolicyIntern(String repositoryId, PropertiesData properties,
+      String folderId, List<String> policies, AccessControlList addAces,
+      AccessControlList removeAces, ExtensionsData extension) {
+    return null;
+  }
+
+  private StoredObject createRelationshipIntern(String repositoryId,
+      PropertiesData properties, List<String> policies, AccessControlList addAces,
+      AccessControlList removeAces, ExtensionsData extension) {
+    return null;
+  }
+
+  private boolean hasDescendant(Folder sourceFolder, Folder targetFolder) {
+    String sourceId = sourceFolder.getId();
+    String targetId = targetFolder.getId();
+    while (targetId != null) {
+      // log.info("comparing source id " + sourceId + " with predecessor " +
+      // targetId);
+      if (targetId.equals(sourceId))
+        return true;
+      targetFolder = targetFolder.getParent();
+      if (null != targetFolder)
+        targetId = targetFolder.getId();
+      else
+        targetId = null;
+    }
+    return false;
+  }
+
+  
+ /**
+   * Recursively delete a tree by traversing it and first deleting all children
+   * and then the object itself
+   * 
+   * @param folderStore
+   * @param parentFolder
+   * @param continueOnFailure
+   * @param allVersions
+   * @param failedToDeleteIds
+   * @return returns true if operation should continue, false if it should stop
+   */
+  private boolean deleteRecursive(ObjectStore folderStore, Folder parentFolder,
+      boolean continueOnFailure, boolean allVersions, List<String> failedToDeleteIds) {
+    List<StoredObject> children = parentFolder.getChildren(-1, -1);
+
+    if (null == children)
+      return true;
+
+    for (StoredObject child : children) {
+      if (child instanceof Folder) {
+        boolean mustContinue = deleteRecursive(folderStore, (Folder) child, continueOnFailure,
+            allVersions, failedToDeleteIds);
+        if (!mustContinue && !continueOnFailure)
+          return false; // stop further deletions
+      } else {
+        try {
+          folderStore.deleteObject(child.getId());
+        } catch (Exception e) {
+          failedToDeleteIds.add(child.getId());
+        }
+      }
+    }
+    folderStore.deleteObject(parentFolder.getId());
+    return true;
+  }
+
+  private ContentStreamData getContentStream(StoredObject so, String streamId, BigInteger offset,
+      BigInteger length) {
+
+    long lOffset = offset == null ? 0 : offset.longValue();
+    long lLength = length == null ? -1 : length.longValue();
+    ContentStreamData csd = ((Content) so).getContent(lOffset, lLength);
+    return csd;
+  }
+
+}

Added: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryRepositoryServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryRepositoryServiceImpl.java?rev=917600&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryRepositoryServiceImpl.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryRepositoryServiceImpl.java Mon Mar  1 17:20:16 2010
@@ -0,0 +1,190 @@
+/*
+ * 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.inmemory.server;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.opencmis.commons.api.ExtensionsData;
+import org.apache.opencmis.commons.api.TypeDefinition;
+import org.apache.opencmis.commons.api.TypeDefinitionContainer;
+import org.apache.opencmis.commons.api.TypeDefinitionList;
+import org.apache.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.opencmis.commons.impl.dataobjects.AbstractTypeDefinition;
+import org.apache.opencmis.commons.impl.dataobjects.TypeDefinitionContainerImpl;
+import org.apache.opencmis.commons.impl.dataobjects.TypeDefinitionListImpl;
+import org.apache.opencmis.commons.provider.RepositoryInfoData;
+import org.apache.opencmis.inmemory.storedobj.api.StoreManager;
+import org.apache.opencmis.server.spi.CallContext;
+import org.apache.opencmis.server.spi.CmisRepositoryService;
+
+public class InMemoryRepositoryServiceImpl extends AbstractServiceImpl implements CmisRepositoryService {
+  
+  public InMemoryRepositoryServiceImpl(StoreManager storeManager) {
+    super(storeManager);
+  }
+
+  public RepositoryInfoData getRepositoryInfo(CallContext context, String repositoryId,
+      ExtensionsData extension) {
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+    
+    RepositoryInfoData repoInfo = getRepositoryInfoFromStoreManager(repositoryId);
+
+    return repoInfo;
+   }
+
+  public List<RepositoryInfoData> getRepositoryInfos(CallContext context, ExtensionsData extension) {
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    List<RepositoryInfoData> res = new ArrayList<RepositoryInfoData>();
+    List<String> repIds = fStoreManager.getAllRepositoryIds();
+    for (String repId : repIds) {
+      res.add(fStoreManager.getRepositoryInfo(repId));
+    }
+    return res;
+  }
+
+  public TypeDefinitionList getTypeChildren(CallContext context, String repositoryId,
+      String typeId, Boolean includePropertyDefinitions, BigInteger maxItems, BigInteger skipCount,
+      ExtensionsData extension) {
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    getRepositoryInfoFromStoreManager(repositoryId); // just to check if repository exists
+
+    int skip = skipCount == null ? 0 : skipCount.intValue();
+    int max = maxItems == null ? -1 : maxItems.intValue();
+      
+    TypeDefinitionListImpl result = new TypeDefinitionListImpl();
+    List<TypeDefinitionContainer> children = getTypeDescendants(context, repositoryId, typeId, 
+        BigInteger.valueOf(1), includePropertyDefinitions, null);
+    result.setNumItems(BigInteger.valueOf(children.size()));
+    result.setHasMoreItems(children.size() > max - skip);
+    List<TypeDefinition> childrenTypes = new ArrayList<TypeDefinition>();
+    ListIterator<TypeDefinitionContainer> it = children.listIterator(skip);
+    if (max<0)
+      max = children.size();
+    for (int i=0; i<max && it.hasNext(); i++)
+      childrenTypes.add(it.next().getTypeDefinition());
+
+    result.setList(childrenTypes);      
+    return result;
+  }
+
+  public TypeDefinition getTypeDefinition(CallContext context, String repositoryId,
+      String typeId, ExtensionsData extension) {
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    getRepositoryInfoFromStoreManager(repositoryId); // just to check if repository exists
+
+    TypeDefinitionContainer tc = fStoreManager.getTypeById(repositoryId, typeId);
+    if (tc != null) {
+      return tc.getTypeDefinition();
+    }
+    else
+      throw new CmisObjectNotFoundException("unknown type id: " + typeId);        
+  }
+
+  public List<TypeDefinitionContainer> getTypeDescendants(CallContext context, String repositoryId,
+      String typeId, BigInteger depth, Boolean includePropertyDefinitions, ExtensionsData extension) {
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    getRepositoryInfoFromStoreManager(repositoryId); // just to check if repository exists
+
+    if (depth != null && depth.intValue() == 0)
+      throw new CmisInvalidArgumentException("depth == 0 is illegal in getTypeDescendants");
+    
+    List<TypeDefinitionContainer> result =  null;
+    if (typeId == null) {
+      // spec says that depth must be ignored in this case
+        Collection<TypeDefinitionContainer> typeColl = fStoreManager.getTypeDefinitionList(repositoryId);
+        result = new ArrayList<TypeDefinitionContainer>(typeColl);
+    }
+    else {
+      TypeDefinitionContainer tc = fStoreManager.getTypeById(repositoryId, typeId);
+      if (tc != null) {
+        if (null==depth || depth.intValue() == -1)
+          result = tc.getChildren();
+        else {
+          result = getLimitedChildrenTypeList(depth.intValue(), tc.getChildren());
+        }
+      }
+      else
+        throw new CmisInvalidArgumentException("unknown type id: " + typeId);        
+    }
+    
+    if (!includePropertyDefinitions) {
+      // copy list and omit properties
+      List<TypeDefinitionContainer> newResult = new ArrayList<TypeDefinitionContainer>(result.size());
+      for (TypeDefinitionContainer c : result) {
+        AbstractTypeDefinition td = ((AbstractTypeDefinition)c.getTypeDefinition()).clone();
+        TypeDefinitionContainerImpl tdc = new TypeDefinitionContainerImpl(td);
+        tdc.setChildren(c.getChildren());
+        td.setPropertyDefinitions(null);
+        newResult.add(tdc);
+      }
+      result = newResult;
+    }
+    return result;
+  }
+
+  private List<TypeDefinitionContainer> getLimitedChildrenTypeList(int depth,
+      List<TypeDefinitionContainer> types) {
+    List<TypeDefinitionContainer> result = new ArrayList<TypeDefinitionContainer>();
+
+    for (TypeDefinitionContainer type : types) {
+      result.addAll(getLimitedChildrenTypeList(depth, type));
+    }
+    return result;
+  }
+
+  private List<TypeDefinitionContainer> getLimitedChildrenTypeList(int depth,
+      TypeDefinitionContainer root) {
+    List<TypeDefinitionContainer> typeDescs = new ArrayList<TypeDefinitionContainer>();
+    if (depth > 0 && root != null) {
+      typeDescs.add(root);
+      for (TypeDefinitionContainer c : root.getChildren()) {
+        typeDescs.addAll(getLimitedChildrenTypeList(depth - 1, c));
+      }
+    }
+    return typeDescs;
+  }
+
+  private RepositoryInfoData getRepositoryInfoFromStoreManager(String repositoryId ) {
+    RepositoryInfoData repoInfo = fStoreManager.getRepositoryInfo(repositoryId);
+    if (null == repoInfo || !repoInfo.getRepositoryId().equals(repositoryId)) {
+      throw new CmisInvalidArgumentException("Unknown repository: " + repositoryId);
+    }
+    return repoInfo;
+  }
+
+}

Added: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryVersioningServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryVersioningServiceImpl.java?rev=917600&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryVersioningServiceImpl.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/InMemoryVersioningServiceImpl.java Mon Mar  1 17:20:16 2010
@@ -0,0 +1,242 @@
+/*
+ * 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.inmemory.server;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.opencmis.commons.api.DocumentTypeDefinition;
+import org.apache.opencmis.commons.api.ExtensionsData;
+import org.apache.opencmis.commons.api.TypeDefinition;
+import org.apache.opencmis.commons.enums.BaseObjectTypeIds;
+import org.apache.opencmis.commons.enums.IncludeRelationships;
+import org.apache.opencmis.commons.exceptions.CmisNotSupportedException;
+import org.apache.opencmis.commons.exceptions.CmisUpdateConflictException;
+import org.apache.opencmis.commons.provider.AccessControlList;
+import org.apache.opencmis.commons.provider.ContentStreamData;
+import org.apache.opencmis.commons.provider.Holder;
+import org.apache.opencmis.commons.provider.ObjectData;
+import org.apache.opencmis.commons.provider.PropertiesData;
+import org.apache.opencmis.inmemory.FilterParser;
+import org.apache.opencmis.inmemory.storedobj.api.Document;
+import org.apache.opencmis.inmemory.storedobj.api.DocumentVersion;
+import org.apache.opencmis.inmemory.storedobj.api.StoreManager;
+import org.apache.opencmis.inmemory.storedobj.api.StoredObject;
+import org.apache.opencmis.inmemory.storedobj.api.VersionedDocument;
+import org.apache.opencmis.inmemory.types.PropertyCreationHelper;
+import org.apache.opencmis.server.spi.CallContext;
+import org.apache.opencmis.server.spi.CmisVersioningService;
+import org.apache.opencmis.server.spi.ObjectInfoHolder;
+
+public class InMemoryVersioningServiceImpl extends AbstractServiceImpl implements
+    CmisVersioningService {
+
+  private static final Log LOG = LogFactory.getLog(InMemoryVersioningServiceImpl.class.getName());
+
+  InMemoryObjectServiceImpl fObjectService; // real implementation of the service
+  AtomLinkInfoProvider fAtomLinkProvider;
+
+  public InMemoryVersioningServiceImpl(StoreManager storeManager,
+      InMemoryObjectServiceImpl objectService) {
+    super(storeManager);
+    fObjectService = objectService;
+    fAtomLinkProvider = new AtomLinkInfoProvider(fStoreManager);
+  }
+
+  public void cancelCheckOut(CallContext context, String repositoryId, String objectId,
+      ExtensionsData extension) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = checkStandardParameters(repositoryId, objectId);
+    String user = RuntimeContext.getRuntimeConfigValue(CallContext.USERNAME);
+    VersionedDocument verDoc = testHasProperCheckedOutStatus(so, user);
+
+    verDoc.cancelCheckOut(user);
+  }
+
+  public ObjectData checkIn(CallContext context, String repositoryId, Holder<String> objectId,
+      Boolean major, PropertiesData properties, ContentStreamData contentStream,
+      String checkinComment, List<String> policies, AccessControlList addAces,
+      AccessControlList removeAces, ExtensionsData extension, ObjectInfoHolder objectInfos) {
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = checkStandardParameters(repositoryId, objectId.getValue());
+    String user = RuntimeContext.getRuntimeConfigValue(CallContext.USERNAME);
+    VersionedDocument verDoc = testHasProperCheckedOutStatus(so, user);
+
+    DocumentVersion pwc = verDoc.getPwc();
+
+    if (null != contentStream)
+      pwc.setContent(contentStream, false);
+
+    if (null != properties && null != properties.getProperties())
+      pwc.setCustomProperties(properties.getProperties());
+
+    verDoc.checkIn(major, checkinComment, user);
+
+    // To be able to provide all Atom links in the response we need additional information:
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+
+    ObjectData od = PropertyCreationHelper.getObjectData(fStoreManager, so, null, false,
+        IncludeRelationships.NONE, null, false, false, extension);
+
+    return od;
+  }
+
+  public ObjectData checkOut(CallContext context, String repositoryId, Holder<String> objectId,
+      ExtensionsData extension, Holder<Boolean> contentCopied, ObjectInfoHolder objectInfos) {
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = checkStandardParameters(repositoryId, objectId.getValue());
+    TypeDefinition typeDef = getTypeDefinition(repositoryId, so);
+    if (!typeDef.getBaseId().equals(BaseObjectTypeIds.CMIS_DOCUMENT))
+      throw new CmisNotSupportedException("Only documents can be checked-out.");
+    else if (!((DocumentTypeDefinition) typeDef).isVersionable())
+      throw new CmisNotSupportedException("Object can't be checked-out, type is not versionable.");
+
+    checkIsVersionableObject(so);
+
+    VersionedDocument verDoc = getVersionedDocumentOfObjectId(so);
+
+    ContentStreamData content = null;
+
+    if (so instanceof DocumentVersion) {
+      // get document the version is contained in to c
+      content = ((DocumentVersion) so).getContent(0, -1);
+    }
+    else {
+      content = ((VersionedDocument) so).getLatestVersion(false).getContent(0, -1);
+    }
+
+    if (verDoc.isCheckedOut())
+      throw new CmisUpdateConflictException("Document " + objectId.getValue()
+          + " is already checked out.");
+
+    String user = RuntimeContext.getRuntimeConfigValue(CallContext.USERNAME);
+    checkHasUser(user);
+
+    DocumentVersion pwc = verDoc.checkOut(content, user);
+    objectId.setValue(pwc.getId()); // return the id of the created pwc
+
+    // To be able to provide all Atom links in the response we need additional information:
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+
+    ObjectData od = PropertyCreationHelper.getObjectData(fStoreManager, so, null, false,
+        IncludeRelationships.NONE, null, false, false, extension);
+
+    return od;
+  }
+
+  public List<ObjectData> getAllVersions(CallContext context, String repositoryId,
+      String versionSeriesId, String filter, Boolean includeAllowableActions,
+      ExtensionsData extension, ObjectInfoHolder objectInfos) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = checkStandardParameters(repositoryId, versionSeriesId);
+
+    if (!(so instanceof VersionedDocument))
+      throw new RuntimeException("Object is not instance of a VersionedDocument (version series)");
+
+    VersionedDocument verDoc = (VersionedDocument) so;
+    List<ObjectData> res = new ArrayList<ObjectData>();
+    List<DocumentVersion> versions = verDoc.getAllVersions();
+    for (DocumentVersion version : versions) {
+      ObjectData objData = getObject(context, repositoryId, version.getId(), filter,
+          includeAllowableActions, extension, objectInfos);
+      res.add(objData);
+    }
+
+    // provide information for Atom links for version series:
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+
+    return res;
+  }
+
+  public ObjectData getObjectOfLatestVersion(CallContext context, String repositoryId,
+      String versionSeriesId, Boolean major, String filter, Boolean includeAllowableActions,
+      IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
+      Boolean includeAcl, ExtensionsData extension, ObjectInfoHolder objectInfos) {
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = checkStandardParameters(repositoryId, versionSeriesId);
+    ObjectData objData = null;
+
+    if (so instanceof VersionedDocument) {
+      VersionedDocument verDoc = (VersionedDocument) so;
+      DocumentVersion latestVersion = verDoc.getLatestVersion(major);
+      objData = getObject(context, repositoryId, latestVersion.getId(), filter,
+          includeAllowableActions, extension, objectInfos);
+    }
+    else if (so instanceof Document) {
+      objData = getObject(context, repositoryId, so.getId(), filter, includeAllowableActions,
+          extension, objectInfos);
+    }
+    else
+      throw new RuntimeException("Object is not instance of a document (version series)");
+
+    // provide information for Atom links for version series:
+    fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfos);
+
+    return objData;
+  }
+
+  public PropertiesData getPropertiesOfLatestVersion(CallContext context, String repositoryId,
+      String versionSeriesId, Boolean major, String filter, ExtensionsData extension) {
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    RuntimeContext.getRuntimeConfig().attachCfg(context);
+
+    StoredObject so = checkStandardParameters(repositoryId, versionSeriesId);
+    StoredObject latestVersionObject = null;
+
+    if (so instanceof VersionedDocument) {
+      VersionedDocument verDoc = (VersionedDocument) so;
+      latestVersionObject = verDoc.getLatestVersion(major);
+    }
+    else if (so instanceof Document) {
+      latestVersionObject = so;
+    }
+    else
+      throw new RuntimeException("Object is not instance of a document (version series)");
+
+    List<String> requestedIds = FilterParser.getRequestedIdsFromFilter(filter);
+    PropertiesData props = PropertyCreationHelper.getPropertiesFromObject(repositoryId,
+        latestVersionObject, fStoreManager, requestedIds);
+
+    return props;
+  }
+
+  private ObjectData getObject(CallContext context, String repositoryId, String objectId,
+      String filter, Boolean includeAllowableActions, ExtensionsData extension,
+      ObjectInfoHolder objectInfos) {
+
+    return fObjectService.getObject(context, repositoryId, objectId, filter,
+        includeAllowableActions, IncludeRelationships.NONE, null, false, includeAllowableActions,
+        extension, objectInfos);
+  }
+}

Modified: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/RuntimeContext.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/RuntimeContext.java?rev=917600&r1=917599&r2=917600&view=diff
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/RuntimeContext.java (original)
+++ incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/main/java/org/apache/opencmis/inmemory/server/RuntimeContext.java Mon Mar  1 17:20:16 2010
@@ -32,12 +32,17 @@
   public static class ThreadLocalRuntimeConfig extends ThreadLocal<CallContext> {    
 
     public void attachCfg(CallContext ctx) {
-      set(ctx);      
+      if (null != ctx)
+        set(ctx);      
     }
 
     public synchronized String getConfigValue(String key) {
       return get().get(key) ;
     }
+
+    public void deleteCfg() {
+      set(null);      
+    }
   };
 
   private static ThreadLocalRuntimeConfig CONN = new ThreadLocalRuntimeConfig();