Author: enorman
Date: Fri Aug  6 22:23:05 2010
New Revision: 983135

URL: http://svn.apache.org/viewvc?rev=983135&view=rev
Log:
SLING-1627 import operation support for overwrite of properties

Added:
    
sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
   (with props)
    
sling/trunk/launchpad/integration-tests/src/main/resources/integration-test/servlets/post/testimport_replaceProps.json
Modified:
    sling/trunk/bundles/jcr/contentloader/pom.xml
    
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
    
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
    
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
    
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java
    
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java
    
sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletImportTest.java

Modified: sling/trunk/bundles/jcr/contentloader/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/pom.xml?rev=983135&r1=983134&r2=983135&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/contentloader/pom.xml (original)
+++ sling/trunk/bundles/jcr/contentloader/pom.xml Fri Aug  6 22:23:05 2010
@@ -161,6 +161,12 @@
             <groupId>org.jmock</groupId>
             <artifactId>jmock-junit4</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-nop</artifactId>
+            <version>1.5.2</version>
+            <scope>test</scope>
+        </dependency>
 
         <!-- for security content loader (users/groups/acls) -->
         <dependency>

Modified: 
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java?rev=983135&r1=983134&r2=983135&view=diff
==============================================================================
--- 
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
 (original)
+++ 
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
 Fri Aug  6 22:23:05 2010
@@ -24,10 +24,34 @@ package org.apache.sling.jcr.contentload
  */
 public abstract class ImportOptions {
 
+       /**
+        * Specifies whether imported nodes should overwrite existing nodes.
+        * NOTE: this means the existing node will be deleted and a new node 
+        * will be created in the same location.
+        * @return true to overwrite nodes, false otherwise
+        */
        public abstract boolean isOverwrite();
 
+       /**
+        * Specifies whether imported properties should overwrite existing 
properties.
+        * @return true to overwrite node properties, false otherwise
+        */
+       public abstract boolean isPropertyOverwrite();
+
+       /**
+        * Specifies whether versionable nodes is automatically checked in at 
the
+        * end of the import operation.
+        * @return true to checkin the versionable nodes, false otherwise
+        */
        public abstract boolean isCheckin();
 
+       /**
+        * Check if the import provider for the given file extension should
+        * be ignored.
+        * 
+        * @param extension the extension to check
+        * @return true to ignore the provider, false otherwise
+        */
        public abstract boolean isIgnoredImportProvider(String extension);
 
 }
\ No newline at end of file

Modified: 
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java?rev=983135&r1=983134&r2=983135&view=diff
==============================================================================
--- 
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
 (original)
+++ 
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
 Fri Aug  6 22:23:05 2010
