You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by md...@apache.org on 2015/03/10 12:23:38 UTC

svn commit: r1665478 - in /jackrabbit/oak/trunk/oak-jcr: ./ src/main/java/org/apache/jackrabbit/oak/jcr/observation/ src/test/java/org/apache/jackrabbit/oak/jcr/observation/

Author: mduerig
Date: Tue Mar 10 11:23:37 2015
New Revision: 1665478

URL: http://svn.apache.org/r1665478
Log:
OAK-2262: Add metadata about the changed value to a PROPERTY_CHANGED event on a multivalued property
Alternative: put beforeValue and/or afterValue into info map

Modified:
    jackrabbit/oak/trunk/oak-jcr/pom.xml
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/QueueingHandler.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java

Modified: jackrabbit/oak/trunk/oak-jcr/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/pom.xml?rev=1665478&r1=1665477&r2=1665478&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-jcr/pom.xml Tue Mar 10 11:23:37 2015
@@ -71,6 +71,7 @@
       <!-- Observation -->
       org.apache.jackrabbit.test.api.observation.NodeRemovedTest#testMultiNodesRemoved  <!-- OAK-1459 -->
       org.apache.jackrabbit.test.api.observation.NodeMovedTest#testMoveWithRemove       <!-- OAK-1459 -->
+      org.apache.jackrabbit.test.api.observation.GetInfoTest#testPropertyAdded          <!--OAK-2262-->
       org.apache.jackrabbit.test.api.observation.GetIdentifierTest#testNodeMoved  <!-- Move in 2nd session not reflected in nodes of 1st session -->
       org.apache.jackrabbit.test.api.observation.NodeReorderTest#testNodeReorderAddRemove          <!-- Uses SNS -->
       org.apache.jackrabbit.test.api.observation.NodeReorderTest#testNodeReorderSameName           <!-- Uses SNS -->

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java?rev=1665478&r1=1665477&r2=1665478&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java Tue Mar 10 11:23:37 2015
@@ -27,14 +27,17 @@ import static org.apache.jackrabbit.JcrC
 import java.util.List;
 import java.util.Map;
 
