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 2008/08/13 08:09:41 UTC

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

Author: cziegeler
Date: Tue Aug 12 23:09:40 2008
New Revision: 685455

URL: http://svn.apache.org/viewvc?rev=685455&view=rev
Log:
SLING-609 : Add persistable map for persisting changes and implement it for the jcr resources.

Added:
    incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistableValueMap.java   (with props)
    incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistenceException.java   (with props)
    incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrModifiablePropertyMap.java   (with props)
Modified:
    incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrPropertyMap.java
    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

Added: incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistableValueMap.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistableValueMap.java?rev=685455&view=auto
==============================================================================
--- incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistableValueMap.java (added)
+++ incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistableValueMap.java Tue Aug 12 23:09:40 2008
@@ -0,0 +1,44 @@
+/*
+ * 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.api.resource;
+
+
+
+/**
+ * The <code>PersistableValueMap</code> is an extension
+ * of the {@link ValueMap} which allows to modify and
+ * persist the properties.
+ *
+ * Note, that each time you call {@link Resource#adaptTo(Class)}
+ * you get a new map instance which does not share modified
+ * properties with other representations.
+ */
+public interface PersistableValueMap extends ValueMap {
+
+    /**
+     * Persists the changes.
+     * @throws PersistenceException If the changes can't be persisted.
+     */
+    void save() throws PersistenceException;
+
+    /**
+     * Reset the changes.
+     */
+    void reset();
+}

Propchange: incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistableValueMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistableValueMap.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistableValueMap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistenceException.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistenceException.java?rev=685455&view=auto
==============================================================================
--- incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistenceException.java (added)
+++ incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistenceException.java Tue Aug 12 23:09:40 2008
@@ -0,0 +1,41 @@
+/*
+ * 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.api.resource;
+
+import java.io.IOException;
+
+/**
+ * This exception will be thrown during the try to persists
+ * changes to a {@link PersistableValueMap}.
+ */
+public class PersistenceException extends IOException {
+
+    public PersistenceException() {
+        super();
+    }
+
+    public PersistenceException(String s) {
+        super(s);
+    }
+
+    public PersistenceException(String s, Throwable t) {
+        super(s);
+        initCause(t);
+    }
+}

Propchange: incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistenceException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistenceException.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: incubator/sling/trunk/api/src/main/java/org/apache/sling/api/resource/PersistenceException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrModifiablePropertyMap.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrModifiablePropertyMap.java?rev=685455&view=auto
==============================================================================
--- incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrModifiablePropertyMap.java (added)
+++ incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrModifiablePropertyMap.java Tue Aug 12 23:09:40 2008
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.sling.api.resource.PersistenceException;
+
+/**
+ * This implementation of the value map allows to change
+ * the properies and save them later on.
+ */
+public class JcrModifiablePropertyMap extends JcrPropertyMap {
+
+    /** Set of removed and changed properties. */
+    private Set<String> changedProperties;
+
+    public JcrModifiablePropertyMap(Node node) {
+        super(node);
+    }
+
+    // ---------- Map
+
+    /**
+     * @see java.util.Map#get(java.lang.Object)
+     */
+    public Object get(Object key) {
+        Object value = cache.get(key);
+        if (value == null &&  !this.fullyRead ) {
+            value = read((String) key);
+        }
+
+        return value;
+    }
+
+    /**
+     * @see java.util.Map#clear()
+     */
+    public void clear() {
+        // we have to read all properties first
+        this.readFully();
+        if ( this.changedProperties == null ) {
+            this.changedProperties = new HashSet<String>();
+        }
+        this.changedProperties.addAll(this.cache.keySet());
+        this.cache.clear();
+    }
+
+    /**
+     * @see java.util.Map#put(java.lang.Object, java.lang.Object)
+     */
+    public Object put(String key, Object value) {
+        readFully();
+        final Object oldValue = this.get(key);
+        if ( this.changedProperties == null ) {
+            this.changedProperties = new HashSet<String>();
+        }
+        this.changedProperties.add(key);
+        this.cache.put(key, value);
+        return oldValue;
+    }
+
+    /**
+     * @see java.util.Map#putAll(java.util.Map)
+     */
+    public void putAll(Map<? extends String, ? extends Object> t) {
+        readFully();
+        if ( t != null ) {
+            final Iterator<?> i = t.entrySet().iterator();
+            while (i.hasNext() ) {
+                @SuppressWarnings("unchecked")
+                final Entry<? extends String, ? extends Object> entry = (Entry<? extends String, ? extends Object>) i.next();
+                put(entry.getKey(), entry.getValue());
+            }
+        }
+    }
+
+    /**
+     * @see java.util.Map#remove(java.lang.Object)
+     */
+    public Object remove(Object key) {
+        readFully();
+        final Object oldValue = this.get(key);
+        if ( this.changedProperties == null ) {
+            this.changedProperties = new HashSet<String>();
+        }
+        this.changedProperties.add(key.toString());
+        return oldValue;
+    }
+
+    /**
+     * @see org.apache.sling.api.resource.PersistableValueMap#reset()
+     */
+    public void reset() {
+        if ( this.changedProperties != null ) {
+            this.changedProperties = null;
+        }
+        this.cache.clear();
+        this.fullyRead = false;
+    }
+
+    /**
+     * @see org.apache.sling.api.resource.PersistableValueMap#save()
+     */
+    public void save() throws PersistenceException {
+        if ( this.changedProperties == null || this.changedProperties.size() == 0 ) {
+            // nothing has changed
+            return;
+        }
+        try {
+            final Node node = getNode();
+            for(final String key : this.changedProperties) {
+                if ( cache.containsKey(key) ) {
+                    JcrResourceUtil.setProperty(node, key, this.cache.get(key));
+                } else {
+                    node.setProperty(key, (String)null);
+                }
+            }
+            node.save();
+        } catch (RepositoryException re) {
+            throw new PersistenceException("Unable to persist changes.", re);
+        }
+        this.reset();
+    }
+}

