You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2008/05/20 12:25:06 UTC

svn commit: r658190 - in /incubator/sling/trunk: launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/ servlets/post/src/main/java/org/apache/sling/servlets/post/ servlets/post/src/main/java/org/apache/sling/se...

Author: fmeschbe
Date: Tue May 20 03:25:05 2008
New Revision: 658190

URL: http://svn.apache.org/viewvc?rev=658190&view=rev
Log:
SLING-464 Add support for multiple resources to apply operations to and
adapt integration tests accordingly

Modified:
    incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCopyTest.java
    incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletDeleteTest.java
    incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletMoveTest.java
    incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/AbstractSlingPostOperation.java
    incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java
    incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCopyMoveOperation.java
    incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/CopyOperation.java
    incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/DeleteOperation.java
    incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/MoveOperation.java

Modified: incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCopyTest.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCopyTest.java?rev=658190&r1=658189&r2=658190&view=diff
==============================================================================
--- incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCopyTest.java (original)
+++ incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCopyTest.java Tue May 20 03:25:05 2008
@@ -17,9 +17,15 @@
 package org.apache.sling.launchpad.webapp.integrationtest.servlets.post;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.sling.commons.json.JSONObject;
 import org.apache.sling.launchpad.webapp.integrationtest.HttpTestBase;
 import org.apache.sling.launchpad.webapp.integrationtest.helpers.HttpStatusCodeException;
 import org.apache.sling.servlets.post.SlingPostConstants;
@@ -35,41 +41,84 @@
     }
 
     public void testCopyNodeAbsolute() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/abs/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/abs/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
         props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
-        
+
         // assert content at new location
-        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
         assertJavascript("Hello", content, "out.println(data.text)");
-        
+
         // assert content at old location
-        content = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        content = getContent(HTTP_BASE_URL + testPath + "/src.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+    }
+
+    public void testCopyNodeAbsoluteBelowDest() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // first test: failure because dest (parent) does not exist
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src",
+            HttpServletResponse.SC_PRECONDITION_FAILED, nvPairs,
+            "Expecting Copy Failure (dest must exist)");
+
+        // create dest as parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", null);
+
+        // copy now succeeds to below dest
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src",
+            HttpServletResponse.SC_CREATED, nvPairs, "Expecting Copy Success");
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+
+        // assert content at old location
+        content = getContent(HTTP_BASE_URL + testPath + "/src.json",
+            CONTENT_TYPE_JSON);
         assertJavascript("Hello", content, "out.println(data.text)");
     }
 
     public void testCopyNodeRelative() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/rel/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/rel/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
         props.put(SlingPostConstants.RP_DEST, "dest");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
-        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
         assertJavascript("Hello", content, "out.println(data.text)");
     }
 
     public void testCopyNodeExistingFail() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/exist/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/exist/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
@@ -79,7 +128,8 @@
         testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
         props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
         try {
             testClient.createNode(HTTP_BASE_URL + testPath, props);
@@ -91,12 +141,14 @@
         }
 
         // expect unmodified dest
-        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
         assertJavascript("Hello Destination", content, "out.println(data.text)");
     }
 
     public void testCopyNodeExistingReplace() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/replace/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/replace/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
@@ -106,24 +158,28 @@
         testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
         props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
         props.put(SlingPostConstants.RP_REPLACE, "true");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
-        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
         assertJavascript("Hello", content, "out.println(data.text)");
     }
 
     public void testCopyNodeDeepRelative() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/new/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/new/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
         props.put(SlingPostConstants.RP_DEST, "deep/new");
-        
+
         try {
             testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
             fail("Moving node to non existing parent location should fail.");
@@ -136,13 +192,15 @@
     }
 
     public void testCopyNodeDeepAbsolute() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/new_fail/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/new_fail/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
         props.put(SlingPostConstants.RP_DEST, "/some/not/existing/structure");
         try {
             testClient.createNode(HTTP_BASE_URL + testPath + "/*", props);
@@ -156,4 +214,232 @@
         }
     }
 
