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 2012/10/25 14:51:15 UTC

svn commit: r1402132 - in /sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper: SlingFileUploadHandler.java SlingPropertyValueHandler.java

Author: cziegeler
Date: Thu Oct 25 12:51:15 2012
New Revision: 1402132

URL: http://svn.apache.org/viewvc?rev=1402132&view=rev
Log:
SLING-2530 : Implement CRUD support

Modified:
    sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java
    sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java

Modified: sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java?rev=1402132&r1=1402131&r2=1402132&view=diff
==============================================================================
--- sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java (original)
+++ sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingFileUploadHandler.java Thu Oct 25 12:51:15 2012
@@ -18,7 +18,9 @@ package org.apache.sling.servlets.post.i
 
 import java.io.IOException;
 import java.util.Calendar;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
@@ -28,6 +30,7 @@ import javax.servlet.ServletContext;
 
 import org.apache.jackrabbit.util.Text;
 import org.apache.sling.api.request.RequestParameter;
+import org.apache.sling.api.resource.ModifiableValueMap;
 import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.servlets.post.Modification;
@@ -104,13 +107,128 @@ public class SlingFileUploadHandler {
      * @param prop the assembled property info
      * @throws RepositoryException if an error occurs
      */
-    private void setFile(Node parent, RequestProperty prop, List<Modification> changes)
-            throws RepositoryException {
-    	RequestParameter[] values = prop.getValues();
-    	for (RequestParameter requestParameter : values) {
-        	RequestParameter value = requestParameter;
+    private void setFile(final Resource parentResource, final Node parent, final RequestProperty prop, RequestParameter value, final List<Modification> changes, String name, final String contentType)
+            throws RepositoryException, PersistenceException {
+        // check type hint. if the type is ok and extends from nt:file,
+        // create an nt:file with that type. if it's invalid, drop it and let
+        // the parent node type decide.
+        boolean createNtFile = parent.isNodeType(NT_FOLDER);
+        String typeHint = prop.getTypeHint();
+        if (typeHint != null) {
+            try {
+                NodeTypeManager ntMgr = parent.getSession().getWorkspace().getNodeTypeManager();
+                NodeType nt = ntMgr.getNodeType(typeHint);
+                createNtFile = nt.isNodeType(NT_FILE);
+            } catch (RepositoryException e) {
+                // assuming type not valid.
+                typeHint = null;
+            }
+        }
+
+        // also create an nt:file if the name contains an extension
+        // the rationale is that if the file name is "important" we want
+        // an nt:file, and an image name with an extension is probably "important"
+        if(!createNtFile && name.indexOf('.') > 0) {
+            createNtFile = true;
+        }
+
+        // set empty type
+        if (typeHint == null) {
+            typeHint = createNtFile ? NT_FILE : NT_RESOURCE;
+        }
+
+        // create nt:file node if needed
+        Resource resParent;
+        if (createNtFile) {
+            // create nt:file
+            resParent = getOrCreateChildResource(parentResource, name, typeHint, changes);
+            name = JCR_CONTENT;
+            typeHint = NT_RESOURCE;
+        } else {
+            resParent = parentResource;
+        }
+
+        // create resource node
+        Resource newResource = getOrCreateChildResource(resParent, name, typeHint, changes);
+        Node res = newResource.adaptTo(Node.class);
+
+        // set properties
+        changes.add(Modification.onModified(
+                res.setProperty(JCR_LASTMODIFIED, Calendar.getInstance()).getPath()
+                ));
+        changes.add(Modification.onModified(
+                res.setProperty(JCR_MIMETYPE, contentType).getPath()
+                ));
+        try {
+            changes.add(Modification.onModified(
+                    res.setProperty(JCR_DATA, value.getInputStream()).getPath()
+                    ));
+        } catch (IOException e) {
+            throw new RepositoryException("Error while retrieving inputstream from parameter value.", e);
+        }
+    }
+
+    /**
+     * Uses the file(s) in the request parameter for creation of new nodes.
+     * if the parent node is a nt:folder a new nt:file is created. otherwise
+     * just a nt:resource. if the <code>name</code> is '*', the filename of
+     * the uploaded file is used.
+     *
+     * @param parent the parent node
+     * @param prop the assembled property info
+     * @throws RepositoryException if an error occurs
+     */
+    private void setFile(final Resource parentResource, final RequestProperty prop, final RequestParameter value, final List<Modification> changes, String name, final String contentType)
+            throws PersistenceException, RepositoryException {
+        String typeHint = prop.getTypeHint();
+        if ( typeHint == null ) {
+            typeHint = NT_FILE;
+        }
 
-        	// ignore if a plain form field or empty
+        // create properties
+        final Map<String, Object> props = new HashMap<String, Object>();
+        props.put("sling:resourceType", typeHint);
+        props.put(JCR_LASTMODIFIED, Calendar.getInstance());
+        props.put(JCR_MIMETYPE, contentType);
+        try {
+            props.put(JCR_DATA, value.getInputStream());
+        } catch (final IOException e) {
+            throw new PersistenceException("Error while retrieving inputstream from parameter value.", e);
+        }
+
+        // get or create resource
+        Resource result = parentResource.getChild(name);
+        if ( result != null ) {
+            final ModifiableValueMap vm = result.adaptTo(ModifiableValueMap.class);
+            if ( vm == null ) {
+                throw new PersistenceException("Resource at " + parentResource.getPath() + '/' + name + " is not modifiable.");
+            }
+            vm.putAll(props);
+        } else {
+            result = parentResource.getResourceResolver().create(parentResource, name, props);
+        }
+        for(final String key : props.keySet()) {
+            changes.add(Modification.onModified(result.getPath() + '/' + key));
+        }
+    }
+
+    private static final String MT_APP_OCTET = "application/octet-stream";
+
+    /**
+     * Uses the file(s) in the request parameter for creation of new nodes.
+     * if the parent node is a nt:folder a new nt:file is created. otherwise
+     * just a nt:resource. if the <code>name</code> is '*', the filename of
+     * the uploaded file is used.
+     *
+     * @param parent the parent node
+     * @param prop the assembled property info
+     * @throws RepositoryException if an error occurs
+     */
+    public void setFile(final Resource parent, final RequestProperty prop, final List<Modification> changes)
+            throws RepositoryException, PersistenceException {
+        for (final RequestParameter value : prop.getValues()) {
+
+            // ignore if a plain form field or empty
             if (value.isFormField() || value.getSize() <= 0) {
                 continue;
             }
@@ -125,48 +243,6 @@ public class SlingFileUploadHandler {
             }
             name = Text.escapeIllegalJcrChars(name);
 
-            // check type hint. if the type is ok and extends from nt:file,
-            // create an nt:file with that type. if it's invalid, drop it and let
-            // the parent node type decide.
-            boolean createNtFile = parent.isNodeType(NT_FOLDER);
-            String typeHint = prop.getTypeHint();
-            if (typeHint != null) {
-                try {
-                    NodeTypeManager ntMgr = parent.getSession().getWorkspace().getNodeTypeManager();
-                    NodeType nt = ntMgr.getNodeType(typeHint);
-                    createNtFile = nt.isNodeType(NT_FILE);
-                } catch (RepositoryException e) {
-                    // assuming type not valid.
-                    typeHint = null;
-                }
-            }
-
-            // also create an nt:file if the name contains an extension
-            // the rationale is that if the file name is "important" we want
-            // an nt:file, and an image name with an extension is probably "important"
-            if(!createNtFile && name.indexOf('.') > 0) {
-                createNtFile = true;
-            }
-
-            // set empty type
-            if (typeHint == null) {
-                typeHint = createNtFile ? NT_FILE : NT_RESOURCE;
-            }
-
-            // create nt:file node if needed
-            Node resParent;
-            if (createNtFile) {
-                // create nt:file
-                resParent = getOrCreateChildNode(parent, name, typeHint, changes);
-                name = JCR_CONTENT;
-                typeHint = NT_RESOURCE;
-            } else {
-            	resParent = parent;
-            }
-
-            // create resource node
-            Node res = getOrCreateChildNode(resParent, name, typeHint, changes);
-
             // get content type
             String contentType = value.getContentType();
             if (contentType != null) {
@@ -175,64 +251,37 @@ public class SlingFileUploadHandler {
                     contentType = contentType.substring(0, idx);
                 }
             }
-            if (contentType == null || contentType.equals("application/octet-stream")) {
+            if (contentType == null || contentType.equals(MT_APP_OCTET)) {
                 // try to find a better content type
                 ServletContext ctx = this.servletContext;
                 if (ctx != null) {
                     contentType = ctx.getMimeType(value.getFileName());
                 }
-                if (contentType == null || contentType.equals("application/octet-stream")) {
-                    contentType = "application/octet-stream";
+                if (contentType == null || contentType.equals(MT_APP_OCTET)) {
+                    contentType = MT_APP_OCTET;
                 }
             }
 
-            // set properties
-            changes.add(Modification.onModified(
-                res.setProperty(JCR_LASTMODIFIED, Calendar.getInstance()).getPath()
-            ));
-            changes.add(Modification.onModified(
-                res.setProperty(JCR_MIMETYPE, contentType).getPath()
-            ));
-            try {
-                changes.add(Modification.onModified(
-                    res.setProperty(JCR_DATA, value.getInputStream()).getPath()
-                ));
-            } catch (IOException e) {
-                throw new RepositoryException("Error while retrieving inputstream from parameter value.", e);
+            final Node node = parent.adaptTo(Node.class);
+            if ( node == null ) {
+                this.setFile(parent, prop, value, changes, name, contentType);
+            } else {
+                this.setFile(parent, node, prop, value, changes, name, contentType);
             }
-		}
+        }
+
     }
 
-    /**
-     * Uses the file(s) in the request parameter for creation of new nodes.
-     * if the parent node is a nt:folder a new nt:file is created. otherwise
-     * just a nt:resource. if the <code>name</code> is '*', the filename of
-     * the uploaded file is used.
-     *
-     * @param parent the parent node
-     * @param prop the assembled property info
-     * @throws RepositoryException if an error occurs
-     */
-    public void setFile(Resource parent, RequestProperty prop, List<Modification> changes)
-    throws RepositoryException, PersistenceException {
-        final Node node = parent.adaptTo(Node.class);
-        if ( node == null ) {
-            // TODO
-            throw new PersistenceException("Binary properties for resource '" + parent.getPath() + "' currently not supported.");
-        }
-        this.setFile(node, prop, changes);
-    }
-
-    private Node getOrCreateChildNode(Node parent, String name, String typeHint,
-            List<Modification> changes) throws RepositoryException {
-        Node result;
-        if (parent.hasNode(name)) {
-            Node existing = parent.getNode(name);
-            if (!existing.isNodeType(typeHint)) {
+    private Resource getOrCreateChildResource(final Resource parent, final String name,
+            final String typeHint,
+            final List<Modification> changes)
+                    throws PersistenceException, RepositoryException {
+        Resource result = parent.getChild(name);
+        if ( result != null ) {
+            final Node existing = result.adaptTo(Node.class);
+            if ( existing != null && !existing.isNodeType(typeHint)) {
                 existing.remove();
                 result = createWithChanges(parent, name, typeHint, changes);
-            } else {
-                result = existing;
             }
         } else {
             result = createWithChanges(parent, name, typeHint, changes);
@@ -240,9 +289,20 @@ public class SlingFileUploadHandler {
         return result;
     }
 
-    private Node createWithChanges(Node parent, String name, String typeHint,
-            List<Modification> changes) throws RepositoryException {
-        Node result = parent.addNode(name, typeHint);
+    private Resource createWithChanges(final Resource parent, final String name,
+            final String typeHint,
+            final List<Modification> changes)
+                    throws PersistenceException {
+        Map<String, Object> properties = null;
+        if ( typeHint != null ) {
+            properties = new HashMap<String, Object>();
+            if ( parent.adaptTo(Node.class) != null ) {
+                properties.put("jcr:primaryType", typeHint);
+            } else {
+                properties.put("sling:resourceType", typeHint);
+            }
+        }
+        final Resource result = parent.getResourceResolver().create(parent, name, properties);
         changes.add(Modification.onCreated(result.getPath()));
         return result;
     }

Modified: sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java?rev=1402132&r1=1402131&r2=1402132&view=diff
==============================================================================
--- sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java (original)
+++ sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java Thu Oct 25 12:51:15 2012
@@ -105,7 +105,7 @@ public class SlingPropertyValueHandler {
      * @throws RepositoryException if a repository error occurs
      */
     public void setProperty(final Resource parent, final RequestProperty prop)
-    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
         final Modifiable mod = new Modifiable();
         mod.resource = parent;
         mod.node = parent.adaptTo(Node.class);
@@ -124,22 +124,22 @@ public class SlingPropertyValueHandler {
             final boolean isNew = (mod.node != null ? mod.node.isNew() : true);
             try {
                 switch (AUTO_PROPS.get(name)) {
-                    case CREATED:
-                        if (isNew) {
-                            setCurrentDate(mod, name);
-                        }
-                        break;
-                    case CREATED_BY:
-                        if (isNew) {
-                            setCurrentUser(mod, name);
-                        }
-                        break;
-                    case MODIFIED:
+                case CREATED:
+                    if (isNew) {
                         setCurrentDate(mod, name);
-                        break;
-                    case MODIFIED_BY:
+                    }
+                    break;
+                case CREATED_BY:
+                    if (isNew) {
                         setCurrentUser(mod, name);
-                        break;
+                    }
+                    break;
+                case MODIFIED:
+                    setCurrentDate(mod, name);
+                    break;
+                case MODIFIED_BY:
+                    setCurrentUser(mod, name);
+                    break;
                 }
             } catch (ConstraintViolationException e) {
             }
@@ -156,7 +156,7 @@ public class SlingPropertyValueHandler {
      * @throws RepositoryException if a repository error occurs
      */
     private void setCurrentDate(Modifiable parent, String name)
-    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
         removePropertyIfExists(parent, name);
         parent.valueMap.put(name, now);
         changes.add(Modification.onModified(parent.resource.getPath() + '/' + name));
@@ -169,7 +169,7 @@ public class SlingPropertyValueHandler {
      * @throws RepositoryException if a repository error occurs
      */
     private void setCurrentUser(Modifiable parent, String name)
-    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
         removePropertyIfExists(parent, name);
         final String user = parent.resource.getResourceResolver().getUserID();
         parent.valueMap.put(name, user);
@@ -187,7 +187,7 @@ public class SlingPropertyValueHandler {
      * @throws RepositoryException if a repository error occurs.
      */
     private String removePropertyIfExists(final Modifiable parent, final String name)
-    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
         if (parent.valueMap.containsKey(name) ) {
             if ( parent.node != null ) {
                 final Property prop = parent.node.getProperty(name);
@@ -212,7 +212,7 @@ public class SlingPropertyValueHandler {
      * @throws RepositoryException if a repository error occurs.
      */
     private void setPropertyAsIs(final Modifiable parent, final RequestProperty prop)
-    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
 
         String[] values = prop.getStringValues();
 
@@ -263,7 +263,7 @@ public class SlingPropertyValueHandler {
      * Patches a multi-value property using add and remove operations per value.
      */
     private String[] patch(final Modifiable parent, String name, String[] values)
-    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
         // we do not use a Set here, as we want to be very restrictive in our
         // actions and avoid touching elements that are not modified through the
         // add/remove patch operations; e.g. if the value "foo" occurs twice
@@ -391,7 +391,7 @@ public class SlingPropertyValueHandler {
      * removes multi-value properties.
      */
     private void clearProperty(final Modifiable parent, RequestProperty prop)
-    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
         if (parent.valueMap.containsKey(prop.getName())) {
             if ( parent.node != null ) {
                 if (parent.node.getProperty(prop.getName()).getDefinition().isMultiple()) {
@@ -402,8 +402,8 @@ public class SlingPropertyValueHandler {
                     }
                 } else {
                     changes.add(Modification.onModified(
-                                    parent.node.setProperty(prop.getName(), "").getPath()
-                    ));
+                            parent.node.setProperty(prop.getName(), "").getPath()
+                            ));
                 }
             } else {
                 parent.valueMap.put(prop.getName(), "");
@@ -416,7 +416,7 @@ public class SlingPropertyValueHandler {
      * Removes the property if it exists.
      */
     private void removeProperty(final Modifiable parent, RequestProperty prop)
-    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
         final String removePath = removePropertyIfExists(parent, prop.getName());
         if ( removePath != null ) {
             changes.add(Modification.onDeleted(removePath));
@@ -427,8 +427,8 @@ public class SlingPropertyValueHandler {
      * Removes the property if it exists and is single-valued.
      */
     private void removeIfSingleValueProperty(final Modifiable parent,
-                    final RequestProperty prop)
-    throws RepositoryException, PersistenceException {
+            final RequestProperty prop)
+                    throws RepositoryException, PersistenceException {
         if (parent.valueMap.containsKey(prop.getName())) {
             if ( parent.node != null ) {
                 if (!parent.node.getProperty(prop.getName()).getDefinition().isMultiple()) {
@@ -455,7 +455,7 @@ public class SlingPropertyValueHandler {
      * @return true only if parsing was successfull and the property was actually changed
      */
     private boolean storeAsDate(final Modifiable parent, String name, String[] values, boolean multiValued, ValueFactory valFac)
-                    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
         if (multiValued) {
             final Value[] array = dateParser.parse(values, valFac);
             if (array != null) {
@@ -494,7 +494,7 @@ public class SlingPropertyValueHandler {
      * @return true only if parsing was successfull and the property was actually changed
      */
     private boolean storeAsReference(final Modifiable parent, String name, String[] values, int type, boolean multiValued, ValueFactory valFac)
-    throws RepositoryException, PersistenceException {
+            throws RepositoryException, PersistenceException {
         if ( parent.node == null ) {
             // TODO
             throw new PersistenceException("Resource " + parent.resource.getPath() + " does not support reference properties.");
@@ -503,8 +503,8 @@ public class SlingPropertyValueHandler {
             Value[] array = referenceParser.parse(values, valFac, isWeakReference(type));
             if (array != null) {
                 changes.add(Modification.onModified(
-                                parent.node.setProperty(name, array).getPath()
-                ));
+                        parent.node.setProperty(name, array).getPath()
+                        ));
                 return true;
             }
         } else {
@@ -512,8 +512,8 @@ public class SlingPropertyValueHandler {
                 Value v = referenceParser.parse(values[0], valFac, isWeakReference(type));
                 if (v != null) {
                     changes.add(Modification.onModified(
-                                    parent.node.setProperty(name, v).getPath()
-                    ));
+                            parent.node.setProperty(name, v).getPath()
+                            ));
                     return true;
                 }
             }
@@ -522,16 +522,15 @@ public class SlingPropertyValueHandler {
     }
 
     /**
-     * Stores the property as string or via a strign value, but with an explicit
+     * Stores the property as string or via a string value, but with an explicit
      * type. Both multi-value or single-value.
      */
     private void store(final Modifiable parent,
-                    final String name,
-                    final String[] values,
-                    final int type,
-                    final boolean multiValued)
-    throws RepositoryException, PersistenceException {
-        // TODO
+            final String name,
+            final String[] values,
+            final int type,
+            final boolean multiValued)
+                    throws RepositoryException, PersistenceException {
         if ( parent.node != null ) {
             Property p = null;