Propchange: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrModifiablePropertyMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrModifiablePropertyMap.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrModifiablePropertyMap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrPropertyMap.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrPropertyMap.java?rev=685455&r1=685454&r2=685455&view=diff
==============================================================================
--- incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrPropertyMap.java (original)
+++ incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrPropertyMap.java Tue Aug 12 23:09:40 2008
@@ -41,13 +41,13 @@
 public class JcrPropertyMap implements ValueMap {
 
     /** default log */
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    private Logger logger = LoggerFactory.getLogger(JcrPropertyMap.class);
 
     private final Node node;
 
-    private final Map<String, Object> cache;
+    protected final Map<String, Object> cache;
 
-    private boolean fullyRead;
+    protected boolean fullyRead;
 
     public JcrPropertyMap(Node node) {
         this.node = node;
@@ -55,6 +55,10 @@
         this.fullyRead = false;
     }
 
+    protected Node getNode() {
+        return node;
+    }
+
     // ---------- ValueMap
 
     @SuppressWarnings("unchecked")
@@ -100,56 +104,76 @@
         return value;
     }
 
+    /**
+     * @see java.util.Map#containsKey(java.lang.Object)
+     */
     public boolean containsKey(Object key) {
         return get(key) != null;
     }
 
+    /**
+     * @see java.util.Map#containsValue(java.lang.Object)
+     */
     public boolean containsValue(Object value) {
         readFully();
         return cache.containsValue(value);
     }
 
+    /**
+     * @see java.util.Map#isEmpty()
+     */
     public boolean isEmpty() {
-        // only start reading if there is nothing in the cache yet
-        if (cache.isEmpty()) {
-            readFully();
-        }
-
-        return cache.isEmpty();
+        return size() == 0;
     }
 
+    /**
+     * @see java.util.Map#size()
+     */
     public int size() {
         readFully();
         return cache.size();
     }
 
+    /**
+     * @see java.util.Map#entrySet()
+     */
     public Set<java.util.Map.Entry<String, Object>> entrySet() {
         readFully();
         return cache.entrySet();
     }
 
+    /**
+     * @see java.util.Map#keySet()
+     */
     public Set<String> keySet() {
         readFully();
         return cache.keySet();
     }
 
+    /**
+     * @see java.util.Map#values()
+     */
     public Collection<Object> values() {
         readFully();
         return cache.values();
     }
 
+    /**
+     * Return the path of the current node.
+     * @throws IllegalStateException If a repository exception occurs
+     */
     public String getPath() {
         try {
             return node.getPath();
         } catch (RepositoryException e) {
-            // TODO
-            return "";
+            throw new IllegalStateException(e);
         }
     }
 
+
     // ---------- Helpers to access the node's property ------------------------
 
