You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by dp...@apache.org on 2010/03/19 11:09:27 UTC

svn commit: r925158 [1/2] - in /incubator/chemistry/trunk/chemistry: chemistry-jcr/ chemistry-jcr/src/main/java/org/apache/chemistry/jcr/ chemistry-parent/ chemistry-tests/ chemistry-tests/src/test/java/org/apache/chemistry/test/ chemistry-tests/src/te...

Author: dpfister
Date: Fri Mar 19 10:09:26 2010
New Revision: 925158

URL: http://svn.apache.org/viewvc?rev=925158&view=rev
Log:
CMIS-167 - Upgrade javax-jcr dependency to 2.0
- Use jackrabbit 2.0.0 in tests

Added:
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrObject.java   (with props)
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrPolicy.java   (with props)
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrRelationship.java   (with props)
    incubator/chemistry/trunk/chemistry/chemistry-tests/src/test/resources/repository.xml   (with props)
Removed:
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrNewDocument.java
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrNewFolder.java
Modified:
    incubator/chemistry/trunk/chemistry/chemistry-jcr/pom.xml
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrCmisMap.java
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrConnection.java
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrContentStream.java
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrDocument.java
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrFolder.java
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrObjectEntry.java
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrRepository.java
    incubator/chemistry/trunk/chemistry/chemistry-parent/pom.xml
    incubator/chemistry/trunk/chemistry/chemistry-tests/pom.xml
    incubator/chemistry/trunk/chemistry/chemistry-tests/src/test/java/org/apache/chemistry/test/TestJcrRepository.java
    incubator/chemistry/trunk/chemistry/chemistry-tests/src/test/resources/nodetypes.cnd

