You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fg...@apache.org on 2010/04/15 12:33:51 UTC

svn commit: r934361 [3/9] - in /incubator/chemistry/opencmis/trunk: chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/ chemistry-opencmis-client/chemistry-opencmis-client-bindings/s...

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java?rev=934361&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java Thu Apr 15 10:33:49 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.chemistry.opencmis.client.bindings.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.chemistry.opencmis.commons.PropertyIds;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.JaxBHelper;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectType;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisProperty;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisPropertyString;
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * 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/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomPubParser.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomPubParser.java?rev=934361&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomPubParser.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomPubParser.java Thu Apr 15 10:33:49 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.chemistry.opencmis.client.bindings.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.chemistry.opencmis.client.bindings.spi.atompub.objects.Acl;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AllowableActions;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomBase;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.RepositoryWorkspace;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.ServiceDoc;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.JaxBHelper;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisAccessControlListType;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisAllowableActionsType;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectType;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisProperty;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisPropertyId;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisRepositoryInfoType;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisTypeDefinitionType;
+import org.apache.chemistry.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/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomPubParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomPubParser.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomPubParser.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubConstants.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubConstants.java?rev=934361&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubConstants.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubConstants.java Thu Apr 15 10:33:49 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.chemistry.opencmis.client.bindings.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/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubConstants.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubConstants.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubSpi.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubSpi.java?rev=934361&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubSpi.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubSpi.java Thu Apr 15 10:33:49 2010
@@ -0,0 +1,191 @@
+/*
+ * 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.CmisSpi;
+import org.apache.chemistry.opencmis.client.bindings.spi.CmisSpiFactory;
+import org.apache.chemistry.opencmis.client.bindings.spi.Session;
+import org.apache.chemistry.opencmis.commons.provider.AclService;
+import org.apache.chemistry.opencmis.commons.provider.DiscoveryService;
+import org.apache.chemistry.opencmis.commons.provider.MultiFilingService;
+import org.apache.chemistry.opencmis.commons.provider.NavigationService;
+import org.apache.chemistry.opencmis.commons.provider.ObjectService;
+import org.apache.chemistry.opencmis.commons.provider.PolicyService;
+import org.apache.chemistry.opencmis.commons.provider.RelationshipService;
+import org.apache.chemistry.opencmis.commons.provider.RepositoryService;
+import org.apache.chemistry.opencmis.commons.provider.VersioningService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @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;
+
+    fRepositoryService = new RepositoryServiceImpl(fSession);
+    fNavigationService = new NavigationServiceImpl(fSession);
+    fObjectService = new ObjectServiceImpl(fSession);
+    fVersioningService = new VersioningServiceImpl(fSession);
+    fDiscoveryService = new DiscoveryServiceImpl(fSession);
+    fMultiFilingService = new MultiFilingServiceImpl(fSession);
+    fRelationshipService = new RelationshipServiceImpl(fSession);
+    fPolicyService = new PolicyServiceImpl(fSession);
+    fACLService = new AclServiceImpl(fSession);
+
+    return this;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getRepositoryService()
+   */
+  public RepositoryService getRepositoryService() {
+    return fRepositoryService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getNavigationService()
+   */
+  public NavigationService getNavigationService() {
+    return fNavigationService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getObjectService()
+   */
+  public ObjectService getObjectService() {
+    return fObjectService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getDiscoveryService()
+   */
+  public DiscoveryService getDiscoveryService() {
+    return fDiscoveryService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getVersioningService()
+   */
+  public VersioningService getVersioningService() {
+    return fVersioningService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getMultiFilingService()
+   */
+  public MultiFilingService getMultiFilingService() {
+    return fMultiFilingService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getRelationshipService()
+   */
+  public RelationshipService getRelationshipService() {
+    return fRelationshipService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getPolicyService()
+   */
+  public PolicyService getPolicyService() {
+    return fPolicyService;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.spi.CMISSPI#getACLService()
+   */
+  public AclService getAclService() {
+    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);
+    }
+  }
+
+}

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

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubSpi.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/CmisAtomPubSpi.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/DiscoveryServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/DiscoveryServiceImpl.java?rev=934361&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/DiscoveryServiceImpl.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/DiscoveryServiceImpl.java Thu Apr 15 10:33:49 2010
@@ -0,0 +1,203 @@
+/*
+ * 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.commons.impl.Converter.convert;
+
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+
+import org.apache.chemistry.opencmis.client.bindings.spi.Session;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
+import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
+import org.apache.chemistry.opencmis.commons.api.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.JaxBHelper;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectType;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisQueryType;
+import org.apache.chemistry.opencmis.commons.impl.jaxb.EnumIncludeRelationships;
+import org.apache.chemistry.opencmis.commons.provider.DiscoveryService;
+import org.apache.chemistry.opencmis.commons.provider.Holder;
+import org.apache.chemistry.opencmis.commons.provider.ObjectData;
+import org.apache.chemistry.opencmis.commons.provider.ObjectList;
+
+/**
+ * Discovery Service AtomPub client.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class DiscoveryServiceImpl extends AbstractAtomPubService implements DiscoveryService {
+
+  /**
+   * Constructor.
+   */
+  public DiscoveryServiceImpl(Session session) {
+    setSession(session);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.DiscoveryService#getContentChanges(java.lang.String,
+   * org.apache.opencmis.client.provider.Holder, java.lang.Boolean, java.lang.String, java.lang.Boolean,
+   * java.lang.Boolean, java.math.BigInteger, org.apache.opencmis.client.provider.ExtensionsData)
+   */
+  public ObjectList getContentChanges(String repositoryId, Holder<String> changeLogToken,
+      Boolean includeProperties, String filter, Boolean includePolicyIds, Boolean includeACL,
+      BigInteger maxItems, ExtensionsData extension) {
+    ObjectListImpl result = new ObjectListImpl();
+
+    // find the link
+    String link = loadRepositoryLink(repositoryId, Constants.REP_REL_CHANGES);
+
+    if (link == null) {
+      throw new CmisObjectNotFoundException("Unknown repository or content changes not supported!");
+    }
+
+    UrlBuilder url = new UrlBuilder(link);
+    url.addParameter(Constants.PARAM_CHANGE_LOG_TOKEN, (changeLogToken == null ? null
+        : changeLogToken.getValue()));
+    url.addParameter(Constants.PARAM_PROPERTIES, includeProperties);
+    url.addParameter(Constants.PARAM_FILTER, filter);
+    url.addParameter(Constants.PARAM_POLICY_IDS, includePolicyIds);
+    url.addParameter(Constants.PARAM_ACL, includeACL);
+    url.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
+
+    // read and parse
+    HttpUtils.Response resp = read(url);
+    AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+    // handle top level
+    for (AtomElement element : feed.getElements()) {
+      if (element.getObject() instanceof AtomLink) {
+        if (isNextLink(element)) {
+          result.setHasMoreItems(Boolean.TRUE);
+        }
+      }
+      else if (isInt(NAME_NUM_ITEMS, element)) {
+        result.setNumItems((BigInteger) element.getObject());
+      }
+    }
+
+    // get the changes
+    if (!feed.getEntries().isEmpty()) {
+      result.setObjects(new ArrayList<ObjectData>(feed.getEntries().size()));
+
+      for (AtomEntry entry : feed.getEntries()) {
+        ObjectData hit = null;
+
+        // walk through the entry
+        for (AtomElement element : entry.getElements()) {
+          if (element.getObject() instanceof CmisObjectType) {
+            hit = convert((CmisObjectType) element.getObject());
+          }
+        }
+
+        if (hit != null) {
+          result.getObjects().add(hit);
+        }
+      }
+    }
+
+    return result;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.DiscoveryService#query(java.lang.String, java.lang.String,
+   * java.lang.Boolean, java.lang.Boolean, org.apache.opencmis.commons.enums.IncludeRelationships,
+   * java.lang.String, java.math.BigInteger, java.math.BigInteger,
+   * org.apache.opencmis.client.provider.ExtensionsData)
+   */
+  public ObjectList query(String repositoryId, String statement, Boolean searchAllVersions,
+      Boolean includeAllowableActions, IncludeRelationships includeRelationships,
+      String renditionFilter, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
+    ObjectListImpl result = new ObjectListImpl();
+
+    // find the link
+    String link = loadCollection(repositoryId, Constants.COLLECTION_QUERY);
+
+    if (link == null) {
+      throw new CmisObjectNotFoundException("Unknown repository or query not supported!");
+    }
+
+    UrlBuilder url = new UrlBuilder(link);
+
+    // compile query request
+    final CmisQueryType query = new CmisQueryType();
+    query.setStatement(statement);
+    query.setSearchAllVersions(searchAllVersions);
+    query.setIncludeAllowableActions(includeAllowableActions);
+    query.setIncludeRelationships(convert(EnumIncludeRelationships.class, includeRelationships));
+    query.setRenditionFilter(renditionFilter);
+    query.setMaxItems(maxItems);
+    query.setSkipCount(skipCount);
+
+    // post the query and parse results
+    HttpUtils.Response resp = post(url, Constants.MEDIATYPE_QUERY, new HttpUtils.Output() {
+      public void write(OutputStream out) throws Exception {
+        JaxBHelper.marshal(JaxBHelper.CMIS_OBJECT_FACTORY.createQuery(query), out, false);
+      }
+    });
+    AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
+
+    // handle top level
+    for (AtomElement element : feed.getElements()) {
+      if (element.getObject() instanceof AtomLink) {
+        if (isNextLink(element)) {
+          result.setHasMoreItems(Boolean.TRUE);
+        }
+      }
+      else if (isInt(NAME_NUM_ITEMS, element)) {
+        result.setNumItems((BigInteger) element.getObject());
+      }
+    }
+
+    // get the result set
+    if (!feed.getEntries().isEmpty()) {
+      result.setObjects(new ArrayList<ObjectData>(feed.getEntries().size()));
+
+      for (AtomEntry entry : feed.getEntries()) {
+        ObjectData hit = null;
+
+        // walk through the entry
+        for (AtomElement element : entry.getElements()) {
+          if (element.getObject() instanceof CmisObjectType) {
+            hit = convert((CmisObjectType) element.getObject());
+          }
+        }
+
+        if (hit != null) {
+          result.getObjects().add(hit);
+        }
+      }
+    }
+
+    return result;
+  }
+}

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

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/DiscoveryServiceImpl.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/DiscoveryServiceImpl.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/HttpUtils.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/HttpUtils.java?rev=934361&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/HttpUtils.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/HttpUtils.java Thu Apr 15 10:33:49 2010
@@ -0,0 +1,284 @@
+/*
+ * 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.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.chemistry.opencmis.client.bindings.impl.CmisBindingsHelper;
+import org.apache.chemistry.opencmis.client.bindings.spi.AbstractAuthenticationProvider;
+import org.apache.chemistry.opencmis.client.bindings.spi.Session;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * HTTP helper methods.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class HttpUtils {
+
+  private static final Log log = LogFactory.getLog(HttpUtils.class);
+
+  private static final int BUFFER_SIZE = 4096;
+
+  private HttpUtils() {
+  }
+
+  public static Response invokeGET(UrlBuilder url, Session session) {
+    return invoke(url, "GET", null, null, session, null, null);
+  }
+
+  public static Response invokeGET(UrlBuilder url, Session session, BigInteger offset,
+      BigInteger length) {
+    return invoke(url, "GET", null, null, session, offset, length);
+  }
+
+  public static Response invokePOST(UrlBuilder url, String contentType, Output writer,
+      Session session) {
+    return invoke(url, "POST", contentType, writer, session, null, null);
+  }
+
+  public static Response invokePUT(UrlBuilder url, String contentType, Output writer,
+      Session session) {
+    return invoke(url, "PUT", contentType, writer, session, null, null);
+  }
+
+  public static Response invokeDELETE(UrlBuilder url, Session session) {
+    return invoke(url, "DELETE", null, null, session, null, null);
+  }
+
+  private static Response invoke(UrlBuilder url, String method, String contentType, Output writer,
+      Session session, BigInteger offset, BigInteger length) {
+    try {
+      // log before connect
+      if (log.isDebugEnabled()) {
+        log.debug(method + " " + url);
+      }
+
+      // connect
+      HttpURLConnection conn = (HttpURLConnection) (new URL(url.toString())).openConnection();
+      conn.setRequestMethod(method);
+      conn.setDoInput(true);
+      conn.setDoOutput(writer != null);
+
+      // set content type
+      if (contentType != null) {
+        conn.setRequestProperty("Content-Type", contentType);
+      }
+
+      // authenticate
+      AbstractAuthenticationProvider authProvider = CmisBindingsHelper
+          .getAuthenticationProvider(session);
+      if (authProvider != null) {
+        Map<String, List<String>> httpHeaders = authProvider.getHTTPHeaders(url.toString());
+        if (httpHeaders != null) {
+          for (Map.Entry<String, List<String>> header : httpHeaders.entrySet()) {
+            if (header.getValue() != null) {
+              for (String value : header.getValue()) {
+                conn.setRequestProperty(header.getKey(), value);
+              }
+            }
+          }
+        }
+      }
+
+      // range
+      if ((offset != null) || (length != null)) {
+        StringBuilder sb = new StringBuilder("bytes=");
+
+        if ((offset == null) || (offset.signum() == -1)) {
+          offset = BigInteger.ZERO;
+        }
+
+        sb.append(offset.toString());
+        sb.append("-");
+
+        if ((length != null) && (length.signum() == 1)) {
+          sb.append(offset.add(length.subtract(BigInteger.ONE)).toString());
+        }
+
+        conn.setRequestProperty("Range", sb.toString());
+      }
+
+      // send data
+      if (writer != null) {
+        OutputStream out = new BufferedOutputStream(conn.getOutputStream(), BUFFER_SIZE);
+        writer.write(out);
+        out.flush();
+      }
+
+      // connect
+      conn.connect();
+
+      // get stream, if present
+      int respCode = conn.getResponseCode();
+      InputStream inputStream = null;
+      if ((respCode == 200) || (respCode == 201) || (respCode == 203) || (respCode == 206)) {
+        inputStream = conn.getInputStream();
+      }
+
+      // get the response
+      return new Response(respCode, conn.getResponseMessage(), conn.getHeaderFields(), inputStream,
+          conn.getErrorStream());
+    }
+    catch (Exception e) {
+      throw new CmisConnectionException("Cannot access " + url + ": " + e.getMessage(), e);
+    }
+  }
+
+  /**
+   * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+   * 
+   */
+  public static class Response {
+    private int fResponseCode;
+    private String fResponseMessage;
+    private Map<String, List<String>> fHeaders;
+    private InputStream fStream;
+    private String fErrorContent;
+
+    public Response(int responseCode, String responseMessage, Map<String, List<String>> headers,
+        InputStream stream, InputStream errorStream) {
+      fResponseCode = responseCode;
+      fResponseMessage = responseMessage;
+      fStream = stream;
+
+      fHeaders = new HashMap<String, List<String>>();
+      if (headers != null) {
+        for (Map.Entry<String, List<String>> e : headers.entrySet()) {
+          fHeaders.put(e.getKey() == null ? null : e.getKey().toLowerCase(), e.getValue());
+        }
+      }
+
+      // if there is an error page, get it
+      if (errorStream != null) {
+        String contentType = getContentTypeHeader();
+        if ((contentType != null) && (contentType.toLowerCase().startsWith("text/"))) {
+          StringBuilder sb = new StringBuilder();
+
+          try {
+            InputStreamReader reader = new InputStreamReader(errorStream);
+            char[] buffer = new char[4096];
+            int b;
+            while ((b = reader.read(buffer)) > -1) {
+              sb.append(buffer, 0, b);
+            }
+            reader.close();
+
+            fErrorContent = sb.toString();
+          }
+          catch (IOException e) {
+            fErrorContent = "Unable to retrieve content: " + e.getMessage();
+          }
+        }
+      }
+    }
+
+    public int getResponseCode() {
+      return fResponseCode;
+    }
+
+    public String getResponseMessage() {
+      return fResponseMessage;
+    }
+
+    public Map<String, List<String>> getHeaders() {
+      return fHeaders;
+    }
+
+    public String getHeader(String name) {
+      List<String> list = fHeaders.get(name.toLowerCase(Locale.US));
+      if ((list == null) || (list.isEmpty())) {
+        return null;
+      }
+
+      return list.get(0);
+    }
+
+    public String getContentTypeHeader() {
+      return getHeader("Content-Type");
+    }
+
+    public BigInteger getContentLengthHeader() {
+      String lengthStr = getHeader("Content-Length");
+      if (lengthStr == null) {
+        return null;
+      }
+
+      try {
+        return new BigInteger(lengthStr);
+      }
+      catch (NumberFormatException e) {
+        return null;
+      }
+    }
+
+    public String getLocactionHeader() {
+      return getHeader("Location");
+    }
+
+    public String getContentLocactionHeader() {
+      return getHeader("Content-Location");
+    }
+
+    public BigInteger getContentLength() {
+      String lenStr = getHeader("Content-Length");
+      if (lenStr == null) {
+        return null;
+      }
+
+      try {
+        return new BigInteger(lenStr);
+      }
+      catch (NumberFormatException nfe) {
+        return null;
+      }
+    }
+
+    public InputStream getStream() {
+      return fStream;
+    }
+
+    public String getErrorContent() {
+      return fErrorContent;
+    }
+  }
+
+  /**
+   * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+   * 
+   */
+  public interface Output {
+    void write(OutputStream out) throws Exception;
+  }
+}

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

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/HttpUtils.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/HttpUtils.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/LinkCache.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/LinkCache.java?rev=934361&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/LinkCache.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/LinkCache.java Thu Apr 15 10:33:49 2010
@@ -0,0 +1,308 @@
+/*
+ * 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.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Map;
+
+import org.apache.chemistry.opencmis.client.bindings.cache.Cache;
+import org.apache.chemistry.opencmis.client.bindings.cache.impl.CacheImpl;
+import org.apache.chemistry.opencmis.client.bindings.cache.impl.ContentTypeCacheLevelImpl;
+import org.apache.chemistry.opencmis.client.bindings.cache.impl.LruCacheLevelImpl;
+import org.apache.chemistry.opencmis.client.bindings.cache.impl.MapCacheLevelImpl;
+import org.apache.chemistry.opencmis.client.bindings.spi.Session;
+import org.apache.chemistry.opencmis.commons.SessionParameter;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+
+/**
+ * Link cache.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class LinkCache implements Serializable {
+
+  private static final long serialVersionUID = 1L;
+
+  private static final int CACHE_SIZE_REPOSITORIES = 10;
+  private static final int CACHE_SIZE_TYPES = 100;
+  private static final int CACHE_SIZE_OBJECTS = 400;
+
+  private Cache fLinkCache;
+  private Cache fTypeLinkCache;
+  private Cache fCollectionLinkCache;
+  private Cache fTemplateCache;
+  private Cache fRepositoryLinkCache;
+
+  /**
+   * Constructor.
+   */
+  public LinkCache(Session session) {
+    int repCount = session.get(SessionParameter.CACHE_SIZE_REPOSITORIES, CACHE_SIZE_REPOSITORIES);
+    if (repCount < 1) {
+      repCount = CACHE_SIZE_REPOSITORIES;
+    }
+
+    int typeCount = session.get(SessionParameter.CACHE_SIZE_TYPES, CACHE_SIZE_TYPES);
+    if (typeCount < 1) {
+      typeCount = CACHE_SIZE_TYPES;
+    }
+
+    int objCount = session.get(SessionParameter.CACHE_SIZE_OBJECTS, CACHE_SIZE_OBJECTS);
+    if (objCount < 1) {
+      objCount = CACHE_SIZE_OBJECTS;
+    }
+
+    fLinkCache = new CacheImpl("Link Cache");
+    fLinkCache.initialize(new String[] {
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
+        LruCacheLevelImpl.class.getName() + " " + LruCacheLevelImpl.MAX_ENTRIES + "=" + objCount, // id
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=16", // rel
+        ContentTypeCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=3,"
+            + MapCacheLevelImpl.SINGLE_VALUE + "=true" // type
+    });
+
+    fTypeLinkCache = new CacheImpl("Type Link Cache");
+    fTypeLinkCache.initialize(new String[] {
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
+        LruCacheLevelImpl.class.getName() + " " + LruCacheLevelImpl.MAX_ENTRIES + "=" + typeCount, // id
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=16", // rel
+        ContentTypeCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=3,"
+            + MapCacheLevelImpl.SINGLE_VALUE + "=true"// type
+    });
+
+    fCollectionLinkCache = new CacheImpl("Collection Link Cache");
+    fCollectionLinkCache.initialize(new String[] {
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=8" // collection
+    });
+
+    fTemplateCache = new CacheImpl("URI Template Cache");
+    fTemplateCache.initialize(new String[] {
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=6" // type
+    });
+
+    fRepositoryLinkCache = new CacheImpl("Repository Link Cache");
+    fRepositoryLinkCache.initialize(new String[] {
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
+        MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=6" // rel
+    });
+  }
+
+  /**
+   * Adds a link.
+   */
+  public void addLink(String repositoryId, String id, String rel, String type, String link) {
+    fLinkCache.put(link, repositoryId, id, rel, type);
+  }
+
+  /**
+   * Removes all links of an object.
+   */
+  public void removeLinks(String repositoryId, String id) {
+    fLinkCache.remove(repositoryId, id);
+  }
+
+  /**
+   * Gets a link.
+   */
+  public String getLink(String repositoryId, String id, String rel, String type) {
+    return (String) fLinkCache.get(repositoryId, id, rel, type);
+  }
+
+  /**
+   * Gets a link.
+   */
+  public String getLink(String repositoryId, String id, String rel) {
+    return getLink(repositoryId, id, rel, null);
+  }
+
+  /**
+   * Checks a link.
+   */
+  public int checkLink(String repositoryId, String id, String rel, String type) {
+    return fLinkCache.check(repositoryId, id, rel, type);
+  }
+
+  /**
+   * Locks the link cache.
+   */
+  public void lockLinks() {
+    fLinkCache.writeLock();
+  }
+
+  /**
+   * Unlocks the link cache.
+   */
+  public void unlockLinks() {
+    fLinkCache.writeUnlock();
+  }
+
+  /**
+   * Adds a type link.
+   */
+  public void addTypeLink(String repositoryId, String id, String rel, String type, String link) {
+    fTypeLinkCache.put(link, repositoryId, id, rel, type);
+  }
+
+  /**
+   * Removes all links of a type.
+   */
+  public void removeTypeLinks(String repositoryId, String id) {
+    fTypeLinkCache.remove(repositoryId, id);
+  }
+
+  /**
+   * Gets a type link.
+   */
+  public String getTypeLink(String repositoryId, String id, String rel, String type) {
+    return (String) fTypeLinkCache.get(repositoryId, id, rel, type);
+  }
+
+  /**
+   * Gets a type link.
+   */
+  public String getTypeLink(String repositoryId, String id, String rel) {
+    return getLink(repositoryId, id, rel, null);
+  }
+
+  /**
+   * Locks the type link cache.
+   */
+  public void lockTypeLinks() {
+    fTypeLinkCache.writeLock();
+  }
+
+  /**
+   * Unlocks the type link cache.
+   */
+  public void unlockTypeLinks() {
+    fTypeLinkCache.writeUnlock();
+  }
+
+  /**
+   * Adds a collection.
+   */
+  public void addCollection(String repositoryId, String collection, String link) {
+    fCollectionLinkCache.put(link, repositoryId, collection);
+  }
+
+  /**
+   * Gets a collection.
+   */
+  public String getCollection(String repositoryId, String collection) {
+    return (String) fCollectionLinkCache.get(repositoryId, collection);
+  }
+
+  /**
+   * Adds an URI template.
+   */
+  public void addTemplate(String repositoryId, String type, String link) {
+    fTemplateCache.put(link, repositoryId, type);
+  }
+
+  /**
+   * Gets an URI template and replaces place holders with the given parameters.
+   */
+  public String getTemplateLink(String repositoryId, String type, Map<String, Object> parameters) {
+    String template = (String) fTemplateCache.get(repositoryId, type);
+    if (template == null) {
+      return null;
+    }
+
+    StringBuilder result = new StringBuilder();
+    StringBuilder param = new StringBuilder();
+
+    boolean paramMode = false;
+    for (int i = 0; i < template.length(); i++) {
+      char c = template.charAt(i);
+
+      if (paramMode) {
+        if (c == '}') {
+          paramMode = false;
+
+          String paramValue = UrlBuilder.normalizeParameter(parameters.get(param.toString()));
+          if (paramValue != null) {
+            try {
+              result.append(URLEncoder.encode(paramValue, "UTF-8"));
+            }
+            catch (UnsupportedEncodingException e) {
+              result.append(paramValue);
+            }
+          }
+
+          param = new StringBuilder();
+        }
+        else {
+          param.append(c);
+        }
+      }
+      else {
+        if (c == '{') {
+          paramMode = true;
+        }
+        else {
+          result.append(c);
+        }
+      }
+    }
+
+    return result.toString();
+  }
+
+  /**
+   * Adds a collection.
+   */
+  public void addRepositoryLink(String repositoryId, String rel, String link) {
+    fRepositoryLinkCache.put(link, repositoryId, rel);
+  }
+
+  /**
+   * Gets a collection.
+   */
+  public String getRepositoryLink(String repositoryId, String rel) {
+    return (String) fRepositoryLinkCache.get(repositoryId, rel);
+  }
+
+  /**
+   * Removes all entries of the given repository from the caches.
+   */
+  public void clearRepository(String repositoryId) {
+    fLinkCache.remove(repositoryId);
+    fTypeLinkCache.remove(repositoryId);
+    fCollectionLinkCache.remove(repositoryId);
+    fTemplateCache.remove(repositoryId);
+    fRepositoryLinkCache.remove(repositoryId);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see java.lang.Object#toString()
+   */
+  @Override
+  public String toString() {
+    return "Link Cache [link cache=" + fLinkCache + ", type link cache=" + fTypeLinkCache
+        + ", collection link cache=" + fCollectionLinkCache + ", repository link cache="
+        + fRepositoryLinkCache + ",  template cache=" + fTemplateCache + "]";
+  }
+}

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

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/LinkCache.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/LinkCache.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/MultiFilingServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/MultiFilingServiceImpl.java?rev=934361&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/MultiFilingServiceImpl.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/MultiFilingServiceImpl.java Thu Apr 15 10:33:49 2010
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.bindings.spi.atompub;
+
+import java.io.OutputStream;
+
+import org.apache.chemistry.opencmis.client.bindings.spi.Session;
+import org.apache.chemistry.opencmis.commons.api.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.provider.MultiFilingService;
+
+/**
+ * MultiFiling Service AtomPub client.
+ * 
+ * @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
+ * 
+ */
+public class MultiFilingServiceImpl extends AbstractAtomPubService implements MultiFilingService {
+
+  /**
+   * Constructor.
+   */
+  public MultiFilingServiceImpl(Session session) {
+    setSession(session);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.MultiFilingService#addObjectToFolder(java.lang.String,
+   * java.lang.String, java.lang.String, java.lang.Boolean,
+   * org.apache.opencmis.client.provider.ExtensionsData)
+   */
+  public void addObjectToFolder(String repositoryId, String objectId, String folderId,
+      Boolean allVersions, ExtensionsData extension) {
+    if (objectId == null) {
+      throw new CmisInvalidArgumentException("Object id must be set!");
+    }
+
+    // find the link
+    String link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+
+    if (link == null) {
+      throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
+    }
+
+    UrlBuilder url = new UrlBuilder(link);
+    url.addParameter(Constants.PARAM_ALL_VERSIONS, allVersions);
+
+    // set up object and writer
+    final AtomEntryWriter entryWriter = new AtomEntryWriter(createIdObject(objectId));
+
+    // post addObjectToFolder request
+    post(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
+      public void write(OutputStream out) throws Exception {
+        entryWriter.write(out);
+      }
+    });
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.opencmis.client.provider.MultiFilingService#removeObjectFromFolder(java.lang.String,
+   * java.lang.String, java.lang.String, org.apache.opencmis.client.provider.ExtensionsData)
+   */
+  public void removeObjectFromFolder(String repositoryId, String objectId, String folderId,
+      ExtensionsData extension) {
+    if (objectId == null) {
+      throw new CmisInvalidArgumentException("Object id must be set!");
+    }
+
+    // find the link
+    String link = loadCollection(repositoryId, Constants.COLLECTION_UNFILED);
+
+    if (link == null) {
+      throw new CmisObjectNotFoundException("Unknown repository or unfiling not supported!");
+    }
+
+    UrlBuilder url = new UrlBuilder(link);
+    url.addParameter(Constants.PARAM_REMOVE_FROM, folderId);
+
+    // set up object and writer
+    final AtomEntryWriter entryWriter = new AtomEntryWriter(createIdObject(objectId));
+
+    // post removeObjectFromFolder request
+    post(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
+      public void write(OutputStream out) throws Exception {
+        entryWriter.write(out);
+      }
+    });
+  }
+}

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

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/MultiFilingServiceImpl.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/MultiFilingServiceImpl.java
------------------------------------------------------------------------------
    svn:keywords = Id