-    private Object read(String key) {
+    protected Object read(String key) {
 
         // if the node has been completely read, we need not check
         // again, as we certainly will not find the key
@@ -172,7 +196,7 @@
         return null;
     }
 
-    private void readFully() {
+    protected void readFully() {
         if (!fullyRead) {
             try {
                 PropertyIterator pi = node.getProperties();
@@ -228,10 +252,10 @@
             }
 
         } catch (ValueFormatException vfe) {
-            log.info("converToType: Cannot convert value of " + name + " to "
+            logger.info("converToType: Cannot convert value of " + name + " to "
                 + type, vfe);
         } catch (RepositoryException re) {
-            log.info("converToType: Cannot get value of " + name, re);
+            logger.info("converToType: Cannot get value of " + name, re);
         }
 
         // fall back to nothing

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=685455&r1=685454&r2=685455&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 Tue Aug 12 23:09:40 2008
@@ -18,11 +18,16 @@
  */
 package org.apache.sling.jcr.resource;
 
+import java.io.InputStream;
+import java.util.Calendar;
+
+import javax.jcr.Node;
 import javax.jcr.Property;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.Value;
+import javax.jcr.ValueFactory;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryManager;
 import javax.jcr.query.QueryResult;
@@ -93,10 +98,69 @@
     }
 
     /**
+     * Creates a {@link javax.jcr.Value JCR Value} for the given object with
+     * the given Session.
+     * Selects the the {@link javax.jcr.PropertyType PropertyType} according
+     * the instance of the object's Class
+     *
+     * @param value object
+     * @param session to create value for
+     * @return the value or null if not convertible to a valid PropertyType
+     * @throws RepositoryException in case of error, accessing the Repository
+     */
+    public static Value createValue(Object value, Session session)
+            throws RepositoryException {
+        Value val;
+        ValueFactory fac = session.getValueFactory();
+        if(value.getClass().isAssignableFrom(Calendar.class)) {
+            val = fac.createValue((Calendar)value);
+        } else if (value.getClass().isAssignableFrom(InputStream.class)) {
+            val = fac.createValue((InputStream)value);
+        } else if (value.getClass().isAssignableFrom(Node.class)) {
+            val = fac.createValue((Node)value);
+        } else if (value.getClass().isAssignableFrom(Long.class)) {
+            val = fac.createValue((Long)value);
+        } else if (value.getClass().isAssignableFrom(Number.class)) {
+            val = fac.createValue(((Number)value).doubleValue());
+        } else if (value.getClass().isAssignableFrom(Boolean.class)) {
+            val = fac.createValue((Boolean) value);
+        } else {
+            val = fac.createValue((String)value);
+        }
+        return val;
+    }
+
+    /**
+     * Sets the value of the property.
+     * Selects the {@link javax.jcr.PropertyType PropertyType} according
+     * to the instance of the object's class.
+     * @param node         The node where the property will be set on.
+     * @param propertyName The name of the property.
+     * @param propertyValue The value for the property.
+     */
+    public static void setProperty(final Node node,
+                                   final String propertyName,
+                                   final Object propertyValue)
+    throws RepositoryException {
+        if ( propertyValue == null ) {
+            node.setProperty(propertyName, (String)null);
+        } else if ( propertyValue.getClass().isArray() ) {
+            final Object[] values = (Object[])propertyValue;
+            final Value[] setValues = new Value[values.length];
+            for(int i=0; i<values.length; i++) {
+                setValues[i] = createValue(values[i], node.getSession());
+            }
+            node.setProperty(propertyName, setValues);
+        } else {
+            node.setProperty(propertyName, createValue(propertyValue, node.getSession()));
+        }
+    }
+
+    /**
      * Helper method, which returns the given resource type as returned from the
      * {@link org.apache.sling.api.resource.Resource#getResourceType()} as a
      * relative path.
-     * 
+     *
      * @param type The resource type to be converted into a path
      * @return The resource type as a path.
      */
@@ -111,7 +175,7 @@
      * <code>Resource</code> addressed by the <code>resourceType</code> to a
      * string. If no such child resource exists or if the resource does not
      * adapt to a string, this method returns <code>null</code>.
-     * 
+     *
      * @param resourceResolver The <code>ResourceResolver</code> used to
      *            access the resource whose path (relative or absolute) is given
      *            by the <code>resourceType</code> parameter.
@@ -151,7 +215,7 @@
      * This mechanism allows to specifically set the resource super type on a
      * per-resource level overwriting any resource super type hierarchy
      * pre-defined by the actual resource type of the resource.
-     * 
+     *
      * @param resource The <code>Resource</code> whose resource super type is
      *            requested.
      * @return The resource super type or <code>null</code> if the algorithm

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=685455&r1=685454&r2=685455&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 Tue Aug 12 23:09:40 2008
@@ -37,10 +37,12 @@
 import javax.jcr.RepositoryException;
 
 import org.apache.jackrabbit.net.URLFactory;
+import org.apache.sling.api.resource.PersistableValueMap;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceMetadata;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.jcr.resource.JcrModifiablePropertyMap;
 import org.apache.sling.jcr.resource.JcrPropertyMap;
 import org.apache.sling.jcr.resource.JcrResourceTypeProvider;
 import org.slf4j.Logger;
@@ -81,6 +83,15 @@
             return (Type) getURL(); // unchecked cast
         } else if (type == Map.class || type == ValueMap.class) {
             return (Type) new JcrPropertyMap(getNode()); // unchecked cast
+        } else if (type == PersistableValueMap.class ) {
+            // check write
+            try {
+                getNode().getSession().checkPermission(getNode().getPath(), "set_property");
+                return (Type) new JcrModifiablePropertyMap(getNode());
+            } catch (RepositoryException e) {
+                // either the user has no write permission or a more
+                // sever exception occured - in both cases we don't return the map
+            }
         }
 
         // fall back to default implementation