- }
\ No newline at end of file
+    public void testCopyNodeMultipleSourceValid() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/cpmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src4", props);
+
+        // copy the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Copy Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Copy Success");
+
+        // assert existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_OK);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testCopyNodeMultipleSourceInValid() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/cpmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src4", props);
+
+        // copy the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot,
+            HttpServletResponse.SC_INTERNAL_SERVER_ERROR, nvPairs,
+            "Expecting Copy Failure (dest must have trailing slash)");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // retest after creating test
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Copy Failure (dest already exists)");
+
+        // assert non-existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testCopyNodeMultipleSourcePartial() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/cpmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+
+        // copy the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Copy Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Copy Success");
+
+        // assert partial existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testCopyNodeMultipleSourceReplace() throws Exception {
+        final String testPath = TEST_BASE_PATH + "/cpmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+
+        // copy the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Copy Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", null);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Copy Success");
+
+        // assert partial existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        // assert content test
+        String content = getContent(HTTP_BASE_URL + testPath
+            + "/dest/src1.json", CONTENT_TYPE_JSON);
+        JSONObject json = new JSONObject(content);
+        assertEquals("Hello", json.get("text"));
+
+        // modify src1 content
+        nvPairs.clear();
+        nvPairs.add(new NameValuePair("text", "Modified Hello"));
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src1",
+            HttpServletResponse.SC_OK, nvPairs, "Expect Content Update Success");
+
+        // copy the src? nodes
+        nvPairs.clear();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Copy Success");
+
+        // assert content test
+        String content2 = getContent(HTTP_BASE_URL + testPath
+            + "/dest/src1.json", CONTENT_TYPE_JSON);
+        JSONObject json2 = new JSONObject(content2);
+        assertEquals("Modified Hello", json2.get("text"));
+
+        // clean up
+        testClient.delete(testRoot);
+    }
+}
\ No newline at end of file

Modified: incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletDeleteTest.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletDeleteTest.java?rev=658190&r1=658189&r2=658190&view=diff
==============================================================================
--- incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletDeleteTest.java (original)
+++ incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletDeleteTest.java Tue May 20 03:25:05 2008
@@ -45,13 +45,13 @@
         final String urlB = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
         final String urlC = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
         final String urlD = testClient.createNode(postUrl + "/specific-location/for-delete", null);
-
+        
         // initially all nodes must be found
         assertHttpStatus(urlA, HttpServletResponse.SC_OK, "A must initially exist");
         assertHttpStatus(urlB, HttpServletResponse.SC_OK, "B must initially exist");
         assertHttpStatus(urlC, HttpServletResponse.SC_OK, "C must initially exist");
         assertHttpStatus(urlD, HttpServletResponse.SC_OK, "D must initially exist");
-
+        
         // delete one and check
         final List <NameValuePair> params = new LinkedList<NameValuePair> ();
         params.add(new NameValuePair(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_DELETE));
@@ -60,7 +60,7 @@
         assertHttpStatus(urlB, HttpServletResponse.SC_OK, "B must still exist");
         assertHttpStatus(urlC, HttpServletResponse.SC_OK, "C must still exist");
         assertHttpStatus(urlD, HttpServletResponse.SC_OK, "D must still exist");
-
+        
         // delete the others with successive requests
         assertPostStatus(urlB,HttpServletResponse.SC_OK,params,"Delete must return expected status (2)");
         assertPostStatus(urlC,HttpServletResponse.SC_OK,params,"Delete must return expected status (2)");
@@ -69,8 +69,45 @@
         assertHttpStatus(urlB, HttpServletResponse.SC_NOT_FOUND, "B must be deleted (2)");
         assertHttpStatus(urlC, HttpServletResponse.SC_NOT_FOUND, "C must be deleted (2)");
         assertHttpStatus(urlD, HttpServletResponse.SC_NOT_FOUND, "D must be deleted (2)");
-
+        
         // attempting to delete non-existing nodes is ok
         assertPostStatus(postUrl,HttpServletResponse.SC_OK,params,"Delete must return expected status (2)");
     }
