You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2012/02/24 22:46:55 UTC

svn commit: r1293440 [3/5] - in /chemistry/opencmis/branches/android: ./ chemistry-opencmis-android/ chemistry-opencmis-android/chemistry-opencmis-android-client/ chemistry-opencmis-android/chemistry-opencmis-android-client/src/ chemistry-opencmis-andr...

Added: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/NavigationServiceImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/NavigationServiceImpl.java?rev=1293440&view=auto
==============================================================================
--- chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/NavigationServiceImpl.java (added)
+++ chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/NavigationServiceImpl.java Fri Feb 24 21:46:54 2012
@@ -0,0 +1,448 @@
+/*
+ * 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.chemistry.opencmis.client.bindings.spi.atompub;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomBase;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
+import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpUtils;
+import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.data.ObjectData;
+import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
+import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
+import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
+import org.apache.chemistry.opencmis.commons.data.ObjectList;
+import org.apache.chemistry.opencmis.commons.data.ObjectParentData;
+import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderContainerImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderDataImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderListImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectParentDataImpl;
+import org.apache.chemistry.opencmis.commons.spi.NavigationService;
+
+/**
+ * Navigation Service AtomPub client.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ */
+public class NavigationServiceImpl extends AbstractAtomPubService implements NavigationService {
+
+    /**
+     * Constructor.
+     */
+    public NavigationServiceImpl(BindingSession session) {
+        setSession(session);
+    }
+
+    public ObjectInFolderList getChildren(String repositoryId, String folderId, String filter, String orderBy,
+            Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
+            Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
+        ObjectInFolderListImpl result = new ObjectInFolderListImpl();
+
+        // find the link
+        String link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+
+        if (link == null) {
+            throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_FILTER, filter);
+        url.addParameter(Constants.PARAM_ORDER_BY, orderBy);
+        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
+        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
+        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
+        url.addParameter(Constants.PARAM_PATH_SEGMENT, includePathSegment);
+        url.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
+        url.addParameter(Constants.PARAM_SKIP_COUNT, skipCount);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+        // handle top level
+        for (AtomElement element : feed.getElements()) {
+            if (element.getObject() instanceof AtomLink) {
+                if (isNextLink(element)) {
+                    result.setHasMoreItems(Boolean.TRUE);
+                }
+            } else if (isInt(NAME_NUM_ITEMS, element)) {
+                result.setNumItems((BigInteger) element.getObject());
+            }
+        }
+
+        // get the children
+        if (!feed.getEntries().isEmpty()) {
+            result.setObjects(new ArrayList<ObjectInFolderData>(feed.getEntries().size()));
+
+            for (AtomEntry entry : feed.getEntries()) {
+                ObjectInFolderDataImpl child = null;
+                String pathSegment = null;
+
+                lockLinks();
+                try {
+                    // clean up cache
+                    removeLinks(repositoryId, entry.getId());
+
+                    // walk through the entry
+                    for (AtomElement element : entry.getElements()) {
+                        if (element.getObject() instanceof AtomLink) {
+                            addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
+                        } else if (isStr(NAME_PATH_SEGMENT, element)) {
+                            pathSegment = (String) element.getObject();
+                        } else if (element.getObject() instanceof ObjectData) {
+                            child = new ObjectInFolderDataImpl();
+                            child.setObject((ObjectData) element.getObject());
+                        }
+                    }
+                } finally {
+                    unlockLinks();
+                }
+
+                if (child != null) {
+                    child.setPathSegment(pathSegment);
+                    result.getObjects().add(child);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    public List<ObjectInFolderContainer> getDescendants(String repositoryId, String folderId, BigInteger depth,
+            String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
+            String renditionFilter, Boolean includePathSegment, ExtensionsData extension) {
+        List<ObjectInFolderContainer> result = new ArrayList<ObjectInFolderContainer>();
+
+        // find the link
+        String link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_DESCENDANTS);
+
+        if (link == null) {
+            throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_DESCENDANTS);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_DEPTH, depth);
+        url.addParameter(Constants.PARAM_FILTER, filter);
+        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
+        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
+        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
+        url.addParameter(Constants.PARAM_PATH_SEGMENT, includePathSegment);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+        // process tree
+        addDescendantsLevel(repositoryId, feed, result);
+
+        return result;
+    }
+
+    public ObjectData getFolderParent(String repositoryId, String folderId, String filter, ExtensionsData extension) {
+        ObjectData result = null;
+
+        // find the link
+        String link = loadLink(repositoryId, folderId, Constants.REL_UP, Constants.MEDIATYPE_ENTRY);
+
+        if (link == null) {
+            throwLinkException(repositoryId, folderId, Constants.REL_UP, Constants.MEDIATYPE_ENTRY);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_FILTER, filter);
+
+        // read
+        HttpUtils.Response resp = read(url);
+
+        AtomBase base = parse(resp.getStream(), AtomBase.class);
+
+        // get the entry
+        AtomEntry entry = null;
+        if (base instanceof AtomFeed) {
+            AtomFeed feed = (AtomFeed) base;
+            if (feed.getEntries().isEmpty()) {
+                throw new CmisRuntimeException("Parent feed is empty!");
+            }
+            entry = feed.getEntries().get(0);
+        } else if (base instanceof AtomEntry) {
+            entry = (AtomEntry) base;
+        } else {
+            throw new CmisRuntimeException("Unexpected document!");
+        }
+
+        lockLinks();
+        try {
+            // clean up cache
+            removeLinks(repositoryId, entry.getId());
+
+            // walk through the entry
+            for (AtomElement element : entry.getElements()) {
+                if (element.getObject() instanceof AtomLink) {
+                    addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
+                } else if (element.getObject() instanceof ObjectData) {
+                    result = (ObjectData) element.getObject();
+                }
+            }
+        } finally {
+            unlockLinks();
+        }
+
+        return result;
+    }
+
+    public List<ObjectInFolderContainer> getFolderTree(String repositoryId, String folderId, BigInteger depth,
+            String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
+            String renditionFilter, Boolean includePathSegment, ExtensionsData extension) {
+        List<ObjectInFolderContainer> result = new ArrayList<ObjectInFolderContainer>();
+
+        // find the link
+        String link = loadLink(repositoryId, folderId, Constants.REL_FOLDERTREE, Constants.MEDIATYPE_DESCENDANTS);
+
+        if (link == null) {
+            throwLinkException(repositoryId, folderId, Constants.REL_FOLDERTREE, Constants.MEDIATYPE_DESCENDANTS);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_DEPTH, depth);
+        url.addParameter(Constants.PARAM_FILTER, filter);
+        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
+        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
+        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
+        url.addParameter(Constants.PARAM_PATH_SEGMENT, includePathSegment);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+        // process tree
+        addDescendantsLevel(repositoryId, feed, result);
+
+        return result;
+    }
+
+    public List<ObjectParentData> getObjectParents(String repositoryId, String objectId, String filter,
+            Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
+            Boolean includeRelativePathSegment, ExtensionsData extension) {
+        List<ObjectParentData> result = new ArrayList<ObjectParentData>();
+
+        // find the link
+        String link = loadLink(repositoryId, objectId, Constants.REL_UP, Constants.MEDIATYPE_FEED);
+
+        if (link == null) {
+            // root and unfiled objects have no UP link
+            return result;
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_FILTER, filter);
+        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
+        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
+        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
+        url.addParameter(Constants.PARAM_RELATIVE_PATH_SEGMENT, includeRelativePathSegment);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+
+        AtomBase base = parse(resp.getStream(), AtomBase.class);
+
+        if (base instanceof AtomFeed) {
+            // it's a feed
+            AtomFeed feed = (AtomFeed) base;
+
+            // walk through the feed
+            for (AtomEntry entry : feed.getEntries()) {
+                ObjectParentDataImpl objectParent = processParentEntry(entry, repositoryId);
+
+                if (objectParent != null) {
+                    result.add(objectParent);
+                }
+            }
+        } else if (base instanceof AtomEntry) {
+            // it's an entry
+            AtomEntry entry = (AtomEntry) base;
+
+            ObjectParentDataImpl objectParent = processParentEntry(entry, repositoryId);
+
+            if (objectParent != null) {
+                result.add(objectParent);
+            }
+        }
+
+        return result;
+    }
+
+    private ObjectParentDataImpl processParentEntry(AtomEntry entry, String repositoryId) {
+        ObjectParentDataImpl result = null;
+        String relativePathSegment = null;
+
+        lockLinks();
+        try {
+            // clean up cache
+            removeLinks(repositoryId, entry.getId());
+
+            // walk through the entry
+            for (AtomElement element : entry.getElements()) {
+                if (element.getObject() instanceof AtomLink) {
+                    addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
+                } else if (element.getObject() instanceof ObjectData) {
+                    result = new ObjectParentDataImpl((ObjectData) element.getObject());
+                } else if (is(NAME_RELATIVE_PATH_SEGMENT, element)) {
+                    relativePathSegment = (String) element.getObject();
+                }
+            }
+        } finally {
+            unlockLinks();
+        }
+
+        if (result != null) {
+            result.setRelativePathSegment(relativePathSegment);
+        }
+
+        return result;
+    }
+
+    public ObjectList getCheckedOutDocs(String repositoryId, String folderId, String filter, String orderBy,
+            Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
+            BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
+        ObjectListImpl result = new ObjectListImpl();
+
+        // find the link
+        String link = loadCollection(repositoryId, Constants.COLLECTION_CHECKEDOUT);
+
+        if (link == null) {
+            throw new CmisObjectNotFoundException("Unknown repository or checkedout collection not supported!");
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_FOLDER_ID, folderId);
+        url.addParameter(Constants.PARAM_FILTER, filter);
+        url.addParameter(Constants.PARAM_ORDER_BY, orderBy);
+        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
+        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
+        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
+        url.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
+        url.addParameter(Constants.PARAM_SKIP_COUNT, skipCount);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+        // handle top level
+        for (AtomElement element : feed.getElements()) {
+            if (element.getObject() instanceof AtomLink) {
+                if (isNextLink(element)) {
+                    result.setHasMoreItems(Boolean.TRUE);
+                }
+            } else if (isInt(NAME_NUM_ITEMS, element)) {
+                result.setNumItems((BigInteger) element.getObject());
+            }
+        }
+
+        // get the documents
+        if (!feed.getEntries().isEmpty()) {
+            result.setObjects(new ArrayList<ObjectData>(feed.getEntries().size()));
+
+            for (AtomEntry entry : feed.getEntries()) {
+                ObjectData child = null;
+
+                lockLinks();
+                try {
+                    // clean up cache
+                    removeLinks(repositoryId, entry.getId());
+
+                    // walk through the entry
+                    for (AtomElement element : entry.getElements()) {
+                        if (element.getObject() instanceof AtomLink) {
+                            addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
+                        } else if (element.getObject() instanceof ObjectData) {
+                            child = (ObjectData) element.getObject();
+                        }
+                    }
+                } finally {
+                    unlockLinks();
+                }
+
+                if (child != null) {
+                    result.getObjects().add(child);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    // ---- internal ----
+
+    /**
+     * Adds descendants level recursively.
+     */
+    private void addDescendantsLevel(String repositoryId, AtomFeed feed, List<ObjectInFolderContainer> containerList) {
+        if ((feed == null) || (feed.getEntries().isEmpty())) {
+            return;
+        }
+
+        // walk through the feed
+        for (AtomEntry entry : feed.getEntries()) {
+            ObjectInFolderDataImpl objectInFolder = null;
+            String pathSegment = null;
+            List<ObjectInFolderContainer> childContainerList = new ArrayList<ObjectInFolderContainer>();
+
+            lockLinks();
+            try {
+                // clean up cache
+                removeLinks(repositoryId, entry.getId());
+
+                // walk through the entry
+                for (AtomElement element : entry.getElements()) {
+                    if (element.getObject() instanceof AtomLink) {
+                        addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
+                    } else if (element.getObject() instanceof ObjectData) {
+                        objectInFolder = new ObjectInFolderDataImpl((ObjectData) element.getObject());
+                    } else if (is(NAME_PATH_SEGMENT, element)) {
+                        pathSegment = (String) element.getObject();
+                    } else if (element.getObject() instanceof AtomFeed) {
+                        addDescendantsLevel(repositoryId, (AtomFeed) element.getObject(), childContainerList);
+                    }
+                }
+            } finally {
+                unlockLinks();
+            }
+
+            if (objectInFolder != null) {
+                objectInFolder.setPathSegment(pathSegment);
+                ObjectInFolderContainerImpl childContainer = new ObjectInFolderContainerImpl(objectInFolder);
+                childContainer.setChildren(childContainerList);
+                containerList.add(childContainer);
+            }
+        }
+    }
+}

Propchange: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/NavigationServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/ObjectServiceImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/ObjectServiceImpl.java?rev=1293440&view=auto
==============================================================================
--- chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/ObjectServiceImpl.java (added)
+++ chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/ObjectServiceImpl.java Fri Feb 24 21:46:54 2012
@@ -0,0 +1,721 @@
+/*
+ * 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.chemistry.opencmis.client.bindings.spi.atompub;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAllowableActions;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
+import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpUtils;
+import org.apache.chemistry.opencmis.commons.PropertyIds;
+import org.apache.chemistry.opencmis.commons.data.Acl;
+import org.apache.chemistry.opencmis.commons.data.AllowableActions;
+import org.apache.chemistry.opencmis.commons.data.ContentStream;
+import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
+import org.apache.chemistry.opencmis.commons.data.ObjectData;
+import org.apache.chemistry.opencmis.commons.data.Properties;
+import org.apache.chemistry.opencmis.commons.data.PropertyData;
+import org.apache.chemistry.opencmis.commons.data.PropertyId;
+import org.apache.chemistry.opencmis.commons.data.RenditionData;
+import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
+import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
+import org.apache.chemistry.opencmis.commons.enums.VersioningState;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.MimeHelper;
+import org.apache.chemistry.opencmis.commons.impl.ReturnVersion;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.FailedToDeleteDataImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl;
+import org.apache.chemistry.opencmis.commons.spi.Holder;
+import org.apache.chemistry.opencmis.commons.spi.ObjectService;
+
+/**
+ * Object Service AtomPub client.
+ */
+public class ObjectServiceImpl extends AbstractAtomPubService implements ObjectService {
+
+    /**
+     * Constructor.
+     */
+    public ObjectServiceImpl(BindingSession session) {
+        setSession(session);
+    }
+
+    public String createDocument(String repositoryId, Properties properties, String folderId,
+            ContentStream contentStream, VersioningState versioningState, List<String> policies, Acl addAces,
+            Acl removeAces, ExtensionsData extension) {
+        checkCreateProperties(properties);
+
+        // find the link
+        String link = null;
+
+        if (folderId == null) {
+            // Creation of unfiled objects via AtomPub is not defined in the
+            // CMIS 1.0 specification. This implementation follow the CMIS 1.1
+            // draft and POSTs the document to the Unfiled collection.
+
+            link = loadCollection(repositoryId, Constants.COLLECTION_UNFILED);
+
+            if (link == null) {
+                throw new CmisObjectNotFoundException("Unknown repository or unfiling not supported!");
+            }
+        } else {
+            link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+
+            if (link == null) {
+                throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+            }
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_VERSIONIG_STATE, versioningState);
+
+        // set up object and writer
+        ObjectDataImpl object = new ObjectDataImpl();
+        object.setProperties(properties);
+        // object.setPolicyIds(convertPolicyIds(policies));
+
+        String mediaType = null;
+        InputStream stream = null;
+
+        if (contentStream != null) {
+            mediaType = contentStream.getMimeType();
+            stream = contentStream.getStream();
+        }
+
+        final AtomEntryWriter entryWriter = new AtomEntryWriter(object, mediaType, stream);
+
+        // post the new folder object
+        HttpUtils.Response resp = post(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
+            public void write(OutputStream out) throws Exception {
+                entryWriter.write(out);
+            }
+        });
+
+        // parse the response
+        AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
+
+        // handle ACL modifications
+        handleAclModifications(repositoryId, entry, addAces, removeAces);
+
+        return entry.getId();
+    }
+
+    public String createDocumentFromSource(String repositoryId, String sourceId, Properties properties,
+            String folderId, VersioningState versioningState, List<String> policies, Acl addACEs, Acl removeACEs,
+            ExtensionsData extension) {
+        throw new CmisNotSupportedException("createDocumentFromSource is not supported by the AtomPub binding!");
+    }
+
+    public String createFolder(String repositoryId, Properties properties, String folderId, List<String> policies,
+            Acl addAces, Acl removeAces, ExtensionsData extension) {
+        checkCreateProperties(properties);
+
+        // find the link
+        String link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+
+        if (link == null) {
+            throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+
+        // set up object and writer
+        ObjectDataImpl object = new ObjectDataImpl();
+        object.setProperties(properties);
+        // CmisObjectType object = new CmisObjectType();
+        // object.setProperties(convert(properties));
+        // object.setPolicyIds(convertPolicyIds(policies));
+
+        final AtomEntryWriter entryWriter = new AtomEntryWriter(object);
+
+        // post the new folder object
+        HttpUtils.Response resp = post(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
+            public void write(OutputStream out) throws Exception {
+                entryWriter.write(out);
+            }
+        });
+
+        // parse the response
+        AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
+
+        // handle ACL modifications
+        handleAclModifications(repositoryId, entry, addAces, removeAces);
+
+        return entry.getId();
+    }
+
+    public String createPolicy(String repositoryId, Properties properties, String folderId, List<String> policies,
+            Acl addAces, Acl removeAces, ExtensionsData extension) {
+        checkCreateProperties(properties);
+
+        // find the link
+        String link = null;
+
+        if (folderId == null) {
+            // Creation of unfiled objects via AtomPub is not defined in the
+            // CMIS 1.0 specification. This implementation follow the CMIS 1.1
+            // draft and POSTs the policy to the Unfiled collection.
+
+            link = loadCollection(repositoryId, Constants.COLLECTION_UNFILED);
+
+            if (link == null) {
+                throw new CmisObjectNotFoundException("Unknown repository or unfiling not supported!");
+            }
+        } else {
+            link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+
+            if (link == null) {
+                throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+            }
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+
+        // set up object and writer
+        ObjectDataImpl object = new ObjectDataImpl();
+        object.setProperties(properties);
+        // CmisObjectType object = new CmisObjectType();
+        // object.setProperties(convert(properties));
+        // object.setPolicyIds(convertPolicyIds(policies));
+
+        final AtomEntryWriter entryWriter = new AtomEntryWriter(object);
+
+        // post the new folder object
+        HttpUtils.Response resp = post(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
+            public void write(OutputStream out) throws Exception {
+                entryWriter.write(out);
+            }
+        });
+
+        // parse the response
+        AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
+
+        // handle ACL modifications
+        handleAclModifications(repositoryId, entry, addAces, removeAces);
+
+        return entry.getId();
+    }
+
+    public String createRelationship(String repositoryId, Properties properties, List<String> policies, Acl addAces,
+            Acl removeAces, ExtensionsData extension) {
+        checkCreateProperties(properties);
+
+        // find source id
+        PropertyData<?> sourceIdProperty = properties.getProperties().get(PropertyIds.SOURCE_ID);
+        if (!(sourceIdProperty instanceof PropertyId)) {
+            throw new CmisInvalidArgumentException("Source Id is not set!");
+        }
+
+        String sourceId = ((PropertyId) sourceIdProperty).getFirstValue();
+        if (sourceId == null) {
+            throw new CmisInvalidArgumentException("Source Id is not set!");
+        }
+
+        // find the link
+        String link = loadLink(repositoryId, sourceId, Constants.REL_RELATIONSHIPS, Constants.MEDIATYPE_FEED);
+
+        if (link == null) {
+            throwLinkException(repositoryId, sourceId, Constants.REL_RELATIONSHIPS, Constants.MEDIATYPE_FEED);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+
+        // set up object and writer
+        ObjectDataImpl object = new ObjectDataImpl();
+        object.setProperties(properties);
+        // CmisObjectType object = new CmisObjectType();
+        // object.setProperties(convert(properties));
+        // object.setPolicyIds(convertPolicyIds(policies));
+        final AtomEntryWriter entryWriter = new AtomEntryWriter(object);
+
+        // post the new folder object
+        HttpUtils.Response resp = post(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
+            public void write(OutputStream out) throws Exception {
+                entryWriter.write(out);
+            }
+        });
+
+        // parse the response
+        AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
+
+        // handle ACL modifications
+        handleAclModifications(repositoryId, entry, addAces, removeAces);
+
+        return entry.getId();
+    }
+
+    public void updateProperties(String repositoryId, Holder<String> objectId, Holder<String> changeToken,
+            Properties properties, ExtensionsData extension) {
+        // we need an object id
+        if ((objectId == null) || (objectId.getValue() == null) || (objectId.getValue().length() == 0)) {
+            throw new CmisInvalidArgumentException("Object id must be set!");
+        }
+
+        // find the link
+        String link = loadLink(repositoryId, objectId.getValue(), Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId.getValue(), Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        if (changeToken != null) {
+            url.addParameter(Constants.PARAM_CHANGE_TOKEN, changeToken.getValue());
+        }
+
+        // set up object and writer
+        ObjectDataImpl object = new ObjectDataImpl();
+        object.setProperties(properties);
+        // CmisObjectType object = new CmisObjectType();
+        // object.setProperties(convert(properties));
+        // object.setPolicyIds(convertPolicyIds(policies));
+
+        final AtomEntryWriter entryWriter = new AtomEntryWriter(object);
+
+        // update
+        HttpUtils.Response resp = put(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
+            public void write(OutputStream out) throws Exception {
+                entryWriter.write(out);
+            }
+        });
+
+        // parse new entry
+        AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
+
+        // we expect a CMIS entry
+        if (entry.getId() == null) {
+            throw new CmisConnectionException("Received Atom entry is not a CMIS entry!");
+        }
+
+        // set object id
+        objectId.setValue(entry.getId());
+
+        if (changeToken != null) {
+            changeToken.setValue(null); // just in case
+        }
+
+        lockLinks();
+        try {
+            // clean up cache
+            removeLinks(repositoryId, entry.getId());
+
+            // walk through the entry
+            for (AtomElement element : entry.getElements()) {
+                if (element.getObject() instanceof AtomLink) {
+                    addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
+                } else if (element.getObject() instanceof ObjectData) {
+                    // extract new change token
+                    if (changeToken != null) {
+                        object = (ObjectDataImpl) element.getObject();
+
+                        // TODO
+                        /*
+                         * if (object.getProperties() != null) { for
+                         * (CmisProperty property :
+                         * object.getProperties().getPropertyList()) { if
+                         * (PropertyIds
+                         * .CHANGE_TOKEN.equals(property.getPropertyDefinitionId
+                         * ()) && (property instanceof CmisPropertyString)) {
+                         * 
+                         * CmisPropertyString changeTokenProperty =
+                         * (CmisPropertyString) property; if
+                         * (!changeTokenProperty.getValue().isEmpty()) {
+                         * changeToken
+                         * .setValue(changeTokenProperty.getValue().get(0)); }
+                         * 
+                         * break; } } }
+                         */
+                    }
+                }
+            }
+        } finally {
+            unlockLinks();
+        }
+    }
+
+    public void deleteObject(String repositoryId, String objectId, Boolean allVersions, ExtensionsData extension) {
+
+        // find the link
+        String link = loadLink(repositoryId, objectId, Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId, Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_ALL_VERSIONS, allVersions);
+
+        delete(url);
+    }
+
+    public FailedToDeleteData deleteTree(String repositoryId, String folderId, Boolean allVersions,
+            UnfileObject unfileObjects, Boolean continueOnFailure, ExtensionsData extension) {
+
+        // find the link
+        String link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_DESCENDANTS);
+
+        if (link == null) {
+            link = loadLink(repositoryId, folderId, Constants.REL_FOLDERTREE, Constants.MEDIATYPE_DESCENDANTS);
+        }
+
+        if (link == null) {
+            throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_DESCENDANTS);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_ALL_VERSIONS, allVersions);
+        url.addParameter(Constants.PARAM_UNFILE_OBJECTS, unfileObjects);
+        url.addParameter(Constants.PARAM_CONTINUE_ON_FAILURE, continueOnFailure);
+
+        // make the call
+        HttpUtils.Response resp = HttpUtils.invokeDELETE(url, getSession());
+
+        // check response code
+        if (resp.getResponseCode() == 200 || resp.getResponseCode() == 202 || resp.getResponseCode() == 204) {
+            return new FailedToDeleteDataImpl();
+        }
+
+        // If the server returned an internal server error, get the remaining
+        // children of the folder. We only retrieve the first level, since
+        // getDescendants() is not supported by all repositories.
+        if (resp.getResponseCode() == 500) {
+            link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+
+            if (link != null) {
+                url = new UrlBuilder(link);
+                // we only want the object ids
+                url.addParameter(Constants.PARAM_FILTER, "cmis:objectId");
+                url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, false);
+                url.addParameter(Constants.PARAM_RELATIONSHIPS, IncludeRelationships.NONE);
+                url.addParameter(Constants.PARAM_RENDITION_FILTER, "cmis:none");
+                url.addParameter(Constants.PARAM_PATH_SEGMENT, false);
+                // 1000 children should be enough to indicate a problem
+                url.addParameter(Constants.PARAM_MAX_ITEMS, 1000);
+                url.addParameter(Constants.PARAM_SKIP_COUNT, 0);
+
+                // read and parse
+                resp = read(url);
+                AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+                // prepare result
+                FailedToDeleteDataImpl result = new FailedToDeleteDataImpl();
+                List<String> ids = new ArrayList<String>();
+                result.setIds(ids);
+
+                // get the children ids
+                for (AtomEntry entry : feed.getEntries()) {
+                    ids.add(entry.getId());
+                }
+
+                return result;
+            }
+        }
+
+        throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
+    }
+
+    public AllowableActions getAllowableActions(String repositoryId, String objectId, ExtensionsData extension) {
+        // find the link
+        String link = loadLink(repositoryId, objectId, Constants.REL_ALLOWABLEACTIONS,
+                Constants.MEDIATYPE_ALLOWABLEACTION);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId, Constants.REL_ALLOWABLEACTIONS,
+                    Constants.MEDIATYPE_ALLOWABLEACTION);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomAllowableActions allowableActions = parse(resp.getStream(), AtomAllowableActions.class);
+
+        return allowableActions.getAllowableActions();
+    }
+
+    public ContentStream getContentStream(String repositoryId, String objectId, String streamId, BigInteger offset,
+            BigInteger length, ExtensionsData extension) {
+        ContentStreamImpl result = new ContentStreamImpl();
+
+        // find the link
+        String link = null;
+        if (streamId != null) {
+            // use the alternate link per spec
+            link = loadLink(repositoryId, objectId, Constants.REL_ALTERNATE, streamId);
+            if (link != null) {
+                streamId = null; // we have a full URL now
+            }
+        }
+        if (link == null) {
+            link = loadLink(repositoryId, objectId, AtomPubParser.LINK_REL_CONTENT, null);
+        }
+
+        if (link == null) {
+            throw new CmisConstraintException("No content stream");
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        // using the content URL and adding a streamId param
+        // is not spec-compliant
+        url.addParameter(Constants.PARAM_STREAM_ID, streamId);
+
+        // get the content
+        HttpUtils.Response resp = HttpUtils.invokeGET(url, getSession(), offset, length);
+
+        // check response code
+        if ((resp.getResponseCode() != 200) && (resp.getResponseCode() != 206)) {
+            throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
+        }
+
+        result.setFileName(null);
+        result.setLength(resp.getContentLength());
+        result.setMimeType(resp.getContentTypeHeader());
+        result.setStream(resp.getStream());
+
+        return result;
+    }
+
+    public ObjectData getObject(String repositoryId, String objectId, String filter, Boolean includeAllowableActions,
+            IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
+            Boolean includeACL, ExtensionsData extension) {
+
+        return getObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.THIS, filter,
+                includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeACL, extension);
+    }
+
+    public ObjectData getObjectByPath(String repositoryId, String path, String filter, Boolean includeAllowableActions,
+            IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
+            Boolean includeACL, ExtensionsData extension) {
+
+        return getObjectInternal(repositoryId, IdentifierType.PATH, path, ReturnVersion.THIS, filter,
+                includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeACL, extension);
+    }
+
+    public Properties getProperties(String repositoryId, String objectId, String filter, ExtensionsData extension) {
+        ObjectData object = getObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.THIS, filter,
+                Boolean.FALSE, IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, Boolean.FALSE, extension);
+
+        return object.getProperties();
+    }
+
+    public List<RenditionData> getRenditions(String repositoryId, String objectId, String renditionFilter,
+            BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
+        ObjectData object = getObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.THIS,
+                PropertyIds.OBJECT_ID, Boolean.FALSE, IncludeRelationships.NONE, renditionFilter, Boolean.FALSE,
+                Boolean.FALSE, extension);
+
+        List<RenditionData> result = object.getRenditions();
+        if (result == null) {
+            result = Collections.emptyList();
+        }
+
+        return result;
+    }
+
+    public void moveObject(String repositoryId, Holder<String> objectId, String targetFolderId, String sourceFolderId,
+            ExtensionsData extension) {
+        if ((objectId == null) || (objectId.getValue() == null) || (objectId.getValue().length() == 0)) {
+            throw new CmisInvalidArgumentException("Object id must be set!");
+        }
+
+        if ((targetFolderId == null) || (targetFolderId.length() == 0) || (sourceFolderId == null)
+                || (sourceFolderId.length() == 0)) {
+            throw new CmisInvalidArgumentException("Source and target folder must be set!");
+        }
+
+        // find the link
+        String link = loadLink(repositoryId, targetFolderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+
+        if (link == null) {
+            throwLinkException(repositoryId, targetFolderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_SOURCE_FOLDER_ID, sourceFolderId);
+
+        // set up object and writer
+        final AtomEntryWriter entryWriter = new AtomEntryWriter(createIdObject(objectId.getValue()));
+
+        // post move request
+        HttpUtils.Response resp = post(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
+            public void write(OutputStream out) throws Exception {
+                entryWriter.write(out);
+            }
+        });
+
+        // parse the response
+        AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
+
+        objectId.setValue(entry.getId());
+    }
+
+    public void setContentStream(String repositoryId, Holder<String> objectId, Boolean overwriteFlag,
+            Holder<String> changeToken, ContentStream contentStream, ExtensionsData extension) {
+        // we need an object id
+        if ((objectId == null) || (objectId.getValue() == null)) {
+            throw new CmisInvalidArgumentException("Object ID must be set!");
+        }
+
+        // we need content
+        if ((contentStream == null) || (contentStream.getStream() == null) || (contentStream.getMimeType() == null)) {
+            throw new CmisInvalidArgumentException("Content must be set!");
+        }
+
+        // find the link
+        String link = loadLink(repositoryId, objectId.getValue(), Constants.REL_EDITMEDIA, null);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId.getValue(), Constants.REL_EDITMEDIA, null);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        if (changeToken != null) {
+            url.addParameter(Constants.PARAM_CHANGE_TOKEN, changeToken.getValue());
+        }
+        url.addParameter(Constants.PARAM_OVERWRITE_FLAG, overwriteFlag);
+
+        final InputStream stream = contentStream.getStream();
+
+        // Content-Disposition header for the filename
+        Map<String, String> headers = null;
+        if (contentStream.getFileName() != null) {
+            headers = Collections
+                    .singletonMap(
+                            MimeHelper.CONTENT_DISPOSITION,
+                            MimeHelper.encodeContentDisposition(MimeHelper.DISPOSITION_ATTACHMENT,
+                                    contentStream.getFileName()));
+        }
+
+        // send content
+        HttpUtils.Response resp = put(url, contentStream.getMimeType(), headers, new HttpUtils.Output() {
+            public void write(OutputStream out) throws Exception {
+                int b;
+                byte[] buffer = new byte[4096];
+
+                while ((b = stream.read(buffer)) > -1) {
+                    out.write(buffer, 0, b);
+                }
+
+                stream.close();
+            }
+        });
+
+        // check response code further
+        if ((resp.getResponseCode() != 200) && (resp.getResponseCode() != 201) && (resp.getResponseCode() != 204)) {
+            throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
+        }
+
+        objectId.setValue(null);
+        if (changeToken != null) {
+            changeToken.setValue(null);
+        }
+    }
+
+    public void deleteContentStream(String repositoryId, Holder<String> objectId, Holder<String> changeToken,
+            ExtensionsData extension) {
+        // we need an object id
+        if ((objectId == null) || (objectId.getValue() == null)) {
+            throw new CmisInvalidArgumentException("Object ID must be set!");
+        }
+
+        // find the link
+        String link = loadLink(repositoryId, objectId.getValue(), Constants.REL_EDITMEDIA, null);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId.getValue(), Constants.REL_EDITMEDIA, null);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        if (changeToken != null) {
+            url.addParameter(Constants.PARAM_CHANGE_TOKEN, changeToken.getValue());
+        }
+
+        delete(url);
+
+        objectId.setValue(null);
+        if (changeToken != null) {
+            changeToken.setValue(null);
+        }
+    }
+
+    // ---- internal ----
+
+    private static void checkCreateProperties(Properties properties) {
+        if ((properties == null) || (properties.getProperties() == null)) {
+            throw new CmisInvalidArgumentException("Properties must be set!");
+        }
+
+        if (!properties.getProperties().containsKey(PropertyIds.OBJECT_TYPE_ID)) {
+            throw new CmisInvalidArgumentException("Property " + PropertyIds.OBJECT_TYPE_ID + " must be set!");
+        }
+
+        if (properties.getProperties().containsKey(PropertyIds.OBJECT_ID)) {
+            throw new CmisInvalidArgumentException("Property " + PropertyIds.OBJECT_ID + " must not be set!");
+        }
+    }
+
+    /**
+     * Handles ACL modifications of newly created objects.
+     */
+    private void handleAclModifications(String repositoryId, AtomEntry entry, Acl addAces, Acl removeAces) {
+        if (!isAclMergeRequired(addAces, removeAces)) {
+            return;
+        }
+
+        Acl originalAces = null;
+
+        // walk through the entry and find the current ACL
+        for (AtomElement element : entry.getElements()) {
+            if (element.getObject() instanceof ObjectData) {
+                // extract current ACL
+                ObjectData object = (ObjectData) element.getObject();
+                originalAces = object.getAcl();
+                // originalAces = convert(object.getAcl(), object.isExactACL());
+
+                break;
+            }
+        }
+
+        if (originalAces != null) {
+            // merge and update ACL
+            Acl newACL = mergeAcls(originalAces, addAces, removeAces);
+            if (newACL != null) {
+                updateAcl(repositoryId, entry.getId(), newACL, null);
+            }
+        }
+    }
+}