Modified: incubator/chemistry/trunk/chemistry/chemistry-jcr/pom.xml
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-jcr/pom.xml?rev=925158&r1=925157&r2=925158&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-jcr/pom.xml (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-jcr/pom.xml Fri Mar 19 10:09:26 2010
@@ -30,7 +30,7 @@
   <name>Chemistry JCR Connector</name>
 
   <properties>
-    <jackrabbit.version>1.6.0</jackrabbit.version>
+    <jackrabbit.version>2.0.0</jackrabbit.version>
   </properties>
 
   <dependencies>
@@ -49,7 +49,6 @@
     <dependency>
       <groupId>javax.jcr</groupId>
       <artifactId>jcr</artifactId>
-      <version>1.0</version>
     </dependency>
     <dependency>
       <groupId>org.apache.jackrabbit</groupId>

Modified: incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrCmisMap.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrCmisMap.java?rev=925158&r1=925157&r2=925158&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrCmisMap.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrCmisMap.java Fri Mar 19 10:09:26 2010
@@ -16,13 +16,17 @@
  */
 package org.apache.chemistry.jcr;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Hashtable;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
 import org.apache.chemistry.Property;
+import org.apache.chemistry.PropertyType;
 import org.apache.jackrabbit.JcrConstants;
 
 /**
@@ -140,6 +144,43 @@ public class JcrCmisMap {
     }
 
     /**
+     * Checks if a JCR node is a document.
+     *
+     * @param node the JCR node
+     * @return {@code true} if the node is a document
+     */
+    public static boolean isNodeFolder(Node node) {
+        for (String nodeTypeName : folderNtList) {
+            try {
+                if (node.isNodeType(nodeTypeName)) {
+                    return true;
+                }
+            } catch (RepositoryException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether a JCR node is an internal node, e.g. <b>jcr:system</b>
+     *
+     * @param node node
+     * @return <code>true</code> if the node is internal;
+     *         <code>false</code> otherwise
+     */
+    public static boolean isInternal(Node node) {
+        try {
+            return node.getName().equals(JcrConstants.JCR_SYSTEM);
+        } catch (RepositoryException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    /**
      * Checks if a JCR name corresponds to a date.
      */
     public static boolean isDate(String s) {
@@ -183,4 +224,64 @@ public class JcrCmisMap {
         }
     }
 
+    /**
+     * Convert a JCR value to a serializable
+     *
+     * @param pd property definition
+     * @param value JCR value
+     * @return serializable
+     * @throws RepositoryException if accessing the value fails
+     */
+    public static Serializable valueToSerializable(PropertyType pd, javax.jcr.Value value)
+            throws RepositoryException {
+
+        switch (pd.ordinal()) {
+        case PropertyType.BOOLEAN_ORD:
+            return Boolean.valueOf(value.getBoolean());
+        case PropertyType.DATETIME_ORD:
+            return value.getDate();
+        case PropertyType.DECIMAL_ORD:
+            return value.getDecimal();
+        case PropertyType.INTEGER_ORD:
+            return Integer.valueOf((int) value.getLong());
+        case PropertyType.HTML_ORD:
+        case PropertyType.ID_ORD:
+        case PropertyType.STRING_ORD:
+        case PropertyType.URI_ORD:
+            return value.getString();
+        default:
+            throw new AssertionError("Unexpected property type ordinal: " + pd.ordinal());
+        }
+    }
+
+    /**
+     * Convert a JCR value to a serializable
+     *
+     * @param pd property definition
+     * @param value JCR value
+     * @return serializable
+     * @throws RepositoryException if accessing the value fails
+     */
+    public static javax.jcr.Value serializableToValue(PropertyType pd, Serializable v,
+                javax.jcr.ValueFactory f)
+            throws RepositoryException {
+
+        switch (pd.ordinal()) {
+        case PropertyType.BOOLEAN_ORD:
+            return f.createValue(((Boolean) v).booleanValue());
+        case PropertyType.DATETIME_ORD:
+            return f.createValue((Calendar) v);
+        case PropertyType.DECIMAL_ORD:
+            return f.createValue((BigDecimal) v);
+        case PropertyType.INTEGER_ORD:
+            return f.createValue(((Integer) v).longValue());
+        case PropertyType.HTML_ORD:
+        case PropertyType.ID_ORD:
+        case PropertyType.STRING_ORD:
+        case PropertyType.URI_ORD:
+            return f.createValue((String) v);
+        default:
+            throw new AssertionError("Unexpected property type ordinal: " + pd.ordinal());
+        }
+    }
 }

Modified: incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrConnection.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrConnection.java?rev=925158&r1=925157&r2=925158&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrConnection.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrConnection.java Fri Mar 19 10:09:26 2010
@@ -23,16 +23,20 @@ package org.apache.chemistry.jcr;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.Workspace;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryManager;
 import javax.jcr.query.QueryResult;
@@ -40,8 +44,11 @@ import javax.xml.namespace.QName;
 
 import org.apache.chemistry.ACE;
 import org.apache.chemistry.ACLPropagation;
+import org.apache.chemistry.BaseType;
 import org.apache.chemistry.CMISObject;
 import org.apache.chemistry.Connection;
+import org.apache.chemistry.ConstraintViolationException;
+import org.apache.chemistry.ContentAlreadyExistsException;
 import org.apache.chemistry.ContentStream;
 import org.apache.chemistry.Document;
 import org.apache.chemistry.Folder;
@@ -50,85 +57,183 @@ import org.apache.chemistry.ListPage;
 import org.apache.chemistry.NameConstraintViolationException;
 import org.apache.chemistry.ObjectEntry;
 import org.apache.chemistry.ObjectId;
+import org.apache.chemistry.ObjectNotFoundException;
 import org.apache.chemistry.Paging;
 import org.apache.chemistry.Policy;
+import org.apache.chemistry.Property;
 import org.apache.chemistry.Relationship;
 import org.apache.chemistry.Rendition;
-import org.apache.chemistry.Repository;
 import org.apache.chemistry.SPI;
 import org.apache.chemistry.Tree;
+import org.apache.chemistry.Type;
 import org.apache.chemistry.Unfiling;
 import org.apache.chemistry.VersioningState;
 import org.apache.chemistry.impl.simple.SimpleListPage;
 import org.apache.chemistry.impl.simple.SimpleObjectId;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.jackrabbit.JcrConstants;
-
-public class JcrConnection implements Connection, SPI {
 
+/**
+ * Connection implementation.
+ */
+class JcrConnection implements Connection, SPI {
+
+    /**
+     * Logger.
+     */
     private static final Log log = LogFactory.getLog(JcrConnection.class);
 
+    /**
+     * JCR session.
+     */
     private final Session session;
 
+    /**
+     * Repository implementation.
+     */
     private final JcrRepository repository;
 
+    /**
+     * Root folder id.
+     */
+    private final ObjectId rootFolderId;
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param session session
+     * @param repository repository implementation
+     */
     public JcrConnection(Session session, JcrRepository repository) {
         this.session = session;
         this.repository = repository;
+        rootFolderId = repository.getRootFolderId();
+    }
+
+    /**
+     * Return the root folder id.
+     *
+     * @return root folder id
+     */
+    public ObjectId getRootFolderId() {
+        return rootFolderId;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public void close() {
         session.logout();
     }
 
-    public CMISObject getObject(ObjectId objectId) {
+    /**
+     * Return an entry for a given object id. If the object id is a <code>JcrObject</code>
+     * derived class, the entry inside that object will be returned
+     *
+     * @param objectId object id
+     * @return entry or <code>null</code>
+     */
+    private JcrObjectEntry getEntry(ObjectId objectId) {
+        if (objectId instanceof JcrObject) {
+            return ((JcrObject) objectId).getEntry();
+        }
         try {
-            String relPath = JcrObjectEntry.getPath(objectId.getId()).substring(
-                    1);
-            if (relPath.equals("")) {
-                return getRootFolder();
+            String id = objectId.getId();
+            if (rootFolderId.getId().equals(id)) {
+                return new JcrObjectEntry(getRootNode(), JcrRepository.ROOT_TYPE, this);
             } else {
-                Node node = session.getRootNode().getNode(relPath);
-                if (JcrCmisMap.isNodeDocument(node)) {
-                    return new JcrDocument(node, this);
-                } else {
-                    return new JcrFolder(node, this);
-                }
+                Node node = session.getNodeByIdentifier(id);
+                return new JcrObjectEntry(node, this);
             }
+        } catch (ItemNotFoundException e) {
+            /* item was not found */
+            return null;
         } catch (RepositoryException e) {
-            String msg = "Unable to get object: " + objectId;
-            log.error(msg, e);
+            String msg = "Unable to get entry with id: " + objectId;
+            if (e.getMessage().startsWith("invalid identifier:")) {
+                /* treat this as if item was not found */
+                log.info(msg, e);
+            } else {
+                log.error(msg, e);
+            }
+            return null;
         }
-        return null;
     }
 
-    public Repository getRepository() {
+    /**
+     * {@inheritDoc}
+     */
+    public JcrObject getObject(ObjectId objectId) {
+        if (objectId instanceof JcrObject) {
+            return (JcrObject) objectId;
+        }
+        JcrObjectEntry entry = getEntry(objectId);
+        if (entry == null) {
+            return null;
+        }
+        return JcrObject.construct(entry);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public JcrRepository getRepository() {
         return repository;
     }
 
-    public Folder getRootFolder() {
-        try {
-            return new JcrFolder(session.getRootNode(), this);
-        } catch (RepositoryException e) {
-            String msg = "Unable to get root entry.";
-            log.error(msg, e);
+    /**
+     * {@inheritDoc}
+     */
+    private Node getRootNode() throws RepositoryException {
+        if (rootFolderId == null) {
+            return session.getRootNode();
+        } else {
+            return session.getNodeByIdentifier(rootFolderId.getId());
         }
-        return null;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public Folder getRootFolder() {
+        return (Folder) getObject(rootFolderId);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public SPI getSPI() {
         return this;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Document newDocument(String typeId, Folder folder) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+        Type type = repository.getType(typeId);
+        if (type == null || type.getBaseType() != BaseType.DOCUMENT) {
+            throw new IllegalArgumentException(typeId);
+        }
+        JcrObjectEntry entry = new JcrObjectEntry(type, this);
+        if (folder != null) {
+            entry.setValue(Property.PARENT_ID, folder.getId());
+        }
+        return new JcrDocument(entry);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Folder newFolder(String typeId, Folder folder) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+        Type type = repository.getType(typeId);
+        if (type == null || type.getBaseType() != BaseType.FOLDER) {
+            throw new IllegalArgumentException(typeId);
+        }
+        JcrObjectEntry entry = new JcrObjectEntry(type, this);
+        if (folder != null) {
+            entry.setValue(Property.PARENT_ID, folder.getId());
+        }
+        return new JcrFolder(entry);
     }
 
     public Policy newPolicy(String typeId, Folder folder) {
@@ -141,6 +246,9 @@ public class JcrConnection implements Co
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Collection<CMISObject> query(String statement,
             boolean searchAllVersions) {
         ListPage<ObjectEntry> entries = query(statement, searchAllVersions,
@@ -153,14 +261,20 @@ public class JcrConnection implements Co
         return objects;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ObjectEntry newObjectEntry(String typeId) {
-        if (JcrCmisMap.isBaseTypeDocument(typeId)) {
-            return new JcrDocument(null, this);
-        } else {
-            return new JcrFolder(null, this);
+        Type type = repository.getType(typeId);
+        if (type == null) {
+            throw new IllegalArgumentException(typeId);
         }
+        return new JcrObjectEntry(type, this);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ObjectId newObjectId(String id) {
         return new SimpleObjectId(id);
     }
@@ -195,23 +309,75 @@ public class JcrConnection implements Co
         throw new UnsupportedOperationException();
     }
 
-    public ObjectId createDocumentFromSource(ObjectId source, ObjectId folder,
+    /**
+     * {@inheritDoc}
+     *
+     * TODO versioningState
+     */
+    public ObjectId createDocumentFromSource(ObjectId sourceId, ObjectId folderId,
             Map<String, Serializable> properties,
             VersioningState versioningState)
             throws NameConstraintViolationException {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+
+        JcrFolder folder = getFolder(folderId);
+        JcrDocument source = getDocument(sourceId);
+
+        try {
+            String sourcePath = source.getEntry().getNode().getPath();
+            String sourceName = null;
+            if (properties != null) {
+                sourceName = (String) properties.get(Property.NAME);
+            }
+            if (sourceName == null) {
+                sourceName = source.getEntry().getNode().getName();
+            }
+            StringBuilder b = new StringBuilder(folder.getEntry().getNode().getPath());
+            if (b.charAt(b.length() - 1) != '/') {
+                b.append('/');
+            }
+            b.append(sourceName);
+            String destPath = b.toString();
+
+            Workspace workspace = session.getWorkspace();
+            workspace.copy(sourcePath, destPath);
+            String id = session.getNode(destPath).getIdentifier();
+
+            JcrObject object = getObject(newObjectId(id));
+            if (!(object instanceof JcrDocument)) {
+                log.error("Target object not found after copying");
+                return null;
+            }
+            if (properties != null) {
+                object.setValues(properties);
+                object.save();
+            }
+            return object;
+
+        } catch (RepositoryException e) {
+            log.error("Unable to copy.", e);
+        }
+        return null;
     }
 
-    // TODO add IOException to throws clause
+    /**
+     * {@inheritDoc}
+     */
     public ObjectId createDocument(Map<String, Serializable> properties,
             ObjectId folderId, ContentStream contentStream,
             VersioningState versioningState)
             throws NameConstraintViolationException {
 
         try {
-            JcrFolder folder = (JcrFolder) getObject(folderId);
-            Document doc = folder.newDocument(null);
+            String typeId = (String) properties.remove(Property.TYPE_ID);
+            if (typeId == null) {
+                // use a default type, useful for pure AtomPub POST
+                typeId = BaseType.DOCUMENT.getId();
+            }
+            Folder folder = null;
+            if (folderId != null) {
+                folder = getFolder(folderId);
+            }
+            Document doc = newDocument(typeId, folder);
             doc.setValues(properties);
             if (contentStream != null) {
                 doc.setName(contentStream.getFileName());
@@ -219,7 +385,7 @@ public class JcrConnection implements Co
                 doc.setContentStream(contentStream);
             }
             doc.save();
-            return new SimpleObjectId(doc.getId());
+            return doc;
         } catch (Exception e) {
             String msg = "Unable to create document.";
             log.error(msg, e);
@@ -227,10 +393,28 @@ public class JcrConnection implements Co
         return null;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ObjectId createFolder(Map<String, Serializable> properties,
             ObjectId folderId) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+
+        String typeId = (String) properties.get(Property.TYPE_ID);
+        if (typeId == null) {
+            throw new IllegalArgumentException("Missing object type id");
+        }
+        Type type = repository.getType(typeId);
+        if (type == null || type.getBaseType() != BaseType.FOLDER) {
+            throw new IllegalArgumentException(typeId);
+        }
+        JcrObjectEntry entry = new JcrObjectEntry(type, this);
+        entry.setValues(properties);
+        if (folderId != null) {
+            entry.setValue(Property.PARENT_ID, folderId.getId());
+        }
+        JcrFolder folder = new JcrFolder(entry);
+        folder.save();
+        return folder;
     }
 
     public ObjectId createPolicy(Map<String, Serializable> properties,
@@ -244,20 +428,95 @@ public class JcrConnection implements Co
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ObjectId deleteContentStream(ObjectId documentId) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+        JcrDocument doc = getDocument(documentId);
+        try {
+            doc.setContentStream(null);
+        } catch (IOException e) {
+            /* this should not happen */
+            log.error("Unexpected I/O exception while deleting the content stream.", e);
+        }
+        return doc;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public void deleteObject(ObjectId objectId, boolean allVersions) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+        JcrObject object = getObject(objectId);
+        if (object == null) {
+            throw new ObjectNotFoundException(objectId.getId());
+        }
+        if (rootFolderId.equals(objectId)) {
+            throw new ConstraintViolationException("Unable to delete root folder");
+        }
+        if (object instanceof JcrFolder) {
+            JcrFolder folder = (JcrFolder) object;
+            if (folder.getChildren().size() > 0) {
+                String msg = "Folder not empty: " + objectId;
+                throw new ConstraintViolationException(msg);
+            }
+        }
+
+        Session session = null;
+
+        try {
+            Node node = object.getEntry().getNode();
+            session = node.getSession();
+
+            node.remove();
+            session.save();
+
+        } catch (RepositoryException e) {
+            log.error("Unable to delete object: " + objectId, e);
+
+            if (session != null) {
+                try {
+                    session.refresh(false);
+                } catch (RepositoryException e2) {
+                    log.error("Error while refreshing session.", e2);
+                }
+            }
+        }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Collection<ObjectId> deleteTree(ObjectId folderId,
             Unfiling unfiling, boolean continueOnFailure) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+
+        if (rootFolderId.getId().equals(folderId.getId())) {
+            throw new ConstraintViolationException("Unable to delete root folder");
+        }
+        JcrFolder folder = getFolder(folderId);
+
+        Session session = null;
+
+        try {
+            Node node = folder.getEntry().getNode();
+            session = node.getSession();
+
+            node.remove();
+            session.save();
+
+        } catch (RepositoryException e) {
+            log.error("Unable to delete folder: " + folderId, e);
+
+            if (session != null) {
+                try {
+                    session.refresh(false);
+                } catch (RepositoryException e2) {
+                    log.error("Error while refreshing session.", e2);
+                }
+            }
+        }
+
+        Collection<ObjectId> result = Collections.emptyList();
+        return result;
     }
 
     public Collection<ObjectEntry> getAllVersions(String versionSeriesId,
@@ -267,8 +526,7 @@ public class JcrConnection implements Co
     }
 
     public Set<QName> getAllowableActions(ObjectId objectId) {
-        // TODO Auto-generated method stub
-        return null;
+        return getProperties(objectId, null).getAllowableActions();
     }
 
     public Collection<ObjectEntry> getAppliedPolicies(ObjectId objectId,
@@ -283,16 +541,23 @@ public class JcrConnection implements Co
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ListPage<ObjectEntry> getChildren(ObjectId folderId,
             Inclusion inclusion, String orderBy, Paging paging) {
 
         try {
-            Node node = session.getRootNode();
-            String relPath = JcrObjectEntry.getPath(folderId.getId()).substring(
-                    1);
-            if (!relPath.equals("")) {
-                node = node.getNode(relPath);
+            JcrObjectEntry entry = getEntry(folderId);
+            if (entry == null) {
+                throw new ObjectNotFoundException(folderId.getId());
+            }
+            if (entry.getBaseType() != BaseType.FOLDER) {
+                throw new IllegalArgumentException("Not a folder: " + folderId);
             }
+
+            Node node = entry.getNode();
+
             NodeIterator iter;
             if (inclusion == null || inclusion.properties == null) {
                 iter = node.getNodes();
@@ -308,11 +573,10 @@ public class JcrConnection implements Co
             SimpleListPage<ObjectEntry> result = new SimpleListPage<ObjectEntry>();
             while (result.size() < maxItems && iter.hasNext()) {
                 Node child = iter.nextNode();
-                if (JcrCmisMap.isNodeDocument(child)) {
-                    result.add(new JcrDocument(child, this));
-                } else {
-                    result.add(new JcrFolder(child, this));
+                if (JcrCmisMap.isInternal(child)) {
+                    continue;
                 }
+                result.add(new JcrObjectEntry(child, this));
             }
             result.setHasMoreItems(iter.hasNext());
             result.setNumItems((int) iter.getSize());
@@ -325,24 +589,16 @@ public class JcrConnection implements Co
         return null;
     }
 
-    public Connection getConnection() {
-        return this;
-    }
-
+    /**
+     * {@inheritDoc}
+     *
+     * TODO contentStreamId
+     */
     public ContentStream getContentStream(ObjectId documentId,
             String contentStreamId) throws IOException {
-        // TODO contentStreamId
-        try {
-            String relPath = JcrObjectEntry.getPath(documentId.getId()).substring(
-                    1);
-            Node node = session.getRootNode().getNode(relPath);
-            JcrDocument document = new JcrDocument(node, this);
-            return document.getContentStream();
-        } catch (RepositoryException e) {
-            String msg = "Unable to get object: " + documentId;
-            log.error(msg, e);
-        }
-        return null;
+
+        JcrDocument doc = getDocument(documentId);
+        return doc.getContentStream();
     }
 
     public Tree<ObjectEntry> getFolderTree(ObjectId folderId, int depth,
@@ -357,68 +613,135 @@ public class JcrConnection implements Co
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ObjectEntry getFolderParent(ObjectId folderId, String filter) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+        JcrObjectEntry entry = getEntry(folderId);
+        if (entry == null) {
+            throw new ObjectNotFoundException(folderId.getId());
+        }
+        String parentId = (String) entry.getValue(Property.PARENT_ID);
+        if (parentId == null) {
+            // TODO: test case expects null, but javadoc says
+            //       to throw IllegalArgumentException
+            return null;
+        }
+        JcrObjectEntry parent = getEntry(newObjectId(parentId));
+        parent.loadValues();
+        return parent;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Collection<ObjectEntry> getObjectParents(ObjectId objectId,
             String filter) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+
+        // TODO JCR 2.0: add support for shareable nodes
+        Collection<ObjectEntry> result;
+        ObjectEntry parent = getFolderParent(objectId, filter);
+        if (parent == null) {
+            result = Collections.emptyList();
+        } else {
+            result = Arrays.asList(new ObjectEntry[] { parent });
+        }
+        return result;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ObjectEntry getObject(ObjectId objectId, Inclusion inclusion) {
         return getProperties(objectId, inclusion);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ObjectEntry getProperties(ObjectId objectId, Inclusion inclusion) {
-
-        try {
-            String relPath = JcrObjectEntry.getPath(objectId.getId()).substring(
-                    1);
-            if (relPath.equals("")) {
-                return (ObjectEntry) getRootFolder();
-            } else {
-                Node node = session.getRootNode().getNode(relPath);
-                if (JcrCmisMap.isNodeDocument(node)) {
-                    return new JcrDocument(node, this);
-                } else {
-                    return new JcrFolder(node, this);
-                }
-            }
-        } catch (RepositoryException e) {
-            String msg = "Unable to get object: " + objectId;
-            log.error(msg, e);
-        }
-        return null;
+        return getEntry(objectId);
     }
 
-    public ObjectEntry getObjectByPath(String path, Inclusion inclusion) {
+    /**
+     * {@inheritDoc}
+     */
+    public JcrObjectEntry getObjectByPath(String path, Inclusion inclusion) {
         try {
+            Node node = getRootNode();
             if (path == null || path.equals("") || path.equals("/")) {
-                return (ObjectEntry) getRootFolder();
-            } else {
-                if (path.startsWith("/")) {
-                    path = path.substring(1);
-                }
-                Node node = session.getRootNode().getNode(path);
-                if (node.isNodeType(JcrConstants.NT_FOLDER)) {
-                    return new JcrFolder(node, this);
-                } else if (node.isNodeType(JcrConstants.NT_FILE)) {
-                    return new JcrDocument(node, this);
-                }
+                return new JcrObjectEntry(node, JcrRepository.ROOT_TYPE, this);
             }
+            node = node.getNode(path.substring(1));
+            return new JcrObjectEntry(node, this);
+        } catch (PathNotFoundException e) {
+            log.info("Requested object does not exist: " + path);
         } catch (RepositoryException e) {
-            String msg = "Unable to get object: " + path;
-            log.error(msg, e);
+            log.error("Unable to get object: " + path, e);
         }
         return null;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Folder getFolder(String path) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+        JcrObjectEntry entry = (JcrObjectEntry) getObjectByPath(path, null);
+        if (entry == null) {
+            return null;
+        }
+        if (entry.getBaseType() != BaseType.FOLDER) {
+            throw new IllegalArgumentException("Not a folder: " + path);
+        }
+        return (Folder) JcrObject.construct(entry);
+    }
+
+    /**
+     * Return a folder given its object id.
+     *
+     * @param objectId object id
+     * @return folder
+     * @throws ObjectNotFoundException if the object is not found
+     * @throws IllegalArgumentException if the object is not a folder
+     */
+    private JcrFolder getFolder(ObjectId objectId)
+            throws ObjectNotFoundException, IllegalArgumentException {
+
+        if (objectId instanceof JcrFolder) {
+            return (JcrFolder) objectId;
+        }
+        JcrObject o = getObject(objectId);
+        if (o == null) {
+            throw new ObjectNotFoundException("Folder not found: " + objectId);
+        }
+        if (!(o instanceof JcrFolder)) {
+            throw new IllegalArgumentException("Not a folder: " + objectId);
+        }
+        return (JcrFolder) o;
+    }
+
+    /**
+     * Return a document given its object id.
+     *
+     * @param objectId object id
+     * @return document
+     * @throws ObjectNotFoundException if the object is not found
+     * @throws IllegalArgumentException if the object is not a document
+     */
+    private JcrDocument getDocument(ObjectId objectId)
+            throws ObjectNotFoundException, IllegalArgumentException {
+
+        if (objectId instanceof JcrDocument) {
+            return (JcrDocument) objectId;
+        }
+        JcrObject o = getObject(objectId);
+        if (o == null) {
+            throw new ObjectNotFoundException("Document not found: " + objectId);
+        }
+        if (!(o instanceof JcrDocument)) {
+            throw new IllegalArgumentException("Not a document: " + objectId);
+        }
+        return (JcrDocument) o;
     }
 
     public Map<String, Serializable> getPropertiesOfLatestVersion(
@@ -427,34 +750,75 @@ public class JcrConnection implements Co
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ListPage<ObjectEntry> getRelationships(ObjectId objectId,
             String typeId, boolean includeSubRelationshipTypes,
             Inclusion inclusion, Paging paging) {
         return SimpleListPage.emptyList();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ListPage<Rendition> getRenditions(ObjectId object,
             Inclusion inclusion, Paging paging) {
         return SimpleListPage.emptyList();
     }
 
-    public boolean hasContentStream(ObjectId document) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasContentStream(ObjectId documentId) {
+        return getDocument(documentId).getContentStream() != null;
     }
 
-    public ObjectId moveObject(ObjectId objectId, ObjectId targetFolderId,
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectId moveObject(ObjectId documentId, ObjectId targetFolderId,
             ObjectId sourceFolderId) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+
+        JcrFolder folder = getFolder(targetFolderId);
+        JcrDocument source = getDocument(documentId);
+
+        if (sourceFolderId != null) {
+            if (!source.getParent().getId().equals(sourceFolderId.getId())) {
+                throw new IllegalArgumentException("Source folder is not the parent of the document");
+            }
+        }
+
+        try {
+            String sourcePath = source.getEntry().getNode().getPath();
+            String sourceName = source.getName();
+            String destPath = folder.getEntry().getNode().getPath() + "/" + sourceName;
+
+            Workspace workspace = session.getWorkspace();
+            workspace.move(sourcePath, destPath);
+
+            JcrObject object = getObject(documentId);
+            if (!(object instanceof JcrDocument)) {
+                log.error("Target object not found after moving");
+                return null;
+            }
+            return object;
+
+        } catch (RepositoryException e) {
+            log.error("Unable to move.", e);
+        }
+        return null;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ListPage<ObjectEntry> query(String statement,
             boolean searchAllVersions, Inclusion inclusion, Paging paging) {
 
         try {
             QueryManager qm = session.getWorkspace().getQueryManager();
-            QueryResult qr = qm.createQuery(statement, Query.SQL).execute();
+            QueryResult qr = qm.createQuery(statement, Query.JCR_SQL2).execute();
             NodeIterator iter = qr.getNodes();
             if (iter.hasNext() && paging != null) {
                 iter.skip(paging.skipCount);
@@ -465,11 +829,10 @@ public class JcrConnection implements Co
             SimpleListPage<ObjectEntry> result = new SimpleListPage<ObjectEntry>();
             while (result.size() < maxItems && iter.hasNext()) {
                 Node child = iter.nextNode();
-                if (child.isNodeType(JcrConstants.NT_FOLDER)) {
-                    result.add(new JcrFolder(child, this));
-                } else if (child.isNodeType(JcrConstants.NT_FILE)) {
-                    result.add(new JcrDocument(child, this));
+                if (JcrCmisMap.isInternal(child)) {
+                    continue;
                 }
+                result.add(new JcrObjectEntry(child, this));
             }
             result.setHasMoreItems(iter.hasNext());
             result.setNumItems((int) iter.getSize());
@@ -478,8 +841,8 @@ public class JcrConnection implements Co
         } catch (RepositoryException e) {
             String msg = "Unable to execute query.";
             log.error(msg, e);
+            return new SimpleListPage<ObjectEntry>();
         }
-        return null;
     }
 
     public void removeObjectFromFolder(ObjectId objectId, ObjectId folderId) {
@@ -492,18 +855,38 @@ public class JcrConnection implements Co
         throw new UnsupportedOperationException();
     }
 
-    public ObjectId setContentStream(ObjectId documentId,
-            ContentStream contentStream, boolean overwrite) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectId setContentStream(ObjectId documentId, ContentStream cs, boolean overwrite)
+            throws ContentAlreadyExistsException, IOException {
+
+        JcrDocument doc = getDocument(documentId);
+        if (!overwrite && doc.getContentStream() != null) {
+            throw new ContentAlreadyExistsException("Document already has a content stream: " + documentId);
+        }
+        doc.setContentStream(cs);
+        return doc;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ObjectId updateProperties(ObjectId objectId, String changeToken,
             Map<String, Serializable> properties) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+
+        JcrObject object = getObject(objectId);
+        if (object == null) {
+            return null;
+        }
+        object.setValues(properties);
+        object.save();
+        return object;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public ListPage<ObjectEntry> getChangeLog(String changeLogToken,
             boolean includeProperties, Paging paging,
             String[] latestChangeLogToken) {
@@ -524,4 +907,10 @@ public class JcrConnection implements Co
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * Internal: return session associated with this connection.
+     */
+    Session getSession() {
+        return session;
+    }
 }

Modified: incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrContentStream.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrContentStream.java?rev=925158&r1=925157&r2=925158&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrContentStream.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrContentStream.java Fri Mar 19 10:09:26 2010
@@ -16,7 +16,6 @@
  */
 package org.apache.chemistry.jcr;
 
-import java.io.IOException;
 import java.io.InputStream;
 
 import javax.jcr.Node;
@@ -27,26 +26,47 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.JcrConstants;
 
-public class JcrContentStream implements ContentStream {
-
-    private static final Log log = LogFactory.getLog(JcrFolder.class);
+/**
+ * Implementation of a content stream.
+ */
+class JcrContentStream implements ContentStream {
 
+    /**
+     * Logger.
+     */
+    private static final Log log = LogFactory.getLog(JcrContentStream.class);
+
+    /**
+     * Content node of type <b>nt:resource</b>.
+     */
     private final Node content;
 
-    public JcrContentStream(Node content) {
+    /**
+     * Filename.
+     */
+    private final String filename;
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param content content node
+     * @param filename content stream file name
+     */
+    public JcrContentStream(Node content, String filename) {
         this.content = content;
+        this.filename = filename;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public String getFileName() {
-        try {
-            return content.getName();
-        } catch (RepositoryException e) {
-            String msg = "Unable to get node name.";
-            log.error(msg, e);
-        }
-        return null;
+        return filename;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public long getLength() {
         try {
             javax.jcr.Property data = content.getProperty(JcrConstants.JCR_DATA);
@@ -58,6 +78,9 @@ public class JcrContentStream implements
         return 0;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public String getMimeType() {
         try {
             javax.jcr.Property mimetype = content.getProperty(JcrConstants.JCR_MIMETYPE);
@@ -69,10 +92,13 @@ public class JcrContentStream implements
         return null;
     }
 
-    public InputStream getStream() throws IOException {
+    /**
+     * {@inheritDoc}
+     */
+    public InputStream getStream() {
         try {
             javax.jcr.Property data = content.getProperty(JcrConstants.JCR_DATA);
-            return data.getStream();
+            return data.getBinary().getStream();
         } catch (RepositoryException e) {
             String msg = "Unable to get stream.";
             log.error(msg, e);

Modified: incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrDocument.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrDocument.java?rev=925158&r1=925157&r2=925158&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrDocument.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrDocument.java Fri Mar 19 10:09:26 2010
@@ -1,52 +1,87 @@
 /*
- * 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
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     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.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
  */
 package org.apache.chemistry.jcr;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Map;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 
-import org.apache.chemistry.BaseType;
-import org.apache.chemistry.ChangeInfo;
 import org.apache.chemistry.ContentStream;
+import org.apache.chemistry.ContentStreamPresence;
 import org.apache.chemistry.Document;
 import org.apache.chemistry.Folder;
 import org.apache.chemistry.NameConstraintViolationException;
 import org.apache.chemistry.Property;
+import org.apache.chemistry.PropertyDefinition;
+import org.apache.chemistry.util.GregorianCalendar;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.JcrConstants;
 
-public class JcrDocument extends JcrObjectEntry implements Document {
+/**
+ * Document implementation.
+ */
+class JcrDocument extends JcrObject implements Document {
 
+    /**
+     * Logger.
+     */
     private static final Log log = LogFactory.getLog(JcrDocument.class);
 
-    public JcrDocument(Node node, JcrConnection connection) {
-        super(node, connection);
-    }
-
+    /**
+     * Content stream.
+     */
+    private ContentStream cs;
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param entry
+     */
+    public JcrDocument(JcrObjectEntry entry) {
+        super(entry);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public ContentStream getContentStream() {
+        if (entry.isNew()) {
+            return cs;
+        }
         try {
+            Node node = entry.getNode();
+
             Node content = node.getNode(JcrConstants.JCR_CONTENT);
-            return new JcrContentStream(content);
+            String filename = null;
+            if (hasCmisPrefix() && node.hasProperty(Property.CONTENT_STREAM_FILE_NAME)) {
+                filename = node.getProperty(Property.CONTENT_STREAM_FILE_NAME).getString();
+            }
+            JcrContentStream cs = new JcrContentStream(content, filename);
+            if (cs.getLength() != 0) {
+                return cs;
+            }
         } catch (RepositoryException e) {
             String msg = "Unable to get parent.";
             log.error(msg, e);
@@ -54,108 +89,243 @@ public class JcrDocument extends JcrObje
         return null;
     }
 
-    public ContentStream getContentStream(String contentStreamId) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
-    }
+    /**
+     * {@inheritDoc}
+     */
+    public void setContentStream(ContentStream cs)
+            throws IOException {
 
-    public Folder getParent() {
-        try {
-            return new JcrFolder(node.getParent(), connection);
-        } catch (RepositoryException e) {
-            String msg = "Unable to get parent.";
-            log.error(msg, e);
+        ContentStreamPresence csa = getType().getContentStreamAllowed();
+        if (csa == ContentStreamPresence.NOT_ALLOWED && cs != null) {
+            throw new IllegalStateException("Content stream not allowed"); // TODO
+        } else if (csa == ContentStreamPresence.REQUIRED
+                && cs == null) {
+            throw new IllegalStateException("Content stream required"); // TODO
         }
-        return null;
-    }
-
-    @Override
-    public String getString(String id) {
-        if (id.equals(Property.CONTENT_STREAM_MIME_TYPE)) {
-            return getContentStream().getMimeType();
+        if (entry.isNew()) {
+            this.cs = cs;
+            return;
         }
-        return super.getString(id);
-    }
 
-    public void setContentStream(ContentStream contentStream)
-            throws IOException {
+        Node node = entry.getNode();
+        Session session = null;
 
-        throw new UnsupportedOperationException();
-    }
+        try {
+            session = node.getSession();
+            Node content;
 
-    public void save() {
-        throw new UnsupportedOperationException();
-    }
+            if (node.hasNode(JcrConstants.JCR_CONTENT)) {
+                content = node.getNode(JcrConstants.JCR_CONTENT);
+            } else {
+                content = node.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE);
+            }
+            if (cs != null) {
+                content.setProperty(JcrConstants.JCR_MIMETYPE, cs.getMimeType());
+                content.setProperty(JcrConstants.JCR_DATA,
+                        session.getValueFactory().createBinary(cs.getStream()));
+
+                String filename = cs.getFileName();
+                if (filename != null) {
+                    node.setProperty(Property.CONTENT_STREAM_FILE_NAME, filename);
+                }
+            } else {
+                content.setProperty(JcrConstants.JCR_MIMETYPE, "application/octet-stream");
+                content.setProperty(JcrConstants.JCR_DATA,
+                        session.getValueFactory().createBinary(new ByteArrayInputStream(new byte[0])));
+            }
+            content.setProperty(JcrConstants.JCR_LASTMODIFIED,
+                    GregorianCalendar.getInstance());
+            session.save();
 
-    public void setName(String value) {
-        throw new UnsupportedOperationException();
-    }
+            entry.setContentStream(cs);
 
-    public void setValue(String id, Serializable value) {
-        throw new UnsupportedOperationException();
+        } catch (RepositoryException e) {
+            log.error("Unable to set content stream.", e);
+
+            if (session != null) {
+                try {
+                    session.refresh(false);
+                } catch (RepositoryException e2) {
+                    log.error("Error while refreshing session.", e2);
+                }
+            }
+        }
     }
 
-    public void setValues(Map<String, Serializable> values) {
-        throw new UnsupportedOperationException();
+    /**
+     * {@inheritDoc}
+     */
+    public Document copy(Folder folder) throws NameConstraintViolationException {
+        return (JcrDocument) connection.createDocumentFromSource(this, folder, null, null);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public Document getDocument() {
-        return this;
+    public void save() {
+        if (entry.isNew()) {
+            add();
+        } else {
+            update();
+        }
     }
 
-    @Override
-    public boolean hasContentStream() {
+    /**
+     * Add a new document.
+     */
+    protected void add() {
+        Session session = null;
+        InputStream is = null;
+
+        if (cs != null) {
+            try {
+                is = cs.getStream();
+            } catch (IOException e) {
+                String msg = "Unable to get stream.";
+                log.error(msg, e);
+                return;
+            }
+        }
+
         try {
-            return node.hasNode(JcrConstants.JCR_CONTENT);
+            String parentId = (String) entry.getValue(Property.PARENT_ID);
+            if (parentId == null) {
+                parentId = connection.getRepository().getInfo().getRootFolderId().getId();
+            }
+            String name = getName();
+            if (name == null) {
+                name = "Untitled";
+            }
+
+            session = connection.getSession();
+            Node parent = session.getNodeByIdentifier(parentId);
+            Node node = parent.addNode(name, JcrConstants.NT_FILE);
+            node.addMixin(JcrRepository.MIX_UNSTRUCTURED);
+
+            Node content = node.addNode(JcrConstants.JCR_CONTENT,
+                    JcrConstants.NT_RESOURCE);
+            if (cs != null) {
+                content.setProperty(JcrConstants.JCR_MIMETYPE, cs.getMimeType());
+                content.setProperty(JcrConstants.JCR_DATA,
+                        session.getValueFactory().createBinary(is));
+
+                String filename = cs.getFileName();
+                if (filename != null) {
+                    node.setProperty(Property.CONTENT_STREAM_FILE_NAME, filename);
+                }
+            } else {
+                content.setProperty(JcrConstants.JCR_MIMETYPE, "application/octet-stream");
+                content.setProperty(JcrConstants.JCR_DATA,
+                        session.getValueFactory().createBinary(new ByteArrayInputStream(new byte[0])));
+            }
+            content.setProperty(JcrConstants.JCR_LASTMODIFIED,
+                    GregorianCalendar.getInstance());
+
+            javax.jcr.ValueFactory f = connection.getSession().getValueFactory();
+            Map<String, Serializable> values = entry.getValues();
+            for (String key : values.keySet()) {
+                if (!key.startsWith(JcrRepository.CMIS_PREFIX)) {
+                    PropertyDefinition pd = type.getPropertyDefinition(key);
+                    Serializable v = values.get(key);
+                    node.setProperty(key, JcrCmisMap.serializableToValue(pd.getType(), v, f));
+                }
+            }
+            node.setProperty(Property.TYPE_ID, entry.getTypeId());
+            session.save();
+
+            entry.setNode(node);
+            entry.setContentStream(cs);
+
         } catch (RepositoryException e) {
-            String msg = "Unable to get sub node: " + JcrConstants.JCR_CONTENT;
-            log.error(msg, e);
+            log.error("Unable to add document.", e);
+
+            if (session != null) {
+                try {
+                    session.refresh(false);
+                } catch (RepositoryException e2) {
+                    log.error("Error while refreshing session.", e2);
+                }
+            }
         }
-        return false;
     }
 
-    public void cancelCheckOut() {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
-    }
+    /**
+     * Update an existing document.
+     */
+    protected void update() {
+        Session session = null;
 
-    public Document checkIn(boolean major, String comment) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
+        try {
+            Node node = entry.getNode();
+            session = node.getSession();
+
+            Map<String, Serializable> values = entry.getValues();
+            for (String key : values.keySet()) {
+                if (!key.startsWith(JcrRepository.CMIS_PREFIX)) {
+                    node.setProperty(key, values.get(key).toString());
+                }
+            }
+            session.save();
+
+        } catch (RepositoryException e) {
+            log.error("Unable to update document.", e);
+
+            if (session != null) {
+                try {
+                    session.refresh(false);
+                } catch (RepositoryException e2) {
+                    log.error("Error while refreshing session.", e2);
+                }
+            }
+        }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Document checkOut() {
         // TODO Auto-generated method stub
         throw new UnsupportedOperationException();
     }
 
-    public void deleteAllVersions() {
+    /**
+     * {@inheritDoc}
+     */
+    public void cancelCheckOut() {
         // TODO Auto-generated method stub
         throw new UnsupportedOperationException();
     }
 
-    public Collection<Document> getAllVersions() {
+    /**
+     * {@inheritDoc}
+     */
+    public Document checkIn(boolean major, String comment) {
         // TODO Auto-generated method stub
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Document getLatestVersion(boolean major) {
         // TODO Auto-generated method stub
         throw new UnsupportedOperationException();
     }
 
-    public BaseType getBaseType() {
-        return BaseType.DOCUMENT;
-    }
-
-    public ChangeInfo getChangeInfo() {
-        return null;
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<Document> getAllVersions() {
+        // TODO Auto-generated method stub
+        throw new UnsupportedOperationException();
     }
 
-    public Document copy(Folder folder) throws NameConstraintViolationException {
+    /**
+     * {@inheritDoc}
+     */
+    public void deleteAllVersions() {
         // TODO Auto-generated method stub
         throw new UnsupportedOperationException();
     }
-
 }

Modified: incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrFolder.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrFolder.java?rev=925158&r1=925157&r2=925158&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrFolder.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrFolder.java Fri Mar 19 10:09:26 2010
@@ -1,12 +1,9 @@
 /*
- * 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
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     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,
@@ -15,55 +12,76 @@
  * limitations under the License.
  *
  * Authors:
- *     Dominique Pfister, Day
- *     Michael Mertins, Saperion
+ *     Florent Guillaume, Nuxeo
  */
 package org.apache.chemistry.jcr;
 
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
 import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 
-import org.apache.chemistry.BaseType;
 import org.apache.chemistry.CMISObject;
-import org.apache.chemistry.ChangeInfo;
-import org.apache.chemistry.ContentStream;
 import org.apache.chemistry.Document;
 import org.apache.chemistry.Folder;
 import org.apache.chemistry.ObjectId;
+import org.apache.chemistry.Property;
 import org.apache.chemistry.Unfiling;
+import org.apache.chemistry.UpdateConflictException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.JcrConstants;
 
-public class JcrFolder extends JcrObjectEntry implements Folder {
+/**
+ * Folder implementation.
+ */
+class JcrFolder extends JcrObject implements Folder {
 
+    /**
+     * Logger.
+     */
     private static final Log log = LogFactory.getLog(JcrFolder.class);
 
-    public JcrFolder(Node node, JcrConnection connection) {
-        super(node, connection);
-    }
-
+    /**
+     * Create a new instance of this class.
+     *
+     * @param entry object entry
+     */
+    public JcrFolder(JcrObjectEntry entry) {
+        super(entry);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<ObjectId> deleteTree(Unfiling unfiling)
+            throws UpdateConflictException {
+        return connection.getSPI().deleteTree(this, unfiling, true);
+    }
+
+    /**
+     * Return all children of this folder.
+     *
+     * @return list of children
+     */
     public List<CMISObject> getChildren() {
         try {
             List<CMISObject> result = new ArrayList<CMISObject>();
 
-            NodeIterator iter = node.getNodes();
+            NodeIterator iter = entry.getNode().getNodes();
             while (iter.hasNext()) {
                 Node child = iter.nextNode();
-                CMISObject entry;
-                if (JcrCmisMap.isNodeDocument(child)) {
-                    entry = new JcrDocument(child, connection);
-                } else {
-                    entry = new JcrFolder(child, connection);
+                if (JcrCmisMap.isInternal(child)) {
+                    continue;
                 }
-                result.add(entry);
+                JcrObjectEntry entry = new JcrObjectEntry(child, connection);
+                result.add(JcrObject.construct(entry));
             }
             return result;
         } catch (RepositoryException e) {
@@ -73,73 +91,121 @@ public class JcrFolder extends JcrObject
         return null;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Document newDocument(String typeId) {
-        return new JcrNewDocument(node, connection);
+        return connection.newDocument(typeId, this);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public Folder newFolder(String typeId) {
-        return new JcrNewFolder(node, connection);
+        return connection.newFolder(typeId, this);
     }
 
-    public Folder getParent() {
-        try {
-            if (node.getDepth() > 0) {
-                return new JcrFolder(node.getParent(), connection);
-            }
-        } catch (RepositoryException e) {
-            String msg = "Unable to get parent.";
-            log.error(msg, e);
-        }
-        return null;
-    }
-
-    public void save() {
+    /**
+     * {@inheritDoc}
+     */
+    public void add(CMISObject object) {
+        // TODO Auto-generated method stub
         throw new UnsupportedOperationException();
     }
 
-    public void setName(String id) {
+    /**
+     * {@inheritDoc}
+     */
+    public void remove(CMISObject object) {
+        // TODO Auto-generated method stub
         throw new UnsupportedOperationException();
     }
 
-    public void setValue(String id, Serializable value) {
-        throw new UnsupportedOperationException();
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void save() {
+        if (entry.isNew()) {
+            add();
+        } else {
+            update();
+        }
     }
 
-    public void setValues(Map<String, Serializable> values) {
-        throw new UnsupportedOperationException();
-    }
+    /**
+     * Add a new folder.
+     */
+    protected void add() {
+        Session session = null;
 
-    @Override
-    public Folder getFolder() {
-        return this;
-    }
+        try {
+            String parentId = (String) entry.getValue(Property.PARENT_ID);
+            if (parentId == null) {
+                parentId = connection.getRepository().getInfo().getRootFolderId().getId();
+            }
+            String name = getName();
+            if (name == null) {
+                name = "Untitled";
+            }
 
-    public void add(CMISObject object) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
-    }
+            session = connection.getSession();
+            Node parent = session.getNodeByIdentifier(parentId);
+            Node node = parent.addNode(name, JcrConstants.NT_FOLDER);
+            node.addMixin(JcrRepository.MIX_UNSTRUCTURED);
+
+            Map<String, Serializable> values = entry.getValues();
+            for (String key : values.keySet()) {
+                if (!key.startsWith(JcrRepository.CMIS_PREFIX)) {
+                    node.setProperty(key, values.get(key).toString());
+                }
+            }
+            node.setProperty(Property.TYPE_ID, entry.getTypeId());
 
-    public void remove(CMISObject object) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
-    }
+            parent.getSession().save();
+            entry.setNode(node);
 
-    public Collection<ObjectId> deleteTree(Unfiling unfiling) {
-        delete();
-        return Collections.emptySet();
-    }
+        } catch (RepositoryException e) {
+            log.error("Unable to add folder.", e);
 
-    public BaseType getBaseType() {
-        return BaseType.FOLDER;
+            if (session != null) {
+                try {
+                    session.refresh(false);
+                } catch (RepositoryException e2) {
+                    log.error("Error while refreshing session.", e2);
+                }
+            }
+        }
     }
 
-    public ChangeInfo getChangeInfo() {
-        return null;
-    }
+    /**
+     * Update an existing folder.
+     */
+    protected void update() {
+        Session session = null;
 
-    public ContentStream getContentStream(String contentStreamId) {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException();
-    }
+        try {
+            Node node = entry.getNode();
+            session = node.getSession();
+
+            Map<String, Serializable> values = entry.getValues();
+            for (String key : values.keySet()) {
+                if (!key.startsWith(JcrRepository.CMIS_PREFIX)) {
+                    node.setProperty(key, values.get(key).toString());
+                }
+            }
+            session.save();
+
+        } catch (RepositoryException e) {
+            log.error("Unable to update folder.", e);
 
+            if (session != null) {
+                try {
+                    session.refresh(false);
+                } catch (RepositoryException e2) {
+                    log.error("Error while refreshing session.", e2);
+                }
+            }
+        }
+    }
 }

Added: incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrObject.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrObject.java?rev=925158&view=auto
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrObject.java (added)
+++ incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrObject.java Fri Mar 19 10:09:26 2010
@@ -0,0 +1,246 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
+ */
+package org.apache.chemistry.jcr;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.chemistry.BaseType;
+import org.apache.chemistry.CMISObject;
+import org.apache.chemistry.Connection;
+import org.apache.chemistry.ContentStream;
+import org.apache.chemistry.Folder;
+import org.apache.chemistry.NameConstraintViolationException;
+import org.apache.chemistry.Policy;
+import org.apache.chemistry.Property;
+import org.apache.chemistry.PropertyDefinition;
+import org.apache.chemistry.Relationship;
+import org.apache.chemistry.RelationshipDirection;
+import org.apache.chemistry.Type;
+import org.apache.chemistry.UpdateConflictException;
+import org.apache.chemistry.impl.base.BaseObject;
+import org.apache.chemistry.impl.simple.SimpleProperty;
+
+/**
+ * JCR implementation of a {@link CMISObject}.
+ */
+abstract class JcrObject extends BaseObject {
+
+    /**
+     * Underlying entry.
+     */
+    protected final JcrObjectEntry entry;
+
+    /**
+     * Connection used to create this object.
+     */
+    protected final JcrConnection connection;
+
+    /**
+     * Object type.
+     */
+    protected final Type type;
+
+    /**
+     * Create a new instance of this class. Used for derived classes only.
+     *
+     * @param entry entry
+     */
+    protected JcrObject(JcrObjectEntry entry) {
+        this.entry = entry;
+
+        connection = entry.getConnection();
+        type = connection.getRepository().getType(entry.getTypeId());
+    }
+
+    protected static JcrObject construct(JcrObjectEntry entry) {
+        JcrConnection connection = entry.getConnection();
+        BaseType baseType = connection.getRepository().getType(
+                entry.getTypeId()).getBaseType();
+
+        switch (baseType) {
+        case DOCUMENT:
+            return new JcrDocument(entry);
+        case FOLDER:
+            return new JcrFolder(entry);
+        case POLICY:
+            return new JcrPolicy(entry);
+        case RELATIONSHIP:
+            return new JcrRelationship(entry);
+        default:
+            throw new AssertionError();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Connection getConnection() {
+        return connection;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void move(Folder targetFolder, Folder sourceFolder)
+            throws NameConstraintViolationException, UpdateConflictException {
+        connection.getSPI().moveObject(this, targetFolder, sourceFolder);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void delete() throws UpdateConflictException {
+        connection.getSPI().deleteObject(this, false);
+    }
+
+    public void unfile() {
+        // TODO Auto-generated method stub
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Folder getParent() {
+        String id = (String) entry.getValue(Property.PARENT_ID);
+        if (id == null) {
+            return null;
+        }
+        return (Folder) connection.getObject(connection.newObjectId(id));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<Folder> getParents() {
+        Collection<Folder> result;
+        Folder parent = getParent();
+        if (parent == null) {
+            result = Collections.emptyList();
+        } else {
+            result = Arrays.asList(new Folder[] { parent });
+        }
+        return result;
+    }
+
+    public List<Relationship> getRelationships(RelationshipDirection direction,
+            String typeId, boolean includeSubRelationshipTypes) {
+        // TODO Auto-generated method stub
+        throw new UnsupportedOperationException();
+    }
+
+    public void applyPolicy(Policy policy) {
+        // TODO Auto-generated method stub
+        throw new UnsupportedOperationException();
+    }
+
+    public void removePolicy(Policy policy) {
+        // TODO Auto-generated method stub
+        throw new UnsupportedOperationException();
+    }
+
+    public Collection<Policy> getPolicies() {
+        // TODO Auto-generated method stub
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Type getType() {
+        return type;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public BaseType getBaseType() {
+        return type.getBaseType();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Serializable getValue(String id) {
+        PropertyDefinition pd = getType().getPropertyDefinition(id);
+        if (pd == null) {
+            throw new IllegalArgumentException(id);
+        }
+        Serializable value = entry.getValue(id);
+        if (value == null) {
+            value = pd.getDefaultValue();
+        }
+        return value;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Property getProperty(String id) {
+        PropertyDefinition propertyDefinition = getType().getPropertyDefinition(
+                id);
+        if (propertyDefinition == null) {
+            throw new IllegalArgumentException(id);
+        }
+        return new SimpleProperty(entry, id, propertyDefinition);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ContentStream getContentStream(String contentStreamId) {
+        // TODO Auto-generated method stub
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void save() {
+        /* Derived classes have to implement this */
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + '(' + getTypeId() + ',' + getId()
+                + ')';
+    }
+
+    /**
+     * Return the underlying entry.
+     *
+     * @return entry
+     */
+    JcrObjectEntry getEntry() {
+        return entry;
+    }
+
+    /**
+     * Return a flag indicating whether the namespace prefix <b>cmis</b> is known to
+     * the repository.
+     *
+     * @return namespace URI
+     */
+    boolean hasCmisPrefix() {
+        return connection.getRepository().hasCmisPrefix();
+    }
+}

Propchange: incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrObject.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrObject.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url