Author: mduerig
Date: Thu Mar 6 14:32:33 2014
New Revision: 1574896
URL: http://svn.apache.org/r1574896
Log:
OAK-1514: Support for Sling JcrResourceListener
- Add EventHandler.enter and EventHandler.leave
- Slight tighten the EventHandler contract
- Add injectors for Observers to Oak and Jcr
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/DefaultEventHandler.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/NodeObserver.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventHandler.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/FilteredHandler.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/QueueingHandler.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java?rev=1574896&r1=1574895&r2=1574896&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
Thu Mar 6 14:32:33 2014
@@ -43,8 +43,8 @@ import javax.security.auth.login.LoginEx
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.common.io.Closer;
-
import org.apache.jackrabbit.oak.api.ContentRepository;
import org.apache.jackrabbit.oak.api.ContentSession;
import org.apache.jackrabbit.oak.api.Root;
@@ -112,6 +112,8 @@ public class Oak {
private final List<CommitHook> commitHooks = newArrayList();
+ private final List<Observer> observers = Lists.newArrayList();
+
private List<EditorProvider> editorProviders = newArrayList();
private SecurityProvider securityProvider;
@@ -448,6 +450,12 @@ public class Oak {
return this;
}
+ @Nonnull
+ public Oak with(@Nonnull Observer observer) {
+ observers.add(checkNotNull(observer));
+ return this;
+ }
+
/**
* Enable the asynchronous (background) indexing behavior.
*
@@ -502,6 +510,12 @@ public class Oak {
// add index hooks later to prevent the OakInitializer to do excessive
indexing
with(new IndexUpdateProvider(indexEditors));
withEditorHook();
+
+ // Register observer last to prevent sending events while initialising
+ for (Observer observer : observers) {
+ WhiteboardUtils.registerObserver(whiteboard, observer);
+ }
+
CommitHook commitHook = CompositeHook.compose(commitHooks);
return new ContentRepositoryImpl(
store,
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/DefaultEventHandler.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/DefaultEventHandler.java?rev=1574896&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/DefaultEventHandler.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/DefaultEventHandler.java
Thu Mar 6 14:32:33 2014
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.jackrabbit.oak.plugins.observation;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * Default implementation of {@code EventHandler} that
+ * does nothing.
+ */
+public class DefaultEventHandler implements EventHandler {
+ public static EventHandler INSTANCE = new DefaultEventHandler();
+
+ @Override
+ public void enter(NodeState before, NodeState after) {
+ // do nothing
+ }
+
+ @Override
+ public void leave(NodeState before, NodeState after) {
+ // do nothing
+ }
+
+ /**
+ * @return {@code this}
+ */
+ @Override
+ public EventHandler getChildHandler(String name, NodeState before,
NodeState after) {
+ return this;
+ }
+
+ @Override
+ public void propertyAdded(PropertyState after) {
+ // do nothing
+ }
+
+ @Override
+ public void propertyChanged(PropertyState before, PropertyState after) {
+ // do nothing
+ }
+
+ @Override
+ public void propertyDeleted(PropertyState before) {
+ // do nothing
+ }
+
+ @Override
+ public void nodeAdded(String name, NodeState after) {
+ // do nothing
+ }
+
+ @Override
+ public void nodeDeleted(String name, NodeState before) {
+ // do nothing
+ }
+
+ @Override
+ public void nodeMoved(String sourcePath, String name, NodeState moved) {
+ // do nothing
+ }
+
+ @Override
+ public void nodeReordered(String destName, String name, NodeState
reordered) {
+ // do nothing
+ }
+}
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=1574896&r1=1574895&r2=1574896&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
Thu Mar 6 14:32:33 2014
@@ -143,7 +143,16 @@ public class EventGenerator {
*/
@Override
public void run() {
- after.compareAgainstBaseState(before, this);
+ if (skip == 0) {
+ // Only call enter if this is not a continuation that hit
+ // the MAX_CHANGES_PER_CONTINUATION limit before
+ handler.enter(before, after);
+ }
+ if (after.compareAgainstBaseState(before, this)) {
+ // Only call leave if this continuation exists normally and not
+ // as a result of hitting the MAX_CHANGES_PER_CONTINUATION
limit
+ handler.leave(before, after);
+ }
}
//-------------------------------------------------< NodeStateDiff >--
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventHandler.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventHandler.java?rev=1574896&r1=1574895&r2=1574896&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventHandler.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventHandler.java
Thu Mar 6 14:32:33 2014
@@ -36,11 +36,34 @@ import org.apache.jackrabbit.oak.spi.sta
* information like the path or identifier of the current node based on
* the sequence of those specialization calls.
* <p>
+ * The events belonging to this instance <em>should</em> be delivered
+ * before events to other instance deeper down the tree are delivered.
+ * <p>
* All names and paths passed to handler methods use unmapped Oak names.
*/
public interface EventHandler {
/**
+ * Called before the given before and after states are compared.
+ * The implementation can use this method to initialize any internal
+ * state needed for processing the results of the comparison.
+ *
+ * @param before before state, non-existent if this node was added
+ * @param after after state, non-existent if this node was removed
+ */
+ void enter(NodeState before, NodeState after);
+
+ /**
+ * Called after the given before and after states are compared.
+ * The implementation can use this method to post-process information
+ * collected during the content diff.
+ *
+ * @param before before state, non-existent if this node was added
+ * @param after after state, non-existent if this node was removed
+ */
+ void leave(NodeState before, NodeState after);
+
+ /**
* Returns a handler of events within the given child node, or
* {@code null} if changes within that child are not to be processed.
*
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/FilteredHandler.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/FilteredHandler.java?rev=1574896&r1=1574895&r2=1574896&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/FilteredHandler.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/FilteredHandler.java
Thu Mar 6 14:32:33 2014
@@ -29,7 +29,7 @@ import org.apache.jackrabbit.oak.spi.sta
* on all detected changes, and forwards the filtered change events to a given
* delegate handler.
*/
-public class FilteredHandler implements EventHandler {
+public class FilteredHandler extends DefaultEventHandler {
private final EventFilter filter;
@@ -40,6 +40,17 @@ public class FilteredHandler implements
this.handler = handler;
}
+
+ @Override
+ public void enter(NodeState before, NodeState after) {
+ handler.enter(before, after);
+ }
+
+ @Override
+ public void leave(NodeState before, NodeState after) {
+ handler.leave(before, after);
+ }
+
@Override @CheckForNull
public EventHandler getChildHandler(
String name, NodeState before, NodeState after) {
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/NodeObserver.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/NodeObserver.java?rev=1574896&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/NodeObserver.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/NodeObserver.java
Thu Mar 6 14:32:33 2014
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.jackrabbit.oak.plugins.observation;
+
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.collect.Sets;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.namepath.GlobalNameMapper;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.namepath.NamePathMapperImpl;
+import org.apache.jackrabbit.oak.plugins.observation.filter.VisibleFilter;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * Base class for {@code Observer} instances that group changes
+ * by node instead of tracking them down to individual properties.
+ */
+public abstract class NodeObserver implements Observer {
+ private final String path;
+
+ private NodeState previousRoot;
+
+ /**
+ * Create a new instance for observing the given path.
+ * @param path
+ */
+ protected NodeObserver(String path) {
+ this.path = path;
+ }
+
+ /**
+ * A node at {@code path} has been added.
+ * @param path Path of the added node.
+ * @param added Names of the added properties.
+ * @param deleted Names of the deleted properties.
+ * @param changed Names of the changed properties.
+ * @param commitInfo commit info associated with this change.
+ */
+ protected abstract void added(
+ @Nonnull String path,
+ @Nonnull Set<String> added,
+ @Nonnull Set<String> deleted,
+ @Nonnull Set<String> changed,
+ @Nonnull CommitInfo commitInfo);
+
+ /**
+ * A node at {@code path} has been deleted.
+ * @param path Path of the deleted node.
+ * @param added Names of the added properties.
+ * @param deleted Names of the deleted properties.
+ * @param changed Names of the changed properties.
+ * @param commitInfo commit info associated with this change.
+ */
+ protected abstract void deleted(
+ @Nonnull String path,
+ @Nonnull Set<String> added,
+ @Nonnull Set<String> deleted,
+ @Nonnull Set<String> changed,
+ @Nonnull CommitInfo commitInfo);
+
+ /**
+ * A node at {@code path} has been changed.
+ * @param path Path of the changed node.
+ * @param added Names of the added properties.
+ * @param deleted Names of the deleted properties.
+ * @param changed Names of the changed properties.
+ * @param commitInfo commit info associated with this change.
+ */
+ protected abstract void changed(
+ @Nonnull String path,
+ @Nonnull Set<String> added,
+ @Nonnull Set<String> deleted,
+ @Nonnull Set<String> changed,
+ @Nonnull CommitInfo commitInfo);
+
+ @Override
+ public void contentChanged(@Nonnull NodeState root, @Nullable CommitInfo
info) {
+ if (previousRoot != null) {
+ NamePathMapper namePathMapper = new NamePathMapperImpl(
+ new GlobalNameMapper(new ImmutableRoot(root)));
+
+ NodeState before = previousRoot;
+ NodeState after = root;
+ EventHandler handler = new FilteredHandler(
+ new VisibleFilter(),
+ new NodeEventHandler("/", info, namePathMapper));
+ for (String name : PathUtils.elements(path)) {
+ before = before.getChildNode(name);
+ after = after.getChildNode(name);
+ handler = handler.getChildHandler(name, before, after);
+ }
+
+ EventGenerator generator = new EventGenerator(previousRoot, root,
handler);
+ while (!generator.isDone()) {
+ generator.generate();
+ }
+ }
+
+ previousRoot = root;
+ }
+
+ private enum EventType {ADDED, DELETED, CHANGED}
+
+ private class NodeEventHandler extends DefaultEventHandler {
+ private final String path;
+ private final CommitInfo commitInfo;
+ private final NamePathMapper namePathMapper;
+ private final EventType eventType;
+ private final Set<String> added = Sets.newHashSet();
+ private final Set<String> deleted = Sets.newHashSet();
+ private final Set<String> changed = Sets.newHashSet();
+
+ public NodeEventHandler(String path, CommitInfo commitInfo,
NamePathMapper namePathMapper) {
+ this.path = path;
+ this.commitInfo = commitInfo == null ? CommitInfo.EMPTY :
commitInfo;
+ this.namePathMapper = namePathMapper;
+ this.eventType = EventType.CHANGED;
+ }
+
+ private NodeEventHandler(NodeEventHandler parent, String name,
EventType eventType) {
+ this.path = "/".equals(parent.path) ? '/' + name : parent.path +
'/' + name;
+ this.commitInfo = parent.commitInfo;
+ this.namePathMapper = parent.namePathMapper;
+ this.eventType = eventType;
+ }
+
+ @Override
+ public void leave(NodeState before, NodeState after) {
+ switch (eventType) {
+ case ADDED:
+ added(namePathMapper.getJcrPath(path), added, deleted,
changed, commitInfo);
+ break;
+ case DELETED:
+ deleted(namePathMapper.getJcrPath(path), added, deleted,
changed, commitInfo);
+ break;
+ case CHANGED:
+ if (!added.isEmpty() || ! deleted.isEmpty() ||
!changed.isEmpty()) {
+ changed(namePathMapper.getJcrPath(path), added,
deleted, changed, commitInfo);
+ }
+ break;
+ }
+ }
+
+ @Override
+ public EventHandler getChildHandler(String name, NodeState before,
NodeState after) {
+ if (!before.exists()) {
+ return new NodeEventHandler(this, name, EventType.ADDED);
+ } else if (!after.exists()) {
+ return new NodeEventHandler(this, name, EventType.DELETED);
+ } else {
+ return new NodeEventHandler(this, name, EventType.CHANGED);
+ }
+ }
+
+ @Override
+ public void propertyAdded(PropertyState after) {
+ added.add(namePathMapper.getJcrName(after.getName()));
+ }
+
+ @Override
+ public void propertyChanged(PropertyState before, PropertyState after)
{
+ changed.add(namePathMapper.getJcrName(after.getName()));
+ }
+
+ @Override
+ public void propertyDeleted(PropertyState before) {
+ deleted.add(namePathMapper.getJcrName(before.getName()));
+ }
+
+ }
+}
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java?rev=1574896&r1=1574895&r2=1574896&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
Thu Mar 6 14:32:33 2014
@@ -47,6 +47,7 @@ import org.apache.jackrabbit.oak.spi.com
import org.apache.jackrabbit.oak.spi.commit.Editor;
import org.apache.jackrabbit.oak.spi.commit.EditorHook;
import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
@@ -153,6 +154,12 @@ public class Jcr {
return this;
}
+ @Nonnull
+ public final Jcr with(@Nonnull Observer observer) {
+ oak.with(checkNotNull(observer));
+ return this;
+ }
+
public Jcr withAsyncIndexing() {
oak.withAsyncIndexing();
return this;
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=1574896&r1=1574895&r2=1574896&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
Thu Mar 6 14:32:33 2014
@@ -21,6 +21,7 @@ package org.apache.jackrabbit.oak.jcr.ob
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.namepath.PathTracker;
import org.apache.jackrabbit.oak.plugins.identifier.IdentifierTracker;
+import org.apache.jackrabbit.oak.plugins.observation.DefaultEventHandler;
import org.apache.jackrabbit.oak.plugins.observation.EventHandler;
import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -29,7 +30,7 @@ import org.apache.jackrabbit.oak.spi.sta
* and identifier information to translate change callbacks to corresponding
* JCR events that are then placed in the given {@link EventQueue}.
*/
-class QueueingHandler implements EventHandler {
+class QueueingHandler extends DefaultEventHandler {
private final EventQueue queue;