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 2013/11/18 17:46:34 UTC
svn commit: r1543077 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter:
./ EventGenerator.java EventIterator.java Filters.java
Author: mduerig
Date: Mon Nov 18 16:46:33 2013
New Revision: 1543077
URL: http://svn.apache.org/r1543077
Log:
OAK-1133: Observation listener PLUS
Add generic classes and interfaces for event filtering and generation
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventGenerator.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventIterator.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/Filters.java
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventGenerator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventGenerator.java?rev=1543077&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventGenerator.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventGenerator.java Mon Nov 18 16:46:33 2013
@@ -0,0 +1,265 @@
+/*
+ * 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.filter;
+
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.MISSING_NODE;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.spi.state.MoveValidator;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * {@link Filter filter} and report changes between node states to the {@link Listener}.
+ */
+public class EventGenerator implements MoveValidator {
+ private final Filter filter;
+ private final Listener listener;
+
+ /**
+ * Filter for determining what changes to report the the {@link Listener}.
+ */
+ public interface Filter {
+
+ /**
+ * Include an added property
+ * @param after added property
+ * @return {@code true} if the property should be included
+ */
+ boolean includeAdd(PropertyState after);
+
+ /**
+ * Include a changed property
+ * @param before property before the change
+ * @param after property after the change
+ * @return {@code true} if the property should be included
+ */
+ boolean includeChange(PropertyState before, PropertyState after);
+
+ /**
+ * Include a deleted property
+ * @param before deleted property
+ * @return {@code true} if the property should be included
+ */
+ boolean includeDelete(PropertyState before);
+
+ /**
+ * Include an added node
+ * @param name name of the node
+ * @param after added node
+ * @return {@code true} if the node should be included
+ */
+ boolean includeAdd(String name, NodeState after);
+
+ /**
+ * Include a changed node
+ * @param name name of the node
+ * @param before node before the change
+ * @param after node after the change
+ * @return {@code true} if the node should be included
+ */
+ boolean includeChange(String name, NodeState before, NodeState after);
+
+ /**
+ * Include a deleted node
+ * @param name name of the node
+ * @param before deleted node
+ * @return {@code true} if the node should be included
+ */
+ boolean includeDelete(String name, NodeState before);
+
+ /**
+ * Include a moved node
+ * @param sourcePath source path of the move operation
+ * @param destPath destination path of the move operation
+ * @param moved the moved node
+ * @return {@code true} if the node should be included
+ */
+ boolean includeMove(String sourcePath, String destPath, NodeState moved);
+
+ /**
+ * Factory for creating a filter instance for the given child node
+ * @param name name of the child node
+ * @param before before state of the child node
+ * @param after after state of the child node
+ * @return filter instance for filtering the child node or {@code null} to
+ * exclude the sub tree rooted at this child node.
+ */
+ @CheckForNull
+ Filter create(String name, NodeState before, NodeState after);
+ }
+
+ /**
+ * Listener for listening to changes.
+ */
+ public interface Listener {
+
+ /**
+ * Notification for an added property
+ * @param after added property
+ */
+ void propertyAdded(PropertyState after);
+
+ /**
+ * Notification for a changed property
+ * @param before property before the change
+ * @param after property after the change
+ */
+ void propertyChanged(PropertyState before, PropertyState after);
+
+ /**
+ * Notification for a deleted property
+ * @param before deleted property
+ */
+ void propertyDeleted(PropertyState before);
+
+ /**
+ * Notification for an added node
+ * @param name name of the node
+ * @param after added node
+ */
+ void childNodeAdded(String name, NodeState after);
+
+ /**
+ * Notification for a changed node
+ * @param name name of the node
+ * @param before node before the change
+ * @param after node after the change
+ */
+ void childNodeChanged(String name, NodeState before, NodeState after);
+
+ /**
+ * Notification for a deleted node
+ * @param name name of the deleted node
+ * @param before deleted node
+ */
+ void childNodeDeleted(String name, NodeState before);
+
+ /**
+ * Notification for a moved node
+ * @param sourcePath source of the moved node
+ * @param destPath destination of the moved node
+ * @param moved moved node
+ */
+ void nodeMoved(String sourcePath, String destPath, NodeState moved);
+
+ /**
+ * Factory for creating a filter instance for the given child node
+ * @param name name of the child node
+ * @param before before state of the child node
+ * @param after after state of the child node
+ * @return listener for the child node
+ */
+ @Nonnull
+ Listener create(String name, NodeState before, NodeState after);
+ }
+
+ /**
+ * Create a new instance of a {@code EventGenerator} reporting events to the
+ * passed {@code listener} after filtering with the passed {@code filter}.
+ * @param filter filter for filtering changes
+ * @param listener listener for listening to the filtered changes
+ */
+ public EventGenerator(Filter filter, Listener listener) {
+ this.filter = filter;
+ this.listener = listener;
+ }
+
+ @Override
+ public void move(String sourcePath, String destPath, NodeState moved) throws CommitFailedException {
+ if (filter.includeMove(sourcePath, destPath, moved)) {
+ listener.nodeMoved(sourcePath, destPath, moved);
+ }
+ }
+
+ @Override
+ public void enter(NodeState before, NodeState after) throws CommitFailedException {
+ }
+
+ @Override
+ public void leave(NodeState before, NodeState after) throws CommitFailedException {
+ }
+
+ @Override
+ public void propertyAdded(PropertyState after) throws CommitFailedException {
+ if (filter.includeAdd(after)) {
+ listener.propertyAdded(after);
+ }
+ }
+
+ @Override
+ public void propertyChanged(PropertyState before, PropertyState after) throws CommitFailedException {
+ if (filter.includeChange(before, after)) {
+ listener.propertyChanged(before, after);
+ }
+ }
+
+ @Override
+ public void propertyDeleted(PropertyState before) throws CommitFailedException {
+ if (filter.includeDelete(before)) {
+ listener.propertyDeleted(before);
+ }
+ }
+
+ @Override
+ public MoveValidator childNodeAdded(String name, NodeState after) throws CommitFailedException {
+ if (filter.includeAdd(name, after)) {
+ listener.childNodeAdded(name, after);
+ }
+ return createChildGenerator(name, MISSING_NODE, after);
+ }
+
+ @Override
+ public MoveValidator childNodeChanged(String name, NodeState before, NodeState after) throws CommitFailedException {
+ if (filter.includeChange(name, before, after)) {
+ listener.childNodeChanged(name, before, after);
+ }
+ return createChildGenerator(name, before, after);
+ }
+
+ @Override
+ public MoveValidator childNodeDeleted(String name, NodeState before) throws CommitFailedException {
+ if (filter.includeDelete(name, before)) {
+ listener.childNodeDeleted(name, before);
+ }
+ return createChildGenerator(name, before, MISSING_NODE);
+ }
+
+ /**
+ * Factory method for creating {@code EventGenerator} instances of child nodes.
+ * @param name name of the child node
+ * @param before before state of the child node
+ * @param after after state of the child node
+ * @return {@code EventGenerator} for a child node
+ */
+ protected EventGenerator createChildGenerator(String name, NodeState before, NodeState after) {
+ Filter childFilter = filter.create(name, before, after);
+ if (childFilter != null) {
+ return new EventGenerator(
+ childFilter,
+ listener.create(name, before, after));
+ } else {
+ return null;
+ }
+ }
+}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventIterator.java?rev=1543077&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventIterator.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/EventIterator.java Mon Nov 18 16:46:33 2013
@@ -0,0 +1,142 @@
+/*
+ * 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.filter;
+
+import static com.google.common.collect.Iterators.concat;
+import static com.google.common.collect.Lists.newArrayList;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
+import org.apache.jackrabbit.oak.spi.commit.EditorDiff;
+import org.apache.jackrabbit.oak.spi.commit.VisibleEditor;
+import org.apache.jackrabbit.oak.spi.state.MoveDetector;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.util.LazyValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This {@link EventGenerator} implementation provides a traversable view for
+ * events.
+ * @param <T> type of the event returned by this iterator
+ */
+public class EventIterator<T> extends EventGenerator implements Iterator<T> {
+ private static final Logger LOG = LoggerFactory.getLogger(EventIterator.class);
+
+ private final ImmutableTree beforeTree;
+ private final ImmutableTree afterTree;
+
+ private final Filter filter;
+ private final IterableListener<T> listener;
+
+ private final List<Iterator<T>> childEvents = newArrayList();
+
+ private final LazyValue<Iterator<T>> eventIterator = new LazyValue<Iterator<T>>() {
+ @Override
+ protected Iterator<T> createValue() {
+ CommitFailedException e = EditorDiff.process(
+ new VisibleEditor(
+ new MoveDetector(EventIterator.this, afterTree.getPath())),
+ beforeTree.getNodeState(), afterTree.getNodeState());
+
+ if (e != null) {
+ LOG.error("Error while extracting observation events", e);
+ }
+
+ return concat(listener.iterator(), concat(childEvents.iterator()));
+ }
+ };
+
+ /**
+ * Specialisation of {@link Listener} that provides the events reported
+ * to it as an iterator.
+ *
+ * @param <S> type of the events in the iterator
+ */
+ public interface IterableListener<S> extends Listener, Iterable<S> {
+ @Override
+ @Nonnull
+ IterableListener<S> create(String name, NodeState before, NodeState after);
+ }
+
+ /**
+ * Create a new instance of a {@code EventIterator} reporting events to the
+ * passed {@code listener} after filtering with the passed {@code filter}.
+ *
+ * @param before before state
+ * @param after after state
+ * @param filter filter for filtering changes
+ * @param listener listener for listening to the filtered changes
+ */
+ public EventIterator(NodeState before, NodeState after, Filter filter,
+ IterableListener<T> listener) {
+ super(filter, listener);
+ this.beforeTree = new ImmutableTree(before);
+ this.afterTree = new ImmutableTree(after);
+ this.filter = filter;
+ this.listener = listener;
+ }
+
+ private EventIterator(ImmutableTree before, ImmutableTree after, Filter filter,
+ IterableListener<T> listener) {
+ super(filter, listener);
+ this.beforeTree = before;
+ this.afterTree = after;
+ this.filter = filter;
+ this.listener = listener;
+ }
+
+ //------------------------------------------------------------< EventGenerator >---
+
+ @Override
+ protected EventGenerator createChildGenerator(String name, NodeState before, NodeState after) {
+ Filter childFilter = filter.create(name, before, after);
+ if (childFilter != null) {
+ childEvents.add(new EventIterator<T>(
+ beforeTree.getChild(name), afterTree.getChild(name),
+ childFilter,
+ listener.create(name, before, after)));
+ }
+ return null;
+ }
+
+ //------------------------------------------------------------< Iterator >---
+
+ @Override
+ public boolean hasNext() {
+ return eventIterator.get().hasNext();
+ }
+
+ @Override
+ public T next() {
+ return eventIterator.get().next();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/Filters.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/Filters.java?rev=1543077&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/Filters.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/Filters.java Mon Nov 18 16:46:33 2013
@@ -0,0 +1,231 @@
+/*
+ * 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.filter;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.observation.filter.EventGenerator.Filter;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * This utility class provides common {@link Filter} instances
+ */
+public final class Filters {
+ private Filters() {
+ }
+
+ /**
+ * A filter that matches if and only if any of the filters passed to this
+ * method matches.
+ * @param filters filters of which any must match
+ * @return {@code true} if any of {@code filters} match.
+ */
+ public static Filter any(@Nonnull final Filter... filters) {
+ return any(Lists.newArrayList(checkNotNull(filters)));
+ }
+
+ /**
+ * A filter that matches if and only if all of the filters passed to this
+ * method matches.
+ * @param filters filters of which all must match
+ * @return {@code true} if all of {@code filters} match.
+ */
+ public static Filter all(@Nonnull final Filter... filters) {
+ return all(Lists.newArrayList(checkNotNull(filters)));
+ }
+
+ private static Filter any(final List<Filter> filters) {
+ return new Filter() {
+ @Override
+ public boolean includeAdd(PropertyState after) {
+ for (Filter filter : filters) {
+ if (filter.includeAdd(after)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean includeChange(PropertyState before, PropertyState after) {
+ for (Filter filter : filters) {
+ if (filter.includeChange(before, after)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean includeDelete(PropertyState before) {
+ for (Filter filter : filters) {
+ if (filter.includeDelete(before)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean includeAdd(String name, NodeState after) {
+ for (Filter filter : filters) {
+ if (filter.includeAdd(name, after)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean includeChange(String name, NodeState before, NodeState after) {
+ for (Filter filter : filters) {
+ if (filter.includeChange(name, before, after)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean includeDelete(String name, NodeState before) {
+ for (Filter filter : filters) {
+ if (filter.includeDelete(name, before)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean includeMove(String sourcePath, String destPath, NodeState moved) {
+ for (Filter filter : filters) {
+ if (filter.includeMove(sourcePath, destPath, moved)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public Filter create(String name, NodeState before, NodeState after) {
+ List<Filter> childFilters = Lists.newArrayList();
+ for (Filter filter : filters) {
+ Filter childFilter = filter.create(name, before, after);
+ if (childFilter != null) {
+ childFilters.add(childFilter);
+ }
+ }
+ return any(childFilters);
+ }
+ };
+ }
+
+ private static Filter all(final List<Filter> filters) {
+ return new Filter() {
+ @Override
+ public boolean includeAdd(PropertyState after) {
+ for (Filter filter : filters) {
+ if (!filter.includeAdd(after)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean includeChange(PropertyState before, PropertyState after) {
+ for (Filter filter : filters) {
+ if (!filter.includeChange(before, after)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean includeDelete(PropertyState before) {
+ for (Filter filter : filters) {
+ if (!filter.includeDelete(before)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean includeAdd(String name, NodeState after) {
+ for (Filter filter : filters) {
+ if (!filter.includeAdd(name, after)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean includeChange(String name, NodeState before, NodeState after) {
+ for (Filter filter : filters) {
+ if (!filter.includeChange(name, before, after)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean includeDelete(String name, NodeState before) {
+ for (Filter filter : filters) {
+ if (!filter.includeDelete(name, before)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean includeMove(String sourcePath, String destPath, NodeState moved) {
+ for (Filter filter : filters) {
+ if (!filter.includeMove(sourcePath, destPath, moved)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Filter create(String name, NodeState before, NodeState after) {
+ List<Filter> childFilters = Lists.newArrayList();
+ for (Filter filter : filters) {
+ Filter childFilter = filter.create(name, before, after);
+ if (childFilter != null) {
+ childFilters.add(childFilter);
+ }
+ }
+ return all(childFilters);
+ }
+ };
+ }
+}