+
+    public void testDeleteMultiple() throws IOException {
+        final String urlA = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        final String urlB = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        final String urlC = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        final String urlD = testClient.createNode(postUrl + "/specific-location/for-delete", null);
+
+        // initially all nodes must be found
+        assertHttpStatus(urlA, HttpServletResponse.SC_OK, "A must initially exist");
+        assertHttpStatus(urlB, HttpServletResponse.SC_OK, "B must initially exist");
+        assertHttpStatus(urlC, HttpServletResponse.SC_OK, "C must initially exist");
+        assertHttpStatus(urlD, HttpServletResponse.SC_OK, "D must initially exist");
+
+        // delete one and check
+        final List <NameValuePair> params = new LinkedList<NameValuePair> ();
+        params.add(new NameValuePair(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_DELETE));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlA.substring(HTTP_BASE_URL.length())));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlB.substring(HTTP_BASE_URL.length())));
+        assertPostStatus(urlC,HttpServletResponse.SC_OK,params,"Delete must return expected status (3)");
+        assertHttpStatus(urlA, HttpServletResponse.SC_NOT_FOUND, "A must be deleted (1)");
+        assertHttpStatus(urlB, HttpServletResponse.SC_NOT_FOUND, "B must be deleted (1)");
+        assertHttpStatus(urlC, HttpServletResponse.SC_OK, "C must still exist");
+        assertHttpStatus(urlD, HttpServletResponse.SC_OK, "D must still exist");
+
+        // delete the others with successive requests
+        params.clear();
+        params.add(new NameValuePair(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_DELETE));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlA.substring(HTTP_BASE_URL.length())));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlB.substring(HTTP_BASE_URL.length())));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlC.substring(HTTP_BASE_URL.length())));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlD.substring(HTTP_BASE_URL.length())));
+        assertPostStatus(urlC,HttpServletResponse.SC_OK,params,"Delete must return expected status (3)");
+        assertHttpStatus(urlA, HttpServletResponse.SC_NOT_FOUND, "A must be deleted (2)");
+        assertHttpStatus(urlB, HttpServletResponse.SC_NOT_FOUND, "B must be deleted (2)");
+        assertHttpStatus(urlC, HttpServletResponse.SC_NOT_FOUND, "C must be deleted (2)");
+        assertHttpStatus(urlD, HttpServletResponse.SC_NOT_FOUND, "D must be deleted (2)");
+    }
 }
\ No newline at end of file

Modified: incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletMoveTest.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletMoveTest.java?rev=658190&r1=658189&r2=658190&view=diff
==============================================================================
--- incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletMoveTest.java (original)
+++ incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletMoveTest.java Tue May 20 03:25:05 2008
@@ -17,11 +17,15 @@
 package org.apache.sling.launchpad.webapp.integrationtest.servlets.post;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.sling.commons.json.JSONObject;
 import org.apache.sling.launchpad.webapp.integrationtest.HttpTestBase;
 import org.apache.sling.launchpad.webapp.integrationtest.helpers.HttpStatusCodeException;
 import org.apache.sling.servlets.post.SlingPostConstants;
@@ -37,42 +41,83 @@
     }
 
     public void testMoveNodeAbsolute() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/abs/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/abs/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
         props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
-        
+
         // assert content at new location
-        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
         assertJavascript("Hello", content, "out.println(data.text)");
-        
+
         // assert no content at old location
         assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
             HttpServletResponse.SC_NOT_FOUND,
             "Expected Not_Found for old content");
     }
 
+    public void testMoveNodeAbsoluteBelowDest() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // first test: failure because dest (parent) does not exist
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src",
+            HttpServletResponse.SC_PRECONDITION_FAILED, nvPairs,
+            "Expecting Move Failure (dest must exist)");
+
+        // create dest as parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", null);
+
+        // move now succeeds to below dest
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src",
+            HttpServletResponse.SC_CREATED, nvPairs, "Expecting Move Success");
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+
+        // assert content at old location
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
+            HttpServletResponse.SC_NOT_FOUND);
+    }
+
     public void testMoveNodeRelative() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/rel/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/rel/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
         props.put(SlingPostConstants.RP_DEST, "dest");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
