jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mdue...@apache.org
Subject svn commit: r903343 - in /jackrabbit/sandbox/jackrabbit-spi2cmis/src: main/java/org/apache/jackrabbit/spi2cmis/ main/java/org/apache/jackrabbit/spi2cmis/util/ main/resources/ test/java/org/apache/jackrabbit/spi2cmis/
Date Tue, 26 Jan 2010 17:56:55 GMT
Author: mduerig
Date: Tue Jan 26 17:56:54 2010
New Revision: 903343

URL: http://svn.apache.org/viewvc?rev=903343&view=rev
Log:
- Exposing CMIS folder as JCR type nt:folder
- Exposing CMIS document as JCR type nt:file
- Exposing content streams via jcr:data property

Added:
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Arrays.java   (with props)
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Functions.java   (with props)
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Iterators.java   (with props)
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Predicate.java   (with props)
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Streams.java   (with props)
Removed:
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/SuppressWarning.java
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/Util.java
Modified:
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/CmisRepositoryService.java
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ItemTransformer.java
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/PathTransformer.java
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/TypeTransformer.java
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ValueTransformer.java
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/resources/nodetypes.cnd
    jackrabbit/sandbox/jackrabbit-spi2cmis/src/test/java/org/apache/jackrabbit/spi2cmis/ReadTest.java

Modified: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/CmisRepositoryService.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/CmisRepositoryService.java?rev=903343&r1=903342&r2=903343&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/CmisRepositoryService.java (original)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/CmisRepositoryService.java Tue Jan 26 17:56:54 2010
@@ -17,8 +17,6 @@
 package org.apache.jackrabbit.spi2cmis;
 
 
-import static org.apache.jackrabbit.spi2cmis.SuppressWarning.unchecked;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -26,6 +24,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.jcr.Credentials;
@@ -38,22 +37,19 @@
 import org.apache.chemistry.CMIS;
 import org.apache.chemistry.CMISObject;
 import org.apache.chemistry.Connection;
+import org.apache.chemistry.ContentStream;
 import org.apache.chemistry.Folder;
 import org.apache.chemistry.ListPage;
 import org.apache.chemistry.ObjectEntry;
-import org.apache.chemistry.ObjectId;
 import org.apache.chemistry.Property;
 import org.apache.chemistry.Repository;
 import org.apache.chemistry.RepositoryCapabilities;
 import org.apache.chemistry.RepositoryInfo;
 import org.apache.chemistry.Type;
-import org.apache.commons.collections.Transformer;
-import org.apache.commons.collections.iterators.EmptyIterator;
-import org.apache.commons.collections.iterators.SingletonIterator;
-import org.apache.commons.collections.iterators.TransformIterator;
 import org.apache.jackrabbit.commons.cnd.CompactNodeTypeDefReader;
 import org.apache.jackrabbit.commons.cnd.ParseException;
 import org.apache.jackrabbit.spi.ChildInfo;
+import org.apache.jackrabbit.spi.IdFactory;
 import org.apache.jackrabbit.spi.ItemId;
 import org.apache.jackrabbit.spi.ItemInfo;
 import org.apache.jackrabbit.spi.Name;
@@ -69,10 +65,17 @@
 import org.apache.jackrabbit.spi.RepositoryService;
 import org.apache.jackrabbit.spi.SessionInfo;
 import org.apache.jackrabbit.spi.commons.AbstractRepositoryService;
+import org.apache.jackrabbit.spi.commons.ChildInfoImpl;
+import org.apache.jackrabbit.spi.commons.NodeInfoImpl;
+import org.apache.jackrabbit.spi.commons.PropertyInfoImpl;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
 import org.apache.jackrabbit.spi.commons.nodetype.QDefinitionBuilderFactory;
-import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl;
+import org.apache.jackrabbit.spi2cmis.util.Arrays;
+import org.apache.jackrabbit.spi2cmis.util.Iterators;
+import org.apache.jackrabbit.spi2cmis.util.Streams;
+import org.apache.jackrabbit.spi2cmis.util.Functions.Function;
+import org.apache.jackrabbit.spi2cmis.util.Functions.PartialFunction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
@@ -82,10 +85,6 @@
  * Implements a direct mapping of CMIS types to JCR types and of the CMIS content structure
  * to a JCR content structure.
  * <ul>
- *   <li>todo implement: expose cmis:folder as nt:folder and cmis:document as nt:file
- *   </li>
- *   <li>todo implement: expose content streams
- *   </li>
  *   <li>todo implement: implement query support
  *   </li>
  *   <li>todo implement: access control
@@ -117,7 +116,7 @@
      * @param cmisRepository  the underlying CMIS repository
      * @throws RepositoryException
      */
-    protected CmisRepositoryService(Repository cmisRepository) throws RepositoryException {
+    protected CmisRepositoryService(final Repository cmisRepository) throws RepositoryException {
         super();
         this.cmisRepository = cmisRepository;
 
@@ -141,9 +140,8 @@
         }
 
         // Register JCR related node types
-        for (QNodeTypeDefinition ntd : cndReader.getNodeTypeDefinitions()) {
-            nodeTypeDefs.registerNodeTypes(new QNodeTypeDefinition[] { ntd }, true);
-        }
+        List<QNodeTypeDefinition> jcrTypes = cndReader.getNodeTypeDefinitions();
+        nodeTypeDefs.registerNodeTypes(jcrTypes.toArray(new QNodeTypeDefinition[jcrTypes.size()]), true);
 
         // Register JCR related name spaces
         Map<String, String> prefix2Uri = cndReader.getNamespaceMapping().getPrefixToURIMapping();
@@ -153,58 +151,46 @@
 
         // Register node types of the CMIS repository
         Collection<Type> cmisTypes = cmisRepository.getTypes();
-        QNodeTypeDefinition[] ntds = new QNodeTypeDefinition[cmisTypes.size()];
-        int k = 0;
-        for (Type cmisType : cmisTypes) {
-            ntds[k++] = TypeTransformer.jcrNodeTypeDef(cmisRepository, cmisType, namespaces);
-        }
-        nodeTypeDefs.registerNodeTypes(ntds, true);
+        nodeTypeDefs.registerNodeTypes(Arrays.map(cmisTypes, new QNodeTypeDefinition[cmisTypes.size()],
+            new PartialFunction<Type, QNodeTypeDefinition, RepositoryException>() {
+                public QNodeTypeDefinition apply(Type cmisType) throws RepositoryException {
+                    return TypeTransformer.jcrNodeTypeDef(cmisRepository, cmisType, namespaces);
+                }
+            }), true);
     }
 
