chemistry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jmpas...@apache.org
Subject svn commit: r1341891 [1/5] - in /chemistry/opencmis/trunk: ./ chemistry-opencmis-android/ chemistry-opencmis-android/chemistry-opencmis-android-client/ chemistry-opencmis-android/chemistry-opencmis-android-client/src/ chemistry-opencmis-android/chemist...
Date Wed, 23 May 2012 15:14:44 GMT
Author: jmpascal
Date: Wed May 23 15:14:42 2012
New Revision: 1341891

URL: http://svn.apache.org/viewvc?rev=1341891&view=rev
Log:
CMIS-507 : OpenCMIS client for Android devices
Initial code

Added:
    chemistry/opencmis/trunk/chemistry-opencmis-android/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/pom.xml
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AbstractAtomPubService.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AclServiceImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomPubParser.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubConstants.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubSpi.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/DiscoveryServiceImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/LinkCache.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/MultiFilingServiceImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/NavigationServiceImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/ObjectServiceImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/PolicyServiceImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RelationshipServiceImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/RepositoryServiceImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/SpiSessionParameter.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/VersioningServiceImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/AtomAcl.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/AtomAllowableActions.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/AtomBase.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/AtomElement.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/AtomEntry.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/AtomFeed.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/AtomLink.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/HtmlDoc.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/RepositoryWorkspace.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/objects/ServiceDoc.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/commons/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/commons/enums/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/commons/enums/AtomPropertyType.java
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/commons/impl/
    chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/commons/impl/AtomPubConverter.java
Modified:
    chemistry/opencmis/trunk/pom.xml