@@ -307,9 +307,10 @@ public class DefaultContentCreator imple
     public void createProperty(String name, int propertyType, String value)
     throws RepositoryException {
         final Node node = this.parentNodeStack.peek();
-        // check if the property already exists, don't overwrite it in this 
case
+        // check if the property already exists and isPropertyOverwrite() is 
false, don't overwrite it in this case
         if (node.hasProperty(name)
-            && !node.getProperty(name).isNew()) {
+            && !this.configuration.isPropertyOverwrite()
+            && !node.getProperty(name).isNew()) { 
             return;
         }
 
@@ -364,8 +365,9 @@ public class DefaultContentCreator imple
     public void createProperty(String name, int propertyType, String[] values)
     throws RepositoryException {
         final Node node = this.parentNodeStack.peek();
-        // check if the property already exists, don't overwrite it in this 
case
+        // check if the property already exists and isPropertyOverwrite() is 
false, don't overwrite it in this case
         if (node.hasProperty(name)
+            && !this.configuration.isPropertyOverwrite()
             && !node.getProperty(name).isNew()) {
             return;
         }

Modified: 
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java?rev=983135&r1=983134&r2=983135&view=diff
==============================================================================
--- 
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
 (original)
+++ 
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
 Fri Aug  6 22:23:05 2010
@@ -41,6 +41,12 @@ public class PathEntry extends ImportOpt
      */
     public static final String OVERWRITE_DIRECTIVE = "overwrite";
 
+    /**
+     * The overwriteProperties directive specifying if content properties 
+     * should be overwritten or just initially added.
+     */
+    public static final String OVERWRITE_PROPERTIES_DIRECTIVE = 
"overwriteProperties";
+
     /** The uninstall directive specifying if content should be uninstalled. */
     public static final String UNINSTALL_DIRECTIVE = "uninstall";
 
@@ -75,6 +81,9 @@ public class PathEntry extends ImportOpt
     /** Should existing content be overwritten? */
     private final boolean overwrite;
 
+    /** Should existing content properties be overwritten? */
+    private final boolean overwriteProperties;
+
     /** Should existing content be uninstalled? */
     private final boolean uninstall;
 
@@ -123,6 +132,14 @@ public class PathEntry extends ImportOpt
             this.overwrite = false;
         }
 
+        // overwriteProperties directive
+        final String overwritePropertiesValue = 
entry.getDirectiveValue(OVERWRITE_PROPERTIES_DIRECTIVE);
+        if (overwritePropertiesValue != null) {
+            this.overwriteProperties = 
Boolean.valueOf(overwritePropertiesValue);
+        } else {
+            this.overwriteProperties = false;
+        }
+        
         // uninstall directive
         final String uninstallValue = 
entry.getDirectiveValue(UNINSTALL_DIRECTIVE);
         if (uninstallValue != null) {
@@ -177,7 +194,15 @@ public class PathEntry extends ImportOpt
         return this.overwrite;
     }
 
-    public boolean isUninstall() {
+    /* (non-Javadoc)
+        * @see 
org.apache.sling.jcr.contentloader.ImportOptions#isPropertyOverwrite()
+        */
+       @Override
+       public boolean isPropertyOverwrite() {
+               return this.overwriteProperties;
+       }
+
+       public boolean isUninstall() {
         return this.uninstall;
     }
 

Added: 
sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java?rev=983135&view=auto
==============================================================================
--- 
sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
 (added)
+++ 
sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
 Fri Aug  6 22:23:05 2010
@@ -0,0 +1,97 @@
+package org.apache.sling.jcr.contentloader.internal;
+
+import java.util.HashMap;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+
+import org.apache.sling.jcr.contentloader.ImportOptions;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JMock;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.junit.runner.RunWith;
+
+...@runwith(JMock.class)
+public class DefaultContentCreatorTest {
+    
+    DefaultContentCreator contentCreator;
+    
+    Mockery mockery = new JUnit4Mockery();
+    
+    Node parentNode;
+    
+    Property prop;
+    
+    @org.junit.Test public void willRewriteUndefinedPropertyType() throws 
RepositoryException {
+        contentCreator = new DefaultContentCreator(null);
+        parentNode = mockery.mock(Node.class);
+        prop = mockery.mock(Property.class);
+        contentCreator.init(new ImportOptions(){
+
+            @Override
+            public boolean isCheckin() {
+                return false;
+            }
+
+            @Override
+            public boolean isIgnoredImportProvider(String extension) {
+                return false;
+            }
+
+            @Override
+            public boolean isOverwrite() {
+                return true;
+            }
+            
+            @Override
+                       public boolean isPropertyOverwrite() {
+                               return true;
+                       } }, new HashMap<String, ImportProvider>(), null, null);
+        
+        contentCreator.prepareParsing(parentNode, null);
+        this.mockery.checking(new Expectations() {{
+            oneOf (parentNode).hasProperty("foo"); 
will(returnValue(Boolean.TRUE));
+            oneOf (parentNode).setProperty(with(equal("foo")), 
with(equal("bar")));
+        }});
+        contentCreator.createProperty("foo", PropertyType.UNDEFINED, "bar");
+    }
+    
+    @org.junit.Test public void willNotRewriteUndefinedPropertyType() throws 
RepositoryException {
+        contentCreator = new DefaultContentCreator(null);
+        parentNode = mockery.mock(Node.class);
+        prop = mockery.mock(Property.class);
+        contentCreator.init(new ImportOptions(){
+
+            @Override
+            public boolean isCheckin() {
+                return false;
+            }
+
+            @Override
+            public boolean isIgnoredImportProvider(String extension) {
+                return false;
+            }
+
+            @Override
+            public boolean isOverwrite() {
+                return false;
+            }
+
+                       @Override
+                       public boolean isPropertyOverwrite() {
+                               return false;
+                       } }, new HashMap<String, ImportProvider>(), null, null);
+        
+        contentCreator.prepareParsing(parentNode, null);
+        this.mockery.checking(new Expectations() {{
+            oneOf (parentNode).hasProperty("foo"); 
will(returnValue(Boolean.TRUE));
+            oneOf (parentNode).getProperty("foo"); will(returnValue(prop));
+            oneOf (prop).isNew(); will(returnValue(Boolean.FALSE));
+        }});
+        contentCreator.createProperty("foo", PropertyType.UNDEFINED, "bar");
+    }
+
+}

Propchange: 
sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java?rev=983135&r1=983134&r2=983135&view=diff
==============================================================================
--- 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java
 (original)
+++ 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/SlingPostConstants.java
 Fri Aug  6 22:23:05 2010
@@ -165,10 +165,22 @@ public interface SlingPostConstants {
      * copy or move operation is to be replaced if existing (value is
      * ":replace"). Copy or move is only possible if the destination exists if
      * the replace parameter is set to the case-insignificant value true.
+     * 
+     * This request parameter is also used to indicate whether the destination 
node
+     * for an import operation is to be replaced if existing. The parameter 
value is 
+     * checked to see if it matches the case-insignificant value true.
      */
     public static final String RP_REPLACE = RP_PREFIX + "replace";
 
     /**
+     * Name of the request parameter indicating whether the destination for a
+     * property change during an import operation is to be replaced if 
existing.
+     * The parameter value is checked to see if it matches the 
case-insignificant 
+     * value true.
+     */
+    public static final String RP_REPLACE_PROPERTIES = RP_PREFIX + 
"replaceProperties";
+    
+    /**
      * Optional request parameter indicating the order of newly created nodes 
in
      * creation, copy and move operation requests (value is ":order").
      * <p>

Modified: 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java?rev=983135&r1=983134&r2=983135&view=diff
==============================================================================
--- 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java
 (original)
+++ 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/operations/ImportOperation.java
 Fri Aug  6 22:23:05 2010
@@ -106,8 +106,9 @@ public class ImportOperation extends Abs
         }
 
         //import options passed as request parameters.
-        final boolean replace = 
"true".equals(request.getParameter(SlingPostConstants.RP_REPLACE));
-        final boolean checkin = 
"true".equals(request.getParameter(SlingPostConstants.RP_CHECKIN));
+        final boolean replace = 
"true".equalsIgnoreCase(request.getParameter(SlingPostConstants.RP_REPLACE));
+        final boolean replaceProperties = 
"true".equalsIgnoreCase(request.getParameter(SlingPostConstants.RP_REPLACE_PROPERTIES));
+        final boolean checkin = 
"true".equalsIgnoreCase(request.getParameter(SlingPostConstants.RP_CHECKIN));
         
         String basePath = getItemPath(request);
         basePath = removeAndValidateWorkspace(basePath, 
request.getResourceResolver().adaptTo(Session.class));
@@ -165,6 +166,14 @@ public class ImportOperation extends Abs
                                                        public boolean 
isOverwrite() {
                                                                return replace;
                                                        }
+
+                                                       /* (non-Javadoc)
+                                                        * @see 
org.apache.sling.jcr.contentloader.ImportOptions#isPropertyOverwrite()
+                                                        */
+                                                       @Override
+                                                       public boolean 
isPropertyOverwrite() {
+                                                               return 
replaceProperties;
+                                                       }
                                        },
                                        new ContentImportListener() {
                                                        

Modified: 
sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletImportTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletImportTest.java?rev=983135&r1=983134&r2=983135&view=diff
==============================================================================
--- 
sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletImportTest.java
 (original)
+++ 
sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletImportTest.java
 Fri Aug  6 22:23:05 2010
@@ -111,7 +111,6 @@ public class PostServletImportTest exten
        }
     }
     
-    
     /**
      * Test import operation which replaces existing content
      */
@@ -153,6 +152,67 @@ public class PostServletImportTest exten
     }
 
     /**
+     * SLING-1627: test import of content over existing content with the 
':replaceProperties"
+     * parameter set and the ":replace" property not set.
+     */
+    public void testImportReplaceProperties() throws IOException, 
JSONException {
+        final String testPath = TEST_BASE_PATH;
+        Map<String, String> props = new HashMap<String, String>();
+        String testNode = testClient.createNode(HTTP_BASE_URL + testPath, 
props);
+        urlsToDelete.add(testNode);
+
+        //1. First import some initial content
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+                       SlingPostConstants.OPERATION_IMPORT);
+        
+        String testNodeName = "testNode_" + String.valueOf(random.nextInt());
+        props.put(SlingPostConstants.RP_NODE_NAME_HINT, testNodeName);
+        String jsonContent = 
(String)getStreamAsString(getClass().getResourceAsStream("/integration-test/servlets/post/testimport.json"));
+        props.put(SlingPostConstants.RP_CONTENT, jsonContent);
+        props.put(SlingPostConstants.RP_CONTENT_TYPE, "json");
+        props.put(SlingPostConstants.RP_REDIRECT_TO, testPath + "/*");
+        String importedNodeUrl = testClient.createNode(HTTP_BASE_URL + 
testPath, props);
+
+        // assert content at new location
+        String content = getContent(importedNodeUrl + ".3.json", 
CONTENT_TYPE_JSON);
+
+               JSONObject jsonObj = new JSONObject(content);
+               assertNotNull(jsonObj);
+
+               //assert the imported content is there.
+        String expectedJsonContent = 
(String)getStreamAsString(getClass().getResourceAsStream("/integration-test/servlets/post/importresults.json"));
+               assertExpectedJSON(new JSONObject(expectedJsonContent), 
jsonObj);
+
+       
+               //2. Second, import on top of the node from #1 to replace some 
properties.
+               
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+                       SlingPostConstants.OPERATION_IMPORT);
+        
+        String jsonContent2 = 
(String)getStreamAsString(getClass().getResourceAsStream("/integration-test/servlets/post/testimport_replaceProps.json"));
+
+        props.put(SlingPostConstants.RP_CONTENT, jsonContent2);
+        props.put(SlingPostConstants.RP_CONTENT_TYPE, "json");
+        props.put(SlingPostConstants.RP_REDIRECT_TO, importedNodeUrl);
+        props.put(SlingPostConstants.RP_REPLACE, "false");
+        props.put(SlingPostConstants.RP_REPLACE_PROPERTIES, "true");
+        String importedNodeUrl2 = testClient.createNode(importedNodeUrl, 
props);
+        assertEquals(importedNodeUrl, importedNodeUrl2);
+        
+        // assert content at new location
+        String content2 = getContent(importedNodeUrl2 + ".3.json", 
CONTENT_TYPE_JSON);
+
+               JSONObject jsonObj2 = new JSONObject(content2);
+               assertNotNull(jsonObj2);
+
+               //assert the imported content is there.
+        String expectedJsonContent2 = 
(String)getStreamAsString(getClass().getResourceAsStream("/integration-test/servlets/post/testimport_replaceProps.json"));
+               assertExpectedJSON(new JSONObject(expectedJsonContent2), 
jsonObj2);
+    }
+    
+    /**
      * Test import operation which checks in versionable nodes.
      */
     public void testImportCheckinNodes() throws IOException, JSONException {
@@ -635,5 +695,6 @@ public class PostServletImportTest exten
                String postUrl = location.substring(0, 
location.lastIndexOf('/'));
                assertPostStatus(postUrl + 
SlingPostConstants.DEFAULT_CREATE_SUFFIX, 
HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, null);
     }
+
     
 }

Added: 
sling/trunk/launchpad/integration-tests/src/main/resources/integration-test/servlets/post/testimport_replaceProps.json
URL: 
http://svn.apache.org/viewvc/sling/trunk/launchpad/integration-tests/src/main/resources/integration-test/servlets/post/testimport_replaceProps.json?rev=983135&view=auto
==============================================================================
--- 
sling/trunk/launchpad/integration-tests/src/main/resources/integration-test/servlets/post/testimport_replaceProps.json
 (added)
+++ 
sling/trunk/launchpad/integration-tests/src/main/resources/integration-test/servlets/post/testimport_replaceProps.json
 Fri Aug  6 22:23:05 2010
@@ -0,0 +1,20 @@
+{
+       "propOne" : "propOneValueChanged",
+       "childOne" : {
+               "childPropOne" : false
+       },
+        "propIntArray" : [
+              6,
+              7,
+              8,
+              9
+        ],
+        "propBoolArray" : [
+              false,
+              true,
+              true,
+              true,
+              false,
+              true
+        ]
+}


Reply via email to