-    private static void initRepositoryDescriptors(Map<String, QValue[]> descriptors, RepositoryInfo info)
+    private void initRepositoryDescriptors(Map<String, QValue[]> descriptors, RepositoryInfo info)
             throws ValueFormatException, RepositoryException {
 
-        QValueFactory qvf = QValueFactoryImpl.getInstance();
+        QValueFactory factory = getQValueFactory();
 
-        descriptors.put(CMIS.DESCRIPTION.toString(), qValue(info.getDescription(), qvf));
-        descriptors.put(CMIS.VENDOR_NAME.toString(), qValue(info.getVendorName(), qvf));
-        descriptors.put(CMIS.PRODUCT_NAME.toString(), qValue(info.getProductName(), qvf));
-        descriptors.put(CMIS.PRODUCT_VERSION.toString(), qValue(info.getProductVersion(), qvf));
-        descriptors.put(CMIS.VERSION_SUPPORTED.toString(), qValue(info.getVersionSupported(), qvf));
+        descriptors.put(CMIS.DESCRIPTION.toString(), qValue(info.getDescription(), factory));
+        descriptors.put(CMIS.VENDOR_NAME.toString(), qValue(info.getVendorName(), factory));
+        descriptors.put(CMIS.PRODUCT_NAME.toString(), qValue(info.getProductName(), factory));
+        descriptors.put(CMIS.PRODUCT_VERSION.toString(), qValue(info.getProductVersion(), factory));
+        descriptors.put(CMIS.VERSION_SUPPORTED.toString(), qValue(info.getVersionSupported(), factory));
 
         Document repoSpecific = info.getRepositorySpecificInformation();
         if (repoSpecific != null) {
-            descriptors.put(CMIS.REPOSITORY_SPECIFIC_INFORMATION.toString(), qValue(repoSpecific.toString(), qvf));
+            descriptors.put(CMIS.REPOSITORY_SPECIFIC_INFORMATION.toString(), qValue(repoSpecific.toString(), factory));
         }
 
         RepositoryCapabilities caps = info.getCapabilities();
-        descriptors.put(CMIS.CAPABILITY_MULTIFILING.toString(), qValue(caps.hasMultifiling(), qvf));
-        descriptors.put(CMIS.CAPABILITY_UNFILING.toString(), qValue(caps.hasUnfiling() , qvf));
-        descriptors.put(CMIS.CAPABILITY_VERSION_SPECIFIC_FILING.toString(), qValue(caps.hasVersionSpecificFiling(), qvf));
-        descriptors.put(CMIS.CAPABILITY_PWC_UPDATABLE.toString(), qValue(caps.isPWCUpdatable(), qvf));
-        descriptors.put(CMIS.CAPABILITY_PWC_SEARCHABLE.toString(), qValue(caps.isPWCSearchable() , qvf));
-        descriptors.put(CMIS.CAPABILITY_ALL_VERSIONS_SEARCHABLE.toString(), qValue(caps.isAllVersionsSearchable() , qvf));
-        descriptors.put(CMIS.CAPABILITY_CAN_GET_DESCENDANTS.toString(), qValue(caps.hasGetDescendants() , qvf));
-        descriptors.put(CMIS.CAPABILITY_CAN_GET_FOLDER_TREE.toString(), qValue(caps.hasGetFolderTree(), qvf));
-        descriptors.put(CMIS.CAPABILITY_CONTENT_STREAM_UPDATABILITY.toString(), qValue(caps.isContentStreamUpdatableAnytime() , qvf));
-
-        descriptors.put(CMIS.CAPABILITY_QUERY.toString(), qValue(caps.getQueryCapability(), qvf));
-        descriptors.put(CMIS.CAPABILITY_JOIN.toString(), qValue(caps.getJoinCapability(), qvf));
-        descriptors.put(CMIS.CAPABILITY_RENDITIONS.toString(), qValue(caps.getRenditionCapability(), qvf));
-        descriptors.put(CMIS.CAPABILITY_CHANGES.toString(), qValue(caps.getChangeCapability(), qvf));
-        descriptors.put(CMIS.CAPABILITY_ACL.toString(), qValue(caps.getACLCapability(), qvf));
-    }
-
-    private static QValue[] qValue(String value, QValueFactory factory) throws RepositoryException {
-        return new QValue[] { factory.create(value, PropertyType.STRING) };
-    }
-
-    private static QValue[] qValue(boolean value, QValueFactory factory) throws RepositoryException {
-        return new QValue[] { factory.create(value) };
-    }
-
-    private static QValue[] qValue(Enum<?> value, QValueFactory factory) throws RepositoryException {
-        return qValue(value.toString(), factory);
+        descriptors.put(CMIS.CAPABILITY_MULTIFILING.toString(), qValue(caps.hasMultifiling(), factory));
+        descriptors.put(CMIS.CAPABILITY_UNFILING.toString(), qValue(caps.hasUnfiling() , factory));
+        descriptors.put(CMIS.CAPABILITY_VERSION_SPECIFIC_FILING.toString(), qValue(caps.hasVersionSpecificFiling(), factory));
+        descriptors.put(CMIS.CAPABILITY_PWC_UPDATABLE.toString(), qValue(caps.isPWCUpdatable(), factory));
+        descriptors.put(CMIS.CAPABILITY_PWC_SEARCHABLE.toString(), qValue(caps.isPWCSearchable() , factory));
+        descriptors.put(CMIS.CAPABILITY_ALL_VERSIONS_SEARCHABLE.toString(), qValue(caps.isAllVersionsSearchable() , factory));
+        descriptors.put(CMIS.CAPABILITY_CAN_GET_DESCENDANTS.toString(), qValue(caps.hasGetDescendants() , factory));
+        descriptors.put(CMIS.CAPABILITY_CAN_GET_FOLDER_TREE.toString(), qValue(caps.hasGetFolderTree(), factory));
+        descriptors.put(CMIS.CAPABILITY_CONTENT_STREAM_UPDATABILITY.toString(), qValue(caps.isContentStreamUpdatableAnytime() , factory));
+
+        descriptors.put(CMIS.CAPABILITY_QUERY.toString(), qValue(caps.getQueryCapability(), factory));
+        descriptors.put(CMIS.CAPABILITY_JOIN.toString(), qValue(caps.getJoinCapability(), factory));
+        descriptors.put(CMIS.CAPABILITY_RENDITIONS.toString(), qValue(caps.getRenditionCapability(), factory));
+        descriptors.put(CMIS.CAPABILITY_CHANGES.toString(), qValue(caps.getChangeCapability(), factory));
+        descriptors.put(CMIS.CAPABILITY_ACL.toString(), qValue(caps.getACLCapability(), factory));
     }
 
     private static void close(Reader sr) {
@@ -232,9 +218,10 @@
 
     @Override
     protected QNodeDefinition createRootNodeDefinition(SessionInfo sessionInfo) throws RepositoryException {
+        Name rootName = NameTransformer.jcrName(BaseType.FOLDER.getId(), namespaces);
         Connection conn = getCmisConnection(sessionInfo);
         Folder root = conn.getRootFolder();
-        return TypeTransformer.jcrNodeDef(NameConstants.NT_BASE, root.getType(), namespaces);
+        return TypeTransformer.jcrNodeDef(rootName, root.getType(), namespaces);
     }
 
     // -----------------------------------------------------< Workspaces >---
@@ -259,36 +246,66 @@
 
     public NodeInfo getNodeInfo(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
         Connection conn = cmisConnections.get(sessionInfo);
-        CMISObject obj = getCMISObject(conn, nodeId);
-        return ItemTransformer.jcrNode(obj, namespaces);
+
+        if (denotesJcrContent(nodeId)) {
+            // Create node info for synthetic node jcr:content
+            CMISObject parent = getCMISParentObject(conn, nodeId);
+            IdFactory factory = getIdFactory();
+
+            Path parentPath = PathTransformer.jcrPath(parent, namespaces);
+            Path path = getPathFactory().create(parentPath, NameConstants.JCR_CONTENT, false);
+            Iterator<PropertyId> propertyIds = Iterators.iterator (
+                factory.createPropertyId(nodeId, NameConstants.JCR_DATA),
+                factory.createPropertyId(nodeId, NameConstants.JCR_MIMETYPE),
+                factory.createPropertyId(nodeId, NameConstants.JCR_LASTMODIFIED),
+                factory.createPropertyId(nodeId, NameConstants.JCR_LASTMODIFIEDBY)
+            );
+
+            return new NodeInfoImpl(path, nodeId, Path.INDEX_DEFAULT, NameConstants.NT_RESOURCE,
+                    Name.EMPTY_ARRAY, Iterators.<Object> empty(), propertyIds, null);
+        }
+        else {
+            CMISObject obj = getCMISObject(conn, nodeId);
+            return ItemTransformer.jcrNodeInfo(obj, namespaces);
+        }
     }
 
     public Iterator<? extends ItemInfo> getItemInfos(SessionInfo sessionInfo, NodeId nodeId)
             throws RepositoryException {
 
-        // todo implement: batch reading
-        return unchecked(new SingletonIterator(getNodeInfo(sessionInfo, nodeId)));
+        return Iterators.<NodeInfo>singleton(getNodeInfo(sessionInfo, nodeId));
     }
 
     public Iterator<ChildInfo> getChildInfos(SessionInfo sessionInfo, NodeId parentId)
             throws RepositoryException {
 
+        if (denotesJcrContent(parentId)) {
+            // jcr:content has no children
+            return Iterators.empty();
+        }
+
         final Connection conn = cmisConnections.get(sessionInfo);
         CMISObject parent = getCMISObject(conn, parentId);
 
-        // If parentId refers to a folder...
+        // If parentId refers...
         if (BaseType.FOLDER == parent.getBaseType()) {
-            // ... retrieve children and transform them into ChildInfos
+            // ... to a folder, retrieve children and transform them into ChildInfos
             ListPage<ObjectEntry> children = conn.getSPI().getChildren(parent, null, null, null); // todo fix: specify inclusions
-            return unchecked(new TransformIterator(children.iterator(), new Transformer() {
-                public Object transform(Object entry) {
-                    CMISObject obj = conn.getObject((ObjectId) entry);
-                    return ItemTransformer.jcrChildInfo(obj, namespaces);
-                }
-            }));
+
+            return Iterators.map(children.iterator(),
+                new Function<ObjectEntry, ChildInfo>() {
+                    public ChildInfo apply(ObjectEntry entry) {
+                        CMISObject obj = conn.getObject(entry);
+                        return ItemTransformer.jcrChildInfo(obj, namespaces);
+                }});
+        }
+        else if (BaseType.DOCUMENT == parent.getBaseType()) {
+            // ... to a document, add jcr:content as single child node
+            return Iterators.<ChildInfo>singleton(new ChildInfoImpl(NameConstants.JCR_CONTENT, null, Path.INDEX_DEFAULT));
         }
         else {
-            return unchecked(EmptyIterator.INSTANCE);
+            // ... otherwise there are no child nodes
+            return Iterators.empty();
         }
     }
 
@@ -296,17 +313,105 @@
             boolean weakReferences) throws RepositoryException {
 
         // todo implement: getReferences
-        return unchecked(EmptyIterator.INSTANCE);
+        return Iterators.empty();
     }
 
     public PropertyInfo getPropertyInfo(SessionInfo sessionInfo, PropertyId propertyId)
             throws RepositoryException {
 
-        NodeId parentId = propertyId.getParentId();
-        Connection conn = getCmisConnection(sessionInfo);
-        CMISObject parent = getCMISObject(conn, parentId);
-        Property prop = parent.getProperty(IdTransformer.cmisId(propertyId.getName(), namespaces));
-        return ItemTransformer.jcrPropertyInfo(parent, prop, namespaces);
+        Name propertyName = propertyId.getName();
+        CMISObject parentCmisObject;
+        Path parentPath;
+        {
+            Connection conn = getCmisConnection(sessionInfo);
+            NodeId parentId = propertyId.getParentId();
+
+            if (denotesJcrContent(parentId)) {
+                parentCmisObject = getCMISParentObject(conn, parentId);
+                parentPath = PathTransformer.jcrPath(parentCmisObject, namespaces);
+                parentPath = getPathFactory().create(parentPath, NameConstants.JCR_CONTENT, false);
+            }
+            else {
+                parentCmisObject = getCMISObject(conn, parentId);
+                parentPath = PathTransformer.jcrPath(parentCmisObject, namespaces);
+            }
+        }
+
+        Path propertyPath = getPathFactory().create(parentPath, propertyId.getName(), false);
+        final QValueFactory factory = getQValueFactory();
+        try {
+            // Properties from nt:base
+            if (NameConstants.JCR_PRIMARYTYPE.equals(propertyName)) {
+                Name primaryType = TypeTransformer.jcrTypeName(parentCmisObject.getType(), namespaces);
+                QValue[] values = qValue(primaryType, factory);
+                return new PropertyInfoImpl(propertyPath, propertyId, PropertyType.NAME, false, values);
+            }
+            else if (NameConstants.JCR_MIXINTYPES.equals(propertyName)) {
+                Name[] mixinTypes = TypeTransformer.jcrMixinNames(parentCmisObject.getType(), namespaces);
+                QValue[] values = Arrays.map(mixinTypes, new QValue[mixinTypes.length],
+                    new PartialFunction<Name, QValue, RepositoryException>() {
+                        public QValue apply(Name name) throws RepositoryException {
+                            return factory.create(name);
+                        }
+                    });
+                return new PropertyInfoImpl(propertyPath, propertyId, PropertyType.NAME, true, values);
+            }
+
+            // properties from mix:created
+            else if (NameConstants.JCR_CREATED.equals(propertyName)) {
+                Property prop = parentCmisObject.getProperty("cmis:creationDate");
+                QValue[] values = ValueTransformer.jcrValue(prop);
+                return new PropertyInfoImpl(propertyPath, propertyId, PropertyType.DATE, false, values);
+            }
+            else if (NameConstants.JCR_CREATEDBY.equals(propertyName)) {
+                Property prop = parentCmisObject.getProperty("cmis:createdBy");
+                QValue[] values = ValueTransformer.jcrValue(prop);
+                return new PropertyInfoImpl(propertyPath, propertyId, PropertyType.STRING, false, values);
+            }
+
+            // properties from nt:resource
+            else if (NameConstants.JCR_DATA.equals(propertyName)) {
+                QValue[] values;
+                try {
+                    ContentStream content = parentCmisObject.getContentStream(null);
+                    values = qValue(content.getStream(), factory);
+                }
+                catch (UnsupportedOperationException e) {
+                    // todo fix: Remove when SimpleObject#getContentStream is implemented
+                    values = qValue(Streams.emptyInStream(), factory);
+                }
+                return new PropertyInfoImpl(propertyPath, propertyId, PropertyType.BINARY, false, values);
+            }
+
+            // properties from mix:lastModified
+            else if (NameConstants.JCR_LASTMODIFIED.equals(propertyName)) {
+                Property prop = parentCmisObject.getProperty("cmis:lastModificationDate");
+                QValue[] values = ValueTransformer.jcrValue(prop);
+                return new PropertyInfoImpl(propertyPath, propertyId, PropertyType.DATE, false, values);
+            }
+            else if (NameConstants.JCR_LASTMODIFIEDBY.equals(propertyName)) {
+                Property prop = parentCmisObject.getProperty("cmis:lastModifiedBy");
+                QValue[] values = ValueTransformer.jcrValue(prop);
+                return new PropertyInfoImpl(propertyPath, propertyId, PropertyType.STRING, false, values);
+            }
+
+            // properties from mix:mimeType
+            else if (NameConstants.JCR_MIMETYPE.equals(propertyName)) {
+                Property prop = parentCmisObject.getProperty("cmis:contentStreamMimeType");
+                QValue[] values = ValueTransformer.jcrValue(prop);
+                return new PropertyInfoImpl(propertyPath, propertyId, PropertyType.STRING, false, values);
+            }
+            else {
+                Property prop = parentCmisObject.getProperty(IdTransformer.cmisId(propertyName, namespaces));
+                return ItemTransformer.jcrPropertyInfo(parentCmisObject, prop, namespaces);
+            }
+        }
+        catch (ValueFormatException e) {
+            throw new PathNotFoundException(e);
+        }
+        catch (IOException e) {
+            throw new PathNotFoundException(e);
+        }
     }
 
     // -----------------------------------------------------< private >---