+import javax.jcr.Value;
 import javax.jcr.observation.Event;
 
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import org.apache.jackrabbit.api.observation.JackrabbitEvent;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 
 /**
@@ -76,7 +79,7 @@ public class EventFactory {
     }
 
     Event propertyAdded(
-            final String primaryType, final Iterable<String> mixinTypes,
+            final PropertyState after, final String primaryType, final Iterable<String> mixinTypes,
             String path, String name, String identifier) {
         return new EventImpl(path, name, identifier) {
             @Override
@@ -85,12 +88,16 @@ public class EventFactory {
             }
             @Override
             public Map<?, ?> getInfo() {
-                return createInfoMap(primaryType, mixinTypes);
+                return ImmutableMap.builder()
+                        .putAll(createInfoMap(primaryType, mixinTypes))
+                        .put("afterValue", createValue(after))
+                        .build();
             }
         };
     }
 
     Event propertyChanged(
+            final PropertyState before, final PropertyState after,
             final String primaryType, final Iterable<String> mixinTypes,
             String path, String name, String identifier) {
         return new EventImpl(path, name, identifier) {
@@ -100,13 +107,17 @@ public class EventFactory {
             }
             @Override
             public Map<?, ?> getInfo() {
-                return createInfoMap(primaryType, mixinTypes);
+                return ImmutableMap.builder()
+                        .putAll(createInfoMap(primaryType, mixinTypes))
+                        .put("beforeValue", createValue(before))
+                        .put("afterValue", createValue(after))
+                        .build();
             }
         };
     }
 
     Event propertyDeleted(
-            final String primaryType, final Iterable<String> mixinTypes,
+            final PropertyState before, final String primaryType, final Iterable<String> mixinTypes,
             String path, String name, String identifier) {
         return new EventImpl(path, name, identifier) {
             @Override
@@ -115,11 +126,23 @@ public class EventFactory {
             }
             @Override
             public Map<?, ?> getInfo() {
-                return createInfoMap(primaryType, mixinTypes);
+                return ImmutableMap.builder()
+                        .putAll(createInfoMap(primaryType, mixinTypes))
+                        .put("beforeValue", createValue(before))
+                        .build();
             }
         };
     }
 
+    private Object createValue(PropertyState property) {
+        if (property.isArray()) {
+            List<Value> values = ValueFactoryImpl.createValues(property, mapper);
+            return values.toArray(new Value[values.size()]);
+        } else {
+            return ValueFactoryImpl.createValue(property, mapper);
+        }
+    }
+
     Event nodeAdded(final String primaryType, final Iterable<String> mixinTypes,
             String path, String name, String identifier) {
         return new EventImpl(path, name, identifier) {

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/QueueingHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/QueueingHandler.java?rev=1665478&r1=1665477&r2=1665478&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/QueueingHandler.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/QueueingHandler.java Tue Mar 10 11:23:37 2015
@@ -103,6 +103,7 @@ class QueueingHandler extends DefaultEve
     @Override
     public void propertyAdded(PropertyState after) {
         queue.addEvent(factory.propertyAdded(
+                after,
                 parentType, parentMixins,
                 pathTracker.getPath(), after.getName(),
                 identifierTracker.getIdentifier()));
@@ -111,6 +112,7 @@ class QueueingHandler extends DefaultEve
     @Override
     public void propertyChanged(PropertyState before, PropertyState after) {
         queue.addEvent(factory.propertyChanged(
+                before, after,
                 parentType, parentMixins,
                 pathTracker.getPath(), after.getName(),
                 identifierTracker.getIdentifier()));
@@ -119,6 +121,7 @@ class QueueingHandler extends DefaultEve
     @Override
     public void propertyDeleted(PropertyState before) {
         queue.addEvent(factory.propertyDeleted(
+                before,
                 parentType, parentMixins,
                 pathTracker.getPath(), before.getName(),
                 identifierTracker.getIdentifier()));

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java?rev=1665478&r1=1665477&r2=1665478&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java Tue Mar 10 11:23:37 2015
@@ -37,6 +37,7 @@ import static org.junit.Assert.assertNot
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -49,8 +50,10 @@ import java.util.concurrent.TimeoutExcep
 
 import javax.jcr.Node;
 import javax.jcr.Property;
+import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.Value;
 import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.nodetype.NodeTypeTemplate;
 import javax.jcr.observation.Event;
@@ -111,6 +114,8 @@ public class ObservationTest extends Abs
         ntMgr.registerNodeType(mixTest, false);
 
         Node n = session.getRootNode().addNode(TEST_NODE);
+        n.setProperty("test_property1", 42);
+        n.setProperty("test_property2", "forty_two");
         n.addMixin(TEST_TYPE);
         Node refNode = n.addNode(REFERENCEABLE_NODE);
         refNode.addMixin(JcrConstants.MIX_REFERENCEABLE);
@@ -957,6 +962,66 @@ public class ObservationTest extends Abs
         assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
     }
 
+    @Test
+    public void propertyValue() throws RepositoryException, ExecutionException, InterruptedException {
+        ExpectationListener listener = new ExpectationListener();
+        observationManager.addEventListener(listener, ALL_EVENTS, "/", true, null, null, false);
+        try {
+            Node n = getNode(TEST_PATH);
+            n.setProperty("added", 42);
+            listener.expectValue(null, n.getProperty("added").getValue());
+
+            Value before = n.getProperty("test_property1").getValue();
+            n.getProperty("test_property1").setValue(43);
+            listener.expectValue(before, n.getProperty("test_property1").getValue());
+
+            before = n.getProperty("test_property2").getValue();
+            n.getProperty("test_property2").remove();
+            listener.expectValue(before, null);
+            getAdminSession().save();
+
+            List<Expectation> missing = listener.getMissing(TIME_OUT, TimeUnit.SECONDS);
+            assertTrue("Missing events: " + missing, missing.isEmpty());
+            List<Event> unexpected = listener.getUnexpected();
+            assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
+        }
+        finally {
+            observationManager.removeEventListener(listener);
+        }
+    }
+
+    @Test
+    public void propertyValues() throws RepositoryException, ExecutionException, InterruptedException {
+        Node n = getNode(TEST_PATH);
+        n.setProperty("toChange", new String[]{"one", "two"}, PropertyType.STRING);
+        n.setProperty("toDelete", new String[]{"three", "four"}, PropertyType.STRING);
+        getAdminSession().save();
+
+        ExpectationListener listener = new ExpectationListener();
+        observationManager.addEventListener(listener, ALL_EVENTS, "/", true, null, null, false);
+        try {
+            n.setProperty("added", new String[]{"five", "six"}, PropertyType.STRING);
+            listener.expectValues(null, n.getProperty("added").getValues());
+
+            Value[] before = n.getProperty("toChange").getValues();
+            n.getProperty("toChange").setValue(new String[]{"1", "2"});
+            listener.expectValues(before, n.getProperty("toChange").getValues());
+
+            before = n.getProperty("toDelete").getValues();
+            n.getProperty("toDelete").remove();
+            listener.expectValues(before, null);
+            getAdminSession().save();
+
+            List<Expectation> missing = listener.getMissing(TIME_OUT, TimeUnit.SECONDS);
+            assertTrue("Missing events: " + missing, missing.isEmpty());
+            List<Event> unexpected = listener.getUnexpected();
+            assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
+        }
+        finally {
+            observationManager.removeEventListener(listener);
+        }
+    }
+
     //------------------------------------------------------------< private >---
 
     private Node getNode(String path) throws RepositoryException {
@@ -1088,6 +1153,26 @@ public class ObservationTest extends Abs
                 }
             });
         }
+
+        public void expectValue(final Value before, final Value after) {
+            expect(new Expectation("Before value " + before + " after value " + after) {
+                @Override
+                public boolean onEvent(Event event) throws Exception {
+                    return equal(before, event.getInfo().get("beforeValue")) &&
+                           equal(after, event.getInfo().get("afterValue"));
+                }
+            });
+        }
+
+        public void expectValues(final Value[] before, final Value[] after) {
+            expect(new Expectation("Before valuse " + before + " after values " + after) {
+                @Override
+                public boolean onEvent(Event event) throws Exception {
+                    return Arrays.equals(before, (Object[])event.getInfo().get("beforeValue")) &&
+                           Arrays.equals(after, (Object[]) event.getInfo().get("afterValue"));
+                }
+            });
+        }
 
         public List<Expectation> getMissing(int time, TimeUnit timeUnit)
                 throws ExecutionException, InterruptedException {