Propchange: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/ObjectServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/PolicyServiceImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/PolicyServiceImpl.java?rev=1293440&view=auto
==============================================================================
--- chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/PolicyServiceImpl.java (added)
+++ chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/PolicyServiceImpl.java Fri Feb 24 21:46:54 2012
@@ -0,0 +1,185 @@
+/*
+ * 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.chemistry.opencmis.client.bindings.spi.atompub;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
+import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpUtils;
+import org.apache.chemistry.opencmis.commons.PropertyIds;
+import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.data.ObjectData;
+import org.apache.chemistry.opencmis.commons.data.PropertyData;
+import org.apache.chemistry.opencmis.commons.data.PropertyId;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.spi.PolicyService;
+
+/**
+ * Policy Service AtomPub client.
+ */
+public class PolicyServiceImpl extends AbstractAtomPubService implements PolicyService {
+
+    /**
+     * Constructor.
+     */
+    public PolicyServiceImpl(BindingSession session) {
+        setSession(session);
+    }
+
+    public void applyPolicy(String repositoryId, String policyId, String objectId, ExtensionsData extension) {
+        // find the link
+        String link = loadLink(repositoryId, objectId, Constants.REL_POLICIES, Constants.MEDIATYPE_FEED);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId, Constants.REL_POLICIES, Constants.MEDIATYPE_FEED);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+
+        // set up object and writer
+        final AtomEntryWriter entryWriter = new AtomEntryWriter(createIdObject(objectId));
+
+        // post applyPolicy request
+        post(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
+            public void write(OutputStream out) throws Exception {
+                entryWriter.write(out);
+            }
+        });
+    }
+
+    public List<ObjectData> getAppliedPolicies(String repositoryId, String objectId, String filter,
+            ExtensionsData extension) {
+        List<ObjectData> result = new ArrayList<ObjectData>();
+
+        // find the link
+        String link = loadLink(repositoryId, objectId, Constants.REL_POLICIES, Constants.MEDIATYPE_FEED);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId, Constants.REL_POLICIES, Constants.MEDIATYPE_FEED);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_FILTER, filter);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+        // get the policies
+        if (!feed.getEntries().isEmpty()) {
+            for (AtomEntry entry : feed.getEntries()) {
+                ObjectData policy = null;
+
+                // walk through the entry
+                for (AtomElement element : entry.getElements()) {
+                    if (element.getObject() instanceof ObjectData) {
+                        policy = (ObjectData) element.getObject();
+                    }
+                }
+
+                if (policy != null) {
+                    result.add(policy);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    public void removePolicy(String repositoryId, String policyId, String objectId, ExtensionsData extension) {
+        // we need a policy id
+        if (policyId == null) {
+            throw new CmisInvalidArgumentException("Policy id must be set!");
+        }
+
+        // find the link
+        String link = loadLink(repositoryId, objectId, Constants.REL_POLICIES, Constants.MEDIATYPE_FEED);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId, Constants.REL_POLICIES, Constants.MEDIATYPE_FEED);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_FILTER, PropertyIds.OBJECT_ID);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+        // find the policy
+        String policyLink = null;
+        boolean found = false;
+
+        if (!feed.getEntries().isEmpty()) {
+            for (AtomEntry entry : feed.getEntries()) {
+                // walk through the entry
+                for (AtomElement element : entry.getElements()) {
+                    if (element.getObject() instanceof AtomLink) {
+                        AtomLink atomLink = (AtomLink) element.getObject();
+                        if (Constants.REL_SELF.equals(atomLink.getRel())) {
+                            policyLink = atomLink.getHref();
+                        }
+                    } else if (element.getObject() instanceof ObjectData) {
+                        String id = findIdProperty((ObjectData) element.getObject());
+                        if (policyId.equals(id)) {
+                            found = true;
+                        }
+                    }
+                }
+
+                if (found) {
+                    break;
+                }
+            }
+        }
+
+        // if found, delete it
+        if (found && (policyLink != null)) {
+            delete(new UrlBuilder(policyLink));
+        }
+    }
+
+    /**
+     * Finds the id property within a CMIS object.
+     */
+    private static String findIdProperty(ObjectData object) {
+        if ((object == null) || (object.getProperties() == null)) {
+            return null;
+        }
+
+        for (PropertyData<?> property : object.getProperties().getPropertyList()) {
+            if (PropertyIds.OBJECT_ID.equals(property.getId()) && (property instanceof PropertyId)) {
+                List<String> values = ((PropertyId) property).getValues();
+                if (values.size() == 1) {
+                    return values.get(0);
+                }
+            }
+        }
+
+        return null;
+    }
+}

