You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2009/09/29 14:25:04 UTC

svn commit: r819904 - in /sling/trunk/bundles/jcr/resource/src: main/java/org/apache/sling/jcr/resource/internal/ test/java/org/apache/sling/jcr/resource/internal/

Author: cziegeler
Date: Tue Sep 29 12:25:04 2009
New Revision: 819904

URL: http://svn.apache.org/viewvc?rev=819904&view=rev
Log:
SLING-1126 : Support serializable objects - it's now possible to put serializable objects into the map, and retrieve them via get(String, Serializable.class) (or a sub class of Serializable)

Modified:
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMap.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrPropertyMap.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMapTest.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrPropertyMapTest.java

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMap.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMap.java?rev=819904&r1=819903&r2=819904&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMap.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMap.java Tue Sep 29 12:25:04 2009
@@ -65,14 +65,17 @@
      */
     public Object put(String key, Object value) {
         if ( key == null || key.indexOf('/') != -1 ) {
-            throw new IllegalArgumentException("Invalud key: " + key);
+            throw new IllegalArgumentException("Invalid key: " + key);
+        }
+        if ( value == null ) {
+            throw new NullPointerException("Value should not be null (key = " + key + ")");
         }
         readFully();
         final Object oldValue = this.get(key);
         try {
-            this.cache.put(key, new CacheEntry(value, getNode()));
+            this.cache.put(key, new CacheEntry(value, getNode().getSession()));
         } catch (RepositoryException re) {
-            throw new IllegalArgumentException("Value can't be put into node: " + value, re);
+            throw new IllegalArgumentException("Value for key " + key + " can't be put into node: " + value, re);
         }
         this.valueCache.put(key, value);
         if ( this.changedProperties == null ) {

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrPropertyMap.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrPropertyMap.java?rev=819904&r1=819903&r2=819904&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrPropertyMap.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrPropertyMap.java Tue Sep 29 12:25:04 2009
@@ -18,6 +18,12 @@
  */
 package org.apache.sling.jcr.resource.internal;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -33,6 +39,7 @@
 import javax.jcr.PropertyIterator;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 import javax.jcr.Value;
 import javax.jcr.ValueFormatException;
 
@@ -338,8 +345,14 @@
     }
 
     @SuppressWarnings("unchecked")
-    private <T> T convertToType(final CacheEntry entry, int index, Value jcrValue,
-            Class<T> type) throws ValueFormatException, RepositoryException {
+    private <T> T convertToType(final CacheEntry entry,
+                                final int index,
+                                final Value jcrValue,
+                                final Class<T> type)
+    throws ValueFormatException, RepositoryException {
+        if ( type.isInstance(entry.defaultValue) ) {
+            return (T) entry.defaultValue;
+        }
 
         if (String.class == type) {
             return (T) jcrValue.getString();
@@ -382,6 +395,29 @@
 
         } else if (Property.class == type) {
             return (T) entry.property;
+
+        } else if (Serializable.class.isAssignableFrom(type)
+                && jcrValue.getType() == PropertyType.BINARY) {
+            ObjectInputStream ois = null;
+            try {
+                ois = new ObjectInputStream(jcrValue.getStream(), null);
+                final Object obj = ois.readObject();
+                if ( type.isInstance(obj) ) {
+                    return (T)obj;
+                }
+            } catch (ClassNotFoundException cnfe) {
+                 // ignore and use fallback
+            } catch (IOException ioe) {
+                // ignore and use fallback
+            } finally {
+                if ( ois != null ) {
+                    try {
+                        ois.close();
+                    } catch (IOException ignore) {
+                        // ignore
+                    }
+                }
+            }
         }
 
         // fallback in case of unsupported type
@@ -408,6 +444,33 @@
 
         public final Object defaultValue;
 
+        /**
+         * Create a value for the object.
+         * If the value type is supported directly through a jcr property type,
+         * the corresponding value is created. If the value is serializable,
+         * it is serialized through an object stream. Otherwise null is returned.
+         */
+        private Value createValue(final Object obj, final Session session)
+        throws RepositoryException {
+            Value value = JcrResourceUtil.createValue(obj, session);
+            if ( value == null && obj instanceof Serializable ) {
+                try {
+                    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    final ObjectOutputStream oos = new ObjectOutputStream(baos);
+                    oos.writeObject(obj);
+                    oos.close();
+                    final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+                    value = session.getValueFactory().createValue(bais);
+                } catch (IOException ioe) {
+                    // we ignore this here and return null
+                }
+            }
+            return value;
+        }
+
+        /**
+         * Create a new cache entry from a property.
+         */
         public CacheEntry(final Property prop)
         throws RepositoryException {
             this.property = prop;
@@ -421,7 +484,10 @@
             this.defaultValue = JcrResourceUtil.toJavaObject(prop);
         }
 
-        public CacheEntry(final Object value, final Node node)
+        /**
+         * Create a new cache entry from a value.
+         */
+        public CacheEntry(final Object value, final Session session)
         throws RepositoryException {
             this.property = null;
             this.defaultValue = value;
@@ -430,12 +496,43 @@
                 final Object[] values = (Object[])value;
                 this.values = new Value[values.length];
                 for(int i=0; i<values.length; i++) {
-                    this.values[i] = JcrResourceUtil.createValue(values[i], node.getSession());
+                    this.values[i] = this.createValue(values[i], session);
+                    if ( this.values[i] == null ) {
+                        throw new IllegalArgumentException("Value can't be stored in the repository: " + values[i]);
+                    }
                 }
             } else {
                 this.isMulti = false;
-                this.values = new Value[] {JcrResourceUtil.createValue(value, node.getSession())};
+                this.values = new Value[] {this.createValue(value, session)};
+                if ( this.values[0] == null ) {
+                    throw new IllegalArgumentException("Value can't be stored in the repository: " + value);
+                }
+            }
+        }
+    }
+
+    /**
+     * This is an extended version of the object input stream which uses the
+     * thread context class loader.
+     */
+    private static class ObjectInputStream extends java.io.ObjectInputStream {
+
+        private ClassLoader classloader;
+
+        public ObjectInputStream(final InputStream in, final ClassLoader classLoader) throws IOException {
+            super(in);
+            this.classloader = classLoader;
+        }
+
+        /**
+         * @see java.io.ObjectInputStream#resolveClass(java.io.ObjectStreamClass)
+         */
+        @Override
+        protected Class<?> resolveClass(java.io.ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {
+            if ( this.classloader != null ) {
+                return Class.forName(classDesc.getName(), true, this.classloader);
             }
+            return super.resolveClass(classDesc);
         }
     }
 }

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMapTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMapTest.java?rev=819904&r1=819903&r2=819904&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMapTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrModifiablePropertyMapTest.java Tue Sep 29 12:25:04 2009
@@ -1,7 +1,28 @@
+/*
+ * 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;
 
 import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.jcr.Node;
@@ -93,6 +114,47 @@
         assertContains(pvm2, initialSet());
     }
 
+    public void testSerializable()
+    throws IOException {
+        final PersistableValueMap pvm = new JcrModifiablePropertyMap(this.rootNode);
+        assertContains(pvm, initialSet());
+        assertNull(pvm.get("something"));
+
+        // now put a serializable object
+        final List<String> strings = new ArrayList<String>();
+        strings.add("a");
+        strings.add("b");
+        pvm.put("something", strings);
+
+        // check if we get the list again
+        final List<String> strings2 = (List<String>) pvm.get("something");
+        assertEquals(strings, strings2);
+
+        pvm.save();
+
+        final PersistableValueMap pvm2 = new JcrModifiablePropertyMap(this.rootNode);
+        // check if we get the list again
+        final List<String> strings3 = (List<String>) pvm2.get("something", Serializable.class);
+        assertEquals(strings, strings3);
+
+    }
+
+    public void testExceptions() {
+        final PersistableValueMap pvm = new JcrModifiablePropertyMap(this.rootNode);
+        try {
+            pvm.put(null, "something");
+            fail("Put with null key");
+        } catch (IllegalArgumentException iae) {}
+        try {
+            pvm.put("something", null);
+            fail("Put with null value");
+        } catch (NullPointerException iae) {}
+        try {
+            pvm.put("something", pvm);
+            fail("Put with non serializable");
+        } catch (IllegalArgumentException iae) {}
+    }
+
     protected JcrPropertyMap createPropertyMap(final Node node) {
         return new JcrModifiablePropertyMap(node);
     }

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrPropertyMapTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrPropertyMapTest.java?rev=819904&r1=819903&r2=819904&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrPropertyMapTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrPropertyMapTest.java Tue Sep 29 12:25:04 2009
@@ -1,4 +1,3 @@
-package org.apache.sling.jcr.resource.internal;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -17,6 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.sling.jcr.resource.internal;
+
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Iterator;