jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mreut...@apache.org
Subject svn commit: r790826 - in /jackrabbit/trunk: jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observa...
Date Fri, 03 Jul 2009 08:39:58 GMT
Author: mreutegg
Date: Fri Jul  3 08:39:57 2009
New Revision: 790826

URL: http://svn.apache.org/viewvc?rev=790826&view=rev
Log:
JCR-2108: JSR 283 Observation

Added:
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventJournalImpl.java   (with props)
    jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventFactory.java   (with props)
    jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repository.xml   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/FilteredEventIterator.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/InternalEventListener.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/ObservationManagerImpl.java
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AbstractReadableRepositoryService.java
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventBundleImpl.java
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/logging/RepositoryServiceLogger.java
    jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/EventBundle.java
    jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java
    jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
    jackrabbit/trunk/jackrabbit-spi2jcr/pom.xml
    jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventSubscription.java
    jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java
    jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repositoryStubImpl.properties

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java Fri Jul  3 08:39:57 2009
@@ -395,6 +395,22 @@
     }
 
     /**
+     * Returns the events from the journal that occurred after a given date.
+     *
+     * @param filter the event filter to apply.
+     * @param after  a date in milliseconds.
+     * @return the events as a bundle.
+     * @throws RepositoryException if an error occurs.
+     * @throws UnsupportedRepositoryOperationException
+     *                             if the implementation does not support
+     *                             journaled observation.
+     */
+    public EventBundle getEvents(EventFilter filter, long after)
+            throws RepositoryException, UnsupportedRepositoryOperationException {
+        return service.getEvents(sessionInfo, filter, after);
+    }
+
+    /**
      *
      * @param userData
      * @throws RepositoryException

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java Fri Jul  3 08:39:57 2009
@@ -26,6 +26,7 @@
 import org.apache.jackrabbit.spi.EventBundle;
 import org.apache.jackrabbit.spi.NodeId;
 import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.ItemId;
 
 import javax.jcr.RepositoryException;
 import java.util.Collection;
@@ -44,7 +45,7 @@
     private static Logger log = LoggerFactory.getLogger(HierarchyEventListener.class);
 
     private final HierarchyManager hierarchyMgr;
-    private final Collection eventFilter;
+    private final Collection<EventFilter> eventFilter;
 
     public HierarchyEventListener(WorkspaceManager wspManager,
                                   HierarchyManager hierarchyMgr,
@@ -59,14 +60,18 @@
             } catch (RepositoryException e) {
                 // spi does not support observation, or another error occurred.
             }
-            this.eventFilter = (filter == null) ? Collections.EMPTY_LIST : Collections.singletonList(filter);
+            if (filter == null) {
+                this.eventFilter = Collections.emptyList();
+            } else {
+                this.eventFilter = Collections.singletonList(filter);
+            }
             try {
                 wspManager.addEventListener(this);
             } catch (RepositoryException e) {
                 // spi does not support observation, or another error occurred.
             }
         } else {
-            this.eventFilter = Collections.EMPTY_LIST;
+            this.eventFilter = Collections.emptyList();
         }
     }
 
@@ -74,7 +79,7 @@
     /**
      * @see InternalEventListener#getEventFilters()
      */