Propchange: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/PolicyServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RelationshipServiceImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RelationshipServiceImpl.java?rev=1293440&view=auto
==============================================================================
--- chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RelationshipServiceImpl.java (added)
+++ chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RelationshipServiceImpl.java Fri Feb 24 21:46:54 2012
@@ -0,0 +1,120 @@
+/*
+ * 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.chemistry.opencmis.client.bindings.spi.atompub;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+
+import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
+import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpUtils;
+import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.data.ObjectData;
+import org.apache.chemistry.opencmis.commons.data.ObjectList;
+import org.apache.chemistry.opencmis.commons.enums.RelationshipDirection;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
+import org.apache.chemistry.opencmis.commons.spi.RelationshipService;
+
+/**
+ * Relationship Service AtomPub client.
+ */
+public class RelationshipServiceImpl extends AbstractAtomPubService implements RelationshipService {
+
+    /**
+     * Constructor.
+     */
+    public RelationshipServiceImpl(BindingSession session) {
+        setSession(session);
+    }
+
+    public ObjectList getObjectRelationships(String repositoryId, String objectId, Boolean includeSubRelationshipTypes,
+            RelationshipDirection relationshipDirection, String typeId, String filter, Boolean includeAllowableActions,
+            BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
+        ObjectListImpl result = new ObjectListImpl();
+
+        // find the link
+        String link = loadLink(repositoryId, objectId, Constants.REL_RELATIONSHIPS, Constants.MEDIATYPE_FEED);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId, Constants.REL_RELATIONSHIPS, Constants.MEDIATYPE_FEED);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_SUB_RELATIONSHIP_TYPES, includeSubRelationshipTypes);
+        url.addParameter(Constants.PARAM_RELATIONSHIP_DIRECTION, relationshipDirection);
+        url.addParameter(Constants.PARAM_TYPE_ID, typeId);
+        url.addParameter(Constants.PARAM_FILTER, filter);
+        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
+        url.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
+        url.addParameter(Constants.PARAM_SKIP_COUNT, skipCount);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+        // handle top level
+        for (AtomElement element : feed.getElements()) {
+            if (element.getObject() instanceof AtomLink) {
+                if (isNextLink(element)) {
+                    result.setHasMoreItems(Boolean.TRUE);
+                }
+            } else if (isInt(NAME_NUM_ITEMS, element)) {
+                result.setNumItems((BigInteger) element.getObject());
+            }
+        }
+
+        // get the children
+        if (!feed.getEntries().isEmpty()) {
+            result.setObjects(new ArrayList<ObjectData>(feed.getEntries().size()));
+
+            for (AtomEntry entry : feed.getEntries()) {
+                ObjectData relationship = null;
+
+                lockLinks();
+                try {
+                    // clean up cache
+                    removeLinks(repositoryId, entry.getId());
+
+                    // walk through the entry
+                    for (AtomElement element : entry.getElements()) {
+                        if (element.getObject() instanceof AtomLink) {
+                            addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
+                        } else if (element.getObject() instanceof ObjectData) {
+                            relationship = (ObjectData) element.getObject();
+                        }
+                    }
+                } finally {
+                    unlockLinks();
+                }
+
+                if (relationship != null) {
+                    result.getObjects().add(relationship);
+                }
+            }
+
+        }
+
+        return result;
+    }
+}

