Author: fmeschbe
Date: Mon May 19 23:53:30 2008
New Revision: 658124
URL: http://svn.apache.org/viewvc?rev=658124&view=rev
Log:
SLING-455 Implement @CopyFrom and @MoveFrom with integration tests
Added:
incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtCopyTest.java
incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtMoveTest.java
Modified:
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/helper/RequestProperty.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/ModifyOperation.java
Added:
incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtCopyTest.java
URL:
http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtCopyTest.java?rev=658124&view=auto
==============================================================================
---
incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtCopyTest.java
(added)
+++
incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtCopyTest.java
Mon May 19 23:53:30 2008
@@ -0,0 +1,203 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.launchpad.webapp.integrationtest.HttpTestBase;
+import
org.apache.sling.launchpad.webapp.integrationtest.helpers.HttpStatusCodeException;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test item copy support by @CopyFrom suffix (SLING-455) */
+public class PostServletAtCopyTest extends HttpTestBase {
+
+ public static final String TEST_BASE_PATH = "/sling-at-copy-tests";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public void testCopyNodeAbsolute() 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);
+
+ // assert content at source location
+ final String oldContent = getContent(HTTP_BASE_URL + testPath +
"/src.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+ // create dest with text set from src/text
+ props.clear();
+ props.put("[EMAIL PROTECTED]", testPath + "/src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // 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
+ String contentOld = getContent(HTTP_BASE_URL + testPath +
"/src.-1.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", contentOld, "out.println(data.text)");
+ }
+
+ public void testCopyNodeRelative() throws IOException {
+ 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);
+
+ // assert content at source location
+ final String oldContent = getContent(HTTP_BASE_URL + testPath +
"/src.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+ // create dest with text set from src/text
+ props.clear();
+ props.put("[EMAIL PROTECTED]", "../src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // 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
+ String contentOld = getContent(HTTP_BASE_URL + testPath +
"/src.-1.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", contentOld, "out.println(data.text)");
+ }
+
+ public void testCopyPropertyAbsolute() 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);
+
+ // assert content at source location
+ final String oldContent = getContent(HTTP_BASE_URL + testPath +
"/src.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+ // create dest with text set from src/text
+ props.clear();
+ props.put("[EMAIL PROTECTED]", testPath + "/src/text");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // assert content at new location
+ String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
CONTENT_TYPE_JSON);
+ assertJavascript("Hello", content, "out.println(data.text)");
+
+ // assert content at old location
+ String contentOld = getContent(HTTP_BASE_URL + testPath + "/src.json",
CONTENT_TYPE_JSON);
+ assertJavascript("Hello", contentOld, "out.println(data.text)");
+ }
+
+ public void testCopyPropertyRelative() throws IOException {
+ 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);
+
+ // assert content at source location
+ final String oldContent = getContent(HTTP_BASE_URL + testPath +
"/src.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+ // create dest with text set from src/text
+ props.clear();
+ props.put("[EMAIL PROTECTED]", "../src/text");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // assert content at new location
+ String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
CONTENT_TYPE_JSON);
+ assertJavascript("Hello", content, "out.println(data.text)");
+
+ // assert content at old location
+ String contentOld = getContent(HTTP_BASE_URL + testPath + "/src.json",
CONTENT_TYPE_JSON);
+ assertJavascript("Hello", contentOld, "out.println(data.text)");
+ }
+
+ public void testCopyNodeSourceMissing() throws IOException {
+ final String testPath = TEST_BASE_PATH + "/exist/" +
System.currentTimeMillis();
+ Map<String, String> props = new HashMap<String, String>();
+
+ // create dest node
+ props.clear();
+ props.put("text", "Hello Destination");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest/src", props);
+
+ props.clear();
+ props.put("[EMAIL PROTECTED]", testPath + "/non_existing_source");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // expect unmodified dest
+ String content = getContent(HTTP_BASE_URL + testPath +
"/dest.-1.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello Destination", content,
"out.println(data.src.text)");
+ }
+
+ public void testCopyNodeExistingReplace() throws IOException {
+ 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);
+
+ // create dest node
+ props.clear();
+ props.put("text", "Hello Destination");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest/src", props);
+
+ props.clear();
+ props.put("[EMAIL PROTECTED]", "../src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // expect unmodified dest
+ String content = getContent(HTTP_BASE_URL + testPath +
"/dest.-1.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", content, "out.println(data.src.text)");
+ }
+
+ public void testCopyNodeDeepRelative() throws IOException {
+ 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("deep/[EMAIL PROTECTED]", "../../src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // expect new data
+ String content = getContent(HTTP_BASE_URL + testPath +
"/dest.-1.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", content,
"out.println(data.deep['new'].text)");
+ }
+
+ public void testCopyNodeDeepAbsolute() throws IOException {
+ 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(testPath + "/some/not/existing/[EMAIL PROTECTED]", testPath
+ "/src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/*", props);
+
+ // expect new data
+ String content = getContent(HTTP_BASE_URL + testPath +
"/some/not/existing/structure.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", content, "out.println(data.text)");
+ }
+
+ }
\ No newline at end of file
Added:
incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtMoveTest.java
URL:
http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtMoveTest.java?rev=658124&view=auto
==============================================================================
---
incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtMoveTest.java
(added)
+++
incubator/sling/trunk/launchpad/webapp/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtMoveTest.java
Mon May 19 23:53:30 2008
@@ -0,0 +1,211 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.launchpad.webapp.integrationtest.HttpTestBase;
+import
org.apache.sling.launchpad.webapp.integrationtest.helpers.HttpStatusCodeException;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test item move support by @MoveFrom suffix (SLING-455) */
+public class PostServletAtMoveTest extends HttpTestBase {
+
+ public static final String TEST_BASE_PATH = "/sling-at-move-tests";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public void testMoveNodeAbsolute() 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);
+
+ // assert content at source location
+ final String oldContent = getContent(HTTP_BASE_URL + testPath +
"/src.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+ // create dest with text set from src/text
+ props.clear();
+ props.put("[EMAIL PROTECTED]", testPath + "/src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // 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 no content at old location
+ assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
+ HttpServletResponse.SC_NOT_FOUND,
+ "Expected Not_Found for old content");
+ }
+
+ public void testMoveNodeRelative() throws IOException {
+ 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);
+
+ // assert content at source location
+ final String oldContent = getContent(HTTP_BASE_URL + testPath +
"/src.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+ // create dest with text set from src/text
+ props.clear();
+ props.put("[EMAIL PROTECTED]", "../src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // 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 no content at old location
+ assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
+ HttpServletResponse.SC_NOT_FOUND,
+ "Expected Not_Found for old content");
+ }
+
+ public void testMovePropertyAbsolute() 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);
+
+ // assert content at source location
+ final String oldContent = getContent(HTTP_BASE_URL + testPath +
"/src.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+ // create dest with text set from src/text
+ props.clear();
+ props.put("[EMAIL PROTECTED]", testPath + "/src/text");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // assert content at new location
+ 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_OK, "Expected source parent existing");
+ assertHttpStatus(HTTP_BASE_URL + testPath + "/src/text.json",
+ HttpServletResponse.SC_NOT_FOUND,
+ "Expected Not_Found for old content");
+ }
+
+ public void testMovePropertyRelative() throws IOException {
+ 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);
+
+ // assert content at source location
+ final String oldContent = getContent(HTTP_BASE_URL + testPath +
"/src.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+ // create dest with text set from src/text
+ props.clear();
+ props.put("[EMAIL PROTECTED]", "../src/text");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // assert content at new location
+ 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_OK, "Expected source parent existing");
+ assertHttpStatus(HTTP_BASE_URL + testPath + "/src/text.json",
+ HttpServletResponse.SC_NOT_FOUND,
+ "Expected Not_Found for old content");
+ }
+
+ public void testMoveNodeSourceMissing() throws IOException {
+ final String testPath = TEST_BASE_PATH + "/exist/" +
System.currentTimeMillis();
+ Map<String, String> props = new HashMap<String, String>();
+
+ // create dest node
+ props.clear();
+ props.put("text", "Hello Destination");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest/src", props);
+
+ props.clear();
+ props.put("[EMAIL PROTECTED]", testPath + "/non_existing_source");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // expect unmodified dest
+ String content = getContent(HTTP_BASE_URL + testPath +
"/dest.-1.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello Destination", content,
"out.println(data.src.text)");
+ }
+
+ public void testMoveNodeExistingReplace() throws IOException {
+ 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);
+
+ // create dest node
+ props.clear();
+ props.put("text", "Hello Destination");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest/src", props);
+
+ props.clear();
+ props.put("[EMAIL PROTECTED]", "../src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // expect unmodified dest
+ String content = getContent(HTTP_BASE_URL + testPath +
"/dest.-1.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", content, "out.println(data.src.text)");
+ }
+
+ public void testMoveNodeDeepRelative() throws IOException {
+ 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("deep/[EMAIL PROTECTED]", "../../src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+ // expect new data
+ String content = getContent(HTTP_BASE_URL + testPath +
"/dest.-1.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", content,
"out.println(data.deep['new'].text)");
+ }
+
+ public void testMoveNodeDeepAbsolute() throws IOException {
+ 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(testPath + "/some/not/existing/[EMAIL PROTECTED]", testPath
+ "/src");
+ testClient.createNode(HTTP_BASE_URL + testPath + "/*", props);
+
+ // expect new data
+ String content = getContent(HTTP_BASE_URL + testPath +
"/some/not/existing/structure.json", CONTENT_TYPE_JSON);
+ assertJavascript("Hello", content, "out.println(data.text)");
+ }
+
+ }
\ 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=658124&r1=658123&r2=658124&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
Mon May 19 23:53:30 2008
@@ -254,4 +254,30 @@
* 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
+ * "@MoveFrom").
+ * <p>
+ * This suffix is similar to the [EMAIL PROTECTED] #VALUE_FROM_SUFFIX} in
that the
+ * value for the item is not taken from the request parameter itself but
+ * from somewhere else. In this case the value is set by moving another
+ * repository item (in the same workspace) to the location addressed by the
+ * parameter.
+ */
+ public static final String SUFFIX_MOVE_FROM = "@MoveFrom";
+
+ /**
+ * 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
+ * "@CopyFrom").
+ * <p>
+ * This suffix is similar to the [EMAIL PROTECTED] #VALUE_FROM_SUFFIX} in
that the
+ * value for the item is not taken from the request parameter itself but
+ * from somewhere else. In this case the value is set by copying another
+ * repository item (in the same workspace) to the location addressed by the
+ * parameter.
+ */
+ public static final String SUFFIX_COPY_FROM = "@CopyFrom";
}
Modified:
incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/RequestProperty.java
URL:
http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/RequestProperty.java?rev=658124&r1=658123&r2=658124&view=diff
==============================================================================
---
incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/RequestProperty.java
(original)
+++
incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/RequestProperty.java
Mon May 19 23:53:30 2008
@@ -28,9 +28,11 @@
private static final RequestParameter[] EMPTY_PARAM_ARRAY = new
RequestParameter[0];
- public static final String DEFAULT_IGNORE = SlingPostConstants.RP_PREFIX +
"ignore";
+ public static final String DEFAULT_IGNORE = SlingPostConstants.RP_PREFIX
+ + "ignore";
- public static final String DEFAULT_NULL = SlingPostConstants.RP_PREFIX +
"null";
+ public static final String DEFAULT_NULL = SlingPostConstants.RP_PREFIX
+ + "null";
private final String path;
@@ -47,7 +49,11 @@
private RequestParameter[] defaultValues = EMPTY_PARAM_ARRAY;
private boolean isDelete;
-
+
+ private String repositoryResourcePath;
+
+ private boolean isRepositoryResourceMove;
+
public RequestProperty(String path) {
assert path.startsWith("/");
this.path = ResourceUtil.normalize(path);
@@ -59,7 +65,6 @@
return typeHint;
}
-
public void setTypeHint(String typeHint) {
this.typeHint = typeHint;
}
@@ -79,7 +84,7 @@
public boolean hasValues() {
return values != null;
}
-
+
public RequestParameter[] getValues() {
return values;
}
@@ -87,7 +92,7 @@
public void setValues(RequestParameter[] values) {
this.values = values;
}
-
+
public RequestParameter[] getDefaultValues() {
return defaultValues;
}
@@ -105,9 +110,9 @@
}
/**
- * Checks if this property provides any values. this is the case if
- * one of the values is not empty or if the default handling is not
- * 'ignore'
+ * Checks if this property provides any values. this is the case if one of
+ * the values is not empty or if the default handling is not 'ignore'
+ *
* @return <code>true</code> if this property provides values
*/
public boolean providesValue() {
@@ -118,7 +123,7 @@
// get auto-create values
return true;
}
- for (String s: sv) {
+ for (String s : sv) {
if (!s.equals("")) {
return true;
}
@@ -127,17 +132,19 @@
}
/**
- * Returns the assembled string array out of the provided request values
- * and default values.
+ * Returns the assembled string array out of the provided request values
and
+ * default values.
+ *
* @return a String array or <code>null</code> if the property needs to be
* removed.
*/
public String[] getStringValues() {
if (stringValues == null) {
if (values.length > 1) {
- // TODO: how the default values work for MV props is not very
clear
+ // TODO: how the default values work for MV props is not very
+ // clear
stringValues = new String[values.length];
- for (int i=0; i<stringValues.length; i++) {
+ for (int i = 0; i < stringValues.length; i++) {
stringValues[i] = values[i].getString();
}
} else {
@@ -155,17 +162,82 @@
value = defValue;
}
}
- stringValues = new String[]{value};
+ stringValues = new String[] { value };
}
}
return stringValues;
}
+ /**
+ * Specifies whether this property should be deleted before any new content
+ * is to be set according to the values stored.
+ *
+ * @param isDelete <code>true</code> if the repository item described by
+ * this is to be deleted before any other operation.
+ */
public void setDelete(boolean isDelete) {
this.isDelete = isDelete;
}
+ /**
+ * Returns <code>true</code> if the repository item described by this is
+ * to be deleted before setting new content to it.
+ */
public boolean isDelete() {
return isDelete;
}
+
+ /**
+ * Sets the path of the repository item from which the content for this
+ * property is to be copied or moved. The path may be relative in which
case
+ * it will be resolved relative to the absolute path of this property.
+ *
+ * @param path The path of the repository item to get the content from
+ * @param isMove <code>true</code> if the source content is to be moved,
+ * otherwise the source content is copied from the repository
+ * item.
+ */
+ public void setRepositorySource(String sourcePath, boolean isMove) {
+
+ // make source path absolute
+ if (!sourcePath.startsWith("/")) {
+ sourcePath = getParentPath() + "/" + sourcePath;
+ sourcePath = ResourceUtil.normalize(sourcePath);
+ }
+
+ this.repositoryResourcePath = sourcePath;
+ this.isRepositoryResourceMove = isMove;
+ }
+
+ /**
+ * Returns <code>true</code> if the content of this property is to be set
+ * by moving content from another repository item.
+ *
+ * @see #getRepositorySource()
+ */
+ public boolean hasRepositoryMoveSource() {
+ return isRepositoryResourceMove;
+ }
+
+ /**
+ * Returns <code>true</code> if the content of this property is to be set
+ * by copying content from another repository item.
+ *
+ * @see #getRepositorySource()
+ */
+ public boolean hasRepositoryCopySource() {
+ return getRepositorySource() != null && !hasRepositoryMoveSource();
+ }
+
+ /**
+ * Returns the absolute path of the repository item from which the content
+ * for this property is to be copied or moved.
+ *
+ * @see #hasRepositoryCopySource()
+ * @see #hasRepositoryMoveSource()
+ * @see #setRepositorySource(String, boolean)
+ */
+ public String getRepositorySource() {
+ return repositoryResourcePath;
+ }
}
\ No newline at end of file
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=658124&r1=658123&r2=658124&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
Mon May 19 23:53:30 2008
@@ -49,36 +49,83 @@
@Override
protected void execute(HtmlResponse response, Session session,
String source, String dest) throws RepositoryException {
- copyNode((Node) session.getItem(source),
+ copy((Node) session.getItem(source),
(Node) session.getItem(ResourceUtil.getParent(dest)),
ResourceUtil.getName(dest));
response.onCopied(source, dest);
log.debug("copy {} to {}", source, dest);
}
- private void copyNode(Node src, Node dstParent, String 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>
+ * This method does a recursive (deep) copy of the subtree rooted at the
+ * source node to the destination. Any protected child nodes and and
+ * properties are not copied.
+ *
+ * @param src The node 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 node. If this is
+ * <code>null</code> the new node gets the same name as the
+ * <code>src</code> node.
+ * @throws RepositoryException May be thrown in case of any problem copying
+ * the content.
+ */
+ static void copy(Node src, Node dstParent, String name)
throws RepositoryException {
+
+ if (name == null) {
+ name = src.getName();
+ }
+
// create new node
Node dst = dstParent.addNode(name, src.getPrimaryNodeType().getName());
for (NodeType mix : src.getMixinNodeTypes()) {
dst.addMixin(mix.getName());
}
+
// copy the properties
for (PropertyIterator iter = src.getProperties(); iter.hasNext();) {
- Property p = iter.nextProperty();
- if (p.getDefinition().isProtected()) {
- // skip
- } else if (p.getDefinition().isMultiple()) {
- dst.setProperty(p.getName(), p.getValues());
- } else {
- dst.setProperty(p.getName(), p.getValue());
- }
+ copy(iter.nextProperty(), dst, null);
}
+
// copy the child nodes
for (NodeIterator iter = src.getNodes(); iter.hasNext();) {
Node n = iter.nextNode();
if (!n.getDefinition().isProtected()) {
- copyNode(n, dst, n.getName());
+ copy(n, dst, null);
+ }
+ }
+ }
+
+ /**
+ * Copy the <code>src</code> property into the <code>dstParent</code>
+ * node. The name of the newly created property is set to
<code>name</code>.
+ * <p>
+ * If the source property is protected, this method does nothing.
+ *
+ * @param src The property to copy to the new location
+ * @param dstParent The node into which the <code>src</code> property is
+ * to be copied
+ * @param name The name of the newly created property. If this is
+ * <code>null</code> the new property gets the same name as the
+ * <code>src</code> property.
+ * @throws RepositoryException May be thrown in case of any problem copying
+ * the content.
+ */
+ static void copy(Property src, Node dstParent, String name)
+ throws RepositoryException {
+ if (!src.getDefinition().isProtected()) {
+ if (name == null) {
+ name = src.getName();
+ }
+
+ if (src.getDefinition().isMultiple()) {
+ dstParent.setProperty(name, src.getValues());
+ } else {
+ dstParent.setProperty(name, src.getValue());
}
}
}
Modified:
incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java
URL:
http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java?rev=658124&r1=658123&r2=658124&view=diff
==============================================================================
---
incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java
(original)
+++
incubator/sling/trunk/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java
Mon May 19 23:53:30 2008
@@ -21,7 +21,9 @@
import java.util.HashMap;
import java.util.Map;
+import javax.jcr.Item;
import javax.jcr.Node;
+import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletContext;
@@ -81,10 +83,20 @@
// do not change order unless you have a very good reason.
Session session = request.getResourceResolver().adaptTo(Session.class);
+ // ensure root of new content
processCreate(session, reqProperties, response);
+
+ // cleanup any old content (@Delete parameters)
processDeletes(session, reqProperties, response);
+
+ // write content from existing content (@Move/CopyFrom parameters)
+ processMoves(session, reqProperties, response);
+ processCopies(session, reqProperties, response);
+
+ // write content from form
writeContent(session, reqProperties, response);
+ // order content
String path = response.getPath();
orderNode(request, session.getItem(path));
}
@@ -204,6 +216,119 @@
}
/**
+ * Moves all repository content listed as repository move source in the
+ * request properties to the locations indicated by the resource
properties.
+ */
+ private void processMoves(Session session,
+ Map<String, RequestProperty> reqProperties, HtmlResponse response)
+ throws RepositoryException {
+
+ for (RequestProperty property : reqProperties.values()) {
+ if (property.hasRepositoryMoveSource()) {
+ processMovesCopiesInternal(property, true, session,
+ reqProperties, response);
+ }
+ }
+ }
+
+ /**
+ * Copies all repository content listed as repository copy source in the
+ * request properties to the locations indicated by the resource
properties.
+ */
+ private void processCopies(Session session,
+ Map<String, RequestProperty> reqProperties, HtmlResponse response)
+ throws RepositoryException {
+
+ for (RequestProperty property : reqProperties.values()) {
+ if (property.hasRepositoryCopySource()) {
+ processMovesCopiesInternal(property, false, session,
+ reqProperties, response);
+ }
+ }
+ }
+
+ /**
+ * Internal implementation of the
+ * [EMAIL PROTECTED] #processCopies(Session, Map, HtmlResponse)} and
+ * [EMAIL PROTECTED] #processMoves(Session, Map, HtmlResponse)} methods
taking into
+ * account whether the source is actually a property or a node.
+ * <p>
+ * Any intermediary nodes to the destination as indicated by the
+ * <code>property</code> path are created using the
+ * <code>reqProperties</code> as indications for required node types.
+ *
+ * @param property The [EMAIL PROTECTED] RequestProperty} identifying the
source
+ * content of the operation.
+ * @param isMove <code>true</code> if the source item is to be moved.
+ * Otherwise the source item is just copied.
+ * @param session The repository session to use to access the content
+ * @param reqProperties All accepted request properties. This is used to
+ * create intermediary nodes along the property path.
+ * @param response The <code>HtmlResponse</code> into which successfull
+ * copies and moves as well as intermediary node creations are
+ * recorded.
+ * @throws RepositoryException May be thrown if an error occurrs.
+ */
+ private void processMovesCopiesInternal(RequestProperty property,
+ boolean isMove, Session session,
+ Map<String, RequestProperty> reqProperties, HtmlResponse response)
+ throws RepositoryException {
+
+ String propPath = property.getPath();
+ String source = property.getRepositorySource();
+
+ // only continue here, if the source really exists
+ if (session.itemExists(source)) {
+
+ // if the destination item already exists, remove it
+ // first, otherwise ensure the parent location
+ if (session.itemExists(propPath)) {
+ session.getItem(propPath).remove();
+ response.onDeleted(propPath);
+ } else {
+ deepGetOrCreateNode(session, property.getParentPath(),
+ reqProperties, response);
+ }
+
+ // move through the session and record operation
+ Item sourceItem = session.getItem(source);
+ if (sourceItem.isNode()) {
+
+ // node move/copy through session
+ if (isMove) {
+ session.move(source, propPath);
+ } else {
+ Node sourceNode = (Node) sourceItem;
+ Node destParent = (Node)
session.getItem(property.getParentPath());
+ CopyOperation.copy(sourceNode, destParent,
+ property.getName());
+ }
+
+ } else {
+
+ // property move manually
+ Property sourceProperty = (Property) sourceItem;
+
+ // create destination property
+ Node destParent = (Node)
session.getItem(property.getParentPath());
+ CopyOperation.copy(sourceProperty, destParent, null);
+
+ // remove source property (if not just copying)
+ if (isMove) {
+ sourceProperty.remove();
+ }
+ }
+
+ // record successful move
+ if (isMove) {
+ response.onMoved(source, propPath);
+ } else {
+ response.onCopied(source, propPath);
+ }
+ }
+ }
+
+ /**
* Removes all properties listed as [EMAIL PROTECTED]
RequestProperty#isDelete()} from
* the repository.
*
@@ -335,8 +460,7 @@
reqProperties, propPath,
SlingPostConstants.VALUE_FROM_SUFFIX);
- // @ValueFrom params must have exactly one value, else
- // ignored
+ // @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);
@@ -361,6 +485,44 @@
continue;
}
+ // SLING-455: @MoveFrom means moving content to another location
+ // @MoveFrom example:
+ // <input name="./[EMAIL PROTECTED]" 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="./[EMAIL PROTECTED]" 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;
+ }
+
// plain property, create from values
RequestProperty prop = getOrCreateRequestProperty(reqProperties,
propPath, null);