Author: mduerig
Date: Tue Nov 5 16:16:45 2013
New Revision: 1539044
URL: http://svn.apache.org/r1539044
Log:
OAK-1090: Event-listener not notified on Node.orderBefore
Initial implementation generating the move events from looking at the
differences in the :childOrder property of the parent node
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java?rev=1539044&r1=1539043&r2=1539044&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java
Tue Nov 5 16:16:45 2013
@@ -26,7 +26,9 @@ import static javax.jcr.observation.Even
import static javax.jcr.observation.Event.NODE_REMOVED;
import static javax.jcr.observation.Event.PROPERTY_ADDED;
import static javax.jcr.observation.Event.PROPERTY_REMOVED;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
import static org.apache.jackrabbit.oak.commons.PathUtils.getName;
+import static org.apache.jackrabbit.oak.core.AbstractTree.OAK_CHILD_ORDER;
import static
org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager.getIdentifier;
import java.util.Iterator;
@@ -38,6 +40,7 @@ import javax.jcr.observation.Event;
import com.google.common.collect.ForwardingIterator;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
@@ -178,12 +181,53 @@ class EventGenerator extends ForwardingI
@Override
public MoveValidator childNodeChanged(String name, NodeState before,
NodeState after) {
+ if (filter.include(NODE_MOVED, afterTree)) {
+ detectReorder(name, before, after);
+ }
if (filter.includeChildren(afterTree.getPath())) {
childEvents.add(new EventGenerator(this, name));
}
return null;
}
+ private void detectReorder(String name, NodeState before, NodeState after)
{
+ PropertyState afterOrder = after.getProperty(OAK_CHILD_ORDER);
+ PropertyState beforeOrder = before.getProperty(OAK_CHILD_ORDER);
+ if (afterOrder == null || beforeOrder == null) {
+ return;
+ }
+
+ List<String> afterNames = getNames(afterOrder);
+ List<String> beforeNames = getNames(beforeOrder);
+
+ afterNames.retainAll(beforeNames);
+ beforeNames.retainAll(afterNames);
+
+ // Selection sort beforeNames into afterNames recording the swaps as
we go
+ for (int a = 0; a < afterNames.size(); a++) {
+ String afterName = afterNames.get(a);
+ for (int b = a; b < beforeNames.size(); b++) {
+ String beforeName = beforeNames.get(b);
+ if (a != b && beforeName.equals(afterName)) {
+ beforeNames.set(b, beforeNames.get(a));
+ beforeNames.set(a, beforeName);
+ events.add(createEvent(NODE_MOVED,
afterTree.getChild(name).getChild(afterName),
+ ImmutableMap.of(
+ "srcChildRelPath", beforeNames.get(a),
+ "destChildRelPath", beforeNames.get(a +
1))));
+ }
+ }
+ }
+ }
+
+ private static List<String> getNames(PropertyState propertyState) {
+ List<String> names = Lists.newArrayList();
+ for (int k = 0; k < propertyState.count(); k++) {
+ names.add(propertyState.getValue(STRING, k));
+ }
+ return names;
+ }
+
@Override
public void move(String sourcePath, String destPath, NodeState moved)
throws CommitFailedException {
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=1539044&r1=1539043&r2=1539044&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 Nov 5 16:16:45 2013
@@ -31,6 +31,7 @@ import static org.junit.Assert.assertNot
import static org.junit.Assert.assertTrue;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
@@ -288,7 +289,7 @@ public class ObservationTest extends Abs
}
});
- observationManager.addEventListener(listener, NODE_ADDED, path + "/",
true, null, null, false);
+ observationManager.addEventListener(listener, NODE_ADDED, path + '/',
true, null, null, false);
try {
Node root = getNode("/");
root.addNode("events").addNode("only").addNode("here").addNode("at");
@@ -380,6 +381,44 @@ public class ObservationTest extends Abs
assertFalse(observationManager.getRegisteredEventListeners().hasNext());
}
+ @Test
+ public void testReorder() throws RepositoryException,
InterruptedException, ExecutionException {
+ Node testNode = getNode(TEST_PATH);
+ Node nodeA = testNode.addNode("a", "nt:unstructured");
+ Node nodeB = testNode.addNode("b", "nt:unstructured");
+ testNode.getSession().save();
+
+ ExpectationListener listener = new ExpectationListener();
+ observationManager.addEventListener(listener, Event.NODE_MOVED, "/",
true, null, null, false);
+ listener.expect(new Expectation("orderBefore"){
+ @Override
+ public boolean onEvent(Event event) throws Exception {
+ if (event.getType() != NODE_MOVED || event.getInfo() == null) {
+ return false;
+ }
+
+ Map<?, ?> info = event.getInfo();
+ if (PathUtils.concat(TEST_PATH, "a").equals(event.getPath())) {
+ return "a".equals(info.get("srcChildRelPath")) &&
+ "b".equals(info.get("destChildRelPath"));
+ } else if (PathUtils.concat(TEST_PATH,
"b").equals(event.getPath())) {
+ return "b".equals(info.get("srcChildRelPath")) &&
+ "a".equals(info.get("destChildRelPath"));
+ } else {
+ return false;
+ }
+ }
+ });
+
+ testNode.orderBefore(nodeA.getName(), null);
+ testNode.getSession().save();
+
+ List<Expectation> missing = listener.getMissing(2, TimeUnit.SECONDS);
+ assertTrue("Missing events: " + missing, missing.isEmpty());
+ List<Event> unexpected = listener.getUnexpected();
+ assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
+ }
+
//------------------------------------------------------------< private
>---
private Node getNode(String path) throws RepositoryException {