@@ -329,7 +434,7 @@
     /**
      * Retrieve the CMIS object identified by the given nodeId from a CMIS connection.
      */
-    private CMISObject getCMISObject(Connection conn, NodeId nodeId) throws RepositoryException {
+    private static CMISObject getCMISObject(Connection conn, NodeId nodeId) throws RepositoryException {
         String uuid = nodeId.getUniqueID();
         Path path = nodeId.getPath();
 
@@ -349,15 +454,59 @@
         // Otherwise construct the full CMIS path from an absolute part and a relative part.
         String abs = uuid == null
             ? ""
-            : PathTransformer.cmisPath(o) + '/';
+            : PathTransformer.cmisPath(o);
 
         String rel = PathTransformer.cmisPath(path);
 
-        ObjectEntry entry = conn.getSPI().getObjectByPath(abs + rel, null); // todo fix: specify inclusions
+        ObjectEntry entry = conn.getSPI().getObjectByPath(concat(abs, rel), null); // todo fix: specify inclusions
         if (entry == null) {
             throw new PathNotFoundException();
         }
         return conn.getObject(entry);
     }
 
+    private CMISObject getCMISParentObject(Connection conn, NodeId nodeId) throws RepositoryException {
+        String uuid = nodeId.getUniqueID();
+        Path parentPath = nodeId.getPath().getAncestor(1);
+        NodeId id = getIdFactory().createNodeId(uuid, parentPath);
+        return getCMISObject(conn, id);
+    }
+
+    private static String concat(String p1, String p2) {
+        if ("".equals(p1) || "".equals(p2)) {
+            return p1 + p2;
+        }
+        else {
+            return p1 + '/' + p2;
+        }
+    }
+
+    /**
+     * Determine whether a nodeId identifies a jcr:content node
+     */
+    private static boolean denotesJcrContent(NodeId nodeId) {
+        Path path = nodeId.getPath();
+        return path != null && NameConstants.JCR_CONTENT.equals(path.getNameElement().getName());
+    }
+
+    private static QValue[] qValue(String value, QValueFactory factory) throws RepositoryException {
+        return new QValue[] { factory.create(value, PropertyType.STRING) };
+    }
+
+    private static QValue[] qValue(boolean value, QValueFactory factory) throws RepositoryException {
+        return new QValue[] { factory.create(value) };
+    }
+
+    private static QValue[] qValue(Enum<?> value, QValueFactory factory) throws RepositoryException {
+        return qValue(value.toString(), factory);
+    }
+
+    private static QValue[] qValue(Name value, QValueFactory factory) throws RepositoryException {
+        return new QValue[] { factory.create(value) };
+    }
+
+    private static QValue[] qValue(InputStream value, QValueFactory factory) throws RepositoryException, IOException {
+        return new QValue[] { factory.create(value) };
+    }
+
 }

