You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by re...@apache.org on 2011/12/09 16:16:45 UTC

svn commit: r1212472 - in /jackrabbit/trunk: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/ jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/observation/ jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr...

Author: reschke
Date: Fri Dec  9 15:16:44 2011
New Revision: 1212472

URL: http://svn.apache.org/viewvc?rev=1212472&view=rev
Log:
JCR-3172: implement PERSIST events for the EventJournal

Add PERSIST events to EventJournal, add a minimal test case

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventFilter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventJournalImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/FilteredEventIterator.java
    jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/observation/EventJournalTest.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventImpl.java
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventFilterImpl.java
    jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventFactory.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java Fri Dec  9 15:16:44 2011
@@ -242,7 +242,7 @@ class EventConsumer {
         // check if filtered iterator has at least one event
         EventIterator it = new FilteredEventIterator(
                 session, events.iterator(), events.getTimestamp(),
-                events.getUserData(), filter, denied);
+                events.getUserData(), filter, denied, false);
         if (it.hasNext()) {
             long time = System.currentTimeMillis();
             listener.onEvent(it);

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventFilter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventFilter.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventFilter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventFilter.java Fri Dec  9 15:16:44 2011
@@ -25,6 +25,7 @@ import org.apache.jackrabbit.spi.Path;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.nodetype.NodeType;
+import javax.jcr.observation.Event;
 
 /**
  * The <code>EventFilter</code> class implements the filter logic based
@@ -132,6 +133,11 @@ public class EventFilter {
             return true;
         }
 
+        // UUIDs, types, and paths do not need to match for persist
+        if (eventState.getType() == Event.PERSIST) {
+            return false;
+        }
+
         // check UUIDs
         NodeId parentId = eventState.getParentId();
         if (ids != null) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java Fri Dec  9 15:16:44 2011
@@ -104,7 +104,8 @@ public final class EventImpl implements 
      * {@inheritDoc}
      */
     public String getPath() throws RepositoryException {
-        return session.getJCRPath(getQPath());
+        Path p = getQPath();
+        return p != null ? session.getJCRPath(getQPath()) : null;
     }
 
     /**
@@ -132,12 +133,20 @@ public final class EventImpl implements 
      * {@inheritDoc}
      */
     public String getIdentifier() throws RepositoryException {
-        NodeId id = eventState.getChildId();
-        if (id == null) {
-            // property event
-            id = eventState.getParentId();
+        if (eventState.getType() == Event.PERSIST) {
+            return null;
+        }
+        else {
+            NodeId id = eventState.getChildId();
+
+            if (id != null) {
+                return id.toString();
+            }
+            else {
+                // property event
+                return eventState.getParentId().toString();
+            }
         }
-        return id.toString();
     }
 
     /**
@@ -161,18 +170,25 @@ public final class EventImpl implements 
     /**
      * Returns the <code>Path</code> of this event.
      *
-     * @return path
+     * @return path or <code>null</code> when no path is associated with the event
      * @throws RepositoryException if the path can't be constructed
      */
     public Path getQPath() throws RepositoryException {
         try {
             Path parent = eventState.getParentPath();
             Path child = eventState.getChildRelPath();
-            int index = child.getIndex();
-            if (index > 0) {
-                return PathFactoryImpl.getInstance().create(parent, child.getName(), index, false);
-            } else {
-                return PathFactoryImpl.getInstance().create(parent, child.getName(), false);
+
+            if (parent == null || child == null) {
+                // an event without associated path information
+                return null;
+            }
+            else {
+                int index = child.getIndex();
+                if (index > 0) {
+                    return PathFactoryImpl.getInstance().create(parent, child.getName(), index, false);
+                } else {
+                    return PathFactoryImpl.getInstance().create(parent, child.getName(), false);
+                }
             }
         } catch (MalformedPathException e) {
             String msg = "internal error: malformed path for event";

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventJournalImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventJournalImpl.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventJournalImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventJournalImpl.java Fri Dec  9 15:16:44 2011
@@ -415,7 +415,7 @@ public class EventJournalImpl implements
                 List<EventState> eventStates, long timestamp, String userData) {
             this.events = new FilteredEventIterator(
                     session, eventStates.iterator(),
-                    timestamp, userData, filter, Collections.emptySet());
+                    timestamp, userData, filter, Collections.emptySet(), true);
             this.timestamp = timestamp;
         }
     }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java Fri Dec  9 15:16:44 2011
@@ -177,7 +177,7 @@ public class EventState {
                 throw new IllegalArgumentException("childId only allowed for Node events.");
             }
         } else {
-            if (childId == null) {
+            if (childId == null && type != Event.PERSIST) {
                 throw new IllegalArgumentException("childId must not be null for Node events.");
             }
         }
@@ -580,6 +580,20 @@ public class EventState {
     }
 
     /**
+     * Creates a new {@link javax.jcr.observation.Event} of type
+     * {@link javax.jcr.observation.Event#PERSIST}.
+     *
+     * @param session    the session that changed the property.
+     * @param external   flag indicating whether this is an external event
+     * @return an <code>EventState</code> instance.
+     */
+    public static EventState persist(Session session, boolean external) {
+
+        return new EventState(Event.PERSIST, null, null, null, null,
+                null, null, session, external);
+    }
+
+    /**
      * {@inheritDoc}
      */
     public int getType() {
@@ -695,10 +709,12 @@ public class EventState {
     /**
      * Returns the id of the associated item of this <code>EventState</code>.
      *
-     * @return the <code>ItemId</code>.
+     * @return the <code>ItemId</code> or <code>null</code> for {@link Event#PERSIST} events 
      */
     ItemId getTargetId() {
-        if (childId == null) {
+        if (type == Event.PERSIST) {
+            return null;
+        } else if (childId == null) {
             // property event
             return new PropertyId(parentId, childRelPath.getName());
         } else {
@@ -782,8 +798,8 @@ public class EventState {
         if (h == 0) {
             h = 37;
             h = 37 * h + type;
-            h = 37 * h + parentId.hashCode();
-            h = 37 * h + childRelPath.hashCode();
+            h = 37 * h + (parentId != null ? parentId.hashCode() : 0);
+            h = 37 * h + (childRelPath != null ? childRelPath.hashCode() : 0);
             h = 37 * h + session.hashCode();
             h = 37 * h + info.hashCode();
             hashCode = h;
@@ -833,6 +849,8 @@ public class EventState {
             return "PropertyChanged";
         } else if (eventType == Event.PROPERTY_REMOVED) {
             return "PropertyRemoved";
+        } else if (eventType == Event.PERSIST) {
+            return "Persist";
         } else {
             return "UnknownEventType";
         }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/FilteredEventIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/FilteredEventIterator.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/FilteredEventIterator.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/FilteredEventIterator.java Fri Dec  9 15:16:44 2011
@@ -17,9 +17,11 @@
 package org.apache.jackrabbit.core.observation;
 
 import java.util.Iterator;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
 
 import org.apache.jackrabbit.commons.iterator.EventIteratorAdapter;
 import org.apache.jackrabbit.commons.iterator.FilteredRangeIterator;
@@ -64,12 +66,13 @@ class FilteredEventIterator extends Even
      *               event listener.
      * @param denied <code>Set</code> of <code>ItemId</code>s of denied <code>ItemState</code>s
      *               rejected by the <code>AccessManager</code>
+     * @param includePersistEvent whether or not to include the {@link Event#PERSIST} event
      */
     public FilteredEventIterator(
-            SessionImpl session, Iterator<?> eventStates,
+            SessionImpl session, Iterator<EventState> eventStates,
             long timestamp, String userData,
-            final EventFilter filter, final Set<?> denied) {
-        super(new FilteredRangeIterator(eventStates, new Predicate() {
+            final EventFilter filter, final Set<?> denied, boolean includePersistEvent) {
+        super(new FilteredRangeIterator(wrapAndAddPersist(eventStates, includePersistEvent), new Predicate() {
             public boolean evaluate(Object object) {
                 try {
                     EventState state = (EventState) object;
@@ -92,4 +95,58 @@ class FilteredEventIterator extends Even
                 session, (EventState) super.next(), timestamp, userData);
     }
 
+    /**
+     * Optionally wrap the iterator into one that adds PERSIST events
+     */
+    private static Iterator<EventState> wrapAndAddPersist(final Iterator<EventState> states,
+            boolean includePersistEvents) {
+        if (includePersistEvents) {
+            return new PersistEventAddingWrapper(states);
+        }
+        else {
+            return states;
+        }
+    }
+
+    /**
+     * A wrapper around {@link Iterator} that adds a "PERSIST" event at the end.
+     */
+    private static class PersistEventAddingWrapper implements Iterator<EventState> {
+
+        private Iterator<EventState> states;
+        private boolean persistSent = false;
+        private EventState previous = null;
+
+        public PersistEventAddingWrapper(Iterator<EventState> states) {
+            this.states = states;
+        }
+
+        public boolean hasNext() {
+            if (states.hasNext()) {
+                return true;
+            } else {
+                return !persistSent;
+            }
+        }
+
+        public EventState next() {
+            if (states.hasNext()) {
+                previous = states.next();
+                return previous;
+            }
+            else if (persistSent || previous == null) {
+                // we are at the end; either because we already sent
+                // PERSIST, or because the iterator was empty anyway
+                throw new NoSuchElementException();
+            }
+            else {
+                persistSent = true;
+                return EventState.persist(previous.getSession(), previous.isExternal());
+            }
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
 }

Modified: jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/observation/EventJournalTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/observation/EventJournalTest.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/observation/EventJournalTest.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/observation/EventJournalTest.java Fri Dec  9 15:16:44 2011
@@ -185,7 +185,52 @@ public class EventJournalTest extends Ab
 
         checkJournal(new String[]{n2.getPath()}, new String[]{n1.getPath()});
     }
-    
+
+    public void testPersist() throws RepositoryException, NotExecutableException {
+        Node n1 = testRootNode.addNode(nodeName1);
+
+        journal = getEventJournal(Event.PERSIST, testRoot, true, null, null);
+        skipToNow();
+
+        superuser.save();
+
+        boolean hasPersistEvents = journal.hasNext();
+        if (! hasPersistEvents) {
+        	throw new NotExecutableException("repository does not appear to provide PERSIST events");
+        }
+
+        journal = getEventJournal(ALL_TYPES | Event.PERSIST, testRoot, true, null, null);
+        skipToNow();
+
+        // add another child node
+        Node n3 = testRootNode.addNode(nodeName2);
+        String target = n1.getPath();
+        n1.remove();
+        superuser.save();
+
+        // move it
+        superuser.getWorkspace().move(n3.getPath(), target);
+
+        // remove it again
+        n3 = superuser.getNode(target);
+        n3.remove();
+        superuser.save();
+
+        int persistCount = 0;
+        Event e = null;
+        while (journal.hasNext()) {
+        	e = journal.nextEvent();
+        	if (e.getType() == Event.PERSIST) {
+        		persistCount += 1;
+        	}
+        }
+
+        assertEquals(3, persistCount);
+
+        // last event should be persist
+        assertEquals(Event.PERSIST, e.getType());
+    }
+
     //-------------------------------< internal >-------------------------------
 
     private void skipToNow() {

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventImpl.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventImpl.java Fri Dec  9 15:16:44 2011
@@ -91,7 +91,7 @@ final class EventImpl implements Event {
      * {@inheritDoc}
      */
     public String getPath() throws RepositoryException {
-        return resolver.getJCRPath(event.getPath());
+        return event.getPath() != null ? resolver.getJCRPath(event.getPath()) : null;
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventFilterImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventFilterImpl.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventFilterImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventFilterImpl.java Fri Dec  9 15:16:44 2011
@@ -88,6 +88,11 @@ public class EventFilterImpl implements 
             return false;
         }
 
+        // UUIDs, types, and paths do not need to match for persist
+        if (event.getType() == Event.PERSIST) {
+            return true;
+        }
+
         // check UUIDs
         NodeId parentId = event.getParentId();
         if (uuids != null) {

Modified: jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventFactory.java?rev=1212472&r1=1212471&r2=1212472&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventFactory.java (original)
+++ jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventFactory.java Fri Dec  9 15:16:44 2011
@@ -66,11 +66,11 @@ class EventFactory {
 
     public Event fromJCREvent(javax.jcr.observation.Event e)
             throws RepositoryException {
-        Path p = resolver.getQPath(e.getPath());
-        Path parent = p.getAncestor(1);
+        Path p = e.getPath() != null ? resolver.getQPath(e.getPath()) : null;
+        Path parent = p != null ? p.getAncestor(1) : null;
         int type = e.getType();
 
-        NodeId parentId = idFactory.createNodeId((String) null, parent);
+        NodeId parentId = parent != null ?idFactory.createNodeId((String) null, parent) : null;
         String identifier = e.getIdentifier();
         ItemId itemId;
         Node node = null;