-        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
         assertJavascript("Hello", content, "out.println(data.text)");
     }
 
     public void testMoveNodeExistingFail() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/exist/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/exist/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
@@ -82,7 +127,8 @@
         testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
         props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
         try {
             testClient.createNode(HTTP_BASE_URL + testPath, props);
@@ -94,12 +140,14 @@
         }
 
         // expect unmodified dest
-        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
         assertJavascript("Hello Destination", content, "out.println(data.text)");
     }
 
     public void testMoveNodeExistingReplace() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/replace/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/replace/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
@@ -109,24 +157,28 @@
         testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
         props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
         props.put(SlingPostConstants.RP_REPLACE, "true");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
-        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
         assertJavascript("Hello", content, "out.println(data.text)");
     }
 
     public void testMoveNodeDeepRelative() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/new/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/new/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
         props.put(SlingPostConstants.RP_DEST, "deep/new");
-        
+
         try {
             testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
             fail("Moving node to non existing parent location should fail.");
@@ -139,13 +191,15 @@
     }
 
     public void testMoveNodeDeepAbsolute() throws IOException {
-        final String testPath = TEST_BASE_PATH + "/new_fail/" + System.currentTimeMillis();
+        final String testPath = TEST_BASE_PATH + "/new_fail/"
+            + System.currentTimeMillis();
         Map<String, String> props = new HashMap<String, String>();
         props.put("text", "Hello");
         testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
 
         props.clear();
-        props.put(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
         props.put(SlingPostConstants.RP_DEST, "/some/not/existing/structure");
         try {
             testClient.createNode(HTTP_BASE_URL + testPath + "/*", props);
@@ -159,4 +213,264 @@
         }
     }
 
- }
\ No newline at end of file
+    public void testMoveNodeMultipleSourceValid() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/mvmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src4", props);
+
+        // move the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Move Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Move Success");
+
+        // assert existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_OK);
+
+        // assert non-existence of src?
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src1.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src2.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src3.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src4.html",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testMoveNodeMultipleSourceInValid() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/mvmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src4", props);
+
+        // move the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot,
+            HttpServletResponse.SC_INTERNAL_SERVER_ERROR, nvPairs,
+            "Expecting Move Failure (dest must have trailing slash)");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // retest after creating test
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Move Failure (dest already exists)");
+
+        // assert non-existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        // assert non-existence of src?
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src1.html",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src2.html",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src3.html",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src4.html",
+            HttpServletResponse.SC_OK);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testMoveNodeMultipleSourcePartial() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/mvmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+
+        // move the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Move Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Move Success");
+
+        // assert partial existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        // assert non-existence of src?
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src1.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src2.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src3.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src4.html",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testMoveNodeMultipleSourceReplace() throws Exception {
+        final String testPath = TEST_BASE_PATH + "/mvmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+
+        // move the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Move Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", null);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Move Success");
+
+        // assert partial existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        // assert content test
+        String content = getContent(HTTP_BASE_URL + testPath
+            + "/dest/src1.json", CONTENT_TYPE_JSON);
+        JSONObject json = new JSONObject(content);
+        assertEquals("Hello", json.get("text"));
+
+        // modify src1 content
+        nvPairs.clear();
+        nvPairs.add(new NameValuePair("text", "Modified Hello"));
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src1",
+            HttpServletResponse.SC_CREATED, nvPairs,
+            "Expect Content Create Success");
+
+        // move the src? nodes
+        nvPairs.clear();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Move Success");
+
+        // assert content test
+        String content2 = getContent(HTTP_BASE_URL + testPath
+            + "/dest/src1.json", CONTENT_TYPE_JSON);
+        JSONObject json2 = new JSONObject(content2);
+        assertEquals("Modified Hello", json2.get("text"));
+
+        // clean up
+        testClient.delete(testRoot);
+    }
+
+}
\ No newline at end of file

