Author: mduerig
Date: Fri Jul 12 12:20:37 2013
New Revision: 1502527
URL: http://svn.apache.org/r1502527
Log:
OAK-144 Implement observation
Base EventGeneratingNodeStateDiff on ImmutableTree instead of raw node states
in order to track hierarchy information
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeDispatcher.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeDispatcher.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeDispatcher.java?rev=1502527&r1=1502526&r2=1502527&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeDispatcher.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeDispatcher.java
Fri Jul 12 12:20:37 2013
@@ -21,7 +21,6 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import static
org.apache.jackrabbit.oak.plugins.observation.ObservationConstants.OAK_UNKNOWN;
-import static org.apache.jackrabbit.oak.spi.state.NodeStateUtils.getNode;
import java.util.Queue;
import java.util.Set;
@@ -31,16 +30,10 @@ import javax.annotation.Nonnull;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
-import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.ContentSession;
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.spi.commit.PostCommitHook;
import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
-import org.apache.jackrabbit.oak.spi.state.RecursingNodeStateDiff;
import org.apache.jackrabbit.oak.util.TODO;
/**
@@ -254,58 +247,19 @@ public class ChangeDispatcher {
public abstract long getDate();
/**
- * Get the id of the node at the given path as it was before this
change set.
- * @param path path to determine the id for
- * @return id for the item at {@code path} or {@code path} if the
item doesn't exit.
+ * State before the change
+ * @return before state
*/
- @Nonnull
- public String getBeforeId(String path) {
- return getId(before, path);
+ public NodeState getBeforeState() {
+ return before;
}
/**
- * Get the id of the node at the given path as it is after this change
set.
- * @param path path to determine the id for
- * @return id for the item at {@code path} or {@code path} if the
item doesn't exit.
+ * State after the change
+ * @return after state
*/
- @Nonnull
- public String getAfterId(String path) {
- return getId(after, path);
- }
-
- private static String getId(NodeState nodeState, String path) {
- StringBuilder id = new StringBuilder();
-
- id.append(getIdOrName(nodeState, ""));
- for (String name : PathUtils.elements(path)) {
- nodeState = nodeState.getChildNode(name);
- id.append('/').append(getIdOrName(nodeState, name));
- }
-
- if (id.length() == 0) {
- return "/";
- } else {
- return id.toString();
- }
- }
-
- private static String getIdOrName(NodeState nodeState, String name) {
- PropertyState uuid = nodeState.getProperty(JcrConstants.JCR_UUID);
- if (uuid == null) {
- return name;
- } else {
- return uuid.getValue(Type.STRING);
- }
- }
-
- /**
- * {@link NodeStateDiff} of the changes
- * @param diff node state diff instance for traversing the changes.
- * @param path path where diffing should start
- */
- public void diff(RecursingNodeStateDiff diff, String path) {
- NodeStateDiff secureDiff = SecureNodeStateDiff.wrap(diff);
- getNode(after, path).compareAgainstBaseState(getNode(before,
path), secureDiff);
+ public NodeState getAfterState() {
+ return after;
}
@Override
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java?rev=1502527&r1=1502526&r2=1502527&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
Fri Jul 12 12:20:37 2013
@@ -20,6 +20,15 @@ package org.apache.jackrabbit.oak.jcr.ob
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterators.emptyIterator;
+import static com.google.common.collect.Iterators.singletonIterator;
+import static com.google.common.collect.Iterators.transform;
+import static javax.jcr.observation.Event.NODE_ADDED;
+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.core.IdentifierManager.getIdentifier;
+import static org.apache.jackrabbit.oak.spi.state.NodeStateUtils.getNode;
import java.util.ArrayList;
import java.util.Iterator;
@@ -31,24 +40,24 @@ import javax.jcr.observation.Event;
import javax.jcr.observation.EventListener;
import com.google.common.base.Function;
-import com.google.common.base.Predicate;
import com.google.common.collect.Iterators;
-import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.jmx.EventListenerMBean;
import org.apache.jackrabbit.commons.iterator.EventIteratorAdapter;
import org.apache.jackrabbit.commons.observation.ListenerTracker;
import org.apache.jackrabbit.oak.api.ContentSession;
import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
import org.apache.jackrabbit.oak.namepath.NamePathMapper;
import
org.apache.jackrabbit.oak.plugins.observation.ChangeDispatcher.ChangeSet;
import org.apache.jackrabbit.oak.plugins.observation.ChangeDispatcher.Listener;
import org.apache.jackrabbit.oak.plugins.observation.Observable;
-import org.apache.jackrabbit.oak.spi.state.RecursingNodeStateDiff;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.plugins.observation.SecureNodeStateDiff;
import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.apache.jackrabbit.oak.spi.state.RecursingNodeStateDiff;
import org.apache.jackrabbit.oak.spi.state.VisibleDiff;
import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
@@ -185,9 +194,13 @@ class ChangeProcessor implements Runnabl
while (!stopping && changes != null) {
EventFilter filter = filterRef.get();
if (!(filter.excludeLocal() &&
changes.isLocal(contentSession))) {
+ NodeState beforeState = changes.getBeforeState();
+ NodeState afterState = changes.getAfterState();
String path = namePathMapper.getOakPath(filter.getPath());
- EventGeneratingNodeStateDiff diff = new
EventGeneratingNodeStateDiff(changes, path);
- changes.diff(VisibleDiff.wrap(diff), path);
+ EventGeneratingNodeStateDiff diff = new
EventGeneratingNodeStateDiff(
+ changes, new ImmutableRoot(beforeState), new
ImmutableRoot(afterState), path);
+ NodeStateDiff secureDiff =
SecureNodeStateDiff.wrap(VisibleDiff.wrap(diff));
+ getNode(afterState,
path).compareAgainstBaseState(getNode(beforeState, path), secureDiff);
if (!stopping) {
diff.sendEvents();
}
@@ -208,30 +221,24 @@ class ChangeProcessor implements Runnabl
//------------------------------------------------------------< private
>---
private class EventGeneratingNodeStateDiff extends RecursingNodeStateDiff {
- public static final int PURGE_LIMIT = 8192;
+ public static final int EVENT_LIMIT = 8192;
private final ChangeSet changes;
- private final String path;
- private final NodeState beforeParentNode;
- private final NodeState afterParentNode;
- private final String name;
+ private final Tree beforeTree;
+ private final Tree afterTree;
private List<Iterator<Event>> events;
- private int childNodeCount;
-
- EventGeneratingNodeStateDiff(ChangeSet changes, String path,
List<Iterator<Event>> events,
- NodeState beforeParentNode, NodeState afterParentNode, String
name) {
+ private int eventCount;
+ EventGeneratingNodeStateDiff(ChangeSet changes, Tree beforeTree, Tree
afterTree, List<Iterator<Event>> events) {
this.changes = changes;
- this.path = path;
+ this.beforeTree = beforeTree;
+ this.afterTree = afterTree;
this.events = events;
- this.beforeParentNode = beforeParentNode;
- this.afterParentNode = afterParentNode;
- this.name = name;
}
- public EventGeneratingNodeStateDiff(ChangeSet changes, String path) {
- this(changes, path, new ArrayList<Iterator<Event>>(PURGE_LIMIT),
null, null, "");
+ public EventGeneratingNodeStateDiff(ChangeSet changes, Root
beforeRoot, Root afterRoot, String path) {
+ this(changes, beforeRoot.getTree(path), afterRoot.getTree(path),
new ArrayList<Iterator<Event>>(EVENT_LIMIT));
}
public void sendEvents() {
@@ -248,44 +255,44 @@ class ChangeProcessor implements Runnabl
catch (Exception e) {
log.warn("Unhandled exception in observation listener: " +
listener, e);
}
- events = new ArrayList<Iterator<Event>>(PURGE_LIMIT);
+ events = new ArrayList<Iterator<Event>>(EVENT_LIMIT);
}
}
@Override
public boolean propertyAdded(PropertyState after) {
- if (filterRef.get().include(Event.PROPERTY_ADDED, path,
afterParentNode)) {
- Event event = generatePropertyEvent(Event.PROPERTY_ADDED,
path, after, changes.getAfterId(path));
- events.add(Iterators.singletonIterator(event));
+ if (filterRef.get().include(PROPERTY_ADDED, afterTree)) {
+ Event event = generatePropertyEvent(PROPERTY_ADDED, afterTree,
after);
+ events.add(singletonIterator(event));
}
return !stopping;
}
@Override
public boolean propertyChanged(PropertyState before, PropertyState
after) {
- if (filterRef.get().include(Event.PROPERTY_CHANGED, path,
afterParentNode)) {
- Event event = generatePropertyEvent(Event.PROPERTY_CHANGED,
path, after, changes.getAfterId(path));
- events.add(Iterators.singletonIterator(event));
+ if (filterRef.get().include(Event.PROPERTY_CHANGED, afterTree)) {
+ Event event = generatePropertyEvent(Event.PROPERTY_CHANGED,
afterTree, after);
+ events.add(singletonIterator(event));
}
return !stopping;
}
@Override
public boolean propertyDeleted(PropertyState before) {
- if (filterRef.get().include(Event.PROPERTY_REMOVED, path,
afterParentNode)) {
- Event event = generatePropertyEvent(Event.PROPERTY_REMOVED,
path, before, changes.getBeforeId(path));
- events.add(Iterators.singletonIterator(event));
+ if (filterRef.get().include(PROPERTY_REMOVED, afterTree)) {
+ Event event = generatePropertyEvent(PROPERTY_REMOVED,
beforeTree, before);
+ events.add(singletonIterator(event));
}
return !stopping;
}
@Override
public boolean childNodeAdded(String name, NodeState after) {
- if (filterRef.get().includeChildren(path)) {
- Iterator<Event> events = generateNodeEvents(Event.NODE_ADDED,
path, name,
- after, afterParentNode,
changes.getAfterId(PathUtils.concat(path, name)));
+ if (filterRef.get().includeChildren(afterTree.getPath())) {
+ Iterator<Event> events = generateNodeEvents(
+ NODE_ADDED, afterTree.getChild(name));
this.events.add(events);
- if (++childNodeCount > PURGE_LIMIT) {
+ if (++eventCount > EVENT_LIMIT) {
sendEvents();
}
}
@@ -294,9 +301,9 @@ class ChangeProcessor implements Runnabl
@Override
public boolean childNodeDeleted(String name, NodeState before) {
- if (filterRef.get().includeChildren(path)) {
- Iterator<Event> events =
generateNodeEvents(Event.NODE_REMOVED, path, name,
- before, beforeParentNode,
changes.getBeforeId(PathUtils.concat(path, name)));
+ if (filterRef.get().includeChildren(beforeTree.getPath())) {
+ Iterator<Event> events = generateNodeEvents(
+ NODE_REMOVED, beforeTree.getChild(name));
this.events.add(events);
}
return !stopping;
@@ -310,9 +317,9 @@ class ChangeProcessor implements Runnabl
@Nonnull
@Override
public RecursingNodeStateDiff createChildDiff(String name, NodeState
before, NodeState after) {
- if (filterRef.get().includeChildren(path)) {
+ if (filterRef.get().includeChildren(afterTree.getPath())) {
EventGeneratingNodeStateDiff diff = new
EventGeneratingNodeStateDiff(
- changes, PathUtils.concat(path, name), events, before,
after, name);
+ changes, beforeTree.getChild(name),
afterTree.getChild(name), events);
return VisibleDiff.wrap(diff);
} else {
return RecursingNodeStateDiff.EMPTY;
@@ -327,81 +334,53 @@ class ChangeProcessor implements Runnabl
changes.isExternal());
}
- private Event generatePropertyEvent(int eventType, String parentPath,
PropertyState property, String id) {
- String path = PathUtils.concat(parentPath, property.getName());
- return createEvent(eventType, path, id);
+ private Event generatePropertyEvent(int eventType, Tree parent,
PropertyState property) {
+ String path = PathUtils.concat(parent.getPath(),
property.getName());
+ return createEvent(eventType, path, getIdentifier(parent));
}
- private Iterator<Event> generateNodeEvents(int eventType, String
parentPath, String childName,
- NodeState node, NodeState parentNode, final String id) {
+ private Iterator<Event> generateNodeEvents(int eventType, final Tree
tree) {
EventFilter filter = filterRef.get();
- final String path = PathUtils.concat(parentPath, childName);
Iterator<Event> nodeEvent;
- if (filter.include(eventType, parentPath, parentNode)) {
- Event event = createEvent(eventType, path, id);
- nodeEvent = Iterators.singletonIterator(event);
+ if (filter.include(eventType, tree.isRoot() ? null :
tree.getParent())) {
+ Event event = createEvent(eventType, tree.getPath(),
getIdentifier(tree));
+ nodeEvent = singletonIterator(event);
} else {
- nodeEvent = Iterators.emptyIterator();
+ nodeEvent = emptyIterator();
}
- final int propertyEventType = eventType == Event.NODE_ADDED
- ? Event.PROPERTY_ADDED
- : Event.PROPERTY_REMOVED;
+ final int propertyEventType = eventType == NODE_ADDED
+ ? PROPERTY_ADDED
+ : PROPERTY_REMOVED;
Iterator<Event> propertyEvents;
- if (filter.include(propertyEventType, path, parentNode)) {
- propertyEvents = Iterators.transform(
- Iterators.filter(
- node.getProperties().iterator(),
- new Predicate<PropertyState>() {
- @Override
- public boolean apply(PropertyState
propertyState) {
- return
!NodeStateUtils.isHidden(propertyState.getName());
- }
- }),
+ if (filter.include(propertyEventType, tree)) {
+ propertyEvents = transform(
+ tree.getProperties().iterator(),
new Function<PropertyState, Event>() {
@Override
public Event apply(PropertyState property) {
- return
generatePropertyEvent(propertyEventType, path, property, id);
+ return
generatePropertyEvent(propertyEventType, tree, property);
}
});
} else {
- propertyEvents = Iterators.emptyIterator();
+ propertyEvents = emptyIterator();
}
- Iterator<Event> childNodeEvents = filter.includeChildren(path)
- ? Iterators.concat(generateChildEvents(eventType, path,
node, id))
+ Iterator<Event> childNodeEvents =
filter.includeChildren(tree.getPath())
+ ? Iterators.concat(generateChildEvents(eventType, tree))
: Iterators.<Event>emptyIterator();
return Iterators.concat(nodeEvent, propertyEvents,
childNodeEvents);
}
- private Iterator<Iterator<Event>> generateChildEvents(final int
eventType, final String parentPath,
- final NodeState parentNode, final String parentId) {
- return Iterators.transform(
-
Iterators.filter(parentNode.getChildNodeEntries().iterator(),
- new Predicate<ChildNodeEntry>() {
- @Override
- public boolean apply(ChildNodeEntry entry) {
- return
!NodeStateUtils.isHidden(entry.getName());
- }
- }),
- new Function<ChildNodeEntry, Iterator<Event>>() {
+ private Iterator<Iterator<Event>> generateChildEvents(final int
eventType, final Tree tree) {
+ return transform(
+ tree.getChildren().iterator(),
+ new Function<Tree, Iterator<Event>>() {
@Override
- public Iterator<Event> apply(ChildNodeEntry entry) {
- NodeState node = entry.getNodeState();
- String name = entry.getName();
- return generateNodeEvents(eventType, parentPath,
name,
- node, parentNode, getId(parentId, node,
name));
- }
-
- private String getId(String parentId, NodeState node,
String name) {
- PropertyState uuid =
node.getProperty(JcrConstants.JCR_UUID);
- if (uuid == null) {
- return parentId + '/' +
namePathMapper.getJcrName(name);
- } else {
- return uuid.getValue(Type.STRING);
- }
+ public Iterator<Event> apply(Tree child) {
+ return generateNodeEvents(eventType, child);
}
});
}
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java?rev=1502527&r1=1502526&r2=1502527&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFilter.java
Fri Jul 12 12:20:37 2013
@@ -20,7 +20,7 @@ package org.apache.jackrabbit.oak.jcr.ob
import static com.google.common.base.Objects.toStringHelper;
-import javax.annotation.Nullable;
+import javax.annotation.CheckForNull;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
@@ -29,9 +29,7 @@ import org.apache.jackrabbit.oak.api.Pro
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.core.ImmutableTree;
import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
/**
* Filter for filtering observation events according to a certain criterion.
@@ -74,15 +72,15 @@ class EventFilter {
/**
* Match an event against this filter.
* @param eventType type of the event
- * @param path path of the event
- * @param associatedParentNode associated parent node of the event
+ * @param associatedParent associated parent node of the event
* @return {@code true} if the filter matches this event. {@code false}
otherwise.
*/
- public boolean include(int eventType, String path, @Nullable NodeState
associatedParentNode) {
- return include(eventType)
- && include(path)
- && (associatedParentNode == null || includeByType(new
ImmutableTree(associatedParentNode)))
- && (associatedParentNode == null ||
includeByUuid(associatedParentNode));
+ public boolean include(int eventType, @CheckForNull Tree associatedParent)
{
+ return includeByEvent(eventType)
+ && associatedParent != null
+ && includeByPath(associatedParent.getPath())
+ && includeByType(associatedParent)
+ && includeByUuid(associatedParent);
}
/**
@@ -124,11 +122,11 @@ class EventFilter {
//-----------------------------< internal
>---------------------------------
- private boolean include(int eventType) {
+ private boolean includeByEvent(int eventType) {
return (this.eventTypes & eventType) != 0;
}
- private boolean include(String path) {
+ private boolean includeByPath(String path) {
boolean equalPaths = this.path.equals(path);
if (!deep && !equalPaths) {
return false;
@@ -144,16 +142,16 @@ class EventFilter {
* Checks whether to include an event based on the type of the associated
* parent node and the node type filter.
*
- * @param associatedParentNode the associated parent node of the event.
+ * @param associatedParent the associated parent node of the event.
* @return whether to include the event based on the type of the associated
* parent node.
*/
- private boolean includeByType(Tree associatedParentNode) {
+ private boolean includeByType(Tree associatedParent) {
if (nodeTypeOakName == null) {
return true;
} else {
for (String oakName : nodeTypeOakName) {
- if (ntMgr.isNodeType(associatedParentNode, oakName)) {
+ if (ntMgr.isNodeType(associatedParent, oakName)) {
return true;
}
}
@@ -162,7 +160,7 @@ class EventFilter {
}
}
- private boolean includeByUuid(NodeState associatedParentNode) {
+ private boolean includeByUuid(Tree associatedParent) {
if (uuids == null) {
return true;
}
@@ -170,7 +168,7 @@ class EventFilter {
return false;
}
- PropertyState uuidProperty =
associatedParentNode.getProperty(JcrConstants.JCR_UUID);
+ PropertyState uuidProperty =
associatedParent.getProperty(JcrConstants.JCR_UUID);
if (uuidProperty == null) {
return false;
}