You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2008/04/30 16:15:29 UTC

svn commit: r652385 - in /incubator/sling/trunk/jcr/resource/src: main/java/org/apache/sling/jcr/resource/ main/java/org/apache/sling/jcr/resource/internal/helper/jcr/ test/java/org/apache/sling/jcr/resource/internal/helper/jcr/

Author: fmeschbe
Date: Wed Apr 30 07:15:28 2008
New Revision: 652385

URL: http://svn.apache.org/viewvc?rev=652385&view=rev
Log:
SLING-395 Implement JcrNodeResource.adaptTo(Map.class) returning a map of
the node's properties converted to Java Objects.

Added:
    incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyMap.java
Modified:
    incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceUtil.java
    incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java
    incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResourceTestBase.java
    incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java

Modified: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceUtil.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceUtil.java?rev=652385&r1=652384&r2=652385&view=diff
==============================================================================
--- incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceUtil.java (original)
+++ incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceUtil.java Wed Apr 30 07:15:28 2008
@@ -18,6 +18,7 @@
  */
 package org.apache.sling.jcr.resource;
 
+import javax.jcr.Property;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -76,6 +77,30 @@
     }
 
     /**
+     * Converts the value(s) of a JCR Property to a corresponding Java Object.
+     * If the property has multiple values the result is an array of Java
+     * Objects representing the converted values of the property.
+     */
+    public static Object toJavaObject(Property property)
+            throws RepositoryException {
+        // multi-value property: return an array of values
+        if (property.getDefinition().isMultiple()) {
+            Value[] values = property.getValues();
+            Object[] result = new Object[values.length];
+            for (int i = 0; i < values.length; i++) {
+                Value value = values[i];
+                if (value != null) {
+                    result[i] = toJavaObject(value);
+                }
+            }
+            return result;
+        }
+
+        // single value property
+        return toJavaObject(property.getValue());
+    }
+
+    /**
      * Resolves relative path segments '.' and '..' in the absolute path.
      * Returns null if not possible (.. points above root) or if path is not
      * absolute.

Modified: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java?rev=652385&r1=652384&r2=652385&view=diff
==============================================================================
--- incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java (original)
+++ incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java Wed Apr 30 07:15:28 2008
@@ -28,6 +28,7 @@
 import java.net.URL;
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.Map;
 
 import javax.jcr.Item;
 import javax.jcr.ItemNotFoundException;
@@ -53,9 +54,8 @@
 
     private final String resourceType;
 
-    JcrNodeResource(ResourceResolver resourceResolver,
-                    Node node,
-                    JcrResourceTypeProvider[] resourceTypeProviders)
+    JcrNodeResource(ResourceResolver resourceResolver, Node node,
+            JcrResourceTypeProvider[] resourceTypeProviders)
             throws RepositoryException {
         super(resourceResolver, node.getPath(), resourceTypeProviders);
         this.node = node;
@@ -77,6 +77,8 @@
             return (Type) getInputStream(); // unchecked cast
         } else if (type == URL.class) {
             return (Type) getURL(); // unchecked cast
+        } else if (type == Map.class) {
+            return (Type) new JcrPropertyMap(getNode()); // unchecked cast
         }
 
         // fall back to default implementation
@@ -97,9 +99,8 @@
     /**
      * Returns a stream to the <em>jcr:data</em> property if the
      * {@link #getNode() node} is an <em>nt:file</em> or <em>nt:resource</em>
-     * node. Otherwise returns <code>null</code>.
-     * If a valid stream can be returned, this method also sets the
-     * content length resource metadata.
+     * node. Otherwise returns <code>null</code>. If a valid stream can be
+     * returned, this method also sets the content length resource metadata.
      */
     private InputStream getInputStream() {
         // implement this for nt:file only
@@ -140,7 +141,7 @@
                     // binary property which could cause performance loss
                     // for all resources that do need to provide the stream
                     long length = data.getLength();
-                    InputStream stream =  data.getStream();
+                    InputStream stream = data.getStream();
 
                     getResourceMetadata().setContentLength(length);
                     return stream;

Added: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyMap.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyMap.java?rev=652385&view=auto
==============================================================================
--- incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyMap.java (added)
+++ incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyMap.java Wed Apr 30 07:15:28 2008
@@ -0,0 +1,154 @@
+/*
+ * 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.sling.jcr.resource.internal.helper.jcr;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+
+import org.apache.sling.jcr.resource.JcrResourceUtil;
+
+class JcrPropertyMap implements Map<String, Object> {
+
+    private final Node node;
+
+    private final Map<String, Object> cache;
+
+    private boolean fullyRead;
+
+    JcrPropertyMap(Node node) {
+        this.node = node;
+        this.cache = new HashMap<String, Object>();
+        this.fullyRead = false;
+    }
+
+    public Object get(Object key) {
+        Object value = cache.get(key);
+        if (value == null) {
+            value = read((String) key);
+        }
+
+        return value;
+    }
+
+    public boolean containsKey(Object key) {
+        return get(key) != null;
+    }
+
+    public boolean containsValue(Object value) {
+        readFully();
+        return cache.containsValue(value);
+    }
+
+    public boolean isEmpty() {
+        if (cache.isEmpty()) {
+            readFully();
+        }
+
+        return cache.isEmpty();
+    }
+
+    public int size() {
+        readFully();
+        return cache.size();
+    }
+
+    public Set<java.util.Map.Entry<String, Object>> entrySet() {
+        readFully();
+        return cache.entrySet();
+    }
+
+    public Set<String> keySet() {
+        readFully();
+        return cache.keySet();
+    }
+
+    public Collection<Object> values() {
+        readFully();
+        return cache.values();
+    }
+
+    // ---------- Helpers to access the node's property ------------------------
+
+    private Object read(String key) {
+
+        // if the node has been completely read, we need not check
+        // again, as we certainly will not find the key
+        if (fullyRead) {
+            return null;
+        }
+
+        try {
+            if (node.hasProperty(key)) {
+                Property prop = node.getProperty(key);
+                Object value = JcrResourceUtil.toJavaObject(prop);
+                cache.put(key, value);
+                return value;
+            }
+        } catch (RepositoryException re) {
+            // TODO: log !!
+        }
+
+        // property not found or some error accessing it
+        return null;
+    }
+
+    private void readFully() {
+        if (!fullyRead) {
+            try {
+                PropertyIterator pi = node.getProperties();
+                while (pi.hasNext()) {
+                    Property prop = pi.nextProperty();
+                    String key = prop.getName();
+                    if (!cache.containsKey(key)) {
+                        cache.put(key, JcrResourceUtil.toJavaObject(prop));
+                    }
+                }
+                fullyRead = true;
+            } catch (RepositoryException re) {
+                // TODO: log !!
+            }
+        }
+    }
+
+    // ---------- Unsupported Modification methods -----------------------------
+
+    public void clear() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object put(String key, Object value) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void putAll(Map<? extends String, ? extends Object> t) {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object remove(Object key) {
+        throw new UnsupportedOperationException();
+    }
+
+}

Modified: incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResourceTestBase.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResourceTestBase.java?rev=652385&r1=652384&r2=652385&view=diff
==============================================================================
--- incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResourceTestBase.java (original)
+++ incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResourceTestBase.java Wed Apr 30 07:15:28 2008
@@ -76,7 +76,7 @@
     protected void assertEquals(byte[] expected, InputStream actual)
             throws IOException {
         if (actual == null) {
-            fail("Rsource stream is null");
+            fail("Resource stream is null");
         } else {
             try {
                 for (byte b : expected) {

Modified: incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java?rev=652385&r1=652384&r2=652385&view=diff
==============================================================================
--- incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java (original)
+++ incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java Wed Apr 30 07:15:28 2008
@@ -20,6 +20,9 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
@@ -156,6 +159,66 @@
         assertEquals(superTypeName, jnr.getResourceSuperType());
     }
 
+    public void testAdaptToMap() throws Exception {
+
+        String name = "adaptable";
+        Node res = rootNode.addNode(name, JcrConstants.NT_UNSTRUCTURED);
+        setupResource(res);
+        getSession().save();
+
+        res = rootNode.getNode(name);
+        JcrNodeResource jnr = new JcrNodeResource(null, res, null);
+
+        final Map<?, ?> props = jnr.adaptTo(Map.class);
+        
+        // assert we have properties at all, only fails if property
+        // retrieval fails for any reason
+        assertNotNull(props);
+        assertFalse(props.isEmpty());
+        
+        // assert all properties set up
+        assertEquals(TEST_MODIFIED, props.get(JcrConstants.JCR_LASTMODIFIED));
+        assertEquals(TEST_TYPE, props.get(JcrConstants.JCR_MIMETYPE));
+        assertEquals(TEST_ENCODING, props.get(JcrConstants.JCR_ENCODING));
+        assertEquals(TEST_DATA, (InputStream) props.get(JcrConstants.JCR_DATA));
+        
+        // assert JCR managed properties
+        assertEquals(JcrConstants.NT_UNSTRUCTURED, props.get(JcrConstants.JCR_PRIMARYTYPE));
+        
+        // assert we have nothing else left
+        final Set<String> existingKeys = new HashSet<String>();
+        existingKeys.add(JcrConstants.JCR_LASTMODIFIED);
+        existingKeys.add(JcrConstants.JCR_MIMETYPE);
+        existingKeys.add(JcrConstants.JCR_ENCODING);
+        existingKeys.add(JcrConstants.JCR_DATA);
+        existingKeys.add(JcrConstants.JCR_PRIMARYTYPE);
+        final Set<Object> crossCheck = new HashSet<Object>(props.keySet());
+        crossCheck.removeAll(existingKeys);
+        assertTrue(crossCheck.isEmpty());
+
+        // call a second time, ensure the map contains the same data again
+        final Map<?, ?> propsSecond = jnr.adaptTo(Map.class);
+        
+        // assert we have properties at all, only fails if property
+        // retrieval fails for any reason
+        assertNotNull(propsSecond);
+        assertFalse(propsSecond.isEmpty());
+        
+        // assert all properties set up
+        assertEquals(TEST_MODIFIED, propsSecond.get(JcrConstants.JCR_LASTMODIFIED));
+        assertEquals(TEST_TYPE, propsSecond.get(JcrConstants.JCR_MIMETYPE));
+        assertEquals(TEST_ENCODING, propsSecond.get(JcrConstants.JCR_ENCODING));
+        assertEquals(TEST_DATA, (InputStream) propsSecond.get(JcrConstants.JCR_DATA));
+        
+        // assert JCR managed properties
+        assertEquals(JcrConstants.NT_UNSTRUCTURED, propsSecond.get(JcrConstants.JCR_PRIMARYTYPE));
+        
+        // assert we have nothing else left
+        final Set<Object> crossCheck2 = new HashSet<Object>(propsSecond.keySet());
+        crossCheck2.removeAll(existingKeys);
+        assertTrue(crossCheck2.isEmpty());
+    }
+
     private void setupResource(Node res) throws RepositoryException {
         res.setProperty(JcrConstants.JCR_LASTMODIFIED, TEST_MODIFIED);
         res.setProperty(JcrConstants.JCR_MIMETYPE, TEST_TYPE);
@@ -172,4 +235,13 @@
         assertEquals(TEST_ENCODING, rm.getCharacterEncoding());
     }
 
+    private void assertProperty(Object expected, Object actual) {
+        if (expected != null) {
+            assertNotNull(actual);
+            
+            assertEquals(expected, actual);
+        } else {
+            assertNull(actual);
+        }
+    }
 }