Modified: incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/AbstractSlingPostOperation.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/AbstractSlingPostOperation.java?rev=658190&r1=658189&r2=658190&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/AbstractSlingPostOperation.java (original)
+++ incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/AbstractSlingPostOperation.java Tue May 20 03:25:05 2008
@@ -17,6 +17,8 @@
 package org.apache.sling.servlets.post;
 
 import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
 
 import javax.jcr.Item;
 import javax.jcr.Node;
@@ -25,6 +27,8 @@
 import javax.jcr.Session;
 
 import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.servlets.HtmlResponse;
 import org.apache.sling.api.wrappers.SlingRequestPaths;
@@ -110,6 +114,30 @@
             HtmlResponse response) throws RepositoryException;
 
     /**
+     * Returns an iterator on <code>Resource</code> instances addressed in the
+     * {@link SlingPostConstants#RP_APPLY_TO} request parameter. If the request
+     * parameter is not set, <code>null</code> is returned. If the parameter
+     * is set with valid resources an empty iterator is returned. Any resources
+     * addressed in the {@link SlingPostConstants#RP_APPLY_TO} parameter is
+     * ignored.
+     * 
+     * @param request The <code>SlingHttpServletRequest</code> object used to
+     *            get the {@link SlingPostConstants#RP_APPLY_TO} parameter.
+     * @return The iterator of resources listed in the parameter or
+     *         <code>null</code> if the parameter is not set in the request.
+     */
+    protected Iterator<Resource> getApplyToResources(
+            SlingHttpServletRequest request) {
+        
+        String[] applyTo = request.getParameterValues(SlingPostConstants.RP_APPLY_TO);
+        if (applyTo == null) {
+            return null;
+        }
+        
+        return new ApplyToIterator(request, applyTo);
+    }
+
+    /**
      * Returns an external form of the given path prepending the context path
      * and appending a display extension.
      * 
@@ -282,4 +310,57 @@
         }
     }
 
+    private static class ApplyToIterator implements Iterator<Resource> {
+
+        private final ResourceResolver resolver;
+        private final Resource baseResource;
+        private final String[] paths;
+        
+        private int pathIndex;
+        
+        private Resource nextResource;
+        
+        ApplyToIterator(SlingHttpServletRequest request, String[] paths) {
+            this.resolver = request.getResourceResolver();
+            this.baseResource = request.getResource();
+            this.paths = paths;
+            this.pathIndex = 0;
+            
+            nextResource = seek();
+        }
+        
+        public boolean hasNext() {
+            return nextResource != null;
+        }
+
+        public Resource next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            
+            Resource result = nextResource;
+            nextResource = seek();
+            
+            return result;
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+        
+        private Resource seek() {
+            while (pathIndex < paths.length) {
+                String path = paths[pathIndex];
+                pathIndex++;
+
+                Resource res = resolver.getResource(baseResource, path);
+                if (res != null) {
+                    return res;
+                }
+            }
+            
+            // no more elements in the array
+            return null;
+        }
+    }
 }
\ No newline at end of file

Modified: incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java?rev=658190&r1=658189&r2=658190&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java (original)
+++ incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java Tue May 20 03:25:05 2008
@@ -62,6 +62,9 @@
      * <p>
      * The delete operation requires no further request parameters and just
      * deletes the content addressed by the request.
+     * <p>
+     * If the {@link #RP_APPLY_TO} parameter is set the resources listed in that
+     * parameter are deleted instead of the request resource.
      */
     public static final String OPERATION_DELETE = "delete";
 