-    public Collection getEventFilters() {
+    public Collection<EventFilter> getEventFilters() {
         return eventFilter;
     }
 
@@ -84,7 +89,7 @@
      * since workspace operations are reported as local changes as well and
      * might have invoked changes (autocreated items etc.).
      *
-     * @param eventBundle
+     * @param eventBundle the events.
      * @see InternalEventListener#onEvent(EventBundle)
      */
     public void onEvent(EventBundle eventBundle) {
@@ -99,9 +104,9 @@
      * Retrieve the workspace state(s) affected by the given event and refresh
      * them accordingly.
      *
-     * @param events
+     * @param events the events to process.
      */
-    private void pushEvents(Collection events) {
+    private void pushEvents(Collection<Event> events) {
         if (events.isEmpty()) {
             log.debug("Empty event bundle");
             return;
@@ -110,9 +115,9 @@
         // TODO: handle new 283 event types and clean add/remove that is also present as move-event.
 
         // collect set of removed node ids
-        Set removedEvents = new HashSet();
+        Set<ItemId> removedEvents = new HashSet<ItemId>();
         // separately collect the add events
-        Set addEvents = new HashSet();
+        Set<Event> addEvents = new HashSet<Event>();
 
         for (Iterator it = events.iterator(); it.hasNext();) {
             Event event = (Event) it.next();
@@ -170,8 +175,7 @@
         }
 
         /* process all other events (removal, property changed) */
-        for (Iterator it = events.iterator(); it.hasNext(); ) {
-            Event event = (Event) it.next();
+        for (Event event : events) {
             int type = event.getType();
 
             NodeId parentId = event.getParentId();
@@ -211,9 +215,9 @@
         }
     }
 
-    private static Collection getEventCollection(EventBundle eventBundle) {
-        List evs = new ArrayList();
-        for (Iterator it = eventBundle.getEvents(); it.hasNext();) {
+    private static Collection<Event> getEventCollection(EventBundle eventBundle) {
+        List<Event> evs = new ArrayList<Event>();
+        for (Iterator<Event> it = eventBundle.getEvents(); it.hasNext();) {
            evs.add(it.next());
         }
         return evs;

Added: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventJournalImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventJournalImpl.java?rev=790826&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventJournalImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventJournalImpl.java Fri Jul  3 08:39:57 2009
@@ -0,0 +1,169 @@
+/*
+ * 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.jcr2spi.observation;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+import javax.jcr.observation.EventJournal;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.spi.Event;
+import org.apache.jackrabbit.spi.EventFilter;
+import org.apache.jackrabbit.spi.EventBundle;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.jcr2spi.WorkspaceManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <code>EventJournalImpl</code> implement the JSR 283 event journal over SPI.
+ */
+public class EventJournalImpl implements EventJournal {
+
+    /**
+     * The logger instance for this class.
+     */
+    private static final Logger log = LoggerFactory.getLogger(EventJournalImpl.class);
+
+    private final WorkspaceManager wspMgr;
+
+    private final EventFilter filter;
+
+    private final NamePathResolver resolver;
+
+    private List<Event> buffer = new LinkedList<Event>();
+
+    private long lastTimestamp = 0;
+
+    /**
+     * Current position.
+     */
+    private long position = 0;
+
+    public EventJournalImpl(WorkspaceManager wspMgr,
+                            EventFilter filter,
+                            NamePathResolver resolver) {
+        this.wspMgr = wspMgr;
+        this.filter = filter;
+        this.resolver = resolver;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void skipTo(long date) {
+        // first try to skip in buffer
+        while (!buffer.isEmpty()) {
+            long eDate;
+            try {
+                eDate = buffer.get(0).getDate();
+            } catch (RepositoryException e) {
+                eDate = 0;
+            }
+            if (eDate <= date) {
+                buffer.remove(0);
+            } else {
+                return;
+            }
+        }
+        // if we get here then we need to refill the buffer after
+        // the given date
+        lastTimestamp = date;
+        refill();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public javax.jcr.observation.Event nextEvent() {
+        return (javax.jcr.observation.Event) next();
+    }
+
+    public long getDate() {
+        // TODO
+        throw new RuntimeException("Not implemented, see JCR-2086");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void skip(long skipNum) {
+        while (skipNum-- > 0) {
+            next();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getSize() {
+        return -1;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getPosition() {
+        return position;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext() {
+        if (buffer.isEmpty()) {
+            refill();
+        }
+        return !buffer.isEmpty();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object next() {
+        if (hasNext()) {
+            position++;
+            return new EventImpl(buffer.remove(0),
+                    resolver, wspMgr.getIdFactory());
+        } else {
+            throw new NoSuchElementException();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    //----------------------------< internal >----------------------------------
+
+    private void refill() {
+        try {
+            EventBundle bundle = wspMgr.getEvents(filter, lastTimestamp);
+            for (Event e : bundle) {
+                buffer.add(e);
+                lastTimestamp = e.getDate();
+            }
+        } catch (RepositoryException e) {
+            log.warn("Exception while refilling event journal buffer", e);
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/EventJournalImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/FilteredEventIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/FilteredEventIterator.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/FilteredEventIterator.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/FilteredEventIterator.java Fri Jul  3 08:39:57 2009
@@ -22,27 +22,21 @@
 import javax.jcr.observation.Event;
 import javax.jcr.observation.EventIterator;
 
-import org.apache.jackrabbit.spi.EventBundle;
 import org.apache.jackrabbit.spi.EventFilter;
 import org.apache.jackrabbit.spi.IdFactory;
 import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
+ * Implements an event iterator that converts SPI events into JCR events and
+ * filters out the ones that are not accepted by an {@link EventFilter}.
  */
 class FilteredEventIterator implements EventIterator {
 
     /**
-     * Logger instance for this class
-     */
-    private static final Logger log = LoggerFactory.getLogger(FilteredEventIterator.class);
-
-    /**
      * The actual {@link org.apache.jackrabbit.spi.Event}s fired by the repository service
      * (unfiltered).
      */
-    private final Iterator actualEvents;
+    protected final Iterator<org.apache.jackrabbit.spi.Event> actualEvents;
 
     /**
      * For filtering the {@link javax.jcr.observation.Event}s.
@@ -77,20 +71,22 @@
     /**
      * Creates a new <code>FilteredEventIterator</code>.
      *
-     * @param events     the {@link org.apache.jackrabbit.spi.Event}s as a
-     *                   bundle.
-     * @param filter     only event that pass the filter will be dispatched to
- *                   the event listener.
-     * @param resolver
-     * @param idFactory
+     * @param events    the {@link org.apache.jackrabbit.spi.Event}s as an
+     *                  iterator.
+     * @param isLocal   whether the events were caused by the local session.
+     * @param filter    only event that pass the filter will be dispatched to
+     *                  the event listener.
+     * @param resolver  the name path resolver.
+     * @param idFactory the id factory.
      */
-    public FilteredEventIterator(EventBundle events,
+    public FilteredEventIterator(Iterator<org.apache.jackrabbit.spi.Event> events,
+                                 boolean isLocal,
                                  EventFilter filter,
                                  NamePathResolver resolver,
                                  IdFactory idFactory) {
-        this.actualEvents = events.getEvents();
+        this.actualEvents = events;
         this.filter = filter;
-        this.isLocal = events.isLocal();
+        this.isLocal = isLocal;
         this.resolver = resolver;
         this.idFactory = idFactory;
         fetchNext();
@@ -177,7 +173,7 @@
         org.apache.jackrabbit.spi.Event event;
         next = null;
         while (next == null && actualEvents.hasNext()) {
-            event = (org.apache.jackrabbit.spi.Event) actualEvents.next();
+            event = actualEvents.next();
             next = filter.accept(event, isLocal) ? new EventImpl(event, resolver, idFactory) : null;
         }
     }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/InternalEventListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/InternalEventListener.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/InternalEventListener.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/InternalEventListener.java Fri Jul  3 08:39:57 2009
@@ -44,5 +44,5 @@
      * @return an unmodifiable collection of {@link EventFilter}s currently
      * in use by this event listener.
      */
-    public Collection getEventFilters();
+    public Collection<EventFilter> getEventFilters();
 }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/ObservationManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/ObservationManagerImpl.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/ObservationManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/observation/ObservationManagerImpl.java Fri Jul  3 08:39:57 2009
@@ -19,12 +19,10 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
 import javax.jcr.RepositoryException;
-import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.observation.EventJournal;
 import javax.jcr.observation.EventListener;
 import javax.jcr.observation.EventListenerIterator;
@@ -37,6 +35,7 @@
 import org.apache.jackrabbit.spi.EventFilter;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.Event;
 import org.apache.jackrabbit.spi.commons.conversion.NameException;
 import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
 import org.slf4j.Logger;
@@ -71,21 +70,22 @@
     /**
      * Live mapping of <code>EventListener</code> to <code>EventFilter</code>.
      */
-    private final Map subscriptions = new HashMap();
+    private final Map<EventListener, EventFilter> subscriptions = new HashMap<EventListener, EventFilter>();
 
     /**
      * A read only mapping of <code>EventListener</code> to <code>EventFilter</code>.
      */
-    private Map readOnlySubscriptions;
+    private Map<EventListener, EventFilter> readOnlySubscriptions;
 
     /**
      * Creates a new observation manager for <code>session</code>.
+     *
      * @param wspManager the WorkspaceManager.
-     * @param resolver
+     * @param resolver   the name path resolver for this session.
      * @param ntRegistry The <code>NodeTypeRegistry</code> of the session.
-     * @param valueFactory
      */
-    public ObservationManagerImpl(WorkspaceManager wspManager, NamePathResolver resolver,
+    public ObservationManagerImpl(WorkspaceManager wspManager,
+                                  NamePathResolver resolver,
                                   NodeTypeRegistry ntRegistry) {
         this.wspManager = wspManager;
         this.resolver = resolver;
@@ -102,33 +102,8 @@
                                  String[] uuids,
                                  String[] nodeTypeNames,
                                  boolean noLocal) throws RepositoryException {
-        Path path;
-        try {
-            path = resolver.getQPath(absPath).getCanonicalPath();
-        } catch (NameException e) {
-            throw new RepositoryException("Malformed path: " + absPath);
-        }
-
-        // create NodeType instances from names
-        Name[] qNodeTypeNames;
-        if (nodeTypeNames == null) {
-            qNodeTypeNames = null;
-        } else {
-            try {
-                qNodeTypeNames = new Name[nodeTypeNames.length];
-                for (int i = 0; i < nodeTypeNames.length; i++) {
-                    Name ntName = resolver.getQName(nodeTypeNames[i]);
-                    if (!ntRegistry.isRegistered(ntName)) {
-                        throw new RepositoryException("unknown node type: " + nodeTypeNames[i]);
-                    }
-                    qNodeTypeNames[i] = ntName;
-                }
-            } catch (NameException e) {
-                throw new RepositoryException(e.getMessage());
-            }
-        }
-
-        EventFilter filter = wspManager.createEventFilter(eventTypes, path, isDeep, uuids, qNodeTypeNames, noLocal);
+        EventFilter filter = createEventFilter(eventTypes, absPath,
+                isDeep, uuids, nodeTypeNames, noLocal);
         synchronized (subscriptions) {
             subscriptions.put(listener, filter);
             readOnlySubscriptions = null;
@@ -173,15 +148,18 @@
      * @see javax.jcr.observation.ObservationManager#getEventJournal()
      */
     public EventJournal getEventJournal() throws RepositoryException {
-        // TODO
-        throw new UnsupportedRepositoryOperationException("JCR-2108");
+        return getEventJournal(Event.ALL_TYPES, "/", true, null, null);
     }
 
+    /**
+     * @see javax.jcr.observation.ObservationManager#getEventJournal(int, String, boolean, String[], String[])
+     */
     public EventJournal getEventJournal(
             int eventTypes, String absPath, boolean isDeep,
             String[] uuid, String[] nodeTypeName)
             throws RepositoryException {
-        throw new UnsupportedRepositoryOperationException("JCR-2108");
+        EventFilter filter = createEventFilter(eventTypes, absPath, isDeep, uuid, nodeTypeName, false);
+        return new EventJournalImpl(wspManager, filter, resolver);
     }
 
     /**
@@ -193,8 +171,8 @@
 
     //-----------------------< InternalEventListener >--------------------------
 
-    public Collection getEventFilters() {
-        List filters = new ArrayList();
+    public Collection<EventFilter> getEventFilters() {
+        List<EventFilter> filters = new ArrayList<EventFilter>();
         synchronized (subscriptions) {
             ensureReadOnlyMap();
             filters.addAll(readOnlySubscriptions.values());
@@ -204,16 +182,17 @@
 
     public void onEvent(EventBundle eventBundle) {
         // get active listeners
-        Map activeListeners;
+        Map<EventListener, EventFilter> activeListeners;
         synchronized (subscriptions) {
             ensureReadOnlyMap();
             activeListeners = readOnlySubscriptions;
         }
-        for (Iterator it = activeListeners.entrySet().iterator(); it.hasNext(); ) {
-            Map.Entry entry = (Map.Entry) it.next();
-            EventListener listener = (EventListener) entry.getKey();
-            EventFilter filter = (EventFilter) entry.getValue();
-            FilteredEventIterator eventIter = new FilteredEventIterator(eventBundle, filter, resolver, wspManager.getIdFactory());
+        for (Map.Entry<EventListener, EventFilter> entry : activeListeners.entrySet()) {
+            EventListener listener = entry.getKey();
+            EventFilter filter = entry.getValue();
+            FilteredEventIterator eventIter = new FilteredEventIterator(
+                    eventBundle.getEvents(), eventBundle.isLocal(), filter,
+                    resolver, wspManager.getIdFactory());
             if (eventIter.hasNext()) {
                 try {
                     listener.onEvent(eventIter);
@@ -235,8 +214,58 @@
      */
     private void ensureReadOnlyMap() {
         if (readOnlySubscriptions == null) {
-            readOnlySubscriptions = new HashMap(subscriptions);
+            readOnlySubscriptions = new HashMap<EventListener, EventFilter>(subscriptions);
         }
     }
 
+    /**
+     * Creates an SPI event filter from the given list of constraints.
+     *
+     * @param eventTypes    the event types.
+     * @param absPath       an absolute path.
+     * @param isDeep        whether to include events for descendant items of
+     *                      the node at absPath.
+     * @param uuids         uuid filters.
+     * @param nodeTypeNames node type filters.
+     * @param noLocal       whether to exclude changes from the local session.
+     * @return the SPI event filter instance.
+     * @throws RepositoryException if an error occurs while creating the event
+     *                             filter.
+     */
+    private EventFilter createEventFilter(int eventTypes,
+                                          String absPath,
+                                          boolean isDeep,
+                                          String[] uuids,
+                                          String[] nodeTypeNames,
+                                          boolean noLocal)
+            throws RepositoryException {
+        Path path;
+        try {
+            path = resolver.getQPath(absPath).getCanonicalPath();
+        } catch (NameException e) {
+            throw new RepositoryException("Malformed path: " + absPath);
+        }
+
+        // create NodeType instances from names
+        Name[] qNodeTypeNames;
+        if (nodeTypeNames == null) {
+            qNodeTypeNames = null;
+        } else {
+            try {
+                qNodeTypeNames = new Name[nodeTypeNames.length];
+                for (int i = 0; i < nodeTypeNames.length; i++) {
+                    Name ntName = resolver.getQName(nodeTypeNames[i]);
+                    if (!ntRegistry.isRegistered(ntName)) {
+                        throw new RepositoryException("unknown node type: " + nodeTypeNames[i]);
+                    }
+                    qNodeTypeNames[i] = ntName;
+                }
+            } catch (NameException e) {
+                throw new RepositoryException(e.getMessage());
+            }
+        }
+
+        return wspManager.createEventFilter(eventTypes, path, isDeep,
+                uuids, qNodeTypeNames, noLocal);
+    }
 }

Modified: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AbstractReadableRepositoryService.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AbstractReadableRepositoryService.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AbstractReadableRepositoryService.java (original)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AbstractReadableRepositoryService.java Fri Jul  3 08:39:57 2009
@@ -726,6 +726,15 @@
     /**
      * @throws UnsupportedRepositoryOperationException always.
      */
+    public EventBundle getEvents(SessionInfo sessionInfo, EventFilter filter,
+                                   long after) throws
+            RepositoryException, UnsupportedRepositoryOperationException {
+        throw new UnsupportedRepositoryOperationException();
+    }
+
+    /**
+     * @throws UnsupportedRepositoryOperationException always.
+     */
     public void dispose(Subscription subscription) throws RepositoryException {
         throw new UnsupportedRepositoryOperationException();
     }

Modified: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventBundleImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventBundleImpl.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventBundleImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/EventBundleImpl.java Fri Jul  3 08:39:57 2009
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.spi.commons;
 
 import org.apache.jackrabbit.spi.EventBundle;
+import org.apache.jackrabbit.spi.Event;
 
 import java.io.Serializable;
 import java.util.Collection;
@@ -35,7 +36,7 @@
     /**
      * The events in this bundle.
      */
-    private final Collection events;
+    private final Collection<Event> events;
 
     /**
      * Creates a new event bundle with <code>events</code>.
@@ -43,7 +44,7 @@
      * @param events   the events for this bundle.
      * @param isLocal  if this events were created due to a local change.
      */
-    public EventBundleImpl(Collection events, boolean isLocal) {
+    public EventBundleImpl(Collection<Event> events, boolean isLocal) {
         this.events = events;
         this.isLocal = isLocal;
     }
@@ -51,7 +52,7 @@
     /**
      * {@inheritDoc}
      */
-    public Iterator getEvents() {
+    public Iterator<Event> getEvents() {
         return events.iterator();
     }
 
@@ -61,4 +62,13 @@
     public boolean isLocal() {
         return isLocal;
     }
+
+    //-----------------------------< Iterable >---------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<Event> iterator() {
+        return getEvents();
+    }
 }

Modified: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/logging/RepositoryServiceLogger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/logging/RepositoryServiceLogger.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/logging/RepositoryServiceLogger.java (original)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/logging/RepositoryServiceLogger.java Fri Jul  3 08:39:57 2009
@@ -615,6 +615,18 @@
         return result;
     }
 
+    public EventBundle getEvents(final SessionInfo sessionInfo,
+                                 final EventFilter filter,
+                                 final long after) throws RepositoryException,
+            UnsupportedRepositoryOperationException {
+        return (EventBundle) execute(new Callable() {
+            public Object call() throws RepositoryException {
+                return service.getEvents(sessionInfo, filter, after);
+            }
+        }, "getEvents(SessionInfo, EventFilter, long)",
+                new Object[]{unwrap(sessionInfo), filter, after});
+    }
+
     public void updateEventFilters(final Subscription subscription, final EventFilter[] eventFilters)
             throws RepositoryException {
 

Modified: jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/EventBundle.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/EventBundle.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/EventBundle.java (original)
+++ jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/EventBundle.java Fri Jul  3 08:39:57 2009
@@ -24,7 +24,7 @@
  * <code>EventIterator</code> an <code>EventBundle</code> allows to retrieve
  * the events multiple times using the {@link #getEvents} method.
  */
-public interface EventBundle {
+public interface EventBundle extends Iterable<Event> {
 
     /**
      * Returns the events of this bundle.

Modified: jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java (original)
+++ jackrabbit/trunk/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java Fri Jul  3 08:39:57 2009
@@ -1031,6 +1031,29 @@
             throws RepositoryException, InterruptedException;
 
     /**
+     * Returns events from the <code>EventJournal</code> after a given point in
+     * time. The returned event bundle may only contain events up to a given
+     * time. In order to retrieve more events a client must call this method
+     * again with the timestamp from the last event bundle. An empty bundle
+     * indicates that there are no more events.
+     *
+     * @param sessionInfo the session info.
+     * @param filter      the event filter to apply. Please note: the
+     *                    <code>noLocal</code> flag is ignored.
+     * @param after       retrieve events that occurred after the given
+     *                    timestamp.
+     * @return the event bundle.
+     * @throws RepositoryException if an error occurs.
+     * @throws UnsupportedRepositoryOperationException
+     *                             if the underlying implementation does not
+     *                             support event journaling.
+     */
+    public EventBundle getEvents(SessionInfo sessionInfo,
+                                 EventFilter filter,
+                                 long after)
+            throws RepositoryException, UnsupportedRepositoryOperationException;
+
+    /**
      * Indicates that the passed subscription is no longer needed.
      * <p/>
      * <b>Note on thread-safety:</b> it is permissible to call this methods

Modified: jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java Fri Jul  3 08:39:57 2009
@@ -1760,6 +1760,16 @@
     }
 
     /**
+     * @see RepositoryService#getEvents(SessionInfo, EventFilter,long) 
+     */
+    public EventBundle getEvents(SessionInfo sessionInfo, EventFilter filter,
+                                   long after) throws
+            RepositoryException, UnsupportedRepositoryOperationException {
+        // TODO
+        throw new UnsupportedRepositoryOperationException();
+    }
+
+    /**
      * @see RepositoryService#createSubscription(SessionInfo, EventFilter[])
      */
     public Subscription createSubscription(SessionInfo sessionInfo,

Modified: jackrabbit/trunk/jackrabbit-spi2jcr/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2jcr/pom.xml?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2jcr/pom.xml (original)
+++ jackrabbit/trunk/jackrabbit-spi2jcr/pom.xml Fri Jul  3 08:39:57 2009
@@ -69,7 +69,6 @@
               <value>
                 org.apache.jackrabbit.jcr2spi.name.NamespaceRegistryTest#testReRegisteredNamespaceVisibility
                 org.apache.jackrabbit.jcr2spi.name.NamespaceRegistryTest#testRegisteredNamespaceVisibility
-                org.apache.jackrabbit.test.api.observation.EventJournalTest
                 org.apache.jackrabbit.test.api.ShareableNodeTest
                 org.apache.jackrabbit.test.api.version.simple
                 org.apache.jackrabbit.test.api.NodeReadMethodsTest#testGetPropertiesNamePatternArray

Added: 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=790826&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventFactory.java (added)
+++ jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventFactory.java Fri Jul  3 08:39:57 2009
@@ -0,0 +1,156 @@
+/*
+ * 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.spi2jcr;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.PropertyType;
+import javax.jcr.Session;
+import javax.jcr.NamespaceException;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.jackrabbit.spi.Event;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.QValue;
+import org.apache.jackrabbit.spi.IdFactory;
+import org.apache.jackrabbit.spi.QValueFactory;
+import org.apache.jackrabbit.spi.commons.value.ValueFormat;
+import org.apache.jackrabbit.spi.commons.EventImpl;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.spi.commons.conversion.NameException;
+import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
+
+/**
+ * <code>EventFactory</code> implements a factory for SPI Event instances.
+ */
+class EventFactory {
+
+    private final Session session;
+
+    private final NamePathResolver resolver;
+
+    private final IdFactory idFactory;
+
+    private final QValueFactory qValueFactory;
+
+    public EventFactory(Session session,
+                        NamePathResolver resolver,
+                        IdFactory idFactory,
+                        QValueFactory qValueFactory) {
+        this.session = session;
+        this.resolver = resolver;
+        this.idFactory = idFactory;
+        this.qValueFactory = qValueFactory;
+    }
+
+    public Event fromJCREvent(javax.jcr.observation.Event e)
+            throws RepositoryException {
+        Path p = resolver.getQPath(e.getPath());
+        Path parent = p.getAncestor(1);
+        int type = e.getType();
+
+        NodeId parentId = idFactory.createNodeId((String) null, parent);
+        String identifier = e.getIdentifier();
+        ItemId itemId;
+        Node node = null;
+        if (identifier != null) {
+            itemId = idFactory.fromJcrIdentifier(e.getIdentifier());
+            try {
+                node = session.getItem(e.getPath()).getParent();
+            } catch (RepositoryException re) {
+                // ignore. TODO improve
+            }
+        } else {
+            switch (type) {
+                case Event.NODE_ADDED:
+                case Event.NODE_MOVED:
+                    node = session.getItem(e.getPath()).getParent();
+                case Event.NODE_REMOVED:
+                    itemId = idFactory.createNodeId((String) null, p);
+                    break;
+                case Event.PROPERTY_ADDED:
+                case Event.PROPERTY_CHANGED:
+                    node = session.getItem(e.getPath()).getParent();
+                case Event.PROPERTY_REMOVED:
+                    itemId = idFactory.createPropertyId(parentId,
+                            p.getNameElement().getName());
+                    break;
+                case Event.PERSIST:
+                default:
+                    itemId = null;
+            }
+        }
+
+        Name nodeTypeName = null;
+        Name[] mixinTypes = new Name[0];
+        if (node != null) {
+            try {
+                parentId = idFactory.createNodeId(node.getUUID(), null);
+            } catch (UnsupportedRepositoryOperationException ex) {
+                // not referenceable
+            }
+            nodeTypeName = resolver.getQName(node.getPrimaryNodeType().getName());
+            mixinTypes = getNodeTypeNames(node.getMixinNodeTypes(), resolver);
+        }
+        Map<Name, QValue> info = new HashMap<Name, QValue>();
+        Map<String, Object> jcrInfo = e.getInfo();
+        for (Map.Entry<String, Object> entry : jcrInfo.entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+
+            Name name = resolver.getQName(key);
+            if (value != null) {
+                // event information is generated for NODE_MOVED only in which
+                // case all values are of type PATH.
+                QValue v = ValueFormat.getQValue(value.toString(), PropertyType.PATH, resolver, qValueFactory);
+                info.put(name, v);
+            } else {
+                info.put(name, null);
+            }
+        }
+        return new EventImpl(e.getType(), p, itemId, parentId, nodeTypeName,
+                mixinTypes, e.getUserID(), e.getUserData(), e.getDate(), info);
+    }
+
+    /**
+     * Returns the names of the passed node types using the namespace resolver
+     * to parse the names.
+     *
+     * @param nt       the node types
+     * @param resolver the name resolver.
+     * @return the names of the node types.
+     * @throws NameException      if a node type returns an illegal name.
+     * @throws NamespaceException if the name of a node type contains a prefix
+     *                            that is not known to <code>resolver</code>.
+     */
+    private static Name[] getNodeTypeNames(NodeType[] nt, NameResolver resolver)
+            throws NameException, NamespaceException {
+        Name[] names = new Name[nt.length];
+        for (int i = 0; i < nt.length; i++) {
+            Name ntName = resolver.getQName(nt[i].getName());
+            names[i] = ntName;
+        }
+        return names;
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventSubscription.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventSubscription.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventSubscription.java (original)
+++ jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/EventSubscription.java Fri Jul  3 08:39:57 2009
@@ -19,40 +19,22 @@
 import org.apache.jackrabbit.spi.EventBundle;
 import org.apache.jackrabbit.spi.EventFilter;
 import org.apache.jackrabbit.spi.Event;
-import org.apache.jackrabbit.spi.ItemId;
-import org.apache.jackrabbit.spi.NodeId;
 import org.apache.jackrabbit.spi.IdFactory;
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.Subscription;
-import org.apache.jackrabbit.spi.QValue;
 import org.apache.jackrabbit.spi.QValueFactory;
-import org.apache.jackrabbit.spi.commons.EventImpl;
 import org.apache.jackrabbit.spi.commons.EventBundleImpl;
 import org.apache.jackrabbit.spi.commons.EventFilterImpl;
-import org.apache.jackrabbit.spi.commons.value.ValueFormat;
-import org.apache.jackrabbit.spi.commons.conversion.NameException;
-import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
-import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
 import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
 
 import javax.jcr.observation.EventListener;
 import javax.jcr.observation.ObservationManager;
-import javax.jcr.Session;
-import javax.jcr.Node;
-import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.NamespaceException;
 import javax.jcr.RepositoryException;
-import javax.jcr.PropertyType;
-import javax.jcr.nodetype.NodeType;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Iterator;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * <code>EventSubscription</code> listens for JCR events and creates SPI event
@@ -76,37 +58,33 @@
             | javax.jcr.observation.Event.NODE_MOVED
             | javax.jcr.observation.Event.PERSIST;
 
-    private final List eventBundles = new ArrayList();
-
-    private final IdFactory idFactory;
-
-    private final QValueFactory qValueFactory;
+    private final List<EventBundle> eventBundles = new ArrayList<EventBundle>();
 
     private final SessionInfoImpl sessionInfo;
 
     /**
      * Current list of filters. Copy on write is performed on this list.
      */
-    private volatile List filters;
+    private volatile List<EventFilter> filters;
 
     /**
-     * The resolver of the underlying session.
+     * Set to <code>true</code> if this subscription has been disposed.
      */
-    private final NamePathResolver resolver;
+    private volatile boolean disposed = false;
 
     /**
-     * Set to <code>true</code> if this subscription has been disposed.
+     * The event factory.
      */
-    private volatile boolean disposed = false;
+    private final EventFactory eventFactory;
 
     /**
      * Creates a new subscription for the passed session.
      *
-     * @param idFactory   the id factory.
-     * @param qValueFactory
-     * @param sessionInfo the session info.
-     * @param filters     the filters that should be applied to the generated
-     *                    events.
+     * @param idFactory     the id factory.
+     * @param qValueFactory the QValueFactory.
+     * @param sessionInfo   the session info.
+     * @param filters       the filters that should be applied to the generated
+     *                      events.
      * @throws RepositoryException if an error occurs while an event listener is
      *                             registered with the session.
      */
@@ -114,14 +92,12 @@
                       QValueFactory qValueFactory,
                       SessionInfoImpl sessionInfo,
                       EventFilter[] filters) throws RepositoryException {
-        this.idFactory = idFactory;
-        this.qValueFactory = qValueFactory;
         this.sessionInfo = sessionInfo;
-        this.resolver = sessionInfo.getNamePathResolver();
+        this.eventFactory = new EventFactory(sessionInfo.getSession(),
+                sessionInfo.getNamePathResolver(), idFactory, qValueFactory);
         setFilters(filters);
         ObservationManager obsMgr = sessionInfo.getSession().getWorkspace().getObservationManager();
-        obsMgr.addEventListener(this, EventSubscription.ALL_EVENTS,
-                "/", true, null, null, true);
+        obsMgr.addEventListener(this, EventSubscription.ALL_EVENTS, "/", true, null, null, true);
     }
 
     /**
@@ -140,12 +116,12 @@
      */
     void setFilters(EventFilter[] filters) throws RepositoryException {
         // check type
-        for (int i = 0; i < filters.length; i++) {
-            if (!(filters[i] instanceof EventFilterImpl)) {
+        for (EventFilter filter : filters) {
+            if (!(filter instanceof EventFilterImpl)) {
                 throw new RepositoryException("Unknown filter implementation");
             }
         }
-        List tmp = new ArrayList(Arrays.asList(filters));
+        List<EventFilter> tmp = new ArrayList<EventFilter>(Arrays.asList(filters));
         this.filters = Collections.unmodifiableList(tmp);
 
     }
@@ -234,76 +210,10 @@
         if (disposed) {
             return;
         }
-        List spiEvents = new ArrayList();
+        List<Event> spiEvents = new ArrayList<Event>();
         while (events.hasNext()) {
             try {
-                Session session = sessionInfo.getSession();
-                javax.jcr.observation.Event e = events.nextEvent();
-                Path p = resolver.getQPath(e.getPath());
-                Path parent = p.getAncestor(1);
-                int type = e.getType();
-
-                NodeId parentId = idFactory.createNodeId((String) null, parent);
-                String identifier = e.getIdentifier();
-                ItemId itemId;
-                Node node = null;
-                if (identifier != null) {
-                    itemId = idFactory.fromJcrIdentifier(e.getIdentifier());
-                    try {
-                        node = session.getItem(e.getPath()).getParent();
-                    } catch (RepositoryException re) {
-                        // ignore. TODO improve
-                    }
-                } else {
-                    switch (type) {
-                        case Event.NODE_ADDED:
-                        case Event.NODE_MOVED:
-                            node = session.getItem(e.getPath()).getParent();
-                        case Event.NODE_REMOVED:
-                            itemId = idFactory.createNodeId((String) null, p);
-                            break;
-                        case Event.PROPERTY_ADDED:
-                        case Event.PROPERTY_CHANGED:
-                            node = session.getItem(e.getPath()).getParent();
-                        case Event.PROPERTY_REMOVED:
-                            itemId = idFactory.createPropertyId(parentId,
-                                    p.getNameElement().getName());
-                            break;
-                        case Event.PERSIST:
-                        default:
-                            itemId = null;
-                    }
-                }
-
-                Name nodeTypeName = null;
-                Name[] mixinTypes = new Name[0];
-                if (node != null) {
-                    try {
-                        parentId = idFactory.createNodeId(node.getUUID(), null);
-                    } catch (UnsupportedRepositoryOperationException ex) {
-                        // not referenceable
-                    }
-                    nodeTypeName = resolver.getQName(node.getPrimaryNodeType().getName());
-                    mixinTypes = getNodeTypeNames(node.getMixinNodeTypes(), resolver);
-                }
-                Map<Name, QValue> info = new HashMap();
-                Map jcrInfo = e.getInfo();
-                for (Iterator it = jcrInfo.keySet().iterator(); it.hasNext();) {
-                    String key = it.next().toString();
-                    Object value = jcrInfo.get(key);
-
-                    Name name = resolver.getQName(key);
-                    if (value != null) {
-                        // event information is generated for NODE_MOVED only in which
-                        // case all values are of type PATH.
-                        QValue v = ValueFormat.getQValue(value.toString(), PropertyType.PATH, resolver, qValueFactory);
-                        info.put(name, v);
-                    } else {
-                        info.put(name, null);
-                    }
-                }
-                Event spiEvent = new EventImpl(e.getType(), p, itemId, parentId,
-                        nodeTypeName, mixinTypes, e.getUserID(), e.getUserData(), e.getDate(), info);
+                Event spiEvent = eventFactory.fromJCREvent(events.nextEvent());
                 spiEvents.add(spiEvent);
             } catch (Exception ex) {
                 log.warn("Unable to create SPI Event: " + ex);
@@ -315,25 +225,4 @@
             eventBundles.notify();
         }
     }
-
-    /**
-     * Returns the names of the passed node types using the namespace
-     * resolver to parse the names.
-     *
-     * @param nt         the node types
-     * @param resolver
-     * @return the names of the node types.
-     * @throws NameException if a node type returns an illegal name.
-     * @throws NamespaceException if the name of a node type contains a
-     * prefix that is not known to <code>resolver</code>.
-     */
-    private static Name[] getNodeTypeNames(NodeType[] nt, NameResolver resolver)
-            throws NameException, NamespaceException {
-        Name[] names = new Name[nt.length];
-        for (int i = 0; i < nt.length; i++) {
-            Name ntName = resolver.getQName(nt[i].getName());
-            names[i] = ntName;
-        }
-        return names;
-    }
 }

Modified: jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java Fri Jul  3 08:39:57 2009
@@ -39,7 +39,9 @@
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.Subscription;
 import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.apache.jackrabbit.spi.Event;
 import org.apache.jackrabbit.spi.commons.EventFilterImpl;
+import org.apache.jackrabbit.spi.commons.EventBundleImpl;
 import org.apache.jackrabbit.spi.commons.nodetype.NodeTypeDefinitionImpl;
 import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
 import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
@@ -83,6 +85,7 @@
 import javax.jcr.util.TraversingItemVisitor;
 import javax.jcr.observation.ObservationManager;
 import javax.jcr.observation.EventListener;
+import javax.jcr.observation.EventJournal;
 import javax.jcr.query.InvalidQueryException;
 import javax.jcr.query.QueryManager;
 import javax.jcr.query.Query;
@@ -1100,6 +1103,37 @@
     /**
      * {@inheritDoc}
      */
+    public EventBundle getEvents(SessionInfo sessionInfo,
+                                   EventFilter filter,
+                                   long after)
+            throws RepositoryException, UnsupportedRepositoryOperationException {
+        SessionInfoImpl sInfo = getSessionInfoImpl(sessionInfo);
+        EventJournal journal = sInfo.getSession().getWorkspace().getObservationManager().getEventJournal();
+        if (journal == null) {
+            throw new UnsupportedRepositoryOperationException();
+        }
+        EventFactory factory = new EventFactory(sInfo.getSession(),
+                sInfo.getNamePathResolver(), idFactory, qValueFactory);
+        journal.skipTo(after);
+        List<Event> events = new ArrayList<Event>();
+        int batchSize = 1024;
+        boolean distinctDates = true;
+        long lastDate = Long.MIN_VALUE;
+        while (journal.hasNext() && (batchSize > 0 || !distinctDates)) {
+            Event e = factory.fromJCREvent(journal.nextEvent());
+            if (filter.accept(e, false)) {
+                distinctDates = lastDate != e.getDate();
+                lastDate = e.getDate();
+                events.add(e);
+                batchSize--;
+            }
+        }
+        return new EventBundleImpl(events, false);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public void updateEventFilters(Subscription subscription,
                                    EventFilter[] filters)
             throws RepositoryException {

Added: jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repository.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repository.xml?rev=790826&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repository.xml (added)
+++ jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repository.xml Fri Jul  3 08:39:57 2009
@@ -0,0 +1,146 @@
+<?xml version="1.0"?>
+<!--
+   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.
+-->
+<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
+                            "http://jackrabbit.apache.org/dtd/repository-1.6.dtd">
+<!-- Example Repository Configuration File
+     Used by
+     - org.apache.jackrabbit.core.config.RepositoryConfigTest.java
+     -
+-->
+<Repository>
+    <Cluster id="node1">
+        <Journal class="org.apache.jackrabbit.core.journal.FileJournal">
+            <param name="revision" value="${rep.home}/repository/revision"/>
+            <param name="directory" value="${rep.home}/repository/journal"/>
+        </Journal>
+    </Cluster>
+
+    <!--
+        virtual file system where the repository stores global state
+        (e.g. registered namespaces, custom node types, etc.)
+    -->
+    <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+        <param name="path" value="${rep.home}/repository"/>
+    </FileSystem>
+
+    <!--
+        security configuration
+    -->
+    <Security appName="Jackrabbit">
+        <!--
+            security manager:
+            class: FQN of class implementing the JackrabbitSecurityManager interface
+        -->
+        <SecurityManager class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager" workspaceName="security">
+            <!--
+            workspace access:
+            class: FQN of class implementing the WorkspaceAccessManager interface
+            -->
+            <!-- <WorkspaceAccessManager class="..."/> -->
+            <!-- <param name="config" value="${rep.home}/security.xml"/> -->
+        </SecurityManager>
+
+        <!--
+            access manager:
+            class: FQN of class implementing the AccessManager interface
+        -->
+        <AccessManager class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
+            <!-- <param name="config" value="${rep.home}/access.xml"/> -->
+        </AccessManager>
+
+        <LoginModule class="org.apache.jackrabbit.core.security.simple.SimpleLoginModule">
+           <!-- 
+              anonymous user name ('anonymous' is the default value)
+            -->
+           <param name="anonymousId" value="anonymous"/>
+           <!--
+              administrator user id (default value if param is missing is 'admin')
+            -->
+           <param name="adminId" value="admin"/>
+        </LoginModule>
+    </Security>
+
+    <!--
+        location of workspaces root directory and name of default workspace
+    -->
+    <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
+    <!--
+        workspace configuration template:
+        used to create the initial workspace if there's no workspace yet
+    -->
+    <Workspace name="${wsp.name}">
+        <!--
+            virtual file system of the workspace:
+            class: FQN of class implementing the FileSystem interface
+        -->
+        <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+            <param name="path" value="${wsp.home}"/>
+        </FileSystem>
+        <!--
+            persistence manager of the workspace:
+            class: FQN of class implementing the PersistenceManager interface
+        -->
+        <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
+          <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
+          <param name="schemaObjectPrefix" value="${wsp.name}_"/>
+        </PersistenceManager>
+        <!--
+            Search index and the file system it uses.
+            class: FQN of class implementing the QueryHandler interface
+        -->
+        <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+            <param name="path" value="${wsp.home}/index"/>
+            <param name="extractorPoolSize" value="2"/>
+            <param name="supportHighlighting" value="true"/>
+        </SearchIndex>
+    </Workspace>
+
+    <!--
+        Configures the versioning
+    -->
+    <Versioning rootPath="${rep.home}/version">
+        <!--
+            Configures the filesystem to use for versioning for the respective
+            persistence manager
+        -->
+        <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+            <param name="path" value="${rep.home}/version" />
+        </FileSystem>
+
+        <!--
+            Configures the persistence manager to be used for persisting version state.
+            Please note that the current versioning implementation is based on
+            a 'normal' persistence manager, but this could change in future
+            implementations.
+        -->
+        <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
+          <param name="url" value="jdbc:derby:${rep.home}/version/db;create=true"/>
+          <param name="schemaObjectPrefix" value="version_"/>
+        </PersistenceManager>
+    </Versioning>
+
+    <!--
+        Search index for content that is shared repository wide
+        (/jcr:system tree, contains mainly versions)
+    -->
+    <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+        <param name="path" value="${rep.home}/repository/index"/>
+        <param name="extractorPoolSize" value="2"/>
+        <param name="supportHighlighting" value="true"/>
+    </SearchIndex>
+</Repository>

Propchange: jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repository.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repositoryStubImpl.properties
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repositoryStubImpl.properties?rev=790826&r1=790825&r2=790826&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repositoryStubImpl.properties (original)
+++ jackrabbit/trunk/jackrabbit-spi2jcr/src/test/resources/repositoryStubImpl.properties Fri Jul  3 08:39:57 2009
@@ -22,6 +22,9 @@
 # Use this stub implementation for testing Jackrabbit-Core without intermediate SPI
 # javax.jcr.tck.repository_stub_impl=org.apache.jackrabbit.spi2jcr.DefaultRepositoryStub
 
+# the repository configuration
+org.apache.jackrabbit.repository.config=target/test-classes/repository.xml
+
 # alternative workspace used for update tests etc.
 org.apache.jackrabbit.jcr2spi.workspace2.name=test
 



Mime
View raw message