Added: chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/pom.xml
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/pom.xml?rev=1341891&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/pom.xml (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/pom.xml Wed May 23 15:14:42 2012
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+    <!--
+        Licensed 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.
+    -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.chemistry.opencmis</groupId>
+		<artifactId>chemistry-opencmis</artifactId>
+		<version>0.8.0-SNAPSHOT</version>
+		<relativePath>../../pom.xml</relativePath>
+	</parent>
+
+	<artifactId>chemistry-opencmis-android-client</artifactId>
+	<name>OpenCMIS Android Client</name>
+	<packaging>jar</packaging>
+
+	<properties>
+		<parentBasedir>../../</parentBasedir>
+	</properties>
+
+
+	<dependencies>
+		<dependency>
+			<groupId>com.googlecode.json-simple</groupId>
+			<artifactId>json-simple</artifactId>
+			<version>1.1</version>
+		</dependency>
+		<dependency>
+			<groupId>com.google.android</groupId>
+			<artifactId>android</artifactId>
+			<version>2.3.3</version>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-simple</artifactId>
+			<version>1.6.1</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+		    <plugin>
+                 <artifactId>maven-antrun-plugin</artifactId>
+                 <version>1.5</version>
+                 <executions>
+                     <execution>
+                         <phase>generate-resources</phase>
+                         <configuration>
+                             <target>
+                          		<property name="gendir" value="${project.build.directory}/opencmis-core" />
+
+								<property name="basedir" value="${maven.basedir}" />
+                                <property name="commons-api" value="${basedir}/../../chemistry-opencmis-commons/chemistry-opencmis-commons-api" />
+                                <property name="commons-impl" value="${basedir}/../../chemistry-opencmis-commons/chemistry-opencmis-commons-impl" />
+                                <property name="client-bindings" value="${basedir}/../../chemistry-opencmis-client/chemistry-opencmis-client-bindings" />
+                                <property name="client-api" value="${basedir}/../../chemistry-opencmis-client/chemistry-opencmis-client-api" />
+                                <property name="client-impl" value="${basedir}/../../chemistry-opencmis-client/chemistry-opencmis-client-impl" />
+
+                                <property name="sourcefiles" value="src/main/java" />
+                                 
+								<copy todir="${gendir}">
+									<fileset dir="${commons-api}/${sourcefiles}">
+										<include name="**/*.java" />
+									</fileset>
+								</copy>
+                                
+                           		<copy todir="${gendir}">
+									<fileset dir="${commons-impl}/${sourcefiles}">
+										<include name="**/*.java" />
+										<exclude name="**/tube/**" />
+										<exclude name="**/jaxb/**" />
+										<exclude name="**/impl/JaxBHelper.*" />
+										<exclude name="**/impl/Converter.*" />
+									</fileset>
+								</copy>
+                                
+                            	<copy todir="${gendir}">
+									<fileset dir="${client-bindings}/${sourcefiles}">
+										<include name="**/*.java" />
+										<exclude name="**/spi/local/**" />
+										<exclude name="**/spi/webservices/**" />
+										<exclude name="**/spi/atompub/**" />
+									</fileset>
+								</copy>                            
+                                
+                            	<copy todir="${gendir}">
+									<fileset dir="${client-api}/${sourcefiles}">
+										<include name="**/*.java" />
+									</fileset>
+								</copy>                            
+                                
+                            	<copy todir="${gendir}">
+									<fileset dir="${client-impl}/${sourcefiles}">
+										<include name="**/*.java" />
+										<exclude name="**/osgi/**" />
+									</fileset>
+								</copy>                                   
+                             </target>
+                         </configuration>
+                         <goals>
+                             <goal>run</goal>
+                         </goals>
+                     </execution>
+                 </executions>
+            </plugin>
+            <plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>build-helper-maven-plugin</artifactId>
+				<executions>
+					<execution>
+						<phase>generate-sources</phase>
+						<goals>
+							<goal>add-source</goal>
+						</goals>
+    			        <configuration>
+    			            <sources>
+   								<source>${project.build.directory}/opencmis-core</source>
+							</sources>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+
+</project>
\ No newline at end of file

Added: chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AbstractAtomPubService.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AbstractAtomPubService.java?rev=1341891&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AbstractAtomPubService.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AbstractAtomPubService.java Wed May 23 15:14:42 2012
@@ -0,0 +1,870 @@
+/*
+ * 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.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
+import org.apache.chemistry.opencmis.client.bindings.spi.LinkAccess;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAcl;
+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.AtomLink;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.RepositoryWorkspace;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.ServiceDoc;
+import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpUtils;
+import org.apache.chemistry.opencmis.commons.PropertyIds;
+import org.apache.chemistry.opencmis.commons.SessionParameter;
+import org.apache.chemistry.opencmis.commons.data.Ace;
+import org.apache.chemistry.opencmis.commons.data.Acl;
+import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.data.ObjectData;
+import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
+import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
+import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisFilterNotValidException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisNameConstraintViolationException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisProxyAuthenticationException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisUnauthorizedException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisVersioningException;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.ReturnVersion;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlEntryImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlPrincipalDataImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdImpl;
+
+/**
+ * Base class for all AtomPub client services.
+ */
+public abstract class AbstractAtomPubService implements LinkAccess {
+
+    protected enum IdentifierType {
+        ID, PATH
+    }
+
+    protected static final String NAME_COLLECTION = "collection";
+    protected static final String NAME_URI_TEMPLATE = "uritemplate";
+    protected static final String NAME_PATH_SEGMENT = "pathSegment";
+    protected static final String NAME_RELATIVE_PATH_SEGMENT = "relativePathSegment";
+    protected static final String NAME_NUM_ITEMS = "numItems";
+
+    private BindingSession session;
+
+    /**
+     * Sets the current session.
+     */
+    protected void setSession(BindingSession session) {
+        this.session = session;
+    }
+
+    /**
+     * Gets the current session.
+     */
+    protected BindingSession getSession() {
+        return session;
+    }
+
+    /**
+     * Returns the service document URL of this session.
+     */
+    protected String getServiceDocURL() {
+        Object url = session.get(SessionParameter.ATOMPUB_URL);
+        if (url instanceof String) {
+            return (String) url;
+        }
+
+        return null;
+    }
+
+    // ---- link cache ----
+
+    /**
+     * Returns the link cache or creates a new cache if it doesn't exist.
+     */
+    protected LinkCache getLinkCache() {
+        LinkCache linkCache = (LinkCache) getSession().get(SpiSessionParameter.LINK_CACHE);
+        if (linkCache == null) {
+            linkCache = new LinkCache(getSession());
+            getSession().put(SpiSessionParameter.LINK_CACHE, linkCache);
+        }
+
+        return linkCache;
+    }
+
+    /**
+     * Gets a link from the cache.
+     */
+    protected String getLink(String repositoryId, String id, String rel, String type) {
+        if (repositoryId == null) {
+            throw new CmisInvalidArgumentException("Repository id must be set!");
+        }
+
+        if (id == null) {
+            throw new CmisInvalidArgumentException("Object id must be set!");
+        }
+
+        return getLinkCache().getLink(repositoryId, id, rel, type);
+    }
+
+    /**
+     * Gets a link from the cache.
+     */
+    protected String getLink(String repositoryId, String id, String rel) {
+        return getLink(repositoryId, id, rel, null);
+    }
+
+    /**
+     * Gets a link from the cache if it is there or loads it into the cache if
+     * it is not there.
+     */
+    public String loadLink(String repositoryId, String id, String rel, String type) {
+        String link = getLink(repositoryId, id, rel, type);
+        if (link == null) {
+            getObjectInternal(repositoryId, IdentifierType.ID, id, ReturnVersion.THIS, null, null, null, null, null,
+                    null, null);
+            link = getLink(repositoryId, id, rel, type);
+        }
+
+        return link;
+    }
+
+    /**
+     * Gets the content link from the cache if it is there or loads it into the
+     * cache if it is not there.
+     */
+    public String loadContentLink(String repositoryId, String id) {
+        return loadLink(repositoryId, id, AtomPubParser.LINK_REL_CONTENT, null);
+    }
+
+    /**
+     * Adds a link to the cache.
+     */
+    protected void addLink(String repositoryId, String id, String rel, String type, String link) {
+        getLinkCache().addLink(repositoryId, id, rel, type, link);
+    }
+
+    /**
+     * Adds a link to the cache.
+     */
+    protected void addLink(String repositoryId, String id, AtomLink link) {
+        getLinkCache().addLink(repositoryId, id, link.getRel(), link.getType(), link.getHref());
+    }
+
+    /**
+     * Removes all links of an object.
+     */
+    protected void removeLinks(String repositoryId, String id) {
+        getLinkCache().removeLinks(repositoryId, id);
+    }
+
+    /**
+     * Locks the link cache.
+     */
+    protected void lockLinks() {
+        getLinkCache().lockLinks();
+    }
+
+    /**
+     * Unlocks the link cache.
+     */
+    protected void unlockLinks() {
+        getLinkCache().unlockLinks();
+    }
+
+    /**
+     * Checks a link throw an appropriate exception.
+     */
+    protected void throwLinkException(String repositoryId, String id, String rel, String type) {
+        int index = getLinkCache().checkLink(repositoryId, id, rel, type);
+
+        switch (index) {
+        case 0:
+            throw new CmisObjectNotFoundException("Unknown repository!");
+        case 1:
+            throw new CmisObjectNotFoundException("Unknown object!");
+        case 2:
+            throw new CmisNotSupportedException("Operation not supported by the repository for this object!");
+        case 3:
+            throw new CmisNotSupportedException("No link with matching media type!");
+        case 4:
+            throw new CmisRuntimeException("Nothing wrong! Either this is a bug or a threading issue.");
+        default:
+            throw new CmisRuntimeException("Unknown error!");
+        }
+    }
+
+    /**
+     * Gets a type link from the cache.
+     */
+    protected String getTypeLink(String repositoryId, String typeId, String rel, String type) {
+        if (repositoryId == null) {
+            throw new CmisInvalidArgumentException("Repository id must be set!");
+        }
+
+        if (typeId == null) {
+            throw new CmisInvalidArgumentException("Type id must be set!");
+        }
+
+        return getLinkCache().getTypeLink(repositoryId, typeId, rel, type);
+    }
+
+    /**
+     * Gets a type link from the cache.
+     */
+    protected String getTypeLink(String repositoryId, String typeId, String rel) {
+        return getTypeLink(repositoryId, typeId, rel, null);
+    }
+
+    /**
+     * Gets a link from the cache if it is there or loads it into the cache if
+     * it is not there.
+     */
+    protected String loadTypeLink(String repositoryId, String typeId, String rel, String type) {
+        String link = getTypeLink(repositoryId, typeId, rel, type);
+        if (link == null) {
+            getTypeDefinitionInternal(repositoryId, typeId);
+            link = getTypeLink(repositoryId, typeId, rel, type);
+        }
+
+        return link;
+    }
+
+    /**
+     * Adds a type link to the cache.
+     */
+    protected void addTypeLink(String repositoryId, String typeId, String rel, String type, String link) {
+        getLinkCache().addTypeLink(repositoryId, typeId, rel, type, link);
+    }
+
+    /**
+     * Adds a type link to the cache.
+     */
+    protected void addTypeLink(String repositoryId, String typeId, AtomLink link) {
+        getLinkCache().addTypeLink(repositoryId, typeId, link.getRel(), link.getType(), link.getHref());
+    }
+
+    /**
+     * Removes all links of a type.
+     */
+    protected void removeTypeLinks(String repositoryId, String id) {
+        getLinkCache().removeTypeLinks(repositoryId, id);
+    }
+
+    /**
+     * Locks the type link cache.
+     */
+    protected void lockTypeLinks() {
+        getLinkCache().lockTypeLinks();
+    }
+
+    /**
+     * Unlocks the type link cache.
+     */
+    protected void unlockTypeLinks() {
+        getLinkCache().unlockTypeLinks();
+    }
+
+    /**
+     * Gets a collection from the cache.
+     */
+    protected String getCollection(String repositoryId, String collection) {
+        return getLinkCache().getCollection(repositoryId, collection);
+    }
+
+    /**
+     * Gets a collection from the cache if it is there or loads it into the
+     * cache if it is not there.
+     */
+    protected String loadCollection(String repositoryId, String collection) {
+        String link = getCollection(repositoryId, collection);
+        if (link == null) {
+            // cache repository info
+            getRepositoriesInternal(repositoryId);
+            link = getCollection(repositoryId, collection);
+        }
+
+        return link;
+    }
+
+    /**
+     * Adds a collection to the cache.
+     */
+    protected void addCollection(String repositoryId, String collection, String link) {
+        getLinkCache().addCollection(repositoryId, collection, link);
+    }
+
+    /**
+     * Gets a repository link from the cache.
+     */
+    protected String getRepositoryLink(String repositoryId, String rel) {
+        return getLinkCache().getRepositoryLink(repositoryId, rel);
+    }
+
+    /**
+     * Gets a repository link from the cache if it is there or loads it into the
+     * cache if it is not there.
+     */
+    protected String loadRepositoryLink(String repositoryId, String rel) {
+        String link = getRepositoryLink(repositoryId, rel);
+        if (link == null) {
+            // cache repository info
+            getRepositoriesInternal(repositoryId);
+            link = getRepositoryLink(repositoryId, rel);
+        }
+
+        return link;
+    }
+
+    /**
+     * Adds a repository link to the cache.
+     */
+    protected void addRepositoryLink(String repositoryId, String rel, String link) {
+        getLinkCache().addRepositoryLink(repositoryId, rel, link);
+    }
+
+    /**
+     * Adds a repository link to the cache.
+     */
+    protected void addRepositoryLink(String repositoryId, AtomLink link) {
+        addRepositoryLink(repositoryId, link.getRel(), link.getHref());
+    }
+
+    /**
+     * Gets an URI template from the cache.
+     */
+    protected String getTemplateLink(String repositoryId, String type, Map<String, Object> parameters) {
+        return getLinkCache().getTemplateLink(repositoryId, type, parameters);
+    }
+
+    /**
+     * Gets a template link from the cache if it is there or loads it into the
+     * cache if it is not there.
+     */
+    protected String loadTemplateLink(String repositoryId, String type, Map<String, Object> parameters) {
+        String link = getTemplateLink(repositoryId, type, parameters);
+        if (link == null) {
+            // cache repository info
+            getRepositoriesInternal(repositoryId);
+            link = getTemplateLink(repositoryId, type, parameters);
+        }
+
+        return link;
+    }
+
+    /**
+     * Adds an URI template to the cache.
+     */
+    protected void addTemplate(String repositoryId, String type, String link) {
+        getLinkCache().addTemplate(repositoryId, type, link);
+    }
+
+    // ---- exceptions ----
+
+    /**
+     * Converts a HTTP status code into an Exception.
+     */
+    protected CmisBaseException convertStatusCode(int code, String message, String errorContent, Throwable t) {
+        String exception = extractException(errorContent);
+        message = extractErrorMessage(message, errorContent);
+
+        switch (code) {
+        case 400:
+            if (CmisFilterNotValidException.EXCEPTION_NAME.equals(exception)) {
+                return new CmisFilterNotValidException(message, errorContent, t);
+            }
+            return new CmisInvalidArgumentException(message, errorContent, t);
+        case 401:
+            return new CmisUnauthorizedException(message, errorContent, t);
+        case 403:
+            if (CmisStreamNotSupportedException.EXCEPTION_NAME.equals(exception)) {
+                return new CmisStreamNotSupportedException(message, errorContent, t);
+            }
+            return new CmisPermissionDeniedException(message, errorContent, t);
+        case 404:
+            return new CmisObjectNotFoundException(message, errorContent, t);
+        case 405:
+            return new CmisNotSupportedException(message, errorContent, t);
+        case 407:
+            return new CmisProxyAuthenticationException(message, errorContent, t);
+        case 409:
+            if (CmisContentAlreadyExistsException.EXCEPTION_NAME.equals(exception)) {
+                return new CmisContentAlreadyExistsException(message, errorContent, t);
+            } else if (CmisVersioningException.EXCEPTION_NAME.equals(exception)) {
+                return new CmisVersioningException(message, errorContent, t);
+            } else if (CmisUpdateConflictException.EXCEPTION_NAME.equals(exception)) {
+                return new CmisUpdateConflictException(message, errorContent, t);
+            } else if (CmisNameConstraintViolationException.EXCEPTION_NAME.equals(exception)) {
+                return new CmisNameConstraintViolationException(message, errorContent, t);
+            }
+            return new CmisConstraintException(message, errorContent, t);
+        default:
+            if (CmisStorageException.EXCEPTION_NAME.equals(exception)) {
+                return new CmisStorageException(message, errorContent, t);
+            }
+            return new CmisRuntimeException(message, errorContent, t);
+        }
+    }
+
+    protected String extractException(String errorContent) {
+        if (errorContent == null) {
+            return null;
+        }
+
+        int begin = errorContent.indexOf("<!--exception-->");
+        int end = errorContent.indexOf("<!--/exception-->");
+
+        if (begin == -1 || end == -1 || begin > end) {
+            return null;
+        }
+
+        return errorContent.substring(begin + "<!--exception-->".length(), end);
+    }
+
+    protected String extractErrorMessage(String message, String errorContent) {
+        if (errorContent == null) {
+            return message;
+        }
+
+        int begin = errorContent.indexOf("<!--message-->");
+        int end = errorContent.indexOf("<!--/message-->");
+
+        if (begin == -1 || end == -1 || begin > end) {
+            return message;
+        }
+
+        return errorContent.substring(begin + "<!--message-->".length(), end);
+    }
+
+    // ---- helpers ----
+
+    protected boolean is(String name, AtomElement element) {
+        return name.equals(element.getName().getLocalPart());
+    }
+
+    protected boolean isStr(String name, AtomElement element) {
+        return is(name, element) && (element.getObject() instanceof String);
+    }
+
+    protected boolean isInt(String name, AtomElement element) {
+        return is(name, element) && (element.getObject() instanceof BigInteger);
+    }
+
+    protected boolean isNextLink(AtomElement element) {
+        return Constants.REL_NEXT.equals(((AtomLink) element.getObject()).getRel());
+    }
+
+    /**
+     * Creates a CMIS object that only contains an id in the property list.
+     * Modified
+     */
+    protected ObjectData createIdObject(String objectId) {
+        ObjectDataImpl object = new ObjectDataImpl();
+
+        PropertiesImpl properties = new PropertiesImpl();
+        object.setProperties(properties);
+
+        PropertyIdImpl idProperty = new PropertyIdImpl(PropertyIds.OBJECT_ID, objectId);
+        properties.addProperty(idProperty);
+
+        return object;
+    }
+
+    /**
+     * Parses an input stream.
+     */
+    @SuppressWarnings("unchecked")
+    protected <T extends AtomBase> T parse(InputStream stream, Class<T> clazz) {
+        AtomPubParser parser = new AtomPubParser(stream);
+
+        try {
+            parser.parse();
+        } catch (Exception e) {
+            throw new CmisConnectionException("Parsing exception!", e);
+        }
+
+        AtomBase parseResult = parser.getResults();
+
+        if (!clazz.isInstance(parseResult)) {
+            throw new CmisConnectionException("Unexpected document! Received "
+                    + (parseResult == null ? "something unknown" : parseResult.getType()) + "!");
+        }
+
+        return (T) parseResult;
+    }
+
+    /**
+     * Performs a GET on an URL, checks the response code and returns the
+     * result.
+     */
+    protected HttpUtils.Response read(UrlBuilder url) {
+        // make the call
+        HttpUtils.Response resp = HttpUtils.invokeGET(url, session);
+
+        // check response code
+        if (resp.getResponseCode() != 200) {
+            throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
+        }
+
+        return resp;
+    }
+
+    /**
+     * Performs a POST on an URL, checks the response code and returns the
+     * result.
+     */
+    protected HttpUtils.Response post(UrlBuilder url, String contentType, HttpUtils.Output writer) {
+        // make the call
+        HttpUtils.Response resp = HttpUtils.invokePOST(url, contentType, writer, session);
+
+        // check response code
+        if (resp.getResponseCode() != 201) {
+            throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
+        }
+
+        return resp;
+    }
+
+    /**
+     * Performs a PUT on an URL, checks the response code and returns the
+     * result.
+     */
+    protected HttpUtils.Response put(UrlBuilder url, String contentType, HttpUtils.Output writer) {
+        return put(url, contentType, null, writer);
+    }
+
+    /**
+     * Performs a PUT on an URL, checks the response code and returns the
+     * result.
+     */
+    protected HttpUtils.Response put(UrlBuilder url, String contentType, Map<String, String> headers,
+            HttpUtils.Output writer) {
+        // make the call
+        HttpUtils.Response resp = HttpUtils.invokePUT(url, contentType, headers, writer, session);
+
+        // check response code
+        if ((resp.getResponseCode() < 200) || (resp.getResponseCode() > 299)) {
+            throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
+        }
+
+        return resp;
+    }
+
+    /**
+     * Performs a DELETE on an URL, checks the response code and returns the
+     * result.
+     */
+    protected void delete(UrlBuilder url) {
+        // make the call
+        HttpUtils.Response resp = HttpUtils.invokeDELETE(url, session);
+
+        // check response code
+        if (resp.getResponseCode() != 204) {
+            throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
+        }
+    }
+
+    // ---- common operations ----
+
+    /**
+     * Checks if at least one ACE list is not empty.
+     */
+    protected boolean isAclMergeRequired(Acl addAces, Acl removeAces) {
+        return (addAces != null && addAces.getAces() != null && !addAces.getAces().isEmpty())
+                || (removeAces != null && removeAces.getAces() != null && !removeAces.getAces().isEmpty());
+    }
+
+    /**
+     * Merges the new ACL from original, add and remove ACEs lists.
+     */
+    protected Acl mergeAcls(Acl originalAces, Acl addAces, Acl removeAces) {
+        Map<String, Set<String>> originals = convertAclToMap(originalAces);
+        Map<String, Set<String>> adds = convertAclToMap(addAces);
+        Map<String, Set<String>> removes = convertAclToMap(removeAces);
+        List<Ace> newAces = new ArrayList<Ace>();
+
+        // iterate through the original ACEs
+        for (Map.Entry<String, Set<String>> ace : originals.entrySet()) {
+
+            // add permissions
+            Set<String> addPermissions = adds.get(ace.getKey());
+            if (addPermissions != null) {
+                ace.getValue().addAll(addPermissions);
+            }
+
+            // remove permissions
+            Set<String> removePermissions = removes.get(ace.getKey());
+            if (removePermissions != null) {
+                ace.getValue().removeAll(removePermissions);
+            }
+
+            // create new ACE
+            if (!ace.getValue().isEmpty()) {
+                newAces.add(new AccessControlEntryImpl(new AccessControlPrincipalDataImpl(ace.getKey()),
+                        new ArrayList<String>(ace.getValue())));
+            }
+        }
+
+        // find all ACEs that should be added but are not in the original ACE
+        // list
+        for (Map.Entry<String, Set<String>> ace : adds.entrySet()) {
+            if (!originals.containsKey(ace.getKey()) && !ace.getValue().isEmpty()) {
+                newAces.add(new AccessControlEntryImpl(new AccessControlPrincipalDataImpl(ace.getKey()),
+                        new ArrayList<String>(ace.getValue())));
+            }
+        }
+
+        return new AccessControlListImpl(newAces);
+    }
+
+    /**
+     * Converts a list of ACEs into Map for better handling.
+     */
+    private static Map<String, Set<String>> convertAclToMap(Acl acl) {
+        Map<String, Set<String>> result = new HashMap<String, Set<String>>();
+
+        if (acl == null || acl.getAces() == null) {
+            return result;
+        }
+
+        for (Ace ace : acl.getAces()) {
+            // don't consider indirect ACEs - we can't change them
+            if (!ace.isDirect()) {
+                // ignore
+                continue;
+            }
+
+            // although a principal must not be null, check it
+            if (ace.getPrincipal() == null || ace.getPrincipal().getId() == null) {
+                // ignore
+                continue;
+            }
+
+            Set<String> permissions = result.get(ace.getPrincipal().getId());
+            if (permissions == null) {
+                permissions = new HashSet<String>();
+                result.put(ace.getPrincipal().getId(), permissions);
+            }
+
+            if (ace.getPermissions() != null) {
+                permissions.addAll(ace.getPermissions());
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Retrieves the Service Document from the server and caches the repository
+     * info objects, collections, links, URI templates, etc.
+     */
+    @SuppressWarnings("unchecked")
+    protected List<RepositoryInfo> getRepositoriesInternal(String repositoryId) {
+        List<RepositoryInfo> repInfos = new ArrayList<RepositoryInfo>();
+
+        // retrieve service doc
+        UrlBuilder url = new UrlBuilder(getServiceDocURL());
+        url.addParameter(Constants.PARAM_REPOSITORY_ID, repositoryId);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        ServiceDoc serviceDoc = parse(resp.getStream(), ServiceDoc.class);
+
+        // walk through the workspaces
+        for (RepositoryWorkspace ws : serviceDoc.getWorkspaces()) {
+            if (ws.getId() == null) {
+                // found a non-CMIS workspace
+                continue;
+            }
+
+            for (AtomElement element : ws.getElements()) {
+                if (is(NAME_COLLECTION, element)) {
+                    Map<String, String> colMap = (Map<String, String>) element.getObject();
+                    addCollection(ws.getId(), colMap.get("collectionType"), colMap.get("href"));
+                } else if (element.getObject() instanceof AtomLink) {
+                    addRepositoryLink(ws.getId(), (AtomLink) element.getObject());
+                } else if (is(NAME_URI_TEMPLATE, element)) {
+                    Map<String, String> tempMap = (Map<String, String>) element.getObject();
+                    addTemplate(ws.getId(), tempMap.get("type"), tempMap.get("template"));
+                } else if (element.getObject() instanceof RepositoryInfo) {
+                    repInfos.add((RepositoryInfo) element.getObject());
+                }
+            }
+        }
+
+        return repInfos;
+    }
+
+    /**
+     * Retrieves an object from the server and caches the links.
+     */
+    protected ObjectData getObjectInternal(String repositoryId, IdentifierType idOrPath, String objectIdOrPath,
+            ReturnVersion returnVersion, String filter, Boolean includeAllowableActions,
+            IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
+            Boolean includeAcl, ExtensionsData extension) {
+
+        Map<String, Object> parameters = new HashMap<String, Object>();
+        parameters.put(Constants.PARAM_ID, objectIdOrPath);
+        parameters.put(Constants.PARAM_PATH, objectIdOrPath);
+        parameters.put(Constants.PARAM_RETURN_VERSION, returnVersion);
+        parameters.put(Constants.PARAM_FILTER, filter);
+        parameters.put(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
+        parameters.put(Constants.PARAM_ACL, includeAcl);
+        parameters.put(Constants.PARAM_POLICY_IDS, includePolicyIds);
+        parameters.put(Constants.PARAM_RELATIONSHIPS, includeRelationships);
+        parameters.put(Constants.PARAM_RENDITION_FILTER, renditionFilter);
+
+        String link = loadTemplateLink(repositoryId, (idOrPath == IdentifierType.ID ? Constants.TEMPLATE_OBJECT_BY_ID
+                : Constants.TEMPLATE_OBJECT_BY_PATH), parameters);
+        if (link == null) {
+            throw new CmisObjectNotFoundException("Unknown repository!");
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        // workaround for missing template parameter in the CMIS spec
+        if (returnVersion != null && returnVersion != ReturnVersion.THIS) {
+            url.addParameter(Constants.PARAM_RETURN_VERSION, returnVersion);
+        }
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        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!");
+        }
+
+        lockLinks();
+        ObjectData result = null;
+        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;
+    }
+
+    /**
+     * Retrieves a type definition.
+     */
+    protected TypeDefinition getTypeDefinitionInternal(String repositoryId, String typeId) {
+
+        Map<String, Object> parameters = new HashMap<String, Object>();
+        parameters.put(Constants.PARAM_ID, typeId);
+
+        String link = loadTemplateLink(repositoryId, Constants.TEMPLATE_TYPE_BY_ID, parameters);
+        if (link == null) {
+            throw new CmisObjectNotFoundException("Unknown repository!");
+        }
+
+        // read and parse
+        HttpUtils.Response resp = read(new UrlBuilder(link));
+        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!");
+        }
+
+        lockTypeLinks();
+        TypeDefinition result = null;
+        try {
+            // clean up cache
+            removeTypeLinks(repositoryId, entry.getId());
+
+            // 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) {
+                    result = (TypeDefinition) element.getObject();
+                }
+            }
+        } finally {
+            unlockTypeLinks();
+        }
+
+        return result;
+    }
+
+    /**
+     * Updates the ACL of an object.
+     */
+    protected AtomAcl updateAcl(String repositoryId, String objectId, final Acl acl, AclPropagation aclPropagation) {
+
+        // find the link
+        String link = loadLink(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
+        }
+
+        UrlBuilder aclUrl = new UrlBuilder(link);
+        aclUrl.addParameter(Constants.PARAM_ACL_PROPAGATION, aclPropagation);
+
+        // update
+        HttpUtils.Response resp = put(aclUrl, Constants.MEDIATYPE_ACL, new HttpUtils.Output() {
+            public void write(OutputStream out) throws Exception {
+                // TODO not implemented
+                AtomEntryWriter.writeACL(out, acl);
+            }
+        });
+
+        // parse new entry
+        return parse(resp.getStream(), AtomAcl.class);
+    }
+
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AclServiceImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AclServiceImpl.java?rev=1341891&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AclServiceImpl.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AclServiceImpl.java Wed May 23 15:14:42 2012
@@ -0,0 +1,83 @@
+/*
+ * 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 org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAcl;
+import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpUtils;
+import org.apache.chemistry.opencmis.commons.data.Acl;
+import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.spi.AclService;
+
+/**
+ * ACL Service AtomPub client.
+ */
+public class AclServiceImpl extends AbstractAtomPubService implements AclService {
+
+    /**
+     * Constructor.
+     */
+    public AclServiceImpl(BindingSession session) {
+        setSession(session);
+    }
+
+    public Acl applyAcl(String repositoryId, String objectId, Acl addAces, Acl removeAces,
+            AclPropagation aclPropagation, ExtensionsData extension) {
+
+        // fetch the current ACL
+        Acl originalAces = getAcl(repositoryId, objectId, false, null);
+
+        // if no changes required, just return the ACL
+        if (!isAclMergeRequired(addAces, removeAces)) {
+            return originalAces;
+        }
+
+        // merge ACLs
+        Acl newACL = mergeAcls(originalAces, addAces, removeAces);
+
+        // update ACL
+        AtomAcl acl = updateAcl(repositoryId, objectId, newACL, aclPropagation);
+        Acl result = acl.getACL();
+
+        return result;
+    }
+
+    public Acl getAcl(String repositoryId, String objectId, Boolean onlyBasicPermissions, ExtensionsData extension) {
+
+        // find the link
+        String link = loadLink(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
+
+        if (link == null) {
+            throwLinkException(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
+        }
+
+        UrlBuilder url = new UrlBuilder(link);
+        url.addParameter(Constants.PARAM_ONLY_BASIC_PERMISSIONS, onlyBasicPermissions);
+
+        // read and parse
+        HttpUtils.Response resp = read(url);
+        AtomAcl acl = parse(resp.getStream(), AtomAcl.class);
+
+        return acl.getACL();
+    }
+
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java?rev=1341891&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-android/chemistry-opencmis-android-client/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java Wed May 23 15:14:42 2012
@@ -0,0 +1,352 @@
+/*
+ * 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 static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.ATTR_PROPERTY_DEFINITION_ID;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ATOM_ID;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ATOM_TITLE;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ATOM_UPDATED;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_CONTENT;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_CONTENT_BASE64;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_CONTENT_MEDIATYPE;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ENTRY;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_QUERY;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_QUERY_STATEMENT;
+import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_VALUE;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.apache.chemistry.opencmis.commons.PropertyIds;
+import org.apache.chemistry.opencmis.commons.data.Acl;
+import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
+import org.apache.chemistry.opencmis.commons.data.ObjectData;
+import org.apache.chemistry.opencmis.commons.data.PropertyBoolean;
+import org.apache.chemistry.opencmis.commons.data.PropertyData;
+import org.apache.chemistry.opencmis.commons.data.PropertyDateTime;
+import org.apache.chemistry.opencmis.commons.data.PropertyDecimal;
+import org.apache.chemistry.opencmis.commons.data.PropertyHtml;
+import org.apache.chemistry.opencmis.commons.data.PropertyId;
+import org.apache.chemistry.opencmis.commons.data.PropertyInteger;
+import org.apache.chemistry.opencmis.commons.data.PropertyString;
+import org.apache.chemistry.opencmis.commons.data.PropertyUri;
+import org.apache.chemistry.opencmis.commons.enums.AtomPropertyType;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.chemistry.opencmis.commons.impl.Base64;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.util.Xml;
+
+/**
+ * Writes a CMIS Atom entry to an output stream.
+ */
+public class AtomEntryWriter {
+
+    private static final String PREFIX_ATOM = "atom";
+    private static final String PREFIX_CMIS = "cmis";
+    private static final String PREFIX_RESTATOM = "cmisra";
+    private static final String ENCODING = "UTF-8";
+
+    private static final int BUFFER_SIZE = 64 * 1024;
+
+    private final ObjectData object;
+    private final InputStream stream;
+    private final String mediaType;
+
+    /**
+     * Constructor.
+     */
+    public AtomEntryWriter(ObjectData object) {
+        this(object, null, null);
+    }
+
+    /**
+     * Constructor.
+     */
+    public AtomEntryWriter(ObjectData object, String mediaType, InputStream stream) {
+        if ((object == null) || (object.getProperties() == null)) {
+            throw new CmisInvalidArgumentException("Object and properties must not be null!");
+        }
+
+        if ((stream != null) && (mediaType == null)) {
+            throw new CmisInvalidArgumentException("Media type must be set if a stream is present!");
+        }
+
+        this.object = object;
+        this.mediaType = mediaType;
+
+        if (stream != null && !(stream instanceof BufferedInputStream) && !(stream instanceof ByteArrayInputStream)) {
+            // avoid double buffering
+            stream = new BufferedInputStream(stream, BUFFER_SIZE);
+        }
+
+        this.stream = stream;
+    }
+
+    /**
+     * Writes the entry to an output stream.
+     */
+    public void write(OutputStream out) throws Exception {
+        XmlSerializer writer = Xml.newSerializer();
+        writer.setOutput(out, ENCODING);
+
+        // start doc
+        writer.startDocument(ENCODING, false);
+        writer.setPrefix(PREFIX_ATOM, Constants.NAMESPACE_ATOM);
+        writer.setPrefix(PREFIX_CMIS, Constants.NAMESPACE_CMIS);
+        writer.setPrefix(PREFIX_RESTATOM, Constants.NAMESPACE_RESTATOM);
+
+        // start entry
+        writer.startTag(Constants.NAMESPACE_ATOM, TAG_ENTRY);
+        writer.attribute("", PREFIX_ATOM, Constants.NAMESPACE_ATOM);
+        writer.attribute("", PREFIX_CMIS, Constants.NAMESPACE_CMIS);
+        writer.attribute("", PREFIX_RESTATOM, Constants.NAMESPACE_RESTATOM);
+
+        // atom:id
+        writeTag(writer, Constants.NAMESPACE_ATOM, TAG_ATOM_ID, "urn:uuid:00000000-0000-0000-0000-00000000000");
+
+        // atom:title
+        writeTag(writer, Constants.NAMESPACE_ATOM, TAG_ATOM_TITLE, getTitle());
+
+        // atom:updated
+        writeTag(writer, Constants.NAMESPACE_ATOM, TAG_ATOM_UPDATED, getUpdated());
+
+        // content
+        if (stream != null) {
+            writer.startTag(Constants.NAMESPACE_RESTATOM, TAG_CONTENT);
+
+            writeTag(writer, Constants.NAMESPACE_RESTATOM, TAG_CONTENT_MEDIATYPE, mediaType);
+
+            writer.startTag(Constants.NAMESPACE_RESTATOM, TAG_CONTENT_BASE64);
+            writeContent(writer);
+            writer.endTag(Constants.NAMESPACE_RESTATOM, TAG_CONTENT_BASE64);
+
+            writer.endTag(Constants.NAMESPACE_RESTATOM, TAG_CONTENT);
+        }
+
+        // object
+        writeObject(writer, object);
+
+        // end entry
+        writer.endTag(Constants.NAMESPACE_ATOM, TAG_ENTRY);
+
+        // end document
+        writer.endDocument();
+
+        writer.flush();
+    }
+
+    public static void writeQuery(OutputStream out, Map<String, String> queryParams) throws Exception {
+        XmlSerializer writer = Xml.newSerializer();
+        writer.setOutput(out, ENCODING);
+        writer.setPrefix(PREFIX_CMIS, Constants.NAMESPACE_CMIS);
+        writer.startTag(Constants.NAMESPACE_CMIS, TAG_QUERY);
+        writer.attribute(null, PREFIX_CMIS, Constants.NAMESPACE_CMIS);
+
+        writer.startTag(Constants.NAMESPACE_CMIS, TAG_QUERY_STATEMENT);
+        writer.cdsect(queryParams.get(TAG_QUERY_STATEMENT));
+        writer.endTag(Constants.NAMESPACE_CMIS, TAG_QUERY_STATEMENT);
+        writeTagIfNotNull(writer, Constants.NAMESPACE_CMIS, Constants.PARAM_SEARCH_ALL_VERSIONS,
+                queryParams.get(Constants.PARAM_SEARCH_ALL_VERSIONS));
+        writeTagIfNotNull(writer, Constants.NAMESPACE_CMIS, Constants.PARAM_ALLOWABLE_ACTIONS,
+                queryParams.get(Constants.PARAM_ALLOWABLE_ACTIONS));
+        writeTagIfNotNull(writer, Constants.NAMESPACE_CMIS, Constants.PARAM_RELATIONSHIPS,
+                queryParams.get(Constants.PARAM_RELATIONSHIPS));
+        writeTagIfNotNull(writer, Constants.NAMESPACE_CMIS, Constants.PARAM_RENDITION_FILTER,
+                queryParams.get(Constants.PARAM_RENDITION_FILTER));
+        writeTagIfNotNull(writer, Constants.NAMESPACE_CMIS, Constants.PARAM_MAX_ITEMS,
+                queryParams.get(Constants.PARAM_MAX_ITEMS));
+        writeTagIfNotNull(writer, Constants.NAMESPACE_CMIS, Constants.PARAM_SKIP_COUNT,
+                queryParams.get(Constants.PARAM_SKIP_COUNT));
+
+        writer.endTag(Constants.NAMESPACE_CMIS, TAG_QUERY);
+        writer.flush();
+    }
+
+    public static void writeACL(OutputStream out, Acl acl) throws Exception {
+        XmlSerializer writer = Xml.newSerializer();
+        writer.setOutput(out, ENCODING);
+        writer.setPrefix(PREFIX_CMIS, Constants.NAMESPACE_CMIS);
+        writer.startTag(Constants.NAMESPACE_CMIS, "acl");
+        writer.attribute(null, PREFIX_CMIS, Constants.NAMESPACE_CMIS);
+
+        writer.startTag(Constants.NAMESPACE_CMIS, "permission");
+
+        // TODO Implements
+        // writeTag(writer, Constants.NAMESPACE_CMIS, "direct",
+        // acl.getAces().get(0).)
+
+        writer.endTag(Constants.NAMESPACE_CMIS, "permission");
+
+        writer.endTag(Constants.NAMESPACE_CMIS, "acl");
+        writer.flush();
+    }
+
+    // ---- internal ----
+
+    private String getTitle() {
+        String result = "";
+
+        List<PropertyData<?>> list = object.getProperties().getPropertyList();
+        for (PropertyData<?> propertyData : list) {
+            if (PropertyIds.NAME.equals(propertyData.getId()) && (propertyData instanceof PropertyString)) {
+                List<String> values = ((PropertyString) propertyData).getValues();
+                if (!values.isEmpty()) {
+                    return values.get(0);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    private static String getUpdated() {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+
+        return sdf.format(new Date());
+    }
+
+    private void writeContent(XmlSerializer writer) throws Exception {
+        Base64.InputStream b64stream = new Base64.InputStream(stream, Base64.ENCODE);
+
+        byte[] buffer = new byte[BUFFER_SIZE * 3 / 4];
+        int b;
+        while ((b = b64stream.read(buffer)) > -1) {
+            if (b > 0) {
+                writer.text(new String(buffer, 0, b, "US-ASCII"));
+            }
+        }
+
+        b64stream.close();
+    }
+
+    private static void writeObject(XmlSerializer writer, ObjectData object) throws Exception {
+        writer.startTag(Constants.NAMESPACE_RESTATOM, Constants.SELECTOR_OBJECT);
+        if (object.getProperties() != null) {
+            writer.startTag(Constants.NAMESPACE_CMIS, Constants.SELECTOR_PROPERTIES);
+            writeProperties(writer, object.getProperties().getPropertyList());
+
+            if (object.getProperties().getExtensions() != null
+                    && object.getProperties().getExtensions().isEmpty() == false) {
+                writeExtensions(writer, object.getProperties().getExtensions());
+            }
+
+            writer.endTag(Constants.NAMESPACE_CMIS, Constants.SELECTOR_PROPERTIES);
+        }
+        writer.endTag(Constants.NAMESPACE_RESTATOM, Constants.SELECTOR_OBJECT);
+    }
+
+    private static void writeTagIfNotNull(XmlSerializer writer, String tagNameSpace, String tagName, String text)
+            throws Exception {
+        if (text != null) {
+            writeTag(writer, tagNameSpace, tagName, text);
+        }
+    }
+
+    private static void writeTag(XmlSerializer writer, String tagNameSpace, String tagName, String text)
+            throws Exception {
+        writer.startTag(tagNameSpace, tagName);
+        writer.text(text);
+        writer.endTag(tagNameSpace, tagName);
+    }
+
+    private static void writeProperties(XmlSerializer writer, List<PropertyData<?>> props) throws Exception {
+        for (PropertyData<?> propertyData : props) {
+            writeProperty(writer, propertyData);
+        }
+    }
+
+    private static void writeProperty(XmlSerializer writer, PropertyData<?> prop) throws Exception {
+        writer.startTag(Constants.NAMESPACE_CMIS, getPropertyTypeTag(prop));
+        writer.attribute(null, ATTR_PROPERTY_DEFINITION_ID, prop.getId());
+        writeValues(writer, prop.getValues());
+        writer.endTag(Constants.NAMESPACE_CMIS, getPropertyTypeTag(prop));
+    }
+
+    private static void writeExtensions(XmlSerializer writer, List<CmisExtensionElement> extensions) throws Exception {
+        for (CmisExtensionElement cmisExtensionElement : extensions) {
+            writer.startTag(cmisExtensionElement.getNamespace(), cmisExtensionElement.getName());
+            writeAttributes(writer, cmisExtensionElement.getAttributes());
+            if (cmisExtensionElement.getChildren() != null && cmisExtensionElement.getChildren().isEmpty() == false) {
+                writeExtensions(writer, cmisExtensionElement.getChildren());
+            } else if (cmisExtensionElement.getValue() != null) {
+                writer.text(cmisExtensionElement.getValue());
+            }
+            writer.endTag(cmisExtensionElement.getNamespace(), cmisExtensionElement.getName());
+        }
+    }
+
+    private static void writeAttributes(XmlSerializer writer, Map<String, String> values) throws Exception {
+        for (Map.Entry<String, String> value : values.entrySet()) {
+            writer.attribute(null, value.getKey(), value.getValue());
+        }
+    }
+
+    private static void writeValues(XmlSerializer writer, List<?> values) throws Exception {
+        for (Object value : values) {
+            writeTag(writer, Constants.NAMESPACE_CMIS, TAG_VALUE, convertPropertyValue(value));
+        }
+    }
+
+    private static String convertPropertyValue(Object value) {
+        if (value == null) {
+            return null;
+        }
+
+        if (value instanceof GregorianCalendar) {
+            return "" + ((GregorianCalendar) value).getTimeInMillis();
+        }
+
+        return value.toString();
+    }
+
+    // Not sure its the right way
+    private static String getPropertyTypeTag(PropertyData<?> prop) {
+        if (prop instanceof PropertyString) {
+            return AtomPropertyType.STRING.value();
+        } else if (prop instanceof PropertyId) {
+            return AtomPropertyType.ID.value();
+        } else if (prop instanceof PropertyBoolean) {
+            return AtomPropertyType.BOOLEAN.value();
+        } else if (prop instanceof PropertyInteger) {
+            return AtomPropertyType.INTEGER.value();
+        } else if (prop instanceof PropertyDecimal) {
+            return AtomPropertyType.DECIMAL.value();
+        } else if (prop instanceof PropertyDateTime) {
+            return AtomPropertyType.DATETIME.value();
+        } else if (prop instanceof PropertyHtml) {
+            return AtomPropertyType.HTML.value();
+        } else if (prop instanceof PropertyUri) {
+            return AtomPropertyType.URI.value();
+        } else {
+            return null;
+        }
+    }
+
+}



Mime
View raw message