@@ -74,6 +77,9 @@
      * order of the destination node. Finally the {@link #RP_REPLACE} parameter
      * may be set to indicate whether an existing item at the destination should
      * be replaced or not.
+     * <p>
+     * If the {@link #RP_APPLY_TO} parameter is set the resources listed in that
+     * parameter are copied instead of the request resource.
      */
     public static final String OPERATION_COPY = "copy";
 
@@ -86,12 +92,26 @@
      * order of the destination node. Finally the {@link #RP_REPLACE} parameter
      * may be set to indicate whether an existing item at the destination should
      * be replaced or not.
+     * <p>
+     * If the {@link #RP_APPLY_TO} parameter is set the resources listed in that
+     * parameter are moved instead of the request resource.
      */
     public static final String OPERATION_MOVE = "move";
 
     /**
+     * Name of the request parameter used to indicate the resource to apply the
+     * operation to (value is ":applyTo").
+     * <p>
+     * This property is used by certain opertaions - namely
+     * {@link #OPERATION_COPY}, {@link #OPERATION_DELETE} and
+     * {@link #OPERATION_MOVE} - to apply the operation to multiple resources
+     * instead of the request resource.
+     */
+    public static final String RP_APPLY_TO = RP_PREFIX + "applyTo";
+
+    /**
      * Name of the request parameter used to indicate the destination for the
-     * copy and move operations (value is "dest"). This request parameter is
+     * copy and move operations (value is ":dest"). This request parameter is
      * required by the copy and move operations.
      */
     public static final String RP_DEST = RP_PREFIX + "dest";
@@ -99,7 +119,7 @@
     /**
      * Name of the request parameter indicating whether the destination for a
      * copy or move operation is to be replaced if existing (value is
-     * "replace"). Copy or move is only possible if the destination exists if
+     * ":replace"). Copy or move is only possible if the destination exists if
      * the replace parameter is set to the case-insignificant value true.
      */
     public static final String RP_REPLACE = RP_PREFIX + "replace";
@@ -254,7 +274,7 @@
      * applying any new content (value is "@Delete").
      */
     public static final String SUFFIX_DELETE = "@Delete";
-    
+
     /**
      * Suffix indicating that the named item is to be set from an item whose
      * absolute or relative path is given in the parameter's value (value is

Modified: incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCopyMoveOperation.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCopyMoveOperation.java?rev=658190&r1=658189&r2=658190&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCopyMoveOperation.java (original)
+++ incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractCopyMoveOperation.java Tue May 20 03:25:05 2008
@@ -16,6 +16,8 @@
  */
 package org.apache.sling.servlets.post.impl.operations;
 
+import java.util.Iterator;
+
 import javax.jcr.Item;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -43,40 +45,40 @@
         Resource resource = request.getResource();
         String source = resource.getPath();
 
-        // ensure we have an item underlying the request's resource
-        Item item = resource.adaptTo(Item.class);
-        if (item == null) {
-            throw new ResourceNotFoundException("Missing source " + resource
-                + " for " + getOperationName());
-        }
-
         // ensure dest is not empty/null and is absolute
         String dest = request.getParameter(SlingPostConstants.RP_DEST);
         if (dest == null || dest.length() == 0) {
             throw new IllegalArgumentException("Unable to process "
                 + getOperationName() + ". Missing destination");
         }
+
+        // register whether the path ends with a trailing slash
+        boolean trailingSlash = dest.endsWith("/");
+
+        // ensure destination is an absolute and normalized path
         if (!dest.startsWith("/")) {
             dest = ResourceUtil.getParent(source) + "/" + dest;
-            dest = ResourceUtil.normalize(dest);
         }
+        dest = ResourceUtil.normalize(dest);
 
-        Session session = item.getSession();
+        // destination parent and name
+        String dstParent = trailingSlash ? dest : ResourceUtil.getParent(dest);
 
         // delete destination if already exists
-        String dstParent = ResourceUtil.getParent(dest);
-        if (session.itemExists(dest)) {
+        Session session = request.getResourceResolver().adaptTo(Session.class);
+        if (!trailingSlash && session.itemExists(dest)) {
+
             final String replaceString = request.getParameter(SlingPostConstants.RP_REPLACE);
             final boolean isReplace = "true".equalsIgnoreCase(replaceString);
-            if (isReplace) {
-                session.getItem(dest).remove();
-            } else {
+            if (!isReplace) {
                 response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED,
                     "Cannot " + getOperationName() + " " + resource + " to "
                         + dest + ": destination exists");
                 return;
             }
+
         } else {
+
             // check if path to destination exists and create it, but only
             // if it's a descendant of the current node
             if (!dstParent.equals("") && !session.itemExists(dstParent)) {
@@ -90,7 +92,43 @@
             response.setCreateRequest(true);
         }
 
-        execute(response, session, source, dest);
+        Iterator<Resource> resources = getApplyToResources(request);
+        if (resources == null) {
+
+            // ensure we have an item underlying the request's resource
+            Item item = resource.adaptTo(Item.class);
+            if (item == null) {
+                throw new ResourceNotFoundException("Missing source "
+                    + resource + " for " + getOperationName());
+            }
+
+            String dstName = trailingSlash ? null : ResourceUtil.getName(dest);
+            execute(response, item, dstParent, dstName);
+
+        } else {
+
+            // multiple applyTo requires trailing slash on destination
+            if (!trailingSlash) {
+                throw new IllegalArgumentException(
+                    "Applying "
+                        + getOperationName()
+                        + " to multiple resources requires a trailing slash on the destination");
+            }
+
+            // multiple copy will never return 201/CREATED
+            response.setCreateRequest(false);
+
+            while (resources.hasNext()) {
+                Resource applyTo = resources.next();
+                Item item = applyTo.adaptTo(Item.class);
+                if (item != null) {
+                    execute(response, item, dstParent, null);
+                }
+            }
+
+        }
+
+        // finally apply the ordering parameter
         orderNode(request, session.getItem(dest));
     }
 
@@ -104,14 +142,15 @@
      * 
      * @param response The <code>HtmlResponse</code> used to record success of
      *            the operation.
-     * @param session The JCR <code>Session</code> used to execute the
-     *            operation.
-     * @param source The absolute path of the source item act upon.
-     * @param dest The absolute path of the target item.
+     * @param source The source item to act upon.
+     * @param destParent The absolute path of the parent of the target item.
+     * @param destName The name of the target item inside the
+     *            <code>destParent</code>. If <code>null</code> the name of
+     *            the <code>source</code> is used as the target item name.
      * @throws RepositoryException May be thrown if an error occurrs executing
      *             the operation.
      */
-    protected abstract void execute(HtmlResponse response, Session session,
-            String source, String dest) throws RepositoryException;
+    protected abstract void execute(HtmlResponse response, Item source,
+            String destParent, String destName) throws RepositoryException;
 
 }

Modified: incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/CopyOperation.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/CopyOperation.java?rev=658190&r1=658189&r2=658190&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/CopyOperation.java (original)
+++ incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/CopyOperation.java Tue May 20 03:25:05 2008
@@ -16,6 +16,7 @@
  */
 package org.apache.sling.servlets.post.impl.operations;
 
+import javax.jcr.Item;
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
 import javax.jcr.Property;
@@ -47,16 +48,41 @@
     }
 
     @Override
-    protected void execute(HtmlResponse response, Session session,
-            String source, String dest) throws RepositoryException {
-        copy((Node) session.getItem(source),
-            (Node) session.getItem(ResourceUtil.getParent(dest)),
-            ResourceUtil.getName(dest));
-        response.onCopied(source, dest);
+    protected void execute(HtmlResponse response, Item source,
+            String destParent, String destName) throws RepositoryException {
+
+        copy(source, (Node) source.getSession().getItem(destParent), destName);
+
+        String dest = destParent + "/" + destName;
+        response.onCopied(source.getPath(), dest);
         log.debug("copy {} to {}", source, dest);
     }
 
     /**
+     * Copy the <code>src</code> item into the <code>dstParent</code> node.
+     * The name of the newly created item is set to <code>name</code>.
+     * 
+     * @param src The item to copy to the new location
+     * @param dstParent The node into which the <code>src</code> node is to be
+     *            copied
+     * @param name The name of the newly created item. If this is
+     *            <code>null</code> the new item gets the same name as the
+     *            <code>src</code> item.
+     * @throws RepositoryException May be thrown in case of any problem copying
+     *             the content.
+     * @see #copy(Node, Node, String)
+     * @see #copy(Property, Node, String)
+     */
+    static void copy(Item src, Node dstParent, String name)
+            throws RepositoryException {
+        if (src.isNode()) {
+            copy((Node) src, dstParent, name);
+        } else {
+            copy((Property) src, dstParent, name);
+        }
+    }
+
+    /**
      * Copy the <code>src</code> node into the <code>dstParent</code> node.
      * The name of the newly created node is set to <code>name</code>.
      * <p>
@@ -76,10 +102,16 @@
     static void copy(Node src, Node dstParent, String name)
             throws RepositoryException {
 
+        // ensure destination name
         if (name == null) {
             name = src.getName();
         }
 
+        // ensure new node creation
+        if (dstParent.hasNode(name)) {
+            dstParent.getNode(name).remove();
+        }
+
         // create new node
         Node dst = dstParent.addNode(name, src.getPrimaryNodeType().getName());
         for (NodeType mix : src.getMixinNodeTypes()) {
@@ -122,6 +154,11 @@
                 name = src.getName();
             }
 
+            // ensure new property creation
+            if (dstParent.hasProperty(name)) {
+                dstParent.getProperty(name).remove();
+            }
+
             if (src.getDefinition().isMultiple()) {
                 dstParent.setProperty(name, src.getValues());
             } else {

Modified: incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/DeleteOperation.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/DeleteOperation.java?rev=658190&r1=658189&r2=658190&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/DeleteOperation.java (original)
+++ incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/DeleteOperation.java Tue May 20 03:25:05 2008
@@ -16,6 +16,8 @@
  */
 package org.apache.sling.servlets.post.impl.operations;
 
+import java.util.Iterator;
+
 import javax.jcr.Item;
 import javax.jcr.RepositoryException;
 
@@ -36,14 +38,31 @@
     protected void doRun(SlingHttpServletRequest request, HtmlResponse response)
             throws RepositoryException {
 
-        Resource resource = request.getResource();
-        Item item = resource.adaptTo(Item.class);
-        if (item == null) {
-            throw new ResourceNotFoundException("Missing source " + resource
-                + " for delete");
+        Iterator<Resource> res = getApplyToResources(request);
+        if (res == null) {
+            
+            Resource resource = request.getResource();
+            Item item = resource.adaptTo(Item.class);
+            if (item == null) {
+                throw new ResourceNotFoundException("Missing source "
+                    + resource + " for delete");
+            }
+
+            item.remove();
+            response.onDeleted(resource.getPath());
+            
+        } else {
+            
+            while (res.hasNext()) {
+                Resource resource = res.next();
+                Item item = resource.adaptTo(Item.class);
+                if (item != null) {
+                    item.remove();
+                    response.onDeleted(resource.getPath());
+                }
+            }
+            
         }
 
-        item.remove();
-        response.onDeleted(resource.getPath());
     }
 }
\ No newline at end of file

Modified: incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/MoveOperation.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/MoveOperation.java?rev=658190&r1=658189&r2=658190&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/MoveOperation.java (original)
+++ incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/MoveOperation.java Tue May 20 03:25:05 2008
@@ -16,6 +16,7 @@
  */
 package org.apache.sling.servlets.post.impl.operations;
 
+import javax.jcr.Item;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
@@ -30,22 +31,29 @@
  */
 public class MoveOperation extends AbstractCopyMoveOperation {
 
-    /**
-     * default log
-     */
-    private static final Logger log = LoggerFactory.getLogger(MoveOperation.class);
-
     @Override
     protected String getOperationName() {
         return "move";
     }
 
     @Override
-    protected void execute(HtmlResponse response, Session session,
-            String source, String dest) throws RepositoryException {
+    protected void execute(HtmlResponse response, Item source,
+            String destParent, String destName) throws RepositoryException {
+
+        if (destName == null) {
+            destName = source.getName();
+        }
+
+        String sourcePath = source.getPath();
+        String destPath = destParent + "/" + destName;
+        Session session = source.getSession();
+        
+        if (session.itemExists(destPath)) {
+            session.getItem(destPath).remove();
+        }
 
-        session.move(source, dest);
-        response.onMoved(source, dest);
-        log.debug("moved {} to {}", source, dest);
+        session.move(sourcePath, destPath);
+        response.onMoved(sourcePath, destPath);
     }
+
 }