You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by dc...@apache.org on 2010/02/16 17:04:07 UTC

svn commit: r910572 [6/36] - in /incubator/chemistry/trunk/opencmis: ./ _dev/ opencmis-client/ opencmis-client/opencmis-client-api/ opencmis-client/opencmis-client-api/src/ opencmis-client/opencmis-client-api/src/main/ opencmis-client/opencmis-client-a...

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/AbstractAuthenticationProvider.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/AbstractAuthenticationProvider.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/AbstractAuthenticationProvider.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/AbstractAuthenticationProvider.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.opencmis.commons.SessionParameter;
+import org.w3c.dom.Element;
+
+/**
+ * Authentication provider class.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public abstract class AbstractAuthenticationProvider implements Serializable {
+
+  private static final long serialVersionUID = 1L;
+
+  private Session fSession;
+
+  /**
+   * Sets the {@link Session} the authentication provider lives in.
+   */
+  public void setSession(Session session) {
+    fSession = session;
+  }
+
+  /**
+   * Returns {@link Session}.
+   */
+  public Session getSession() {
+    return fSession;
+  }
+
+  /**
+   * Returns a set of HTTP headers (key-value pairs) that should be added to a HTTP call. This will
+   * be called by the AtomPub and the Web Services binding. You might want to check the binding in
+   * use before you set the headers.
+   * 
+   * @param url
+   *          the URL of the HTTP call
+   * 
+   * @return the HTTP headers or <code>null</code> if no additional headers should be set
+   */
+  public Map<String, List<String>> getHTTPHeaders(String url) {
+    return null;
+  }
+
+  /**
+   * Returns a SOAP header that should be added to a Web Services call.
+   * 
+   * @param portObject
+   *          the port object
+   * 
+   * @return the SOAP headers or <code>null</code> if no additional headers should be set
+   */
+  public Element getSOAPHeaders(Object portObject) {
+    return null;
+  }
+
+  /**
+   * Gets the user name from the session.
+   * 
+   * @return the user name or <code>null</code> if the user name is not set
+   */
+  protected String getUser() {
+    Object userObject = getSession().get(SessionParameter.USER);
+    if (userObject instanceof String) {
+      return (String) userObject;
+    }
+
+    return null;
+  }
+
+  /**
+   * Gets the password from the session.
+   * 
+   * @return the password or <code>null</code> if the password is not set
+   */
+  protected String getPassword() {
+    Object passwordObject = getSession().get(SessionParameter.PASSWORD);
+    if (passwordObject instanceof String) {
+      return (String) passwordObject;
+    }
+
+    return null;
+  }
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/AbstractAuthenticationProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpi.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpi.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpi.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpi.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi;
+
+import org.apache.opencmis.commons.provider.AclService;
+import org.apache.opencmis.commons.provider.DiscoveryService;
+import org.apache.opencmis.commons.provider.MultiFilingService;
+import org.apache.opencmis.commons.provider.NavigationService;
+import org.apache.opencmis.commons.provider.ObjectService;
+import org.apache.opencmis.commons.provider.PolicyService;
+import org.apache.opencmis.commons.provider.RelationshipService;
+import org.apache.opencmis.commons.provider.RepositoryService;
+import org.apache.opencmis.commons.provider.VersioningService;
+
+/**
+ * CMIS SPI interface.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public interface CmisSpi {
+  /**
+   * Gets a Repository Service interface object.
+   */
+  RepositoryService getRepositoryService();
+
+  /**
+   * Gets a Navigation Service interface object.
+   */
+  NavigationService getNavigationService();
+
+  /**
+   * Gets an Object Service interface object.
+   */
+  ObjectService getObjectService();
+
+  /**
+   * Gets a Versioning Service interface object.
+   */
+  VersioningService getVersioningService();
+
+  /**
+   * Gets a Relationship Service interface object.
+   */
+  RelationshipService getRelationshipService();
+
+  /**
+   * Gets a Discovery Service interface object.
+   */
+  DiscoveryService getDiscoveryService();
+
+  /**
+   * Gets a Multifiling Service interface object.
+   */
+  MultiFilingService getMultiFilingService();
+
+  /**
+   * Gets an ACL Service interface object.
+   */
+  AclService getAclService();
+
+  /**
+   * Gets a Policy Service interface object.
+   */
+  PolicyService getPolicyService();
+
+  /**
+   * Clears all caches of the current session.
+   */
+  void clearAllCaches();
+
+  /**
+   * Clears all caches of the current session that are related to the given repository.
+   * 
+   * @param repositoryId
+   *          the repository id
+   */
+  void clearRepositoryCache(String repositoryId);
+
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpi.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpiFactory.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpiFactory.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpiFactory.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpiFactory.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi;
+
+/**
+ * CMIS SPI factory interface.
+ * 
+ * <p>
+ * A class implementing this interface MUST provide a default constructor.
+ * </p>
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public interface CmisSpiFactory {
+
+  CmisSpi getSpiInstance(Session session);
+
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/CmisSpiFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/Session.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/Session.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/Session.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/Session.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi;
+
+import java.io.Serializable;
+
+/**
+ * CMIS provider session interface.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public interface Session extends Serializable {
+
+  /**
+   * Gets a session value.
+   */
+  Object get(String key);
+
+  /**
+   * Returns a session value or the default value if the key doesn't exist.
+   */
+  Object get(String key, Object defValue);
+
+  /**
+   * Returns a session value or the default value if the key doesn't exist.
+   */
+  int get(String key, int defValue);
+
+  /**
+   * Adds a non-transient session value.
+   */
+  void put(String key, Serializable object);
+
+  /**
+   * Adds a session value.
+   */
+  void put(String key, Object object, boolean isTransient);
+
+  /**
+   * Removes a session value.
+   */
+  void remove(String key);
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/Session.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/StandardAuthenticationProvider.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/StandardAuthenticationProvider.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/StandardAuthenticationProvider.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/StandardAuthenticationProvider.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi;
+
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.opencmis.commons.SessionParameter;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Standard authentication provider class.
+ * 
+ * Adds a basic authentication HTTP header and a WS-Security UsernameToken SOAP header.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class StandardAuthenticationProvider extends AbstractAuthenticationProvider {
+
+  private static final long serialVersionUID = 1L;
+
+  private static final String WSSE_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
+  private static final String WSU_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
+
+  @Override
+  public Map<String, List<String>> getHTTPHeaders(String url) {
+    Map<String, List<String>> result = null;
+
+    // only send HTTP header if configured
+    if (!isTrue(SessionParameter.AUTH_HTTP_BASIC)) {
+      return null;
+    }
+
+    // get user and password
+    String user = getUser();
+    String password = getPassword();
+
+    // if no user is set, don't create HTTP headers
+    if (user == null) {
+      return null;
+    }
+
+    if (password == null) {
+      password = "";
+    }
+
+    String authHeader = "";
+    try {
+      authHeader = "Basic "
+          + new String(Base64.encodeBase64((user + ":" + password).getBytes("ISO-8859-1")),
+              "ISO-8859-1");
+    }
+    catch (UnsupportedEncodingException e) {
+      // shouldn't happen...
+      return null;
+    }
+
+    result = new HashMap<String, List<String>>();
+    result.put("Authorization", Collections.singletonList(authHeader));
+
+    return result;
+  }
+
+  @Override
+  public Element getSOAPHeaders(Object portObject) {
+    // get user and password
+    String user = getUser();
+    String password = getPassword();
+
+    // only send SOAP header if configured
+    if (!isTrue(SessionParameter.AUTH_SOAP_USERNAMETOKEN)) {
+      return null;
+    }
+
+    // if no user is set, don't create SOAP header
+    if (user == null) {
+      return null;
+    }
+
+    if (password == null) {
+      password = "";
+    }
+
+    // set time
+    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+    long created = System.currentTimeMillis();
+    long expires = created + 24 * 60 * 60 * 1000; // 24 hours
+
+    // create the SOAP header
+    try {
+      Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+
+      Element wsseSecurityElement = document.createElementNS(WSSE_NAMESPACE, "Security");
+
+      Element wsuTimestampElement = document.createElementNS(WSU_NAMESPACE, "Timestamp");
+      wsseSecurityElement.appendChild(wsuTimestampElement);
+
+      Element tsCreatedElement = document.createElementNS(WSU_NAMESPACE, "Created");
+      tsCreatedElement.setTextContent(sdf.format(created));
+      wsuTimestampElement.appendChild(tsCreatedElement);
+
+      Element tsExpiresElement = document.createElementNS(WSU_NAMESPACE, "Expires");
+      tsExpiresElement.setTextContent(sdf.format(expires));
+      wsuTimestampElement.appendChild(tsExpiresElement);
+
+      Element usernameTokenElement = document.createElementNS(WSSE_NAMESPACE, "UsernameToken");
+      wsseSecurityElement.appendChild(usernameTokenElement);
+
+      Element usernameElement = document.createElementNS(WSSE_NAMESPACE, "Username");
+      usernameElement.setTextContent(user);
+      usernameTokenElement.appendChild(usernameElement);
+
+      Element passwordElement = document.createElementNS(WSSE_NAMESPACE, "Password");
+      passwordElement.setTextContent(password);
+      passwordElement
+          .setAttribute("Type",
+              "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
+      usernameTokenElement.appendChild(passwordElement);
+
+      Element createdElement = document.createElementNS(WSU_NAMESPACE, "Created");
+      createdElement.setTextContent(sdf.format(created));
+      usernameTokenElement.appendChild(createdElement);
+
+      return wsseSecurityElement;
+    }
+    catch (ParserConfigurationException e) {
+      // shouldn't happen...
+      e.printStackTrace();
+    }
+
+    return null;
+  }
+
+  /**
+   * Returns <code>true</code> if the given parameter exists in the session and is set to true,
+   * <code>false</code> otherwise.
+   */
+  private boolean isTrue(String parameterName) {
+    Object value = getSession().get(parameterName);
+
+    if (value instanceof Boolean) {
+      return ((Boolean) value).booleanValue();
+    }
+
+    if (value instanceof String) {
+      return Boolean.parseBoolean((String) value);
+    }
+
+    return false;
+  }
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/StandardAuthenticationProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AbstractAtomPubService.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AbstractAtomPubService.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AbstractAtomPubService.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AbstractAtomPubService.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,746 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi.atompub;
+
+import static org.apache.opencmis.commons.impl.Converter.convert;
+
+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.opencmis.client.provider.spi.Session;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomBase;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomElement;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomEntry;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomLink;
+import org.apache.opencmis.client.provider.spi.atompub.objects.RepositoryWorkspace;
+import org.apache.opencmis.client.provider.spi.atompub.objects.ServiceDoc;
+import org.apache.opencmis.commons.PropertyIds;
+import org.apache.opencmis.commons.SessionParameter;
+import org.apache.opencmis.commons.api.ExtensionsData;
+import org.apache.opencmis.commons.api.TypeDefinition;
+import org.apache.opencmis.commons.enums.AclPropagation;
+import org.apache.opencmis.commons.enums.IncludeRelationships;
+import org.apache.opencmis.commons.exceptions.CmisBaseException;
+import org.apache.opencmis.commons.exceptions.CmisConnectionException;
+import org.apache.opencmis.commons.exceptions.CmisConstraintException;
+import org.apache.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.opencmis.commons.exceptions.CmisNotSupportedException;
+import org.apache.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.opencmis.commons.exceptions.CmisPermissionDeniedException;
+import org.apache.opencmis.commons.exceptions.CmisRuntimeException;
+import org.apache.opencmis.commons.impl.Constants;
+import org.apache.opencmis.commons.impl.JaxBHelper;
+import org.apache.opencmis.commons.impl.ReturnVersion;
+import org.apache.opencmis.commons.impl.UrlBuilder;
+import org.apache.opencmis.commons.impl.dataobjects.AccessControlEntryImpl;
+import org.apache.opencmis.commons.impl.dataobjects.AccessControlListImpl;
+import org.apache.opencmis.commons.impl.dataobjects.AccessControlPrincipalDataImpl;
+import org.apache.opencmis.commons.impl.jaxb.CmisAccessControlListType;
+import org.apache.opencmis.commons.impl.jaxb.CmisObjectType;
+import org.apache.opencmis.commons.impl.jaxb.CmisPropertiesType;
+import org.apache.opencmis.commons.impl.jaxb.CmisPropertyId;
+import org.apache.opencmis.commons.impl.jaxb.CmisRepositoryInfoType;
+import org.apache.opencmis.commons.impl.jaxb.CmisTypeDefinitionType;
+import org.apache.opencmis.commons.provider.AccessControlEntry;
+import org.apache.opencmis.commons.provider.AccessControlList;
+import org.apache.opencmis.commons.provider.ObjectData;
+import org.apache.opencmis.commons.provider.RepositoryInfoData;
+
+/**
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class AbstractAtomPubService {
+
+  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 Session fSession;
+
+  /**
+   * Sets the current session.
+   */
+  protected void setSession(Session session) {
+    fSession = session;
+  }
+
+  /**
+   * Gets the current session.
+   */
+  protected Session getSession() {
+    return fSession;
+  }
+
+  /**
+   * Returns the service document URL of this session.
+   */
+  protected String getServiceDocURL() {
+    Object url = fSession.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.
+   */
+  protected 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;
+  }
+
+  /**
+   * 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);
+  }
+
+  /**
+   * 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);
+  }
+
+  /**
+   * 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, Throwable t) {
+    switch (code) {
+    case 400:
+      return new CmisInvalidArgumentException(message, t);
+    case 404:
+      return new CmisObjectNotFoundException(message, t);
+    case 403:
+      return new CmisPermissionDeniedException(message, t);
+    case 405:
+      return new CmisNotSupportedException(message, t);
+    case 409:
+      return new CmisConstraintException(message, t);
+    default:
+      return new CmisRuntimeException(message, t);
+    }
+  }
+
+  // ---- 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.
+   */
+  protected CmisObjectType createIdObject(String objectId) {
+    CmisObjectType object = new CmisObjectType();
+
+    CmisPropertiesType properties = new CmisPropertiesType();
+    object.setProperties(properties);
+
+    CmisPropertyId idProperty = new CmisPropertyId();
+    properties.getProperty().add(idProperty);
+    idProperty.setPropertyDefinitionId(PropertyIds.CMIS_OBJECT_ID);
+    idProperty.getValue().add(objectId);
+
+    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, fSession);
+
+    // check response code
+    if (resp.getResponseCode() != 200) {
+      throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), 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, fSession);
+
+    // check response code
+    if (resp.getResponseCode() != 201) {
+      throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), 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) {
+    // make the call
+    HttpUtils.Response resp = HttpUtils.invokePUT(url, contentType, writer, fSession);
+
+    // check response code
+    if ((resp.getResponseCode() < 200) || (resp.getResponseCode() > 299)) {
+      throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), 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, fSession);
+
+    // check response code
+    if (resp.getResponseCode() != 204) {
+      throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), null);
+    }
+  }
+
+  // ---- common operations ----
+
+  /**
+   * Checks if at least one ACE list is not empty.
+   */
+  protected boolean isAclMergeRequired(AccessControlList addAces, AccessControlList 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 AccessControlList mergeAcls(AccessControlList originalAces, AccessControlList addAces,
+      AccessControlList removeAces) {
+
+    if ((originalAces == null) || (originalAces.getAces() == null)) {
+      originalAces = new AccessControlListImpl(new ArrayList<AccessControlEntry>());
+    }
+
+    if ((addAces == null) || (addAces.getAces() == null)) {
+      throw new IllegalArgumentException("add ACEs must not be null!");
+    }
+
+    if ((removeAces == null) || (removeAces.getAces() == null)) {
+      throw new IllegalArgumentException("remove ACEs must not be null!");
+    }
+
+    Map<String, Set<String>> originals = convertACEsToMap(originalAces.getAces());
+    Map<String, Set<String>> adds = convertACEsToMap(addAces.getAces());
+    Map<String, Set<String>> removes = convertACEsToMap(removeAces.getAces());
+    List<AccessControlEntry> newACEs = new ArrayList<AccessControlEntry>();
+
+    // 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 Map<String, Set<String>> convertACEsToMap(List<AccessControlEntry> aces) {
+    Map<String, Set<String>> result = new HashMap<String, Set<String>>();
+
+    for (AccessControlEntry ace : aces) {
+      // 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().getPrincipalId() == null)) {
+        // ignore
+        continue;
+      }
+
+      Set<String> permissions = new HashSet<String>();
+      if (ace.getPermissions() != null) {
+        permissions.addAll(ace.getPermissions());
+      }
+
+      result.put(ace.getPrincipal().getPrincipalId(), permissions);
+    }
+
+    return result;
+  }
+
+  /**
+   * Retrieves the Service Document from the server and caches the repository info objects,
+   * collections, links, URI templates, etc.
+   */
+  @SuppressWarnings("unchecked")
+  protected List<RepositoryInfoData> getRepositoriesInternal(String repositoryId) {
+    List<RepositoryInfoData> repInfos = new ArrayList<RepositoryInfoData>();
+
+    // 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 CmisRepositoryInfoType) {
+          repInfos.add(convert((CmisRepositoryInfoType) 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) {
+    ObjectData result = null;
+
+    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!");
+    }
+
+    // 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 CmisObjectType) {
+        result = convert((CmisObjectType) element.getObject());
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * Retrieves a type definition.
+   */
+  protected TypeDefinition getTypeDefinitionInternal(String repositoryId, String typeId) {
+    TypeDefinition result = null;
+
+    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!");
+    }
+
+    // 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 CmisTypeDefinitionType) {
+        result = convert((CmisTypeDefinitionType) element.getObject());
+        break;
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * Updates the ACL of an object.
+   */
+  protected AtomEntry updateAcl(String repositoryId, String objectId, AccessControlList acl,
+      AclPropagation aclPropagation) {
+
+    // find the link
+    String link = loadLink(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
+
+    if (link == null) {
+      throw new CmisObjectNotFoundException(
+          "Unknown repository or object or ACLs are not supported!");
+    }
+
+    UrlBuilder aclUrl = new UrlBuilder(link);
+    aclUrl.addParameter(Constants.PARAM_ACL_PROPAGATION, aclPropagation);
+
+    // set up object and writer
+    final CmisAccessControlListType aclJaxb = convert(acl);
+
+    // update
+    HttpUtils.Response resp = put(aclUrl, Constants.MEDIATYPE_ACL, new HttpUtils.Output() {
+      public void write(OutputStream out) throws Exception {
+        JaxBHelper.marshal(JaxBHelper.CMIS_OBJECT_FACTORY.createAcl(aclJaxb), out, false);
+      }
+    });
+
+    // parse new entry
+    return parse(resp.getStream(), AtomEntry.class);
+  }
+
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AbstractAtomPubService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AclServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AclServiceImpl.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AclServiceImpl.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AclServiceImpl.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi.atompub;
+
+import static org.apache.opencmis.commons.impl.Converter.convert;
+
+import org.apache.opencmis.client.provider.spi.Session;
+import org.apache.opencmis.client.provider.spi.atompub.objects.Acl;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomElement;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomEntry;
+import org.apache.opencmis.commons.api.ExtensionsData;
+import org.apache.opencmis.commons.enums.AclPropagation;
+import org.apache.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.opencmis.commons.impl.Constants;
+import org.apache.opencmis.commons.impl.UrlBuilder;
+import org.apache.opencmis.commons.impl.jaxb.CmisObjectType;
+import org.apache.opencmis.commons.provider.AccessControlList;
+import org.apache.opencmis.commons.provider.AclService;
+
+/**
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class AclServiceImpl extends AbstractAtomPubService implements AclService {
+
+  /**
+   * Constructor.
+   */
+  public AclServiceImpl(Session session) {
+    setSession(session);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.ACLService#applyACL(java.lang.String, java.lang.String,
+   * org.apache.opencmis.client.provider.AccessControlList, org.apache.opencmis.client.provider.AccessControlList,
+   * org.apache.opencmis.commons.enums.ACLPropagation, org.apache.opencmis.client.provider.ExtensionsData)
+   */
+  public AccessControlList applyAcl(String repositoryId, String objectId,
+      AccessControlList addAces, AccessControlList removeAces, AclPropagation aclPropagation,
+      ExtensionsData extension) {
+    AccessControlList result = null;
+
+    // fetch the current ACL
+    AccessControlList originalAces = getAcl(repositoryId, objectId, false, null);
+
+    // if no changes required, just return the ACL
+    if (!isAclMergeRequired(addAces, removeAces)) {
+      return originalAces;
+    }
+
+    // merge ACLs
+    AccessControlList newACL = mergeAcls(originalAces, addAces, removeAces);
+
+    // update ACL
+    AtomEntry entry = updateAcl(repositoryId, objectId, newACL, aclPropagation);
+
+    // walk through the entry and find updated ACL
+    for (AtomElement element : entry.getElements()) {
+      if (element.getObject() instanceof CmisObjectType) {
+        // extract new ACL
+        CmisObjectType object = (CmisObjectType) element.getObject();
+        result = convert(object.getAcl(), object.isExactACL());
+
+        break;
+      }
+    }
+
+    return result;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.ACLService#getACL(java.lang.String, java.lang.String,
+   * java.lang.Boolean, org.apache.opencmis.client.provider.ExtensionsData)
+   */
+  public AccessControlList 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) {
+      throw new CmisObjectNotFoundException("Unknown repository or object or ACLs are not support!");
+    }
+
+    UrlBuilder url = new UrlBuilder(link);
+    url.addParameter(Constants.PARAM_ONLY_BASIC_PERMISSIONS, onlyBasicPermissions);
+
+    // read and parse
+    HttpUtils.Response resp = read(url);
+    Acl acl = parse(resp.getStream(), Acl.class);
+
+    return convert(acl.getACL(), null);
+  }
+
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AclServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomEntryWriter.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomEntryWriter.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomEntryWriter.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomEntryWriter.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi.atompub;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.opencmis.commons.PropertyIds;
+import org.apache.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.opencmis.commons.impl.Constants;
+import org.apache.opencmis.commons.impl.JaxBHelper;
+import org.apache.opencmis.commons.impl.jaxb.CmisObjectType;
+import org.apache.opencmis.commons.impl.jaxb.CmisProperty;
+import org.apache.opencmis.commons.impl.jaxb.CmisPropertyString;
+
+/**
+ * Writes a CMIS Atom entry to an output stream.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class AtomEntryWriter implements CmisAtomPubConstants {
+
+  private static final String PREFIX_ATOM = "atom";
+  private static final String PREFIX_CMIS = "cmis";
+  private static final String PREFIX_RESTATOM = "cmisra";
+
+  private static final int BUFFER_SIZE = 4096;
+
+  private CmisObjectType fObject;
+  private InputStream fStream;
+  private String fMediaType;
+
+  /**
+   * Constructor.
+   */
+  public AtomEntryWriter(CmisObjectType object) {
+    this(object, null, null);
+  }
+
+  /**
+   * Constructor.
+   */
+  public AtomEntryWriter(CmisObjectType 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!");
+    }
+
+    fObject = object;
+    fMediaType = mediaType;
+    fStream = stream;
+  }
+
+  /**
+   * Writes the entry to an output stream.
+   */
+  public void write(OutputStream out) throws Exception {
+    XMLOutputFactory factory = XMLOutputFactory.newInstance();
+    XMLStreamWriter writer = factory.createXMLStreamWriter(out, "UTF-8");
+
+    writer.setPrefix(PREFIX_ATOM, Constants.NAMESPACE_ATOM);
+    writer.setPrefix(PREFIX_CMIS, Constants.NAMESPACE_CMIS);
+    writer.setPrefix(PREFIX_RESTATOM, Constants.NAMESPACE_RESTATOM);
+
+    // start doc
+    writer.writeStartDocument();
+
+    // start entry
+    writer.writeStartElement(Constants.NAMESPACE_ATOM, TAG_ENTRY);
+    writer.writeNamespace(PREFIX_ATOM, Constants.NAMESPACE_ATOM);
+    writer.writeNamespace(PREFIX_CMIS, Constants.NAMESPACE_CMIS);
+    writer.writeNamespace(PREFIX_RESTATOM, Constants.NAMESPACE_RESTATOM);
+
+    // atom:id
+    writer.writeStartElement(Constants.NAMESPACE_ATOM, TAG_ATOM_ID);
+    writer.writeCharacters("urn:uuid:00000000-0000-0000-0000-00000000000");
+    writer.writeEndElement();
+
+    // atom:title
+    writer.writeStartElement(Constants.NAMESPACE_ATOM, TAG_ATOM_TITLE);
+    writer.writeCharacters(getTitle());
+    writer.writeEndElement();
+
+    // atom:updated
+    writer.writeStartElement(Constants.NAMESPACE_ATOM, TAG_ATOM_UPDATED);
+    writer.writeCharacters(getUpdated());
+    writer.writeEndElement();
+
+    // content
+    if (fStream != null) {
+      writer.writeStartElement(Constants.NAMESPACE_RESTATOM, TAG_CONTENT);
+
+      writer.writeStartElement(Constants.NAMESPACE_RESTATOM, TAG_CONTENT_MEDIATYPE);
+      writer.writeCharacters(fMediaType);
+      writer.writeEndElement();
+
+      writer.writeStartElement(Constants.NAMESPACE_RESTATOM, TAG_CONTENT_BASE64);
+      writer.writeCharacters(getContent());
+      writer.writeEndElement();
+
+      writer.writeEndElement();
+    }
+
+    // object
+    JaxBHelper.marshal(JaxBHelper.CMIS_EXTRA_OBJECT_FACTORY.createObject(fObject), writer, true);
+
+    // end entry
+    writer.writeEndElement();
+
+    // end document
+    writer.writeEndDocument();
+
+    writer.flush();
+  }
+
+  // ---- internal ----
+
+  private String getTitle() {
+    String result = "";
+
+    for (CmisProperty property : fObject.getProperties().getProperty()) {
+      if (PropertyIds.CMIS_NAME.equals(property.getPropertyDefinitionId())
+          && (property instanceof CmisPropertyString)) {
+        List<String> values = ((CmisPropertyString) property).getValue();
+        if (!values.isEmpty()) {
+          return values.get(0);
+        }
+      }
+    }
+
+    return result;
+  }
+
+  private String getUpdated() {
+    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+    return sdf.format(new Date());
+  }
+
+  private String getContent() throws Exception {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+    byte[] buffer = new byte[BUFFER_SIZE];
+    int b;
+    while ((b = fStream.read(buffer)) > -1) {
+      baos.write(buffer, 0, b);
+    }
+
+    return new String(Base64.encodeBase64Chunked(baos.toByteArray()), "UTF-8");
+  }
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomEntryWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomPubParser.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomPubParser.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomPubParser.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomPubParser.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,644 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi.atompub;
+
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.opencmis.client.provider.spi.atompub.objects.Acl;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AllowableActions;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomBase;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomElement;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomEntry;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomFeed;
+import org.apache.opencmis.client.provider.spi.atompub.objects.AtomLink;
+import org.apache.opencmis.client.provider.spi.atompub.objects.RepositoryWorkspace;
+import org.apache.opencmis.client.provider.spi.atompub.objects.ServiceDoc;
+import org.apache.opencmis.commons.impl.Constants;
+import org.apache.opencmis.commons.impl.JaxBHelper;
+import org.apache.opencmis.commons.impl.jaxb.CmisAccessControlListType;
+import org.apache.opencmis.commons.impl.jaxb.CmisAllowableActionsType;
+import org.apache.opencmis.commons.impl.jaxb.CmisObjectType;
+import org.apache.opencmis.commons.impl.jaxb.CmisProperty;
+import org.apache.opencmis.commons.impl.jaxb.CmisPropertyId;
+import org.apache.opencmis.commons.impl.jaxb.CmisRepositoryInfoType;
+import org.apache.opencmis.commons.impl.jaxb.CmisTypeDefinitionType;
+import org.apache.opencmis.commons.impl.jaxb.EnumPropertiesBase;
+
+/**
+ * AtomPub Parser.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class AtomPubParser implements CmisAtomPubConstants {
+
+  // public constants
+  public static final String LINK_REL_CONTENT = "@@content@@";
+
+  private InputStream fStream;
+  private AtomBase fParseResult;
+
+  public AtomPubParser(InputStream stream) {
+    if (stream == null) {
+      throw new IllegalArgumentException("No stream.");
+    }
+
+    fStream = stream;
+  }
+
+  /**
+   * Parses the stream.
+   */
+  public void parse() throws Exception {
+    XMLInputFactory factory = XMLInputFactory.newInstance();
+    XMLStreamReader parser = factory.createXMLStreamReader(fStream);
+
+    while (true) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.START_ELEMENT) {
+        QName name = parser.getName();
+
+        if (Constants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
+          if (TAG_FEED.equals(name.getLocalPart())) {
+            fParseResult = parseFeed(parser);
+            break;
+          }
+          else if (TAG_ENTRY.equals(name.getLocalPart())) {
+            fParseResult = parseEntry(parser);
+            break;
+          }
+        }
+        else if (Constants.NAMESPACE_CMIS.equals(name.getNamespaceURI())) {
+          if (TAG_ALLOWABLEACTIONS.equals(name.getLocalPart())) {
+            fParseResult = parseAllowableActions(parser);
+            break;
+          }
+          else if (TAG_ACL.equals(name.getLocalPart())) {
+            fParseResult = parseACL(parser);
+            break;
+          }
+        }
+        else if (Constants.NAMESPACE_APP.equals(name.getNamespaceURI())) {
+          if (TAG_SERVICE.equals(name.getLocalPart())) {
+            fParseResult = parseServiceDoc(parser);
+            break;
+          }
+        }
+      }
+
+      if (!next(parser)) {
+        break;
+      }
+    }
+
+    parser.close();
+  }
+
+  /**
+   * Return the parse results.
+   */
+  public AtomBase getResults() {
+    return fParseResult;
+  }
+
+  /**
+   * Parses a service document.
+   */
+  private ServiceDoc parseServiceDoc(XMLStreamReader parser) throws Exception {
+    ServiceDoc result = new ServiceDoc();
+
+    next(parser);
+
+    while (true) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.START_ELEMENT) {
+        QName name = parser.getName();
+
+        if (Constants.NAMESPACE_APP.equals(name.getNamespaceURI())) {
+          if (TAG_WORKSPACE.equals(name.getLocalPart())) {
+            result.addWorkspace(parseWorkspace(parser));
+          }
+          else {
+            skip(parser);
+          }
+        }
+        else {
+          skip(parser);
+        }
+      }
+      else if (event == XMLStreamReader.END_ELEMENT) {
+        break;
+      }
+      else {
+        if (!next(parser)) {
+          break;
+        }
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * Parses a workspace element in a service document.
+   */
+  private RepositoryWorkspace parseWorkspace(XMLStreamReader parser) throws Exception {
+    RepositoryWorkspace workspace = new RepositoryWorkspace();
+
+    next(parser);
+
+    while (true) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.START_ELEMENT) {
+        AtomElement element = parseWorkspaceElement(parser);
+
+        // check if we can extract the workspace id
+        if ((element != null) && (element.getObject() instanceof CmisRepositoryInfoType)) {
+          workspace.setId(((CmisRepositoryInfoType) element.getObject()).getRepositoryId());
+        }
+
+        // add to workspace
+        workspace.addElement(element);
+      }
+      else if (event == XMLStreamReader.END_ELEMENT) {
+        break;
+      }
+      else {
+        if (!next(parser)) {
+          break;
+        }
+      }
+    }
+
+    next(parser);
+
+    return workspace;
+  }
+
+  /**
+   * Parses an Atom feed.
+   */
+  private AtomFeed parseFeed(XMLStreamReader parser) throws Exception {
+    AtomFeed result = new AtomFeed();
+
+    next(parser);
+
+    while (true) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.START_ELEMENT) {
+        QName name = parser.getName();
+
+        if (Constants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
+          if (TAG_LINK.equals(name.getLocalPart())) {
+            result.addElement(parseLink(parser));
+          }
+          else if (TAG_ENTRY.equals(name.getLocalPart())) {
+            result.addEntry(parseEntry(parser));
+          }
+          else {
+            skip(parser);
+          }
+        }
+        else if (Constants.NAMESPACE_RESTATOM.equals(name.getNamespaceURI())) {
+          if (TAG_NUM_ITEMS.equals(name.getLocalPart())) {
+            result.addElement(parseBigInteger(parser));
+          }
+          else {
+            skip(parser);
+          }
+        }
+        else {
+          skip(parser);
+        }
+      }
+      else if (event == XMLStreamReader.END_ELEMENT) {
+        break;
+      }
+      else {
+        if (!next(parser)) {
+          break;
+        }
+      }
+    }
+
+    next(parser);
+
+    return result;
+  }
+
+  /**
+   * Parses an Atom entry.
+   */
+  private AtomEntry parseEntry(XMLStreamReader parser) throws Exception {
+    AtomEntry result = new AtomEntry();
+
+    next(parser);
+
+    // walk through all tags in entry
+    while (true) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.START_ELEMENT) {
+        AtomElement element = parseElement(parser);
+        if (element != null) {
+          // add to entry
+          result.addElement(element);
+
+          // find and set object id
+          if (element.getObject() instanceof CmisObjectType) {
+            for (CmisProperty prop : ((CmisObjectType) element.getObject()).getProperties()
+                .getProperty()) {
+              if (EnumPropertiesBase.CMIS_OBJECT_ID.value().equals(prop.getPropertyDefinitionId())) {
+                result.setId(((CmisPropertyId) prop).getValue().get(0));
+              }
+            }
+          }
+          else if (element.getObject() instanceof CmisTypeDefinitionType) {
+            result.setId(((CmisTypeDefinitionType) element.getObject()).getId());
+          }
+        }
+      }
+      else if (event == XMLStreamReader.END_ELEMENT) {
+        break;
+      }
+      else {
+        if (!next(parser)) {
+          break;
+        }
+      }
+    }
+
+    next(parser);
+
+    return result;
+  }
+
+  /**
+   * Parses an Allowable Actions document.
+   */
+  private AllowableActions parseAllowableActions(XMLStreamReader parser) throws Exception {
+    AtomElement elemenet = unmarshalElement(parser, CmisAllowableActionsType.class);
+    return new AllowableActions((CmisAllowableActionsType) elemenet.getObject());
+  }
+
+  /**
+   * Parses an ACL document.
+   */
+  private Acl parseACL(XMLStreamReader parser) throws Exception {
+    AtomElement elemenet = unmarshalElement(parser, CmisAccessControlListType.class);
+    return new Acl((CmisAccessControlListType) elemenet.getObject());
+  }
+
+  /**
+   * Parses an element.
+   */
+  private AtomElement parseElement(XMLStreamReader parser) throws Exception {
+    QName name = parser.getName();
+
+    if (Constants.NAMESPACE_RESTATOM.equals(name.getNamespaceURI())) {
+      if (TAG_OBJECT.equals(name.getLocalPart())) {
+        return unmarshalElement(parser, CmisObjectType.class);
+      }
+      else if (TAG_PATH_SEGMENT.equals(name.getLocalPart())
+          || TAG_RELATIVE_PATH_SEGMENT.equals(name.getLocalPart())) {
+        return parseText(parser);
+      }
+      else if (TAG_TYPE.equals(name.getLocalPart())) {
+        return unmarshalElement(parser, CmisTypeDefinitionType.class);
+      }
+      else if (TAG_CHILDREN.equals(name.getLocalPart())) {
+        return parseChildren(parser);
+      }
+    }
+    else if (Constants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
+      if (TAG_LINK.equals(name.getLocalPart())) {
+        return parseLink(parser);
+      }
+      else if (TAG_CONTENT.equals(name.getLocalPart())) {
+        return parseAtomContentSrc(parser);
+      }
+    }
+
+    // we don't know it - skip it
+    skip(parser);
+
+    return null;
+  }
+
+  /**
+   * Unmarshals a JAXB element.
+   */
+  private <T> AtomElement unmarshalElement(XMLStreamReader parser, Class<T> cmisType)
+      throws Exception {
+    QName name = parser.getName();
+
+    Unmarshaller u = JaxBHelper.createUnmarshaller();
+    JAXBElement<T> object = u.unmarshal(parser, cmisType);
+
+    return new AtomElement(name, object.getValue());
+  }
+
+  /**
+   * Parses a children element.
+   */
+  private AtomElement parseChildren(XMLStreamReader parser) throws Exception {
+    AtomElement result = null;
+    QName childName = parser.getName();
+
+    next(parser);
+
+    // walk through the children tag
+    while (true) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.START_ELEMENT) {
+        QName name = parser.getName();
+
+        if (Constants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
+          if (TAG_FEED.equals(name.getLocalPart())) {
+            result = new AtomElement(childName, parseFeed(parser));
+          }
+          else {
+            skip(parser);
+          }
+        }
+        else {
+          skip(parser);
+        }
+      }
+      else if (event == XMLStreamReader.END_ELEMENT) {
+        break;
+      }
+      else {
+        if (!next(parser)) {
+          break;
+        }
+      }
+    }
+
+    next(parser);
+
+    return result;
+  }
+
+  /**
+   * Parses a workspace element.
+   */
+  private AtomElement parseWorkspaceElement(XMLStreamReader parser) throws Exception {
+    QName name = parser.getName();
+
+    if (Constants.NAMESPACE_RESTATOM.equals(name.getNamespaceURI())) {
+      if (TAG_REPOSITORY_INFO.equals(name.getLocalPart())) {
+        return unmarshalElement(parser, CmisRepositoryInfoType.class);
+      }
+      else if (TAG_URI_TEMPLATE.equals(name.getLocalPart())) {
+        return parseTemplate(parser);
+      }
+    }
+    else if (Constants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
+      if (TAG_LINK.equals(name.getLocalPart())) {
+        return parseLink(parser);
+      }
+    }
+    else if (Constants.NAMESPACE_APP.equals(name.getNamespaceURI())) {
+      if (TAG_COLLECTION.equals(name.getLocalPart())) {
+        return parseCollection(parser);
+      }
+    }
+
+    // we don't know it - skip it
+    skip(parser);
+
+    return null;
+  }
+
+  /**
+   * Parses a collection tag.
+   */
+  private AtomElement parseCollection(XMLStreamReader parser) throws Exception {
+    QName name = parser.getName();
+    Map<String, String> result = new HashMap<String, String>();
+
+    result.put("href", parser.getAttributeValue(null, "href"));
+
+    next(parser);
+
+    while (true) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.START_ELEMENT) {
+        QName tagName = parser.getName();
+        if (Constants.NAMESPACE_RESTATOM.equals(tagName.getNamespaceURI())
+            && TAG_COLLECTION_TYPE.equals(tagName.getLocalPart())) {
+          result.put("collectionType", readText(parser));
+        }
+        else {
+          skip(parser);
+        }
+      }
+      else if (event == XMLStreamReader.END_ELEMENT) {
+        break;
+      }
+      else {
+        if (!next(parser)) {
+          break;
+        }
+      }
+    }
+
+    next(parser);
+
+    return new AtomElement(name, result);
+  }
+
+  /**
+   * Parses a template tag.
+   */
+  private AtomElement parseTemplate(XMLStreamReader parser) throws Exception {
+    QName name = parser.getName();
+    Map<String, String> result = new HashMap<String, String>();
+
+    next(parser);
+
+    while (true) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.START_ELEMENT) {
+        QName tagName = parser.getName();
+        if (Constants.NAMESPACE_RESTATOM.equals(tagName.getNamespaceURI())) {
+          if (TAG_TEMPLATE_TEMPLATE.equals(tagName.getLocalPart())) {
+            result.put("template", readText(parser));
+          }
+          else if (TAG_TEMPLATE_TYPE.equals(tagName.getLocalPart())) {
+            result.put("type", readText(parser));
+          }
+          else {
+            skip(parser);
+          }
+        }
+        else {
+          skip(parser);
+        }
+      }
+      else if (event == XMLStreamReader.END_ELEMENT) {
+        break;
+      }
+      else {
+        if (!next(parser)) {
+          break;
+        }
+      }
+    }
+
+    next(parser);
+
+    return new AtomElement(name, result);
+  }
+
+  /**
+   * Parses a link tag.
+   */
+  private AtomElement parseLink(XMLStreamReader parser) throws Exception {
+    QName name = parser.getName();
+    AtomLink result = new AtomLink();
+
+    // save attributes
+    for (int i = 0; i < parser.getAttributeCount(); i++) {
+      if (LINK_REL.equals(parser.getAttributeLocalName(i))) {
+        result.setRel(parser.getAttributeValue(i));
+      }
+      else if (LINK_HREF.equals(parser.getAttributeLocalName(i))) {
+        result.setHref(parser.getAttributeValue(i));
+      }
+      else if (LINK_TYPE.equals(parser.getAttributeLocalName(i))) {
+        result.setType(parser.getAttributeValue(i));
+      }
+    }
+
+    // skip enclosed tags, if any
+    skip(parser);
+
+    return new AtomElement(name, result);
+  }
+
+  /**
+   * Parses a link tag.
+   */
+  private AtomElement parseAtomContentSrc(XMLStreamReader parser) throws Exception {
+    QName name = parser.getName();
+    AtomLink result = new AtomLink();
+    result.setRel(LINK_REL_CONTENT);
+
+    // save attributes
+    for (int i = 0; i < parser.getAttributeCount(); i++) {
+      if (CONTENT_SRC.equals(parser.getAttributeLocalName(i))) {
+        result.setHref(parser.getAttributeValue(i));
+      }
+    }
+
+    // skip enclosed tags, if any
+    skip(parser);
+
+    return new AtomElement(name, result);
+  }
+
+  /**
+   * Parses a text tag.
+   */
+  private AtomElement parseText(XMLStreamReader parser) throws Exception {
+    QName name = parser.getName();
+    return new AtomElement(name, readText(parser));
+  }
+
+  /**
+   * Parses a text tag and convert it into an integer.
+   */
+  private AtomElement parseBigInteger(XMLStreamReader parser) throws Exception {
+    QName name = parser.getName();
+    return new AtomElement(name, new BigInteger(readText(parser)));
+  }
+
+  /**
+   * Parses a tag that contains text.
+   */
+  private String readText(XMLStreamReader parser) throws Exception {
+    StringBuilder sb = new StringBuilder();
+
+    next(parser);
+
+    while (true) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.END_ELEMENT) {
+        break;
+      }
+      else if (event == XMLStreamReader.CHARACTERS) {
+        String s = parser.getText();
+        if (s != null) {
+          sb.append(s);
+        }
+      }
+      else if (event == XMLStreamReader.START_ELEMENT) {
+        throw new RuntimeException("Unexpected tag: " + parser.getName());
+      }
+
+      if (!next(parser)) {
+        break;
+      }
+    }
+
+    next(parser);
+
+    return sb.toString();
+  }
+
+  /**
+   * Skips a tag or subtree.
+   */
+  private void skip(XMLStreamReader parser) throws Exception {
+    int level = 1;
+    while (next(parser)) {
+      int event = parser.getEventType();
+      if (event == XMLStreamReader.START_ELEMENT) {
+        level++;
+      }
+      else if (event == XMLStreamReader.END_ELEMENT) {
+        level--;
+        if (level == 0) {
+          break;
+        }
+      }
+    }
+
+    next(parser);
+  }
+
+  private boolean next(XMLStreamReader parser) throws Exception {
+    if (parser.hasNext()) {
+      parser.next();
+      return true;
+    }
+
+    return false;
+  }
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/AtomPubParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/CmisAtomPubConstants.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/CmisAtomPubConstants.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/CmisAtomPubConstants.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/CmisAtomPubConstants.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi.atompub;
+
+/**
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public interface CmisAtomPubConstants {
+
+  // service doc
+  String TAG_SERVICE = "service";
+  String TAG_WORKSPACE = "workspace";
+  String TAG_REPOSITORY_INFO = "repositoryInfo";
+  String TAG_COLLECTION = "collection";
+  String TAG_COLLECTION_TYPE = "collectionType";
+  String TAG_URI_TEMPLATE = "uritemplate";
+  String TAG_TEMPLATE_TEMPLATE = "template";
+  String TAG_TEMPLATE_TYPE = "type";
+  String TAG_LINK = "link";
+
+  // atom
+  String TAG_ATOM_ID = "id";
+  String TAG_ATOM_TITLE = "title";
+  String TAG_ATOM_UPDATED = "updated";
+
+  // feed
+  String TAG_FEED = "feed";
+
+  // entry
+  String TAG_ENTRY = "entry";
+  String TAG_OBJECT = "object";
+  String TAG_NUM_ITEMS = "numItems";
+  String TAG_PATH_SEGMENT = "pathSegment";
+  String TAG_RELATIVE_PATH_SEGMENT = "relativePathSegment";
+  String TAG_TYPE = "type";
+  String TAG_CHILDREN = "children";
+  String TAG_CONTENT = "content";
+  String TAG_CONTENT_MEDIATYPE = "mediatype";
+  String TAG_CONTENT_BASE64 = "base64";
+
+  // allowable actions
+  String TAG_ALLOWABLEACTIONS = "allowableActions";
+
+  // ACL
+  String TAG_ACL = "acl";
+
+  // links
+  String LINK_REL = "rel";
+  String LINK_HREF = "href";
+  String LINK_TYPE = "type";
+  String CONTENT_SRC = "src";
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/CmisAtomPubConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/CmisAtomPubSpi.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/CmisAtomPubSpi.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/CmisAtomPubSpi.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-provider-impl/src/main/java/org/apache/opencmis/client/provider/spi/atompub/CmisAtomPubSpi.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.opencmis.client.provider.spi.atompub;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.opencmis.client.provider.spi.CmisSpi;
+import org.apache.opencmis.client.provider.spi.CmisSpiFactory;
+import org.apache.opencmis.client.provider.spi.Session;
+import org.apache.opencmis.commons.provider.AclService;
+import org.apache.opencmis.commons.provider.DiscoveryService;
+import org.apache.opencmis.commons.provider.MultiFilingService;
+import org.apache.opencmis.commons.provider.NavigationService;
+import org.apache.opencmis.commons.provider.ObjectService;
+import org.apache.opencmis.commons.provider.PolicyService;
+import org.apache.opencmis.commons.provider.RelationshipService;
+import org.apache.opencmis.commons.provider.RepositoryService;
+import org.apache.opencmis.commons.provider.VersioningService;
+
+/**
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class CmisAtomPubSpi implements CmisSpiFactory, CmisSpi {
+
+  private static Log log = LogFactory.getLog(CmisAtomPubSpi.class);
+
+  private Session fSession;
+
+  private RepositoryService fRepositoryService;
+  private NavigationService fNavigationService;
+  private ObjectService fObjectService;
+  private VersioningService fVersioningService;
+  private DiscoveryService fDiscoveryService;
+  private MultiFilingService fMultiFilingService;
+  private RelationshipService fRelationshipService;
+  private PolicyService fPolicyService;
+  private AclService fACLService;
+
+  /**
+   * Constructor.
+   */
+  public CmisAtomPubSpi() {
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * org.apache.opencmis.client.provider.spi.CMISSPIFactory#getSPIInstance(org.apache.opencmis.client.provider
+   * .spi.Session)
+   */
+  public CmisSpi getSpiInstance(Session session) {
+    if (log.isDebugEnabled()) {
+      log.debug("Initializing AtomPub SPI...");
+    }
+
+    fSession = session;
+
+    return this;
+
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getRepositoryService()
+   */
+  public RepositoryService getRepositoryService() {
+    if (fRepositoryService == null) {
+      fRepositoryService = new RepositoryServiceImpl(fSession);
+    }
+
+    return fRepositoryService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getNavigationService()
+   */
+  public NavigationService getNavigationService() {
+    if (fNavigationService == null) {
+      fNavigationService = new NavigationServiceImpl(fSession);
+    }
+
+    return fNavigationService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getObjectService()
+   */
+  public ObjectService getObjectService() {
+    if (fObjectService == null) {
+      fObjectService = new ObjectServiceImpl(fSession);
+    }
+
+    return fObjectService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getDiscoveryService()
+   */
+  public DiscoveryService getDiscoveryService() {
+    if (fDiscoveryService == null) {
+      fDiscoveryService = new DiscoveryServiceImpl(fSession);
+    }
+
+    return fDiscoveryService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getVersioningService()
+   */
+  public VersioningService getVersioningService() {
+    if (fVersioningService == null) {
+      fVersioningService = new VersioningServiceImpl(fSession);
+    }
+
+    return fVersioningService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getMultiFilingService()
+   */
+  public MultiFilingService getMultiFilingService() {
+    if (fMultiFilingService == null) {
+      fMultiFilingService = new MultiFilingServiceImpl(fSession);
+    }
+
+    return fMultiFilingService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getRelationshipService()
+   */
+  public RelationshipService getRelationshipService() {
+    if (fRelationshipService == null) {
+      fRelationshipService = new RelationshipServiceImpl(fSession);
+    }
+
+    return fRelationshipService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getPolicyService()
+   */
+  public PolicyService getPolicyService() {
+    if (fPolicyService == null) {
+      fPolicyService = new PolicyServiceImpl(fSession);
+    }
+
+    return fPolicyService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getACLService()
+   */
+  public AclService getAclService() {
+    if (fACLService == null) {
+      fACLService = new AclServiceImpl(fSession);
+    }
+
+    return fACLService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#clearAllCaches()
+   */
+  public void clearAllCaches() {
+    fSession.remove(SpiSessionParameter.LINK_CACHE);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#clearRepositoryCache(java.lang.String)
+   */
+  public void clearRepositoryCache(String repositoryId) {
+    LinkCache linkCache = (LinkCache) fSession.get(SpiSessionParameter.LINK_CACHE);
+    if (linkCache != null) {
+      linkCache.clearRepository(repositoryId);
+    }
+  }
+
+}