Modified: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ItemTransformer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ItemTransformer.java?rev=903343&r1=903342&r2=903343&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ItemTransformer.java (original)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ItemTransformer.java Tue Jan 26 17:56:54 2010
@@ -16,9 +16,9 @@
  */
 package org.apache.jackrabbit.spi2cmis;
 
-import static org.apache.jackrabbit.spi2cmis.SuppressWarning.unchecked;
-
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.jcr.Item;
@@ -28,11 +28,6 @@
 import org.apache.chemistry.Property;
 import org.apache.chemistry.PropertyDefinition;
 import org.apache.chemistry.Type;
-import org.apache.commons.collections.Predicate;
-import org.apache.commons.collections.Transformer;
-import org.apache.commons.collections.iterators.EmptyIterator;
-import org.apache.commons.collections.iterators.FilterIterator;
-import org.apache.commons.collections.iterators.TransformIterator;
 import org.apache.jackrabbit.spi.ChildInfo;
 import org.apache.jackrabbit.spi.IdFactory;
 import org.apache.jackrabbit.spi.Name;
@@ -46,13 +41,16 @@
 import org.apache.jackrabbit.spi.commons.NodeInfoImpl;
 import org.apache.jackrabbit.spi.commons.PropertyInfoImpl;
 import org.apache.jackrabbit.spi.commons.identifier.IdFactoryImpl;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
