Author: ieb
Date: Thu Jul 29 10:20:57 2010
New Revision: 980390

URL: http://svn.apache.org/viewvc?rev=980390&view=rev
Log:
SLING-1615 Refactored to make import POSTs create the target node.

Added:
    
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCreateOperation.java
   (with props)
Modified:
    
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java
    
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java

Added: 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCreateOperation.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCreateOperation.java?rev=980390&view=auto
==============================================================================
--- 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCreateOperation.java
 (added)
+++ 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCreateOperation.java
 Thu Jul 29 10:20:57 2010
@@ -0,0 +1,433 @@
+/*
+ * 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.servlets.post.impl.operations;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.request.RequestParameter;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.servlets.HtmlResponse;
+import org.apache.sling.servlets.post.AbstractSlingPostOperation;
+import org.apache.sling.servlets.post.Modification;
+import org.apache.sling.servlets.post.SlingPostConstants;
+import org.apache.sling.servlets.post.VersioningConfiguration;
+import org.apache.sling.servlets.post.impl.helper.RequestProperty;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.version.VersionException;
+
+abstract class AbstractCreateOperation extends AbstractSlingPostOperation {
+
+    /**
+     * Create node(s) according to current request
+     *
+     * @throws RepositoryException if a repository error occurs
+     */
+    protected void processCreate(Session session,
+            Map<String, RequestProperty> reqProperties, HtmlResponse response, 
List<Modification> changes,
+            VersioningConfiguration versioningConfiguration)
+            throws RepositoryException {
+
+        String path = response.getPath();
+
+        if (!session.itemExists(path)) {
+
+            deepGetOrCreateNode(session, path, reqProperties, changes, 
versioningConfiguration);
+            response.setCreateRequest(true);
+
+        } else {
+
+            String[] mixins = getMixinTypes(reqProperties, path);
+            if (mixins != null) {
+
+                Item item = session.getItem(path);
+                if (item.isNode()) {
+
+                    Set<String> newMixins = new HashSet<String>();
+                    newMixins.addAll(Arrays.asList(mixins));
+
+                    // clear existing mixins first
+                    Node node = (Node) item;
+                    checkoutIfNecessary(node, changes, 
versioningConfiguration);
+
+                    for (NodeType mixin : node.getMixinNodeTypes()) {
+                        String mixinName = mixin.getName();
+                        if (!newMixins.remove(mixinName)) {
+                            node.removeMixin(mixinName);
+                        }
+                    }
+
+                    // add new mixins
+                    for (String mixin : newMixins) {
+                        node.addMixin(mixin);
+                        // this is a bit of a cheat; there isn't a formal 
checkout, but assigning
+                        // the mix:versionable mixin does an implicit checkout
+                        if (mixin.equals("mix:versionable") &&
+                                
versioningConfiguration.isCheckinOnNewVersionableNode()) {
+                            changes.add(Modification.onCheckout(path));
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Collects the properties that form the content to be written back to the
+     * repository.
+     *
+     * @throws RepositoryException if a repository error occurs
+     * @throws ServletException if an internal error occurs
+     */
+    protected Map<String, RequestProperty> collectContent(
+            SlingHttpServletRequest request, HtmlResponse response) {
+
+        boolean requireItemPrefix = requireItemPathPrefix(request);
+
+        // walk the request parameters and collect the properties
+        LinkedHashMap<String, RequestProperty> reqProperties = new 
LinkedHashMap<String, RequestProperty>();
+        for (Map.Entry<String, RequestParameter[]> e : 
request.getRequestParameterMap().entrySet()) {
+            final String paramName = e.getKey();
+
+            // do not store parameters with names starting with sling:post
+            if (paramName.startsWith(SlingPostConstants.RP_PREFIX)) {
+                continue;
+            }
+            // SLING-298: skip form encoding parameter
+            if (paramName.equals("_charset_")) {
+                continue;
+            }
+            // skip parameters that do not start with the save prefix
+            if (requireItemPrefix && !hasItemPathPrefix(paramName)) {
+                continue;
+            }
+
+            // ensure the paramName is an absolute property name
+            String propPath = toPropertyPath(paramName, response);
+
+            // @TypeHint example
+            // <input type="text" name="./age" />
+            // <input type="hidden" name="./a...@typehint" value="long" />
+            // causes the setProperty using the 'long' property type
+            if (propPath.endsWith(SlingPostConstants.TYPE_HINT_SUFFIX)) {
+                RequestProperty prop = getOrCreateRequestProperty(
+                    reqProperties, propPath,
+                    SlingPostConstants.TYPE_HINT_SUFFIX);
+
+                final RequestParameter[] rp = e.getValue();
+                if (rp.length > 0) {
+                    prop.setTypeHintValue(rp[0].getString());
+                }
+
+                continue;
+            }
+
+            // @DefaultValue
+            if (propPath.endsWith(SlingPostConstants.DEFAULT_VALUE_SUFFIX)) {
+                RequestProperty prop = getOrCreateRequestProperty(
+                    reqProperties, propPath,
+                    SlingPostConstants.DEFAULT_VALUE_SUFFIX);
+
+                prop.setDefaultValues(e.getValue());
+
+                continue;
+            }
+
+            // SLING-130: VALUE_FROM_SUFFIX means take the value of this
+            // property from a different field
+            // @ValueFrom example:
+            // <input name="./t...@valuefrom" type="hidden" value="fulltext" />
+            // causes the JCR Text property to be set to the value of the
+            // fulltext form field.
+            if (propPath.endsWith(SlingPostConstants.VALUE_FROM_SUFFIX)) {
+                RequestProperty prop = getOrCreateRequestProperty(
+                    reqProperties, propPath,
+                    SlingPostConstants.VALUE_FROM_SUFFIX);
+
+                // @ValueFrom params must have exactly one value, else ignored
+                if (e.getValue().length == 1) {
+                    String refName = e.getValue()[0].getString();
+                    RequestParameter[] refValues = 
request.getRequestParameters(refName);
+                    if (refValues != null) {
+                        prop.setValues(refValues);
+                    }
+                }
+
+                continue;
+            }
+
+            // SLING-458: Allow Removal of properties prior to update
+            // @Delete example:
+            // <input name="./t...@delete" type="hidden" />
+            // causes the JCR Text property to be deleted before update
+            if (propPath.endsWith(SlingPostConstants.SUFFIX_DELETE)) {
+                RequestProperty prop = getOrCreateRequestProperty(
+                    reqProperties, propPath, SlingPostConstants.SUFFIX_DELETE);
+
+                prop.setDelete(true);
+
+                continue;
+            }
+
+            // SLING-455: @MoveFrom means moving content to another location
+            // @MoveFrom example:
+            // <input name="./t...@movefrom" type="hidden" value="/tmp/path" />
+            // causes the JCR Text property to be set by moving the /tmp/path
+            // property to Text.
+            if (propPath.endsWith(SlingPostConstants.SUFFIX_MOVE_FROM)) {
+                RequestProperty prop = getOrCreateRequestProperty(
+                    reqProperties, propPath,
+                    SlingPostConstants.SUFFIX_MOVE_FROM);
+
+                // @MoveFrom params must have exactly one value, else ignored
+                if (e.getValue().length == 1) {
+                    String sourcePath = e.getValue()[0].getString();
+                    prop.setRepositorySource(sourcePath, true);
+                }
+
+                continue;
+            }
+
+            // SLING-455: @CopyFrom means moving content to another location
+            // @CopyFrom example:
+            // <input name="./t...@copyfrom" type="hidden" value="/tmp/path" />
+            // causes the JCR Text property to be set by copying the /tmp/path
+            // property to Text.
+            if (propPath.endsWith(SlingPostConstants.SUFFIX_COPY_FROM)) {
+                RequestProperty prop = getOrCreateRequestProperty(
+                    reqProperties, propPath,
+                    SlingPostConstants.SUFFIX_COPY_FROM);
+
+                // @MoveFrom params must have exactly one value, else ignored
+                if (e.getValue().length == 1) {
+                    String sourcePath = e.getValue()[0].getString();
+                    prop.setRepositorySource(sourcePath, false);
+                }
+
+                continue;
+            }
+
+            // SLING-1412: @IgnoreBlanks
+            // @Ignore example:
+            // <input name="./Text" type="hidden" value="test" />
+            // <input name="./Text" type="hidden" value="" />
+            // <input name="./t...@string[]" type="hidden" value="true" />
+            // <input name="./t...@ignoreblanks" type="hidden" value="true" />
+            // causes the JCR Text property to be set by copying the /tmp/path
+            // property to Text.
+            if (propPath.endsWith(SlingPostConstants.SUFFIX_IGNORE_BLANKS)) {
+                RequestProperty prop = getOrCreateRequestProperty(
+                    reqProperties, propPath,
+                    SlingPostConstants.SUFFIX_IGNORE_BLANKS);
+
+                if (e.getValue().length == 1) {
+                    prop.setIgnoreBlanks(true);
+                }
+
+                continue;
+            }
+
+            if 
(propPath.endsWith(SlingPostConstants.SUFFIX_USE_DEFAULT_WHEN_MISSING)) {
+                RequestProperty prop = getOrCreateRequestProperty(
+                    reqProperties, propPath,
+                    SlingPostConstants.SUFFIX_USE_DEFAULT_WHEN_MISSING);
+
+                if (e.getValue().length == 1) {
+                    prop.setUseDefaultWhenMissing(true);
+                }
+
+                continue;
+            }
+
+            // plain property, create from values
+            RequestProperty prop = getOrCreateRequestProperty(reqProperties,
+                propPath, null);
+            prop.setValues(e.getValue());
+        }
+
+        return reqProperties;
+    }
+
+    /**
+     * Returns the <code>paramName</code> as an absolute (unnormalized)
+     * property path by prepending the response path 
(<code>response.getPath</code>)
+     * to the parameter name if not already absolute.
+     */
+    private String toPropertyPath(String paramName, HtmlResponse response) {
+        if (!paramName.startsWith("/")) {
+            paramName = ResourceUtil.normalize(response.getPath() + '/' + 
paramName);
+        }
+
+        return paramName;
+    }
+
+    /**
+     * Returns the request property for the given property path. If such a
+     * request property does not exist yet it is created and stored in the
+     * <code>props</code>.
+     *
+     * @param props The map of already seen request properties.
+     * @param paramName The absolute path of the property including the
+     *            <code>suffix</code> to be looked up.
+     * @param suffix The (optional) suffix to remove from the
+     *            <code>paramName</code> before looking it up.
+     * @return The {...@link RequestProperty} for the <code>paramName</code>.
+     */
+    private RequestProperty getOrCreateRequestProperty(
+            Map<String, RequestProperty> props, String paramName, String 
suffix) {
+        if (suffix != null && paramName.endsWith(suffix)) {
+            paramName = paramName.substring(0, paramName.length()
+                - suffix.length());
+        }
+
+        RequestProperty prop = props.get(paramName);
+        if (prop == null) {
+            prop = new RequestProperty(paramName);
+            props.put(paramName, prop);
+        }
+
+        return prop;
+    }
+
+
+    /**
+     * Deep gets or creates a node, parent-padding with default nodes nodes. If
+     * the path is empty, the given parent node is returned.
+     *
+     * @param path path to node that needs to be deep-created
+     * @param checkedOutNodes
+     * @return node at path
+     * @throws RepositoryException if an error occurs
+     * @throws IllegalArgumentException if the path is relative and parent is
+     *             <code>null</code>
+     */
+    protected Node deepGetOrCreateNode(Session session, String path,
+            Map<String, RequestProperty> reqProperties, List<Modification> 
changes,
+            VersioningConfiguration versioningConfiguration)
+            throws RepositoryException {
+        if (log.isDebugEnabled()) {
+            log.debug("Deep-creating Node '{}'", path);
+        }
+        if (path == null || !path.startsWith("/")) {
+            throw new IllegalArgumentException("path must be an absolute 
path.");
+        }
+        // get the starting node
+        String startingNodePath = path;
+        Node startingNode = null;
+        while (startingNode == null) {
+            if (startingNodePath.equals("/")) {
+                startingNode = session.getRootNode();
+            } else if (session.itemExists(startingNodePath)) {
+                startingNode = (Node) session.getItem(startingNodePath);
+            } else {
+                int pos = startingNodePath.lastIndexOf('/');
+                if (pos > 0) {
+                    startingNodePath = startingNodePath.substring(0, pos);
+                } else {
+                    startingNodePath = "/";
+                }
+            }
+        }
+        // is the searched node already existing?
+        if (startingNodePath.length() == path.length()) {
+            return startingNode;
+        }
+        // create nodes
+        int from = (startingNodePath.length() == 1
+                ? 1
+                : startingNodePath.length() + 1);
+        Node node = startingNode;
+        while (from > 0) {
+            final int to = path.indexOf('/', from);
+            final String name = to < 0 ? path.substring(from) : path.substring(
+                from, to);
+            // although the node should not exist (according to the first test
+            // above)
+            // we do a sanety check.
+            if (node.hasNode(name)) {
+                node = node.getNode(name);
+            } else {
+                final String tmpPath = to < 0 ? path : path.substring(0, to);
+                // check for node type
+                final String nodeType = getPrimaryType(reqProperties, tmpPath);
+                checkoutIfNecessary(node, changes, versioningConfiguration);
+
+                try {
+                    if (nodeType != null) {
+                        node = node.addNode(name, nodeType);
+                    } else {
+                        node = node.addNode(name);
+
+                    }
+                } catch (VersionException e) {
+                    log.error("Unable to create node named " + name + " in 
"+node.getPath());
+                    throw e;
+                }
+                // check for mixin types
+                final String[] mixinTypes = getMixinTypes(reqProperties,
+                    tmpPath);
+                if (mixinTypes != null) {
+                    for (String mix : mixinTypes) {
+                        node.addMixin(mix);
+                    }
+                }
+                changes.add(Modification.onCreated(node.getPath()));
+            }
+            from = to + 1;
+        }
+        return node;
+    }
+
+    /**
+     * Checks the collected content for a jcr:primaryType property at the
+     * specified path.
+     *
+     * @param path path to check
+     * @return the primary type or <code>null</code>
+     */
+    private String getPrimaryType(Map<String, RequestProperty> reqProperties,
+            String path) {
+        RequestProperty prop = reqProperties.get(path + "/jcr:primaryType");
+        return prop == null ? null : prop.getStringValues()[0];
+    }
+
+    /**
+     * Checks the collected content for a jcr:mixinTypes property at the
+     * specified path.
+     *
+     * @param path path to check
+     * @return the mixin types or <code>null</code>
+     */
+    private String[] getMixinTypes(Map<String, RequestProperty> reqProperties,
+            String path) {
+        RequestProperty prop = reqProperties.get(path + "/jcr:mixinTypes");
+        return (prop == null) || !prop.hasValues() ? null : 
prop.getStringValues();
+    }
+
+
+}

Propchange: 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCreateOperation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java?rev=980390&r1=980389&r2=980390&view=diff
==============================================================================
--- 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java
 (original)
+++ 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java
 Thu Jul 29 10:20:57 2010
@@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
+import java.util.Map;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
@@ -28,23 +29,23 @@ import javax.servlet.http.HttpServletRes
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.request.RequestParameter;
-import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.servlets.HtmlResponse;
 import org.apache.sling.jcr.contentloader.ContentImportListener;
 import org.apache.sling.jcr.contentloader.ContentImporter;
 import org.apache.sling.jcr.contentloader.ImportOptions;
-import org.apache.sling.servlets.post.AbstractSlingPostOperation;
 import org.apache.sling.servlets.post.Modification;
 import org.apache.sling.servlets.post.ModificationType;
 import org.apache.sling.servlets.post.NodeNameGenerator;
 import org.apache.sling.servlets.post.SlingPostConstants;
+import org.apache.sling.servlets.post.VersioningConfiguration;
+import org.apache.sling.servlets.post.impl.helper.RequestProperty;
 
 /**
  * The <code>ImportOperation</code> class implements the
  * {...@link 
org.apache.sling.servlets.post.SlingPostConstants#OPERATION_IMPORT}
  * import operation for the Sling default POST servlet.
  */
-public class ImportOperation extends AbstractSlingPostOperation {
+public class ImportOperation extends AbstractCreateOperation {
 
     /**
      * The default node name generator
@@ -84,12 +85,31 @@ public class ImportOperation extends Abs
                     "Missing content importer for import");
             return;
        }
+       Map<String, RequestProperty> reqProperties = collectContent(request,
+             response);
+     
+        VersioningConfiguration versioningConfiguration = 
getVersioningConfiguration(request);
+
+        // do not change order unless you have a very good reason.
+        Session session = request.getResourceResolver().adaptTo(Session.class);
+
        
-        Resource resource = request.getResource();
-        Node node = resource.adaptTo(Node.class);
+        processCreate(session, reqProperties, response, changes, 
versioningConfiguration);
+        String path = response.getPath();
+        Node node = null;
+        try {
+            node = (Node) session.getItem(path);
+        } catch ( RepositoryException e ) {
+            log.warn(e.getMessage(),e);
+            // was not able to resolve the node
+        } catch ( ClassCastException e) {
+            log.warn(e.getMessage(),e);
+            // it was not a node
+        }
         if (node == null) {
+            
             response.setStatus(HttpServletResponse.SC_NOT_FOUND,
-                    "Missing target node " + resource + " for import");
+                    "Missing target node " + path + " for import");
             return;
         }
 

Modified: 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java?rev=980390&r1=980389&r2=980390&view=diff
==============================================================================
--- 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java
 (original)
+++ 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java
 Thu Jul 29 10:20:57 2010
@@ -18,12 +18,8 @@
  */
 package org.apache.sling.servlets.post.impl.operations;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import javax.jcr.Item;
 import javax.jcr.Node;
@@ -31,17 +27,14 @@ import javax.jcr.Property;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.nodetype.NodeType;
-import javax.jcr.version.VersionException;
 import javax.servlet.ServletContext;
 
 import org.apache.sling.api.SlingException;
 import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.request.RequestParameter;
 import org.apache.sling.api.resource.NonExistingResource;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.servlets.HtmlResponse;
-import org.apache.sling.servlets.post.AbstractSlingPostOperation;
 import org.apache.sling.servlets.post.Modification;
 import org.apache.sling.servlets.post.SlingPostConstants;
 import org.apache.sling.servlets.post.VersioningConfiguration;
@@ -57,7 +50,7 @@ import org.apache.sling.servlets.post.im
  * called by the Sling default POST servlet if no operation is requested by the
  * client. This operation is able to create and/or modify content.
  */
-public class ModifyOperation extends AbstractSlingPostOperation {
+public class ModifyOperation extends AbstractCreateOperation {
 
     /**
      * The default node name generator
@@ -236,59 +229,6 @@ public class ModifyOperation extends Abs
         return basePath;
     }
 
-    /**
-     * Create node(s) according to current request
-     *
-     * @throws RepositoryException if a repository error occurs
-     */
-    private void processCreate(Session session,
-            Map<String, RequestProperty> reqProperties, HtmlResponse response, 
List<Modification> changes,
-            VersioningConfiguration versioningConfiguration)
-            throws RepositoryException {
-
-        String path = response.getPath();
-
-        if (!session.itemExists(path)) {
-
-            deepGetOrCreateNode(session, path, reqProperties, changes, 
versioningConfiguration);
-            response.setCreateRequest(true);
-
-        } else {
-
-            String[] mixins = getMixinTypes(reqProperties, path);
-            if (mixins != null) {
-
-                Item item = session.getItem(path);
-                if (item.isNode()) {
-
-                    Set<String> newMixins = new HashSet<String>();
-                    newMixins.addAll(Arrays.asList(mixins));
-
-                    // clear existing mixins first
-                    Node node = (Node) item;
-                    checkoutIfNecessary(node, changes, 
versioningConfiguration);
-
-                    for (NodeType mixin : node.getMixinNodeTypes()) {
-                        String mixinName = mixin.getName();
-                        if (!newMixins.remove(mixinName)) {
-                            node.removeMixin(mixinName);
-                        }
-                    }
-
-                    // add new mixins
-                    for (String mixin : newMixins) {
-                        node.addMixin(mixin);
-                        // this is a bit of a cheat; there isn't a formal 
checkout, but assigning
-                        // the mix:versionable mixin does an implicit checkout
-                        if (mixin.equals("mix:versionable") &&
-                                
versioningConfiguration.isCheckinOnNewVersionableNode()) {
-                            changes.add(Modification.onCheckout(path));
-                        }
-                    }
-                }
-            }
-        }
-    }
 
     /**
      * Moves all repository content listed as repository move source in the
@@ -499,335 +439,8 @@ public class ModifyOperation extends Abs
         }
     }
 
-    /**
-     * Collects the properties that form the content to be written back to the
-     * repository.
-     *
-     * @throws RepositoryException if a repository error occurs
-     * @throws ServletException if an internal error occurs
-     */
-    private Map<String, RequestProperty> collectContent(
-            SlingHttpServletRequest request, HtmlResponse response) {
-
-        boolean requireItemPrefix = requireItemPathPrefix(request);
-
-        // walk the request parameters and collect the properties
-        LinkedHashMap<String, RequestProperty> reqProperties = new 
LinkedHashMap<String, RequestProperty>();
-        for (Map.Entry<String, RequestParameter[]> e : 
request.getRequestParameterMap().entrySet()) {
-            final String paramName = e.getKey();
-
-            // do not store parameters with names starting with sling:post
-            if (paramName.startsWith(SlingPostConstants.RP_PREFIX)) {
-                continue;
-            }
-            // SLING-298: skip form encoding parameter
-            if (paramName.equals("_charset_")) {
-                continue;
-            }
-            // skip parameters that do not start with the save prefix
-            if (requireItemPrefix && !hasItemPathPrefix(paramName)) {
-                continue;
-            }
-
-            // ensure the paramName is an absolute property name
-            String propPath = toPropertyPath(paramName, response);
-
-            // @TypeHint example
-            // <input type="text" name="./age" />
-            // <input type="hidden" name="./a...@typehint" value="long" />
-            // causes the setProperty using the 'long' property type
-            if (propPath.endsWith(SlingPostConstants.TYPE_HINT_SUFFIX)) {
-                RequestProperty prop = getOrCreateRequestProperty(
-                    reqProperties, propPath,
-                    SlingPostConstants.TYPE_HINT_SUFFIX);
-
-                final RequestParameter[] rp = e.getValue();
-                if (rp.length > 0) {
-                    prop.setTypeHintValue(rp[0].getString());
-                }
-
-                continue;
-            }
-
-            // @DefaultValue
-            if (propPath.endsWith(SlingPostConstants.DEFAULT_VALUE_SUFFIX)) {
-                RequestProperty prop = getOrCreateRequestProperty(
-                    reqProperties, propPath,
-                    SlingPostConstants.DEFAULT_VALUE_SUFFIX);
-
-                prop.setDefaultValues(e.getValue());
-
-                continue;
-            }
-
-            // SLING-130: VALUE_FROM_SUFFIX means take the value of this
-            // property from a different field
-            // @ValueFrom example:
-            // <input name="./t...@valuefrom" type="hidden" value="fulltext" />
-            // causes the JCR Text property to be set to the value of the
-            // fulltext form field.
-            if (propPath.endsWith(SlingPostConstants.VALUE_FROM_SUFFIX)) {
-                RequestProperty prop = getOrCreateRequestProperty(
-                    reqProperties, propPath,
-                    SlingPostConstants.VALUE_FROM_SUFFIX);
-
-                // @ValueFrom params must have exactly one value, else ignored
-                if (e.getValue().length == 1) {
-                    String refName = e.getValue()[0].getString();
-                    RequestParameter[] refValues = 
request.getRequestParameters(refName);
-                    if (refValues != null) {
-                        prop.setValues(refValues);
-                    }
-                }
-
-                continue;
-            }
-
-            // SLING-458: Allow Removal of properties prior to update
-            // @Delete example:
-            // <input name="./t...@delete" type="hidden" />
-            // causes the JCR Text property to be deleted before update
-            if (propPath.endsWith(SlingPostConstants.SUFFIX_DELETE)) {
-                RequestProperty prop = getOrCreateRequestProperty(
-                    reqProperties, propPath, SlingPostConstants.SUFFIX_DELETE);
-
-                prop.setDelete(true);
-
-                continue;
-            }
-
-            // SLING-455: @MoveFrom means moving content to another location
-            // @MoveFrom example:
-            // <input name="./t...@movefrom" type="hidden" value="/tmp/path" />
-            // causes the JCR Text property to be set by moving the /tmp/path
-            // property to Text.
-            if (propPath.endsWith(SlingPostConstants.SUFFIX_MOVE_FROM)) {
-                RequestProperty prop = getOrCreateRequestProperty(
-                    reqProperties, propPath,
-                    SlingPostConstants.SUFFIX_MOVE_FROM);
-
-                // @MoveFrom params must have exactly one value, else ignored
-                if (e.getValue().length == 1) {
-                    String sourcePath = e.getValue()[0].getString();
-                    prop.setRepositorySource(sourcePath, true);
-                }
-
-                continue;
-            }
-
-            // SLING-455: @CopyFrom means moving content to another location
-            // @CopyFrom example:
-            // <input name="./t...@copyfrom" type="hidden" value="/tmp/path" />
-            // causes the JCR Text property to be set by copying the /tmp/path
-            // property to Text.
-            if (propPath.endsWith(SlingPostConstants.SUFFIX_COPY_FROM)) {
-                RequestProperty prop = getOrCreateRequestProperty(
-                    reqProperties, propPath,
-                    SlingPostConstants.SUFFIX_COPY_FROM);
-
-                // @MoveFrom params must have exactly one value, else ignored
-                if (e.getValue().length == 1) {
-                    String sourcePath = e.getValue()[0].getString();
-                    prop.setRepositorySource(sourcePath, false);
-                }
-
-                continue;
-            }
-
-            // SLING-1412: @IgnoreBlanks
-            // @Ignore example:
-            // <input name="./Text" type="hidden" value="test" />
-            // <input name="./Text" type="hidden" value="" />
-            // <input name="./t...@string[]" type="hidden" value="true" />
-            // <input name="./t...@ignoreblanks" type="hidden" value="true" />
-            // causes the JCR Text property to be set by copying the /tmp/path
-            // property to Text.
-            if (propPath.endsWith(SlingPostConstants.SUFFIX_IGNORE_BLANKS)) {
-                RequestProperty prop = getOrCreateRequestProperty(
-                    reqProperties, propPath,
-                    SlingPostConstants.SUFFIX_IGNORE_BLANKS);
-
-                if (e.getValue().length == 1) {
-                    prop.setIgnoreBlanks(true);
-                }
-
-                continue;
-            }
-
-            if 
(propPath.endsWith(SlingPostConstants.SUFFIX_USE_DEFAULT_WHEN_MISSING)) {
-                RequestProperty prop = getOrCreateRequestProperty(
-                    reqProperties, propPath,
-                    SlingPostConstants.SUFFIX_USE_DEFAULT_WHEN_MISSING);
-
-                if (e.getValue().length == 1) {
-                    prop.setUseDefaultWhenMissing(true);
-                }
-
-                continue;
-            }
-
-            // plain property, create from values
-            RequestProperty prop = getOrCreateRequestProperty(reqProperties,
-                propPath, null);
-            prop.setValues(e.getValue());
-        }
-
-        return reqProperties;
-    }
-
-    /**
-     * Returns the <code>paramName</code> as an absolute (unnormalized)
-     * property path by prepending the response path 
(<code>response.getPath</code>)
-     * to the parameter name if not already absolute.
-     */
-    private String toPropertyPath(String paramName, HtmlResponse response) {
-        if (!paramName.startsWith("/")) {
-            paramName = ResourceUtil.normalize(response.getPath() + '/' + 
paramName);
-        }
 
-        return paramName;
-    }
 
-    /**
-     * Returns the request property for the given property path. If such a
-     * request property does not exist yet it is created and stored in the
-     * <code>props</code>.
-     *
-     * @param props The map of already seen request properties.
-     * @param paramName The absolute path of the property including the
-     *            <code>suffix</code> to be looked up.
-     * @param suffix The (optional) suffix to remove from the
-     *            <code>paramName</code> before looking it up.
-     * @return The {...@link RequestProperty} for the <code>paramName</code>.
-     */
-    private RequestProperty getOrCreateRequestProperty(
-            Map<String, RequestProperty> props, String paramName, String 
suffix) {
-        if (suffix != null && paramName.endsWith(suffix)) {
-            paramName = paramName.substring(0, paramName.length()
-                - suffix.length());
-        }
-
-        RequestProperty prop = props.get(paramName);
-        if (prop == null) {
-            prop = new RequestProperty(paramName);
-            props.put(paramName, prop);
-        }
 
-        return prop;
-    }
-
-    /**
-     * Checks the collected content for a jcr:primaryType property at the
-     * specified path.
-     *
-     * @param path path to check
-     * @return the primary type or <code>null</code>
-     */
-    private String getPrimaryType(Map<String, RequestProperty> reqProperties,
-            String path) {
-        RequestProperty prop = reqProperties.get(path + "/jcr:primaryType");
-        return prop == null ? null : prop.getStringValues()[0];
-    }
-
-    /**
-     * Checks the collected content for a jcr:mixinTypes property at the
-     * specified path.
-     *
-     * @param path path to check
-     * @return the mixin types or <code>null</code>
-     */
-    private String[] getMixinTypes(Map<String, RequestProperty> reqProperties,
-            String path) {
-        RequestProperty prop = reqProperties.get(path + "/jcr:mixinTypes");
-        return (prop == null) || !prop.hasValues() ? null : 
prop.getStringValues();
-    }
-
-    /**
-     * Deep gets or creates a node, parent-padding with default nodes nodes. If
-     * the path is empty, the given parent node is returned.
-     *
-     * @param path path to node that needs to be deep-created
-     * @param checkedOutNodes
-     * @return node at path
-     * @throws RepositoryException if an error occurs
-     * @throws IllegalArgumentException if the path is relative and parent is
-     *             <code>null</code>
-     */
-    private Node deepGetOrCreateNode(Session session, String path,
-            Map<String, RequestProperty> reqProperties, List<Modification> 
changes,
-            VersioningConfiguration versioningConfiguration)
-            throws RepositoryException {
-        if (log.isDebugEnabled()) {
-            log.debug("Deep-creating Node '{}'", path);
-        }
-        if (path == null || !path.startsWith("/")) {
-            throw new IllegalArgumentException("path must be an absolute 
path.");
-        }
-        // get the starting node
-        String startingNodePath = path;
-        Node startingNode = null;
-        while (startingNode == null) {
-            if (startingNodePath.equals("/")) {
-                startingNode = session.getRootNode();
-            } else if (session.itemExists(startingNodePath)) {
-                startingNode = (Node) session.getItem(startingNodePath);
-            } else {
-                int pos = startingNodePath.lastIndexOf('/');
-                if (pos > 0) {
-                    startingNodePath = startingNodePath.substring(0, pos);
-                } else {
-                    startingNodePath = "/";
-                }
-            }
-        }
-        // is the searched node already existing?
-        if (startingNodePath.length() == path.length()) {
-            return startingNode;
-        }
-        // create nodes
-        int from = (startingNodePath.length() == 1
-                ? 1
-                : startingNodePath.length() + 1);
-        Node node = startingNode;
-        while (from > 0) {
-            final int to = path.indexOf('/', from);
-            final String name = to < 0 ? path.substring(from) : path.substring(
-                from, to);
-            // although the node should not exist (according to the first test
-            // above)
-            // we do a sanety check.
-            if (node.hasNode(name)) {
-                node = node.getNode(name);
-            } else {
-                final String tmpPath = to < 0 ? path : path.substring(0, to);
-                // check for node type
-                final String nodeType = getPrimaryType(reqProperties, tmpPath);
-                checkoutIfNecessary(node, changes, versioningConfiguration);
-
-                try {
-                    if (nodeType != null) {
-                        node = node.addNode(name, nodeType);
-                    } else {
-                        node = node.addNode(name);
-
-                    }
-                } catch (VersionException e) {
-                    log.error("Unable to create node named " + name + " in 
"+node.getPath());
-                    throw e;
-                }
-                // check for mixin types
-                final String[] mixinTypes = getMixinTypes(reqProperties,
-                    tmpPath);
-                if (mixinTypes != null) {
-                    for (String mix : mixinTypes) {
-                        node.addMixin(mix);
-                    }
-                }
-                changes.add(Modification.onCreated(node.getPath()));
-            }
-            from = to + 1;
-        }
-        return node;
-    }
 
 }


Reply via email to