Author: enorman
Date: Sun Aug 22 23:16:01 2010
New Revision: 987959

URL: http://svn.apache.org/viewvc?rev=987959&view=rev
Log:
SLING-897 Updating a property fires the wrong JCR events

Modified:
    
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java
    
sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletUpdateTest.java

Modified: 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java?rev=987959&r1=987958&r2=987959&view=diff
==============================================================================
--- 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java
 (original)
+++ 
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/SlingPropertyValueHandler.java
 Sun Aug 22 23:16:01 2010
@@ -222,12 +222,28 @@ public class SlingPropertyValueHandler {
         } else if (values.length == 0) {
             // do not create new prop here, but clear existing
             if (parent.hasProperty(prop.getName())) {
-                changes.add(Modification.onModified(
-                    parent.setProperty(prop.getName(), "").getPath()
-                ));
+                       if 
(parent.getProperty(prop.getName()).getDefinition().isMultiple()) {
+                               //the existing property is multi-valued, so 
just delete it?
+                    final String removePath = removePropertyIfExists(parent, 
prop.getName());
+                    if ( removePath != null ) {
+                        changes.add(Modification.onDeleted(removePath));
+                    }
+                       } else {
+                       changes.add(Modification.onModified(
+                            parent.setProperty(prop.getName(), "").getPath()
+                        ));
+                       }
             }
         } else if (values.length == 1) {
-            // if the provided value is the empty string, just remove the 
existing property (if any).
+            //if a MultiValueTypeHint is supplied, or the current value is 
multiple,
+            // store the updated property as multi-value.
+            boolean storePropertyAsMultiValued = prop.hasMultiValueTypeHint();
+            if (!prop.hasMultiValueTypeHint() && 
parent.hasProperty(prop.getName()) ) {
+               //no type hint supplied, so check the current property 
definition
+                storePropertyAsMultiValued = 
parent.getProperty(prop.getName()).getDefinition().isMultiple();
+            }
+
+               // if the provided value is the empty string, just remove the 
existing property (if any).
             if ( values[0].length() == 0 ) {
                 final String removePath = removePropertyIfExists(parent, 
prop.getName());
                 if ( removePath != null ) {
@@ -239,7 +255,7 @@ public class SlingPropertyValueHandler {
                     // try conversion
                     Calendar c = dateParser.parse(values[0]);
                     if (c != null) {
-                        if ( prop.hasMultiValueTypeHint() ) {
+                        if ( storePropertyAsMultiValued ) {
                             final Value[] array = new Value[1];
                             array[0] = 
parent.getSession().getValueFactory().createValue(c);
                             changes.add(Modification.onModified(
@@ -255,7 +271,7 @@ public class SlingPropertyValueHandler {
                 } else if (isReferencePropertyType(type)) {
                     Value v = referenceParser.parse(values[0], valFac, 
isWeakReference(type));
                     if (v != null) {
-                        if ( prop.hasMultiValueTypeHint() ) {
+                        if ( storePropertyAsMultiValued ) {
                             final Value[] array = new Value[] { v };
                             changes.add(Modification.onModified(
                                 parent.setProperty(prop.getName(), 
array).getPath()
@@ -271,12 +287,17 @@ public class SlingPropertyValueHandler {
                 }
 
                 // fall back to default behaviour
-
                 final Property p;
                 if ( type == PropertyType.UNDEFINED ) {
-                    p = parent.setProperty(prop.getName(), values[0]);
+                       if ( storePropertyAsMultiValued ) {
+                        final Value[] array = new Value[1];
+                        array[0] = 
parent.getSession().getValueFactory().createValue(values[0]);
+                        p = parent.setProperty(prop.getName(), array);
+                       } else {
+                        p = parent.setProperty(prop.getName(), values[0]);
+                       }
                 } else {
-                    if ( prop.hasMultiValueTypeHint() ) {
+                    if ( storePropertyAsMultiValued ) {
                         final Value[] array = new Value[1];
                         array[0] = 
parent.getSession().getValueFactory().createValue(values[0], type);
                         p = parent.setProperty(prop.getName(), array);
@@ -287,6 +308,17 @@ public class SlingPropertyValueHandler {
                 changes.add(Modification.onModified(p.getPath()));
             }
         } else {
+               if (parent.hasProperty(prop.getName())) {
+                       if 
(!parent.getProperty(prop.getName()).getDefinition().isMultiple()) {
+                               //the existing property is single-valued, so we 
have to delete it before setting the
+                               // multi-value variation
+                    final String removePath = removePropertyIfExists(parent, 
prop.getName());
+                    if ( removePath != null ) {
+                        changes.add(Modification.onDeleted(removePath));
+                    }
+                       }
+               }
+                               
             if (type == PropertyType.DATE) {
                 // try conversion
                 Value[] c = dateParser.parse(values, valFac);

Modified: 
sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletUpdateTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletUpdateTest.java?rev=987959&r1=987958&r2=987959&view=diff
==============================================================================
--- 
sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletUpdateTest.java
 (original)
+++ 
sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletUpdateTest.java
 Sun Aug 22 23:16:01 2010
@@ -40,6 +40,7 @@ import org.apache.jackrabbit.commons.Jcr
 import org.apache.sling.commons.json.JSONArray;
 import org.apache.sling.commons.json.JSONException;
 import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.testing.integration.NameValuePairList;
 import 
org.apache.sling.launchpad.webapp.integrationtest.AbstractAuthenticatedTest;
 import org.apache.sling.servlets.post.SlingPostConstants;
 
@@ -196,22 +197,38 @@ public void testPostPathIsUnique() throw
        testUserId = createTestUser();
 
        //2. Create node as admin (OK)
-        // curl -F:name=node -FpropOne=propOneValue1 -FpropOne=propOneValue2 
http://admin:ad...@localhost:8080/test/
+        // curl -F:nameHint=node -FpropOne=propOneValue1 
-FpropOne=propOneValue2 -FpropTwo=propTwoValue 
http://admin:ad...@localhost:8080/test/
         final String createTestNodeUrl = postUrl + 
SlingPostConstants.DEFAULT_CREATE_SUFFIX;
-        Map<String, String> nodeProperties = new HashMap<String, String>();
-        nodeProperties.put(SlingPostConstants.RP_NODE_NAME_HINT, getName());
-        nodeProperties.put("propOne", "propOneValue1");
-        nodeProperties.put("propOne", "propOneValue2");
-       String testNodeUrl = testClient.createNode(createTestNodeUrl, 
nodeProperties);
+        NameValuePairList clientNodeProperties = new NameValuePairList();
+        clientNodeProperties.add(SlingPostConstants.RP_NODE_NAME_HINT, 
getName());
+        clientNodeProperties.add("propOne", "propOneValue1");
+        clientNodeProperties.add("propOne", "propOneValue2");
+        clientNodeProperties.add("propTwo", "propTwoValue");
+       String testNodeUrl = testClient.createNode(createTestNodeUrl, 
clientNodeProperties, null, false);
 
+        String content = getContent(testNodeUrl + ".json", CONTENT_TYPE_JSON);
+        JSONObject json = new JSONObject(content);
+        Object propOneObj = json.opt("propOne");
+        assertTrue(propOneObj instanceof JSONArray);
+        assertEquals(2, ((JSONArray)propOneObj).length());
+        assertEquals("propOneValue1", ((JSONArray)propOneObj).get(0));
+        assertEquals("propOneValue2", ((JSONArray)propOneObj).get(1));
+       
+        Object propTwoObj = json.opt("propTwo");
+        assertTrue(propTwoObj instanceof String);
+        assertEquals("propTwoValue", propTwoObj);
+       
+       
         //3. Attempt to update property of node as testUser (500: 
javax.jcr.AccessDeniedException: /test/node/propOne: not allowed to add or 
modify item)
-        // curl -FpropOne=propOneValueChanged 
http://myuser:passw...@localhost:8080/test/node
+        // curl -FpropOne=propOneValueChanged -FpropTwo=propTwoValueChanged1 
-FpropTwo=propTwoValueChanged2 http://myuser:passw...@localhost:8080/test/node
        List<NameValuePair> postParams = new ArrayList<NameValuePair>();
        postParams.add(new NameValuePair("propOne", "propOneValueChanged"));
+       postParams.add(new NameValuePair("propTwo", "propTwoValueChanged1"));
+       postParams.add(new NameValuePair("propTwo", "propTwoValueChanged2"));
                Credentials testUserCreds = new 
UsernamePasswordCredentials(testUserId, "testPwd");
                String expectedMessage = "Expected 
javax.jcr.AccessDeniedException";
        assertAuthenticatedPostStatus(testUserCreds, testNodeUrl, 
HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, expectedMessage);
-
+       
         //4. Grant jcr:modifyProperties rights to testUser as admin (OK)
         // curl -FprincipalId=myuser -fprivil...@jcr:modifyProperties=granted 
http://admin:ad...@localhost:8080/test/node.modifyAce.html
         Map<String, String> nodeAceProperties = new HashMap<String, String>();
@@ -233,19 +250,27 @@ public void testPostPathIsUnique() throw
                                        testNodePath, //absPath
                                        true, //isDeep 
                                        null, //uuid
-                                       null, //nodeTypeName new String[] 
{"mws:folder"}
+                                       null, //nodeTypeName
                                        false); //noLocal
         
             //5. Attempt to update properties of node (OK)
-            // curl -FpropOne=propOneValueChanged 
http://myuser:passw...@localhost:8080/test/node
+            // curl -FpropOne=propOneValueChanged 
-FpropTwo=propTwoValueChanged1 -FpropTwo=propTwoValueChanged2 
http://myuser:passw...@localhost:8080/test/node
                assertAuthenticatedPostStatus(testUserCreds, testNodeUrl, 
HttpServletResponse.SC_OK, postParams, expectedMessage);
                
                //verify the change happened
-            String content = getContent(testNodeUrl + ".json", 
CONTENT_TYPE_JSON);
-            JSONObject json = new JSONObject(content);
-            Object propOneObj = json.opt("propOne");
-            assertEquals("propOneValueChanged", propOneObj);
+            String afterUpdateContent = getContent(testNodeUrl + ".json", 
CONTENT_TYPE_JSON);
+            JSONObject afterUpdateJson = new JSONObject(afterUpdateContent);
+            Object afterUpdatePropOneObj = afterUpdateJson.opt("propOne");
+            assertTrue(afterUpdatePropOneObj instanceof JSONArray);
+            assertEquals(1, ((JSONArray)afterUpdatePropOneObj).length());
+            assertEquals("propOneValueChanged", 
((JSONArray)afterUpdatePropOneObj).get(0));
                
+            Object afterUpdatePropTwoObj = afterUpdateJson.opt("propTwo");
+            assertTrue(afterUpdatePropTwoObj instanceof JSONArray);
+            assertEquals(2, ((JSONArray)afterUpdatePropTwoObj).length());
+            assertEquals("propTwoValueChanged1", 
((JSONArray)afterUpdatePropTwoObj).get(0));
+            assertEquals("propTwoValueChanged2", 
((JSONArray)afterUpdatePropTwoObj).get(1));
+            
                //wait for the expected JCR events to be delivered
                        for (int second = 0; second < 15; second++) {
                                if (listener.getEventBundlesProcessed() > 0) {
@@ -254,12 +279,15 @@ public void testPostPathIsUnique() throw
                                Thread.sleep(1000);
                        }
                        
-                       assertEquals("Property Added Event was not expected: " 
+ listener.toString(), 
-                                       0, listener.removedProperties.size());
-                       assertEquals("Property Removed Event was not expected: 
" + listener.toString(), 
-                                       0, listener.addedProperties.size());
-                       assertEquals("Property Changed Event was expected: " + 
listener.toString(), 
+                       assertEquals("One property added event was expected: " 
+ listener.toString(), 
+                                       1, listener.addedProperties.size());
+                       assertEquals(testNodePath + "/propTwo", 
listener.addedProperties.get(0));
+                       assertEquals("One property removed event was expected: 
" + listener.toString(), 
+                                       1, listener.removedProperties.size());
+                       assertEquals(testNodePath + "/propTwo", 
listener.removedProperties.get(0));
+                       assertEquals("One property changed event was expected: 
" + listener.toString(), 
                                        1, listener.changedProperties.size());
+                       assertEquals(testNodePath + "/propOne", 
listener.changedProperties.get(0));
         } finally {
                //cleanup
                if (observationManager != null) {


Reply via email to