+import org.apache.jackrabbit.spi2cmis.util.Iterators;
+import org.apache.jackrabbit.spi2cmis.util.Predicate;
+import org.apache.jackrabbit.spi2cmis.util.Functions.Function;
 
 /**
  * Utility class to transform {@link CMISObject}s to JCR {@link Item}s.
  */
 public class ItemTransformer {
-
     private static final IdFactory ID_FACTORY = IdFactoryImpl.getInstance();
 
     private ItemTransformer() {
@@ -61,39 +59,58 @@
 
     /**
      * Transform a {@link CMISObject} into a {@link NodeInfo} with respect to a name space mapping.
-     * @param cmidObject  {@link CMISObject}
+     * @param cmisObject  {@link CMISObject}
      * @param namespaces  name space mapping
      * @return  JCR {@link NodeInfo}
      */
-    public static NodeInfo jcrNode(CMISObject cmidObject, final NamespaceMapping namespaces) {
-        Path path = PathTransformer.jcrPath(cmidObject, namespaces);
-        final NodeId nodeId = IdTransformer.jcrId(cmidObject);
-
-        Type type = cmidObject.getType();
-        Name primaryTypeName = NameTransformer.jcrName(type.getId(), namespaces);
-
-        // todo implement: include references
-        Iterator<PropertyId> references = unchecked(EmptyIterator.INSTANCE);
+    public static NodeInfo jcrNodeInfo(CMISObject cmisObject, final NamespaceMapping namespaces) {
+        Path path = PathTransformer.jcrPath(cmisObject, namespaces);
+        final NodeId nodeId = IdTransformer.jcrId(cmisObject);
+
+        Type cmisType = cmisObject.getType();
+        Name primaryTypeName = TypeTransformer.jcrTypeName(cmisType, namespaces);
+        Name[] mixins = TypeTransformer.jcrMixinNames(cmisType, namespaces);
+        Iterator<PropertyId> references = Iterators.empty(); // todo implement: include references
 
         // From all properties...
-        final Map<String, Property> properties = cmidObject.getProperties();
+        final Map<String, Property> properties = cmisObject.getProperties();
 
-        // ... filter out the ones having null values
-        FilterIterator nonNullProperties = new FilterIterator(properties.keySet().iterator(), new Predicate() {
-            public boolean evaluate(Object id) {
-                return properties.get(id).getValue() != null;
-            }
-        });
+        // ... retain the properties having its value set
+        Iterator<String> setProperties = Iterators
+            .filter(properties.keySet().iterator(), new Predicate<String>() {
+                public boolean evaluate(String id) {
+                    return ValueTransformer.hasValue(properties.get(id));
+                }
+            });
 
         // ... and transform them into valid JCR names
-        Iterator<PropertyId> propertyIds = unchecked(new TransformIterator(nonNullProperties, new Transformer() {
-            public Object transform(Object id) {
-                Name propertyName = NameTransformer.jcrName((String) id, namespaces);
-                return ID_FACTORY.createPropertyId(nodeId, propertyName);
+        Iterator<PropertyId> transformedPropertyIds = Iterators
+            .map(setProperties, new Function<String, PropertyId>(){
+                public PropertyId apply(String id) {
+                    Name propertyName = NameTransformer.jcrName(id, namespaces);
+                    return ID_FACTORY.createPropertyId(nodeId, propertyName);
+                }
+            });
+
+        // ... and add properties of nt:base
+        List<PropertyId> additionalPropertyIds = new ArrayList<PropertyId>();
+        additionalPropertyIds.add(ID_FACTORY.createPropertyId(nodeId, NameConstants.JCR_PRIMARYTYPE));
+        additionalPropertyIds.add(ID_FACTORY.createPropertyId(nodeId, NameConstants.JCR_MIXINTYPES));
+
+        // ... and if this is a hierarchy node from nt:hierarchy
+        if (TypeTransformer.isHierarchyNode(cmisType)) {
+            if (ValueTransformer.hasValue(properties.get("cmis:creationDate"))) {
+                additionalPropertyIds.add(ID_FACTORY.createPropertyId(nodeId, NameConstants.JCR_CREATED));
             }
-        }));
+            if (ValueTransformer.hasValue(properties.get("cmis:createdBy"))) {
+                additionalPropertyIds.add(ID_FACTORY.createPropertyId(nodeId, NameConstants.JCR_CREATEDBY));
+            }
+        }
+
+        Iterator<PropertyId> propertyIds = Iterators
+            .chain(transformedPropertyIds, additionalPropertyIds.iterator());
 
-        return new NodeInfoImpl(path, nodeId, 0, primaryTypeName, new Name[0], references, propertyIds, null);
+        return new NodeInfoImpl(path, nodeId, 0, primaryTypeName, mixins, references, propertyIds, null);
     }
 
     /**

Modified: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/PathTransformer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/PathTransformer.java?rev=903343&r1=903342&r2=903343&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/PathTransformer.java (original)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/PathTransformer.java Tue Jan 26 17:56:54 2010
@@ -52,6 +52,11 @@
         StringBuilder s = new StringBuilder();
         boolean first = true;
         for (Path.Element element : path.getNormalizedPath().getElements()) {
+            if (element.denotesCurrent()) {
+                continue;
+            }
+            assert !element.denotesParent();
+
             if (element.denotesRoot()) {
                 s.append('/');
             }

Modified: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/TypeTransformer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/TypeTransformer.java?rev=903343&r1=903342&r2=903343&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/TypeTransformer.java (original)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/TypeTransformer.java Tue Jan 26 17:56:54 2010
@@ -32,6 +32,7 @@
 import org.apache.chemistry.Repository;
 import org.apache.chemistry.Type;
 import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
 import org.apache.jackrabbit.spi.QNodeDefinition;
 import org.apache.jackrabbit.spi.QNodeTypeDefinition;
 import org.apache.jackrabbit.spi.QPropertyDefinition;
@@ -41,12 +42,14 @@
 import org.apache.jackrabbit.spi.commons.QNodeTypeDefinitionImpl;
 import org.apache.jackrabbit.spi.commons.QPropertyDefinitionImpl;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
 import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
 
 /**
  * Utility class to transform CMIS {@link Type}s to JCR {@link QNodeTypeDefinition}s.
  */
 public class TypeTransformer {
+    private static final NameFactory nameFactory = NameFactoryImpl.getInstance();
 
     private TypeTransformer() {
         super();
@@ -67,12 +70,23 @@
         Name name = NameTransformer.jcrName(cmisType.getId(), namespaces);
 
         String parentId = cmisType.getParentId();
-        Name[] supertypes = parentId == null
-            ? Name.EMPTY_ARRAY
-            : new Name[] { NameTransformer.jcrName(parentId, namespaces) };
 
-        Name[] supportedMixins = Name.EMPTY_ARRAY;
-        boolean isMixin = false;
+        Name[] supertypes;
+        if (isFolder(cmisType)) {
+            supertypes = new Name[] { NameConstants.NT_FOLDER };
+        }
+        else if (isDocument(cmisType)) {
+            supertypes = new Name[] { NameConstants.NT_FILE };
+        }
+        else if (parentId == null) {
+            supertypes = new Name[] { NameConstants.NT_BASE };
+        }
+        else {
+            supertypes = new Name[] { NameTransformer.jcrName(parentId, namespaces) };
+        }
+
+        Name[] supportedMixins = null;
+        boolean isMixin = isFolder(cmisType);
         boolean isAbstract = false;
         boolean isQueryable = cmisType.isQueryable();
         boolean hasOrderableChildNodes = false;
@@ -90,16 +104,9 @@
 
         QPropertyDefinition[] declaredPropDefs = dpd.toArray(new QPropertyDefinition[dpd.size()]);
 
-        QNodeDefinition[] declaredNodeDefs;
-        if (BaseType.FOLDER.getId().equals(cmisType.getId())) {
-            declaredNodeDefs = new QNodeDefinition[] { createResidualNodeDef(name) };
-        }
-        else {
-            declaredNodeDefs = QNodeDefinition.EMPTY_ARRAY;
-        }
-
         return new QNodeTypeDefinitionImpl(name, supertypes, supportedMixins, isMixin, isAbstract,
-                isQueryable, hasOrderableChildNodes, primaryItemName, declaredPropDefs, declaredNodeDefs);
+                isQueryable, hasOrderableChildNodes, primaryItemName, declaredPropDefs,
+                QNodeDefinition.EMPTY_ARRAY);
     }
 
     /**
@@ -171,6 +178,78 @@
         return ValueTransformer.getValueTransformer(cmisPropertyType).getJcrPropertyType();
     }
 
+    /**
+     * Name of the JCR type for a CMIS type with respect to a name space mapping
+     * @param cmisType
+     * @param namespaces
+     * @return  JCR type Name
+     */
+    public static Name jcrTypeName(Type cmisType, NamespaceMapping namespaces) {
+        if (isFolder(cmisType)) {
+            return NameConstants.NT_FOLDER;
+        }
+        else if (isDocument(cmisType)) {
+            return NameConstants.NT_FILE;
+        }
+        else {
+            return NameTransformer.jcrName(cmisType.getId(), namespaces);
+        }
+    }
+
+    /**
+     * Names of the JCR mixins for a CMIS type with respect to a name space mapping
+     * @param cmisType
+     * @param namespaces
+     * @return  JCR mixin type names
+     */
+    public static Name[] jcrMixinNames(Type cmisType, NamespaceMapping namespaces) {
+        if (TypeTransformer.isFolder(cmisType)) {
+            return new Name[] { NameTransformer.jcrName(BaseType.FOLDER.getId(), namespaces) };
+        }
+        else if (TypeTransformer.isDocument(cmisType)) {
+            return new Name[] { NameTransformer.jcrName(BaseType.DOCUMENT.getId(), namespaces) };
+        }
+        else {
+            return Name.EMPTY_ARRAY;
+        }
+    }
+
+    /**
+     * Determines whether a type is a cmis:folder
+     * @param cmisType
+     * @return  true iff <code>cmisType</code> is a cmis:folder and no other sub type
+     *   of cmis:folder.
+     */
+    public static boolean isFolder(Type cmisType) {
+        return BaseType.FOLDER.getId().equals(cmisType.getId());
+    }
+
+    /**
+     * Determines whether a type is a cmis:document
+     * @param cmisType
+     * @return  true iff <code>cmisType</code> is a cmis:document no other sub type
+     *   of cmis:document.
+     */
+    public static boolean isDocument(Type cmisType) {
+        return BaseType.DOCUMENT.getId().equals(cmisType.getId());
+    }
+
+    /**
+     * Determines whether a type is a hierarchy type. A hierarchy type is a type whose
+     * base type is wither cmis:document or cmis:folder.
+     * @param cmisType
+     * @return  true iff <code>cmisType</code> is a hierarchy type
+     */
+    public static boolean isHierarchyNode(Type cmisType) {
+        switch (cmisType.getBaseType()) {
+            case DOCUMENT:
+            case FOLDER:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     // -----------------------------------------------------<  >---
 
     private static Set<String> getSuperTypeProperties(Repository cmisRepository, Type cmisType) {
@@ -199,17 +278,4 @@
         return ids;
     }
 
-    private static QNodeDefinitionImpl createResidualNodeDef(Name declaringNodeType) {
-        Name name = NameConstants.ANY_NAME;
-        boolean isAutoCreated = false;
-        boolean isMandatory = false;
-        int onParentVersion = OnParentVersionAction.IGNORE;
-        boolean isProtected = false;
-        Name defaultPrimaryType = NameConstants.NT_BASE;
-        Name[] requiredPrimaryTypes = { NameConstants.NT_BASE };
-        boolean allowsSameNameSiblings = false;
-        return new QNodeDefinitionImpl(name, declaringNodeType, isAutoCreated, isMandatory, onParentVersion,
-                isProtected, defaultPrimaryType, requiredPrimaryTypes, allowsSameNameSiblings);
-    }
-
 }

Modified: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ValueTransformer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ValueTransformer.java?rev=903343&r1=903342&r2=903343&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ValueTransformer.java (original)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/ValueTransformer.java Tue Jan 26 17:56:54 2010
@@ -20,7 +20,6 @@
 import java.math.BigDecimal;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
@@ -28,12 +27,15 @@
 
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
 
 import org.apache.chemistry.Property;
 import org.apache.chemistry.PropertyDefinition;
 import org.apache.jackrabbit.spi.QValue;
 import org.apache.jackrabbit.spi.QValueFactory;
 import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl;
+import org.apache.jackrabbit.spi2cmis.util.Arrays;
+import org.apache.jackrabbit.spi2cmis.util.Functions.PartialFunction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -95,7 +97,7 @@
         new HashMap<org.apache.chemistry.PropertyType, ValueTransformer>();
 
     static {
-        for (ValueTransformer t : Arrays.asList(
+        for (ValueTransformer t : java.util.Arrays.asList (
                 DECIMAL_VALUE_TRANSFORMER, INTEGER_VALUE_TRANSFORMER, BOOLEAN_VALUE_TRANSFORMER,
                 DATE_TIME_VALUE_TRANSFORMER, URI_VALUE_TRANSFORMER, ID_VALUE_TRANSFORMER,
                 STRING_VALUE_TRANSFORMER, HTML_VALUE_TRANSFORMER
@@ -117,29 +119,43 @@
      * @throws RepositoryException
      */
     public static QValue[] jcrValue(Property cmisProperty) throws RepositoryException {
-        PropertyDefinition def = cmisProperty.getDefinition();
-        Serializable val = cmisProperty.getValue();
-        return jcrValue(val, def.getType());
+        if (hasValue(cmisProperty)) {
+            PropertyDefinition def = cmisProperty.getDefinition();
+            return jcrValue(cmisProperty.getValue(), def.getType());
+        }
+        else {
+            throw new ValueFormatException("Null value not allowed");
+        }
+    }
+
+    /**
+     * Determines if a property value is set
+     * @param cmisProperty
+     * @return  true iff the value of <code>cmisProperty</code> is set.
+     */
+    public static boolean hasValue(Property cmisProperty) {
+        return cmisProperty.getValue() != null;
     }
 
     /**
      * Transforms a CMIS value to a JCR {@link QValue}.
-     * @param cmisValue  CMIS value
-     * @param cmisPropertyType  CMIS {@link org.apache.chemistry.PropertyType}
-     * @return  JCR {@link QValue}
+     *
+     * @param cmisValue CMIS value
+     * @param cmisPropertyType CMIS {@link org.apache.chemistry.PropertyType}
+     * @return JCR {@link QValue}
      * @throws RepositoryException
      */
-    public static QValue[] jcrValue(Serializable cmisValue, org.apache.chemistry.PropertyType cmisPropertyType)
+    public static QValue[] jcrValue(Serializable cmisValue, final org.apache.chemistry.PropertyType cmisPropertyType)
             throws RepositoryException {
 
         if (cmisValue.getClass().isArray()) {
-            Serializable[] values = (Serializable[]) cmisValue;
-            QValue[] qValues = new QValue[values.length];
-            int k = 0;
-            for (Serializable v : values) {
-                qValues[k++] = getValueTransformer(cmisPropertyType).getQValue(v);
-            }
-            return qValues;
+            return Arrays.map((Serializable[]) cmisValue, new QValue[((Serializable[]) cmisValue).length],
+                new PartialFunction<Serializable, QValue, RepositoryException>() {
+                    public QValue apply(Serializable value) throws RepositoryException {
+                        return getValueTransformer(cmisPropertyType).getQValue(value);
+                    }
+                });
+
         }
         else {
             return new QValue[] { getValueTransformer(cmisPropertyType).getQValue(cmisValue) };

Added: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Arrays.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Arrays.java?rev=903343&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Arrays.java (added)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Arrays.java Tue Jan 26 17:56:54 2010
@@ -0,0 +1,94 @@
+/*
+ * 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.jackrabbit.spi2cmis.util;
+
+import java.util.Iterator;
+
+import org.apache.jackrabbit.spi2cmis.util.Functions.PartialFunction;
+
+/**
+ * Utility classed providing methods for mapping functions over arrays
+ */
+public class Arrays {
+
+    private Arrays() {
+        super();
+    }
+
+    /**
+     * Map a {@link PartialFunction} over a <code>source</code> array and store the results into a
+     * <code>target</code> array.
+     * @param <S>
+     * @param <T>
+     * @param <E>
+     * @param source
+     * @param target
+     * @param f
+     * @return
+     * @throws E
+     */
+    public static <S, T, E extends Throwable> T[] map(S[] source, T[] target, PartialFunction<S, T, E> f) throws E {
+        int k = 0;
+        for (S s : source) {
+            target[k++] = f.apply(s);
+        }
+
+        return target;
+    }
+
+    /**
+     * Map a {@link PartialFunction} over an interable <code>source</code> and store the results into a
+     * <code>target</code> array.
+     * @param <S>
+     * @param <T>
+     * @param <E>
+     * @param source
+     * @param target
+     * @param f
+     * @return
+     * @throws E
+     */
+    public static <S, T, E extends Throwable> T[] map(Iterable<S> source, T[] target, PartialFunction<S, T, E> f) throws E {
+        int k = 0;
+        for (S s : source) {
+            target[k++] = f.apply(s);
+        }
+
+        return target;
+    }
+
+    /**
+     * Map a {@link PartialFunction} over a <code>source</code> iterator and store the results into a
+     * <code>target</code> array.
+     * @param <S>
+     * @param <T>
+     * @param <E>
+     * @param source
+     * @param target
+     * @param f
+     * @return
+     * @throws E
+     */
+    public static <S, T, E extends Throwable> T[] map(final Iterator<S> source, T[] target, PartialFunction<S, T, E> f) throws E {
+        return map(new Iterable<S>() {
+            public Iterator<S> iterator() {
+                return source;
+            }
+        }, target, f);
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Arrays.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Functions.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Functions.java?rev=903343&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Functions.java (added)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Functions.java Tue Jan 26 17:56:54 2010
@@ -0,0 +1,52 @@
+/*
+ * 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.jackrabbit.spi2cmis.util;
+
+/**
+ * Helper class providing definitions for {@link Function} and {@link PartialFunction}.
+ */
+public class Functions {
+
+    private Functions() {
+        super();
+    }
+
+    /**
+     * A partial function taking an argument of type <code>S</code> to a value of
+     * type <code>T</code> or throwing an exception of type <code>E</code>.
+     * @param <S>
+     * @param <T>
+     * @param <E>
+     */
+    public interface PartialFunction<S, T, E extends Throwable> {
+        public T apply(S s) throws E;
+    }
+
+    /**
+     * A function taking an argument of type <code>S</code> to a value of
+     * type <code>T</code>. <code>Function</code> is a sub type of
+     * {@link PartialFunction} which never throws an exception.
+     * @param <S>
+     * @param <T>
+     */
+    public interface Function<S, T> extends PartialFunction<S, T, None>{
+        public T apply(S s);
+    }
+
+    class None extends Error{ /* empty */}
+
+}
\ No newline at end of file

Propchange: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Functions.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Iterators.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Iterators.java?rev=903343&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Iterators.java (added)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Iterators.java Tue Jan 26 17:56:54 2010
@@ -0,0 +1,117 @@
+/*
+ * 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.jackrabbit.spi2cmis.util;
+
+import java.util.Iterator;
+
+import org.apache.commons.collections.Transformer;
+import org.apache.commons.collections.iterators.ArrayIterator;
+import org.apache.commons.collections.iterators.EmptyIterator;
+import org.apache.commons.collections.iterators.FilterIterator;
+import org.apache.commons.collections.iterators.IteratorChain;
+import org.apache.commons.collections.iterators.SingletonIterator;
+import org.apache.commons.collections.iterators.TransformIterator;
+import org.apache.jackrabbit.spi2cmis.util.Functions.Function;
+
+/**
+ * Helper class providing type safe wrappers for the Iterators provided in Apache
+ * Commons Collection.
+ */
+public class Iterators {
+
+    private Iterators() {
+        super();
+    }
+
+    /**
+     * Iterator of a single value of type <code>T</code>.
+     * @param <T>
+     * @param value
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Iterator<T> singleton(T value) {
+        return new SingletonIterator(value);
+    }
+
+    /**
+     * Map a {@link Functions} of an iterator.
+     * @param <S>
+     * @param <T>
+     * @param source
+     * @param f
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <S, T> Iterator<T> map(Iterator<S> source, final Function<S, T> f) {
+        return new TransformIterator(source, new Transformer() {
+            public Object transform(Object o) {
+                return f.apply((S) o);
+            }
+        });
+    }
+
+    /**
+     * Filter an iterator according to a {@link Predicate}.
+     * @param <T>
+     * @param source
+     * @param predicate
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Iterator<T> filter(Iterator<T> source, final Predicate<T> predicate) {
+        return new FilterIterator(source, new org.apache.commons.collections.Predicate() {
+            public boolean evaluate(Object object) {
+                return predicate.evaluate((T) object);
+            }
+        });
+    }
+
+    /**
+     * Chain two iterators
+     * @param <T>
+     * @param first
+     * @param second
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Iterator<T> chain(Iterator<T> first, Iterator<T> second) {
+        return new IteratorChain(first, second);
+    }
+
+    /**
+     * Empty iterator
+     * @param <T>
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Iterator<T> empty() {
+        return EmptyIterator.INSTANCE;
+    }
+
+    /**
+     * Iterator over a set of values
+     * @param <T>
+     * @param values
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Iterator<T> iterator(T... values) {
+        return new ArrayIterator(values);
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Iterators.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Predicate.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Predicate.java?rev=903343&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Predicate.java (added)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Predicate.java Tue Jan 26 17:56:54 2010
@@ -0,0 +1,25 @@
+/*
+ * 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.jackrabbit.spi2cmis.util;
+
+/**
+ * Predicate
+ * @param <T>
+ */
+public interface Predicate<T> {
+    public boolean evaluate(T value);
+}

Propchange: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Predicate.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Streams.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Streams.java?rev=903343&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Streams.java (added)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Streams.java Tue Jan 26 17:56:54 2010
@@ -0,0 +1,48 @@
+/*
+ * 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.jackrabbit.spi2cmis.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Utility class for handling streams.
+ */
+public class Streams {
+    private final static InputStream EMPTY_IN_STREAM = new EmptyInputStream();
+
+    private Streams() {
+        super();
+    }
+
+    /**
+     * Empty input stream
+     * @return
+     */
+    public static InputStream emptyInStream() {
+        return EMPTY_IN_STREAM;
+    }
+
+    // -----------------------------------------------------< private >---
+
+    private static class EmptyInputStream extends InputStream {
+        @Override
+        public int read() throws IOException {
+            return -1;
+        }
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/java/org/apache/jackrabbit/spi2cmis/util/Streams.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/resources/nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/resources/nodetypes.cnd?rev=903343&r1=903342&r2=903343&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/resources/nodetypes.cnd (original)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/main/resources/nodetypes.cnd Tue Jan 26 17:56:54 2010
@@ -23,5 +23,29 @@
 <xml='http://www.w3.org/XML/1998/namespace'>
 
 [nt:base]
-- jcr:primaryType (NAME) autocreated mandatory protected COMPUTE
-- jcr:mixinTypes  (NAME) autocreated mandatory protected multiple COMPUTE
\ No newline at end of file
+- jcr:primaryType (NAME) autocreated mandatory protected 
+- jcr:mixinTypes  (NAME) autocreated mandatory protected multiple 
+
+[mix:created] mixin
+- jcr:created (DATE) autocreated protected 
+- jcr:createdBy (STRING) autocreated protected 
+
+[mix:lastModified] mixin
+- jcr:lastModified (DATE) autocreated protected
+- jcr:lastModifiedBy (STRING) autocreated protected
+
+[mix:mimeType] mixin
+- jcr:mimeType (STRING) protected
+- jcr:encoding (STRING) protected
+
+[nt:hierarchyNode] > nt:base, mix:created abstract
+
+[nt:file] > nt:hierarchyNode primaryitem jcr:content
++ jcr:content (nt:base) mandatory
+
+[nt:folder] > nt:hierarchyNode
++ * (nt:hierarchyNode) 
+
+[nt:resource] > nt:base, mix:mimeType, mix:lastModified
+primaryitem jcr:data
+- jcr:data (BINARY) mandatory

Modified: jackrabbit/sandbox/jackrabbit-spi2cmis/src/test/java/org/apache/jackrabbit/spi2cmis/ReadTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-spi2cmis/src/test/java/org/apache/jackrabbit/spi2cmis/ReadTest.java?rev=903343&r1=903342&r2=903343&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-spi2cmis/src/test/java/org/apache/jackrabbit/spi2cmis/ReadTest.java (original)
+++ jackrabbit/sandbox/jackrabbit-spi2cmis/src/test/java/org/apache/jackrabbit/spi2cmis/ReadTest.java Tue Jan 26 17:56:54 2010
@@ -30,9 +30,11 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.Value;
+import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.nodetype.NodeTypeIterator;
 import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.PropertyDefinition;
 
 import org.apache.jackrabbit.spi.QNodeTypeDefinition;
 import org.apache.jackrabbit.spi.commons.QNodeTypeDefinitionImpl;
@@ -130,6 +132,27 @@
         }
     }
 
+    public void testGetBinaryValue() throws RepositoryException {
+        String paths[] = {
+//                "/Sites/Franki/d2.txt/jcr:content/jcr:data",
+//                "/default-domain/workspaces/demo-workspace/testi/jcr:content/jcr:data",
+                "/folder 1/folder 2/doc 3/jcr:content/jcr:data",
+        };
+
+        Session session = repository.login();
+        try {
+            for (String path : paths) {
+                Property property = session.getProperty(path);
+                assertEquals(path, property.getPath());
+                dumpProperty(property);
+                System.out.println(property.getString());
+            }
+        }
+        finally {
+            session.logout();
+        }
+    }
+
     public void testTraverse() throws RepositoryException {
         String paths[] = { "/" };
 
@@ -149,7 +172,8 @@
 
     private static void dumpNode(Node node, boolean recursive) throws RepositoryException {
         NodeType nt = node.getPrimaryNodeType();
-        System.out.println(node.getPath() + ": " + nt.getName());
+        NodeDefinition nd = node.getDefinition();
+        System.out.println(node.getPath() + ": " + nt.getName() + " (" + nd.getName() + ")");
 
         dumpProperties(node);
 
@@ -168,19 +192,29 @@
 
     private static void dumpProperty(Property property) throws RepositoryException {
         String value;
+        PropertyDefinition pd = property.getDefinition();
+
         if (property.isMultiple()) {
             Value[] values = property.getValues();
             value = "[";
             for (Value v : values) {
-                value += (v.getString() + ", ");
+                if (PropertyType.BINARY == v.getType()) {
+                    value += "[[BINARY]], ";
+                }
+                else {
+                    value += (v.getString() + ", ");
+                }
             }
             value += "]";
         }
+        else if (PropertyType.BINARY == property.getType()) {
+            value = "[[BINARY]]";
+        }
         else {
             value = property.getString();
         }
         System.out.println(property.getPath() + ": " + PropertyType.nameFromValue(property.getType())
-                + " = " + value);
+                + "(" + pd.getName() + ") = " + value);
     }
 
 }



Mime
View raw message