Propchange: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RelationshipServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RepositoryServiceImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RepositoryServiceImpl.java?rev=1293440&view=auto
==============================================================================
--- chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RepositoryServiceImpl.java (added)
+++ chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RepositoryServiceImpl.java Fri Feb 24 21:46:54 2012
@@ -0,0 +1,213 @@
+/*
+ * 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.chemistry.opencmis.client.bindings.spi.atompub;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
+import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpUtils;
+import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionContainerImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionListImpl;
+import org.apache.chemistry.opencmis.commons.spi.RepositoryService;
+
+/**
+ * Repository Service AtomPub client.
+ */
+public class RepositoryServiceImpl extends AbstractAtomPubService implements RepositoryService {
+
+    /**
+     * Constructor.
+     */
+    public RepositoryServiceImpl(BindingSession session) {
+        setSession(session);
+    }
+
+    public List<RepositoryInfo> getRepositoryInfos(ExtensionsData extension) {
+        return getRepositoriesInternal(null);
+    }
+
+    public RepositoryInfo getRepositoryInfo(String repositoryId, ExtensionsData extension) {
+        List<RepositoryInfo> repositoryInfos = getRepositoriesInternal(repositoryId);
+
+        // find the repository
+        for (RepositoryInfo info : repositoryInfos) {
+            if (info.getId() == null) {
+                continue;
+            }
+
+            if (info.getId().equals(repositoryId)) {
+                return info;
+            }
+        }
+
+        throw new CmisObjectNotFoundException("Repository not found!");
+    }
+
+    public TypeDefinition getTypeDefinition(String repositoryId, String typeId, ExtensionsData extension) {
+        return getTypeDefinitionInternal(repositoryId, typeId);
+    }
+
+    public TypeDefinitionList getTypeChildren(String repositoryId, String typeId, Boolean includePropertyDefinitions,
+            BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
+        TypeDefinitionListImpl result = new TypeDefinitionListImpl();
+
+        // find the link
+        String link = null;
+        if (typeId == null) {
+            link = loadCollection(repositoryId, Constants.COLLECTION_TYPES);
+        } else {
+            link = loadTypeLink(repositoryId, typeId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+        }
+
+        if (link == null) {
+            throw new CmisObjectNotFoundException("Unknown repository or type!");
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_TYPE_ID, typeId);
+        url.addParameter(Constants.PARAM_PROPERTY_DEFINITIONS, includePropertyDefinitions);
+        url.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
+        url.addParameter(Constants.PARAM_SKIP_COUNT, skipCount);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+        // handle top level
+        for (AtomElement element : feed.getElements()) {
+            if (element.getObject() instanceof AtomLink) {
+                if (isNextLink(element)) {
+                    result.setHasMoreItems(Boolean.TRUE);
+                }
+            } else if (isInt(NAME_NUM_ITEMS, element)) {
+                result.setNumItems((BigInteger) element.getObject());
+            }
+        }
+
+        result.setList(new ArrayList<TypeDefinition>(feed.getEntries().size()));
+
+        // get the children
+        if (!feed.getEntries().isEmpty()) {
+            for (AtomEntry entry : feed.getEntries()) {
+                TypeDefinition child = null;
+
+                lockTypeLinks();
+                try {
+                    // walk through the entry
+                    for (AtomElement element : entry.getElements()) {
+                        if (element.getObject() instanceof AtomLink) {
+                            addTypeLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
+                        } else if (element.getObject() instanceof TypeDefinition) {
+                            child = (TypeDefinition) element.getObject();
+                        }
+                    }
+                } finally {
+                    unlockTypeLinks();
+                }
+
+                if (child != null) {
+                    result.getList().add(child);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    public List<TypeDefinitionContainer> getTypeDescendants(String repositoryId, String typeId, BigInteger depth,
+            Boolean includePropertyDefinitions, ExtensionsData extension) {
+        List<TypeDefinitionContainer> result = new ArrayList<TypeDefinitionContainer>();
+
+        // find the link
+        String link = null;
+        if (typeId == null) {
+            link = loadRepositoryLink(repositoryId, Constants.REP_REL_TYPEDESC);
+        } else {
+            link = loadTypeLink(repositoryId, typeId, Constants.REL_DOWN, Constants.MEDIATYPE_DESCENDANTS);
+        }
+
+        if (link == null) {
+            throw new CmisObjectNotFoundException("Unknown repository or type!");
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_TYPE_ID, typeId);
+        url.addParameter(Constants.PARAM_DEPTH, depth);
+        url.addParameter(Constants.PARAM_PROPERTY_DEFINITIONS, includePropertyDefinitions);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+        // process tree
+        addTypeDescendantsLevel(repositoryId, feed, result);
+
+        return result;
+    }
+
+    /**
+     * Adds type descendants level recursively.
+     */
+    private void addTypeDescendantsLevel(String repositoryId, AtomFeed feed, List<TypeDefinitionContainer> containerList) {
+        if ((feed == null) || (feed.getEntries().isEmpty())) {
+            return;
+        }
+
+        // walk through the feed
+        for (AtomEntry entry : feed.getEntries()) {
+            TypeDefinitionContainerImpl childContainer = null;
+            List<TypeDefinitionContainer> childContainerList = new ArrayList<TypeDefinitionContainer>();
+
+            // walk through the entry
+            lockTypeLinks();
+            try {
+                for (AtomElement element : entry.getElements()) {
+                    if (element.getObject() instanceof AtomLink) {
+                        addTypeLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
+                    } else if (element.getObject() instanceof TypeDefinition) {
+                        childContainer = new TypeDefinitionContainerImpl((TypeDefinition) element.getObject());
+                    } else if (element.getObject() instanceof AtomFeed) {
+                        addTypeDescendantsLevel(repositoryId, (AtomFeed) element.getObject(), childContainerList);
+                    }
+                }
+            } finally {
+                unlockTypeLinks();
+            }
+
+            if (childContainer != null) {
+                childContainer.setChildren(childContainerList);
+                containerList.add(childContainer);
+            }
+        }
+    }
+}

Propchange: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RepositoryServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/SpiSessionParameter.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/SpiSessionParameter.java?rev=1293440&view=auto
==============================================================================
--- chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/SpiSessionParameter.java (added)
+++ chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/SpiSessionParameter.java Fri Feb 24 21:46:54 2012
@@ -0,0 +1,30 @@
+/*
+ * 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.chemistry.opencmis.client.bindings.spi.atompub;
+
+/**
+ * Internal session parameters.
+ */
+public final class SpiSessionParameter {
+
+    public static final String LINK_CACHE = "org.apache.chemistry.opencmis.binding.atompub.linkcache";
+
+    private SpiSessionParameter() {
+    }
+}

Propchange: chemistry/opencmis/branches/android/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/SpiSessionParameter.java
------------------------------------------------------------------------------
    svn:eol-style = native