You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2005/02/26 21:51:51 UTC

svn commit: r155583 [1/2] - in incubator/jackrabbit/trunk: applications/test/ src/java/org/apache/jackrabbit/core/ src/java/org/apache/jackrabbit/core/observation/ src/java/org/apache/jackrabbit/core/state/ src/java/org/apache/jackrabbit/core/version/persistence/ src/test/org/apache/jackrabbit/test/ src/test/org/apache/jackrabbit/test/api/observation/ src/test/org/apache/jackrabbit/test/api/version/

Author: mreutegg
Date: Sat Feb 26 12:51:46 2005
New Revision: 155583

URL: http://svn.apache.org/viewcvs?view=rev&rev=155583
Log:
- Redesigned observation to also include workspace modifications
- Extended observation tests and moved them into the api.observation package

Added:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AbstractObservationTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AddEventListenerTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/EventIteratorTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/EventResult.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/EventTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/GetRegisteredEventListenersTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/LockingTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeAddedTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeMovedTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeRemovedTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/PropertyAddedTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/PropertyChangedTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/PropertyRemovedTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/WorkspaceOperationTest.java   (with props)
Modified:
    incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/WorkspaceImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventConsumer.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventFilter.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventState.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerFactory.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/NativePVM.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/TestAll.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/version/AbstractVersionTest.java

Modified: incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties (original)
+++ incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties Sat Feb 26 12:51:46 2005
@@ -21,10 +21,10 @@
 # global test configuration
 javax.jcr.tck.testroot=/testroot
 javax.jcr.tck.nodetype=nt:unstructured
-javax.jcr.tck.nodename1=foo
-javax.jcr.tck.nodename2=bar
-javax.jcr.tck.nodename3=foobar
-javax.jcr.tck.nodename4=myname
+javax.jcr.tck.nodename1=node1
+javax.jcr.tck.nodename2=node2
+javax.jcr.tck.nodename3=node3
+javax.jcr.tck.nodename4=node4
 javax.jcr.tck.propertyname1=prop1
 javax.jcr.tck.propertyname2=prop2
 javax.jcr.tck.workspacename=test

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java Sat Feb 26 12:51:46 2005
@@ -289,7 +289,11 @@
                     // to the same child node, always use the first one
                     NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) entries.get(0);
                     // add to path
-                    builder.addFirst(entry.getName(), entry.getIndex());
+                    if (entry.getIndex() == 1) {
+                        builder.addFirst(entry.getName());
+                    } else {
+                        builder.addFirst(entry.getName(), entry.getIndex());
+                    }
                 } else {
                     PropertyState propState = (PropertyState) state;
                     QName name = propState.getName();
@@ -538,7 +542,11 @@
                     // get a path builder clone from the tail of the queue
                     Path.PathBuilder pb = (Path.PathBuilder) queue.removeLast();
                     // add entry to path
-                    pb.addFirst(entry.getName(), entry.getIndex());
+                    if (entry.getIndex() == 1) {
+                        pb.addFirst(entry.getName());
+                    } else {
+                        pb.addFirst(entry.getName(), entry.getIndex());
+                    }
 
                     // recurse
                     recursiveBuildPaths(new NodeId(parentUUID), pb, builders, includeZombies);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java Sat Feb 26 12:51:46 2005
@@ -20,8 +20,6 @@
 import org.apache.jackrabbit.core.nodetype.NodeDefImpl;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
 import org.apache.jackrabbit.core.nodetype.PropertyDefImpl;
-import org.apache.jackrabbit.core.observation.EventStateCollection;
-import org.apache.jackrabbit.core.observation.ObservationManagerFactory;
 import org.apache.jackrabbit.core.security.AccessManager;
 import org.apache.jackrabbit.core.state.ItemState;
 import org.apache.jackrabbit.core.state.ItemStateException;
@@ -1157,13 +1155,6 @@
                  */
                 validateTransientItems(dirty.iterator());
 
-                WorkspaceImpl wsp = (WorkspaceImpl) session.getWorkspace();
-
-                // list of events that are generated by saved changes
-                ObservationManagerFactory obsFactory = rep.getObservationManagerFactory(wsp.getName());
-                EventStateCollection events = obsFactory.createEventStateCollection(session,
-                        session.getItemStateManager(), session.getHierarchyManager());
-
                 /**
                  * build list of transient descendents in the attic
                  * (i.e. those marked as 'removed')
@@ -1178,17 +1169,6 @@
                 Collection dirtyRefs =
                         checkReferences(dirty.iterator(), removed.iterator());
 
-                /**
-                 * create event states for the affected item states and
-                 * prepare them for event dispatch (this step is necessary in order
-                 * to check access rights on items that will be removed)
-                 *
-                 * todo consolidate event generating and dispatching code (ideally one method call after save has succeeded)
-                 */
-                events.createEventStates(removed);
-                events.createEventStates(dirty);
-                events.prepare();
-
                 try {
                     // start the update operation
                     stateMgr.edit();
@@ -1208,6 +1188,20 @@
                     // process 'new' or 'modified' transient states
                     persistTransientItems(dirty.iterator());
 
+                    // dispose the transient states marked 'new' or 'modified'
+                    // at this point item state data is pushed down one level,
+                    // node instances are disconnected from the transient
+                    // item state and connected to the 'overlayed' item state.
+                    // transient item states must be removed now. otherwise
+                    // the session item state provider will return an orphaned
+                    // item state which is not referenced by any node instance.
+                    iter = dirty.iterator();
+                    while (iter.hasNext()) {
+                        transientState = (ItemState) iter.next();
+                        // dispose the transient state, it is no longer used
+                        stateMgr.disposeTransientItemState(transientState);
+                    }
+
                     // store the references calculated above
                     for (Iterator it = dirtyRefs.iterator(); it.hasNext();) {
                         stateMgr.store((NodeReferences) it.next());
@@ -1225,28 +1219,16 @@
                 }
 
                 // now it is safe to dispose the transient states:
-                // dispose the transient states marked 'removed'
+                // dispose the transient states marked 'removed'.
+                // item states in attic are removed after store, because
+                // the observation mechanism needs to build paths of removed
+                // items in store().
                 iter = removed.iterator();
                 while (iter.hasNext()) {
                     transientState = (ItemState) iter.next();
                     // dispose the transient state, it is no longer used
                     stateMgr.disposeTransientItemStateInAttic(transientState);
                 }
-                // dispose the transient states marked 'new' or 'modified'
-                iter = dirty.iterator();
-                while (iter.hasNext()) {
-                    transientState = (ItemState) iter.next();
-                    // dispose the transient state, it is no longer used
-                    stateMgr.disposeTransientItemState(transientState);
-                }
-
-                /**
-                 * all changes are persisted, now dispatch events;
-                 * forward this to the session to let it decide on the right
-                 * time for those events to be dispatched in case of
-                 * transactional support
-                 */
-                session.dispatch(events);
 
             } finally {
                 // turn off temporary path caching

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/WorkspaceImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/WorkspaceImpl.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/WorkspaceImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/WorkspaceImpl.java Sat Feb 26 12:51:46 2005
@@ -36,6 +36,7 @@
 import org.apache.jackrabbit.core.state.UpdatableItemStateManager;
 import org.apache.jackrabbit.core.util.uuid.UUID;
 import org.apache.jackrabbit.core.xml.ImportHandler;
+import org.apache.jackrabbit.core.observation.ObservationManagerImpl;
 import org.apache.log4j.Logger;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.InputSource;
@@ -103,7 +104,7 @@
     /**
      * The <code>ObservationManager</code> instance for this session.
      */
-    protected ObservationManager obsMgr;
+    protected ObservationManagerImpl obsMgr;
 
     /**
      * The <code>QueryManager</code> for this <code>Workspace</code>.
@@ -123,11 +124,13 @@
      * @param rep
      * @param session
      */
-    WorkspaceImpl(WorkspaceConfig wspConfig, SharedItemStateManager stateMgr,
-                  RepositoryImpl rep, SessionImpl session) {
+    WorkspaceImpl(WorkspaceConfig wspConfig,
+                  SharedItemStateManager stateMgr,
+                  RepositoryImpl rep,
+                  SessionImpl session) {
         this.wspConfig = wspConfig;
         this.rep = rep;
-        this.stateMgr = new TransactionalItemStateManager(stateMgr);
+        this.stateMgr = new TransactionalItemStateManager(stateMgr, this);
         this.hierMgr = new HierarchyManagerImpl(rep.getRootNodeUUID(),
                 this.stateMgr, session.getNamespaceResolver());
         this.session = session;
@@ -933,7 +936,16 @@
     /**
      * @see Workspace#getObservationManager
      */
-    public synchronized ObservationManager getObservationManager()
+    public ObservationManager getObservationManager()
+            throws UnsupportedRepositoryOperationException, RepositoryException {
+        return getObservationManagerImpl();
+    }
+
+    /**
+     * Returns the ObservationManagerImpl for this workspace instance.
+     * @return the ObservationManagerImpl for this workspace instance.
+     */
+    public synchronized ObservationManagerImpl getObservationManagerImpl()
             throws UnsupportedRepositoryOperationException, RepositoryException {
 
         // check state of this instance
@@ -941,7 +953,7 @@
 
         if (obsMgr == null) {
             try {
-                obsMgr = rep.getObservationManagerFactory(wspConfig.getName()).createObservationManager(session, session.getItemManager());
+                obsMgr = rep.getObservationManagerFactory(wspConfig.getName()).createObservationManager(session, session.hierMgr, session.getItemManager());
             } catch (NoSuchWorkspaceException nswe) {
                 // should never get here
                 String msg = "internal error: failed to instantiate observation manager";

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventConsumer.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventConsumer.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventConsumer.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventConsumer.java Sat Feb 26 12:51:46 2005
@@ -130,10 +130,8 @@
      * enough access rights to see the event.
      *
      * @param events the collection of {@link EventState}s.
-     * @throws RepositoryException if an error occurs while checking access
-     *                             rights on the {@link EventStateCollection}.
      */
-    void prepareEvents(EventStateCollection events) throws RepositoryException {
+    void prepareEvents(EventStateCollection events) {
         Iterator it = events.iterator();
         Set denied = null;
         while (it.hasNext()) {
@@ -151,12 +149,18 @@
                 ItemId targetId;
                 if (state.getChildUUID() == null) {
                     // target is a property
-                    targetId = new PropertyId(state.getParentUUID(), state.getChildRelPath().getElements()[0].getName());
+                    targetId = new PropertyId(state.getParentUUID(), state.getChildRelPath().getName());
                 } else {
                     // target is a node
                     targetId = new NodeId(state.getChildUUID());
                 }
-                if (!session.getAccessManager().isGranted(targetId, AccessManager.READ)) {
+                boolean granted = false;
+                try {
+                    granted = session.getAccessManager().isGranted(targetId, AccessManager.READ);
+                } catch (RepositoryException e) {
+                    log.warn("Unable to check access rights for item: " + targetId);
+                }
+                if (!granted) {
                     if (denied == null) {
                         denied = new HashSet();
                     }
@@ -186,7 +190,7 @@
                 ItemId targetId;
                 if (state.getChildUUID() == null) {
                     // target is a property
-                    targetId = new PropertyId(state.getParentUUID(), state.getChildRelPath().getElements()[0].getName());
+                    targetId = new PropertyId(state.getParentUUID(), state.getChildRelPath().getName());
                 } else {
                     // target is a node
                     targetId = new NodeId(state.getChildUUID());

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventFilter.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventFilter.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventFilter.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventFilter.java Sat Feb 26 12:51:46 2005
@@ -21,8 +21,10 @@
 import org.apache.jackrabbit.core.Path;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.log4j.Logger;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
 
 /**
  * The <code>EventFilter</code> class implements the filter logic based
@@ -30,6 +32,11 @@
  */
 class EventFilter {
 
+    /**
+     * Logger instance for this class.
+     */
+    private static final Logger log = Logger.getLogger(EventFilter.class);
+
     static final EventFilter BLOCK_ALL = new BlockAllFilter();
 
     /**
@@ -173,21 +180,11 @@
             }
         }
 
-        /*
-        Node parent = null;
-        try {
-            parent = (Node) itemMgr.getItem(new NodeId(eventState.getParentUUID()));
-        } catch (AccessDeniedException e) {
-            log.debug("Access denied for " + eventState.getParentPath());
-            return true;
-        }
-        */
-
         // check node types
         if (nodeTypes != null) {
             boolean match = false;
             for (int i = 0; i < nodeTypes.length && !match; i++) {
-                match |= eventState.getNodeType().isDerivedFrom(nodeTypes[i].getQName());
+                match |= eventState.getNodeType().equals(nodeTypes[i]) || eventState.getNodeType().isDerivedFrom(nodeTypes[i].getQName());
             }
             if (!match) {
                 return true;
@@ -196,10 +193,25 @@
 
         // finally check path
         try {
-            //parentPath = Path.create(parent.getPath(), session.getNamespaceResolver(), false);
-            boolean match = eventState.getParentPath().equals(path);
+            // the relevant path for the path filter depends on the event type
+            // for node events, the relevant path is the one returned by
+            // Event.getPath().
+            // for property events, the relevant path is the path of the
+            // node where the property belongs to.
+            Path eventPath = null;
+            if (type == Event.NODE_ADDED || type == Event.NODE_REMOVED) {
+                Path.PathElement nameElem = eventState.getChildRelPath();
+                if (nameElem.getIndex() == 0) {
+                    eventPath = Path.create(eventState.getParentPath(), nameElem.getName(), false);
+                } else {
+                    eventPath = Path.create(eventState.getParentPath(), nameElem.getName(), nameElem.getIndex(), false);
+                }
+            } else {
+                eventPath = eventState.getParentPath();
+            }
+            boolean match = eventPath.equals(path);
             if (!match && isDeep) {
-                match = eventState.getParentPath().isDescendantOf(path);
+                match = eventPath.isDescendantOf(path);
             }
 
             return !match;

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventImpl.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventImpl.java Sat Feb 26 12:51:46 2005
@@ -81,7 +81,12 @@
      */
     public String getPath() throws RepositoryException {
         try {
-            Path p = Path.create(eventState.getParentPath(), eventState.getChildRelPath(), false);
+            Path p = null;
+            if (eventState.getChildRelPath().getIndex() > 0) {
+                p = Path.create(eventState.getParentPath(), eventState.getChildRelPath().getName(), eventState.getChildRelPath().getIndex(), false);
+            } else {
+                p = Path.create(eventState.getParentPath(), eventState.getChildRelPath().getName(), false);
+            }
             return p.toJCRPath(session.getNamespaceResolver());
         } catch (MalformedPathException e) {
             String msg = "internal error: malformed path for event";

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventState.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventState.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventState.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventState.java Sat Feb 26 12:51:46 2005
@@ -54,7 +54,7 @@
      * The relative path of the child item associated with this event.
      * This is basically the name of the item with an optional index.
      */
-    private final Path childRelPath;
+    private final Path.PathElement childRelPath;
 
     /**
      * The node type of the parent node.
@@ -97,7 +97,7 @@
                        String parentUUID,
                        Path parentPath,
                        String childUUID,
-                       Path childPath,
+                       Path.PathElement childPath,
                        NodeTypeImpl nodeType,
                        Session session) {
         int mask = (Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED);
@@ -138,7 +138,7 @@
     public static EventState childNodeAdded(String parentUUID,
                                             Path parentPath,
                                             String childUUID,
-                                            Path childPath,
+                                            Path.PathElement childPath,
                                             NodeTypeImpl nodeType,
                                             Session session) {
         return new EventState(Event.NODE_ADDED,
@@ -167,7 +167,7 @@
     public static EventState childNodeRemoved(String parentUUID,
                                               Path parentPath,
                                               String childUUID,
-                                              Path childPath,
+                                              Path.PathElement childPath,
                                               NodeTypeImpl nodeType,
                                               Session session) {
         return new EventState(Event.NODE_REMOVED,
@@ -194,7 +194,7 @@
      */
     public static EventState propertyAdded(String parentUUID,
                                            Path parentPath,
-                                           Path childPath,
+                                           Path.PathElement childPath,
                                            NodeTypeImpl nodeType,
                                            Session session) {
         return new EventState(Event.PROPERTY_ADDED,
@@ -221,7 +221,7 @@
      */
     public static EventState propertyRemoved(String parentUUID,
                                              Path parentPath,
-                                             Path childPath,
+                                             Path.PathElement childPath,
                                              NodeTypeImpl nodeType,
                                              Session session) {
         return new EventState(Event.PROPERTY_REMOVED,
@@ -248,7 +248,7 @@
      */
     public static EventState propertyChanged(String parentUUID,
                                              Path parentPath,
-                                             Path childPath,
+                                             Path.PathElement childPath,
                                              NodeTypeImpl nodeType,
                                              Session session) {
         return new EventState(Event.PROPERTY_CHANGED,
@@ -300,9 +300,9 @@
      * Returns the relative {@link Path} of the child
      * {@link javax.jcr.Item} associated with this event.
      *
-     * @return the <code>Path</code> associated with this event.
+     * @return the <code>Path.PathElement</code> associated with this event.
      */
-    public Path getChildRelPath() {
+    public Path.PathElement getChildRelPath() {
         return childRelPath;
     }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java Sat Feb 26 12:51:46 2005
@@ -16,16 +16,27 @@
  */
 package org.apache.jackrabbit.core.observation;
 
-import org.apache.jackrabbit.core.*;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
-import org.apache.jackrabbit.core.state.*;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.core.Path;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.MalformedPathException;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.ItemStateManager;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
 import org.apache.log4j.Logger;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Arrays;
 
 /**
  * The <code>EventStateCollection</code> class implements how {@link EventState}
@@ -55,11 +66,6 @@
     private final SessionImpl session;
 
     /**
-     * The ItemStateProvider of the session that creates the events.
-     */
-    private final ItemStateManager provider;
-
-    /**
      * The HierarchyManager of the session that creates the events.
      */
     private final HierarchyManager hmgr;
@@ -71,134 +77,335 @@
      */
     EventStateCollection(ObservationManagerFactory dispatcher,
                          SessionImpl session,
-                         ItemStateManager provider,
                          HierarchyManager hmgr) {
         this.dispatcher = dispatcher;
         this.session = session;
-        this.provider = provider;
         this.hmgr = hmgr;
     }
 
     /**
-     * Creates {@link EventState}s for the {@link org.apache.jackrabbit.core.state.ItemState state}
-     * instances contained in the specified collection.
-     *
-     * @param states collection of transient <code>ItemState</code> for whom
-     *               to create {@link EventState}s.
-     * @see #createEventStates(org.apache.jackrabbit.core.state.ItemState)
-     */
-    public void createEventStates(Collection states)
-            throws RepositoryException {
-        Iterator iter = states.iterator();
-        while (iter.hasNext()) {
-            createEventStates((ItemState) iter.next());
-        }
-    }
-
-    /**
-     * Creates {@link EventState}s for the passed {@link org.apache.jackrabbit.core.state.ItemState state}
-     * instance.
-     *
-     * @param state the transient <code>ItemState</code> for whom
-     *              to create {@link EventState}s.
+     * Creates {@link EventState} instances from <code>ItemState</code>
+     * <code>changes</code>.
+     * @param changes the changes on <code>ItemState</code>s.
+     * @param provider an <code>ItemStateProvider</code> to provide <code>ItemState</code>
+     * of items that are not contained in the <code>changes</code> collection.
+     * @throws ItemStateException if an error occurs while creating events
+     * states for the item state changes.
      */
-    public void createEventStates(ItemState state)
-            throws RepositoryException {
-        int status = state.getStatus();
-
-        if (status == ItemState.STATUS_EXISTING_MODIFIED
-                || status == ItemState.STATUS_NEW) {
-
+    public void createEventStates(ChangeLog changes, ItemStateManager provider) throws ItemStateException {
+        for (Iterator it = changes.modifiedStates(); it.hasNext();) {
+            ItemState state = (ItemState) it.next();
             if (state.isNode()) {
-                NodeState currentNode = (NodeState) state;
-                QName nodeTypeName = currentNode.getNodeTypeName();
-                NodeTypeImpl nodeType = session.getNodeTypeManager().getNodeType(nodeTypeName);
-                Path parentPath = hmgr.getPath(currentNode.getId());
-
-                // 1) check added properties
-                List addedProperties = currentNode.getAddedPropertyEntries();
-                for (Iterator it = addedProperties.iterator(); it.hasNext();) {
-                    NodeState.PropertyEntry prop = (NodeState.PropertyEntry) it.next();
-                    events.add(EventState.propertyAdded(currentNode.getUUID(),
-                            parentPath,
-                            Path.create(prop.getName(), 0),
-                            nodeType,
-                            session));
-                }
-
-                // 2) check removed properties
-                List removedProperties = currentNode.getRemovedPropertyEntries();
-                for (Iterator it = removedProperties.iterator(); it.hasNext();) {
-                    NodeState.PropertyEntry prop = (NodeState.PropertyEntry) it.next();
-                    events.add(EventState.propertyRemoved(currentNode.getUUID(),
-                            parentPath,
-                            Path.create(prop.getName(), 0),
-                            nodeType,
-                            session));
-                }
-
-                // 3) check for added nodes
-                List addedNodes = currentNode.getAddedChildNodeEntries();
-                for (Iterator it = addedNodes.iterator(); it.hasNext();) {
-                    NodeState.ChildNodeEntry child = (NodeState.ChildNodeEntry) it.next();
-                    events.add(EventState.childNodeAdded(currentNode.getUUID(),
-                            parentPath,
-                            child.getUUID(),
-                            Path.create(child.getName(), child.getIndex()),
-                            nodeType,
-                            session));
-                }
-
-                // 4) check for removed nodes
-                List removedNodes = currentNode.getRemovedChildNodeEntries();
-                for (Iterator it = removedNodes.iterator(); it.hasNext();) {
-                    NodeState.ChildNodeEntry child = (NodeState.ChildNodeEntry) it.next();
-                    events.add(EventState.childNodeRemoved(currentNode.getUUID(),
-                            parentPath,
-                            child.getUUID(),
-                            Path.create(child.getName(), child.getIndex()),
-                            nodeType,
-                            session));
-                }
-            } else {
-                // only add property changed event if property is existing
-                if (state.getStatus() == ItemState.STATUS_EXISTING_MODIFIED) {
-                    NodeId parentId = new NodeId(state.getParentUUID());
+                // node changed
+                // covers the following cases:
+                // 1) property added
+                // 2) property removed
+                // 3) child node added
+                // 4) child node removed
+                // 5) node moved
+                // cases 1) and 2) are detected with added and deleted states
+                // on the PropertyState itself.
+                // cases 3) and 4) are detected with added and deleted states
+                // on the NodeState itself.
+                // in case 5) two or three nodes change. two nodes are changed
+                // when a child node is renamed. three nodes are changed when
+                // a node is really moved. In any case we are only interested in
+                // the node that actually got moved.
+                NodeState n = (NodeState) state;
+                if (n.getAddedParentUUIDs().size() > 0 && n.getRemovedParentUUIDs().size() > 0) {
+                    // node moved
+                    // generate node removed & node added event
+                    String oldParentUUID = (String) n.getRemovedParentUUIDs().get(0);
+                    NodeTypeImpl nodeType = null;
+                    try {
+                        nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
+                    } catch (NoSuchNodeTypeException e) {
+                        // should never happen actually
+                        String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
+                        log.error(msg);
+                        throw new ItemStateException(msg, e);
+                    }
+                    // FIXME find more efficient way
+                    Path newPath = null;
+                    Path[] allPaths = null;
                     try {
-                        NodeState parentState = (NodeState) provider.getItemState(parentId);
-                        Path parentPath = hmgr.getPath(parentId);
-                        events.add(EventState.propertyChanged(state.getParentUUID(),
+                        newPath = hmgr.getPath(n.getId());
+                        allPaths = hmgr.getAllPaths(n.getId(), true);
+                    } catch (RepositoryException e) {
+                        // should never happen actually
+                        String msg = "Unable to resolve path for item: " + n.getId();
+                        log.error(msg);
+                        throw new ItemStateException(msg, e);
+                    }
+                    List paths = new ArrayList(Arrays.asList(allPaths));
+                    paths.remove(newPath);
+                    if (paths.size() > 0) {
+                        Path removedPath = (Path) paths.get(0);
+                        Path parentPath = null;
+                        try {
+                            parentPath = removedPath.getAncestor(1);
+                        } catch (PathNotFoundException e) {
+                            // should never happen actually, root node cannot
+                            // be removed, thus path has always a parent
+                            String msg = "Path " + removedPath + " has no parent";
+                            log.error(msg);
+                            throw new ItemStateException(msg, e);
+                        }
+                        events.add(EventState.childNodeRemoved(oldParentUUID,
                                 parentPath,
-                                Path.create(((PropertyState) state).getName(), 0),
-                                session.getNodeTypeManager().getNodeType(parentState.getNodeTypeName()),
+                                n.getUUID(),
+                                removedPath.getNameElement(),
+                                nodeType,
                                 session));
-                    } catch (ItemStateException e) {
-                        // should never happen
-                        log.error("internal error: item state exception", e);
+
+                        String newParentUUID = (String) n.getAddedParentUUIDs().get(0);
+                        try {
+                            parentPath = newPath.getAncestor(1);
+                        } catch (PathNotFoundException e) {
+                            // should never happen actually, root node cannot
+                            // be 'added', thus path has always a parent
+                            String msg = "Path " + removedPath + " has no parent";
+                            log.error(msg);
+                            throw new ItemStateException(msg, e);
+                        }
+                        events.add(EventState.childNodeAdded(newParentUUID,
+                                parentPath,
+                                n.getUUID(),
+                                newPath.getNameElement(),
+                                nodeType,
+                                session));
+                    } else {
+                        log.error("Unable to calculate old path of moved node");
+                    }
+                } else {
+                    // a moved node always has a modified parent node
+                    NodeState parent = null;
+                    try {
+                        // root node does not have a parent UUID
+                        if (state.getParentUUID() != null) {
+                            parent = (NodeState) changes.get(new NodeId(state.getParentUUID()));
+                        }
+                    } catch (NoSuchItemStateException e) {
+                        // should never happen actually. this would mean
+                        // the parent of this modified node is deleted
+                        String msg = "Parent of node " + state.getId() + " is deleted.";
+                        log.error(msg);
+                        throw new ItemStateException(msg, e);
+                    }
+                    if (parent != null) {
+                        // check if node has been renamed
+                        NodeState.ChildNodeEntry moved = null;
+                        for (Iterator removedNodes = parent.getRemovedChildNodeEntries().iterator(); removedNodes.hasNext();) {
+                            NodeState.ChildNodeEntry child = (NodeState.ChildNodeEntry) removedNodes.next();
+                            if (child.getUUID().equals(n.getUUID())) {
+                                // found node re-added with different name
+                                moved = child;
+                            }
+                        }
+                        if (moved != null) {
+                            NodeTypeImpl nodeType = null;
+                            try {
+                                nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
+                            } catch (NoSuchNodeTypeException e) {
+                                // should never happen actually
+                                String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
+                                log.error(msg);
+                                throw new ItemStateException(msg, e);
+                            }
+                            Path newPath = null;
+                            Path parentPath = null;
+                            Path oldPath = null;
+                            try {
+                                newPath = hmgr.getPath(state.getId());
+                                parentPath = newPath.getAncestor(1);
+                                oldPath = null;
+                                if (moved.getIndex() == 0) {
+                                    oldPath = Path.create(parentPath, moved.getName(), false);
+                                } else {
+                                    oldPath = Path.create(parentPath, moved.getName(), moved.getIndex(), false);
+                                }
+                            } catch (RepositoryException e) {
+                                // should never happen actually
+                                String msg = "Unable to resolve path for item: " + state.getId();
+                                log.error(msg);
+                                throw new ItemStateException(msg, e);
+                            } catch (MalformedPathException e) {
+                                // should never happen actually
+                                String msg = "Malformed path for item: " + state.getId();
+                                log.error(msg);
+                                throw new ItemStateException(msg, e);
+                            }
+                            events.add(EventState.childNodeRemoved(parent.getUUID(),
+                                    parentPath,
+                                    n.getUUID(),
+                                    oldPath.getNameElement(),
+                                    nodeType,
+                                    session));
+                            events.add(EventState.childNodeAdded(parent.getUUID(),
+                                    parentPath,
+                                    n.getUUID(),
+                                    newPath.getNameElement(),
+                                    nodeType,
+                                    session));
+                        }
                     }
                 }
+            } else {
+                // property changed
+                Path path = null;
+                Path parentPath = null;
+                try {
+                    path = hmgr.getPath(state.getId());
+                    parentPath = path.getAncestor(1);
+                } catch (RepositoryException e) {
+                    // should never happen actually
+                    String msg = "Unable to resolve path for item: " + state.getId();
+                    log.error(msg);
+                    throw new ItemStateException(msg, e);
+                }
+                NodeState parent = (NodeState) provider.getItemState(new NodeId(state.getParentUUID()));
+                NodeTypeImpl nodeType = null;
+                try {
+                    nodeType = session.getNodeTypeManager().getNodeType(parent.getNodeTypeName());
+                } catch (NoSuchNodeTypeException e) {
+                    // should never happen actually
+                    String msg = "Item " + parent.getId() + " has unknown node type: " + parent.getNodeTypeName();
+                    log.error(msg);
+                    throw new ItemStateException(msg, e);
+                }
+                events.add(EventState.propertyChanged(state.getParentUUID(),
+                        parentPath,
+                        path.getNameElement(),
+                        nodeType,
+                        session));
+            }
+        }
+        for (Iterator it = changes.addedStates(); it.hasNext();) {
+            ItemState state = (ItemState) it.next();
+            if (state.isNode()) {
+                // node created
+                NodeState n = (NodeState) state;
+                NodeTypeImpl nodeType = null;
+                try {
+                    nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
+                } catch (NoSuchNodeTypeException e) {
+                    // should never happen actually
+                    String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
+                    log.error(msg);
+                    throw new ItemStateException(msg, e);
+                }
+                Path path = null;
+                Path parentPath = null;
+                try {
+                    path = hmgr.getPath(n.getId());
+                    parentPath = path.getAncestor(1);
+                } catch (RepositoryException e) {
+                    // should never happen actually
+                    String msg = "Unable to resolve path for item: " + n.getId();
+                    log.error(msg);
+                    throw new ItemStateException(msg, e);
+                }
+                events.add(EventState.childNodeAdded(n.getParentUUID(),
+                        parentPath,
+                        n.getUUID(),
+                        path.getNameElement(),
+                        nodeType,
+                        session));
+            } else {
+                // property created / set
+                NodeState n = (NodeState) changes.get(new NodeId(state.getParentUUID()));
+                NodeTypeImpl nodeType = null;
+                try {
+                    nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
+                } catch (NoSuchNodeTypeException e) {
+                    // should never happen actually
+                    String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
+                    log.error(msg);
+                    throw new ItemStateException(msg, e);
+                }
+                Path path = null;
+                Path parentPath = null;
+                try {
+                    path = hmgr.getPath(state.getId());
+                    parentPath = path.getAncestor(1);
+                } catch (RepositoryException e) {
+                    // should never happen actually
+                    String msg = "Unable to resolve path for item: " + n.getId();
+                    log.error(msg);
+                    throw new ItemStateException(msg, e);
+                }
+                events.add(EventState.propertyAdded(state.getParentUUID(),
+                        parentPath,
+                        path.getNameElement(),
+                        nodeType,
+                        session));
             }
-        } else if (status == ItemState.STATUS_EXISTING_REMOVED) {
+        }
+        for (Iterator it = changes.deletedStates(); it.hasNext();) {
+            ItemState state = (ItemState) it.next();
             if (state.isNode()) {
-                // zombie nodes
-                NodeState currentNode = (NodeState) state;
-                QName nodeTypeName = currentNode.getNodeTypeName();
-                NodeTypeImpl nodeType = session.getNodeTypeManager().getNodeType(nodeTypeName);
-
-                // FIXME replace by HierarchyManager.getPath(ItemId id, boolean includeZombie)
-                // when available.
-                Path[] parentPaths = hmgr.getAllPaths(currentNode.getId(), true);   // include zombie
-                for (int i = 0; i < parentPaths.length; i++) {
-                    List removedNodes = currentNode.getRemovedChildNodeEntries();
-                    for (Iterator it = removedNodes.iterator(); it.hasNext();) {
-                        NodeState.ChildNodeEntry child = (NodeState.ChildNodeEntry) it.next();
-                        events.add(EventState.childNodeRemoved(currentNode.getUUID(),
-                                parentPaths[i],
-                                child.getUUID(),
-                                Path.create(child.getName(), child.getIndex()),
+                // node deleted
+                NodeState n = (NodeState) state;
+                NodeTypeImpl nodeType = null;
+                try {
+                    nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
+                } catch (NoSuchNodeTypeException e) {
+                    // should never happen actually
+                    String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
+                    log.error(msg);
+                    throw new ItemStateException(msg, e);
+                }
+                try {
+                    Path[] paths = hmgr.getAllPaths(state.getId(), true);
+                    for (int i = 0; i < paths.length; i++) {
+                        Path parentPath = paths[i].getAncestor(1);
+                        events.add(EventState.childNodeRemoved(n.getParentUUID(),
+                                parentPath,
+                                n.getUUID(),
+                                paths[i].getNameElement(),
                                 nodeType,
                                 session));
                     }
+                } catch (RepositoryException e) {
+                    // should never happen actually
+                    String msg = "Unable to resolve path for item: " + n.getId();
+                    log.error(msg);
+                    throw new ItemStateException(msg, e);
+                }
+            } else {
+                // property removed
+                // only create an event if node still exists
+                try {
+                    NodeState n = (NodeState) changes.get(new NodeId(state.getParentUUID()));
+                    // node state exists -> only property removed
+                    NodeTypeImpl nodeType = null;
+                    try {
+                        nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
+                    } catch (NoSuchNodeTypeException e) {
+                        // should never happen actually
+                        String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
+                        log.error(msg);
+                        throw new ItemStateException(msg, e);
+                    }
+                    Path paths[] = null;
+                    try {
+                        paths = hmgr.getAllPaths(state.getId(), true);
+                        for (int i = 0; i < paths.length; i++) {
+                            Path parentPath = paths[i].getAncestor(1);
+                            events.add(EventState.propertyRemoved(state.getParentUUID(),
+                                    parentPath,
+                                    paths[i].getNameElement(),
+                                    nodeType,
+                                    session));
+                        }
+                    } catch (RepositoryException e) {
+                        // should never happen actually
+                        String msg = "Unable to resolve path for item: " + n.getId();
+                        log.error(msg);
+                        throw new ItemStateException(msg, e);
+                    }
+                } catch (NoSuchItemStateException e) {
+                    // also node removed -> do not create an event
                 }
             }
         }
@@ -207,7 +414,7 @@
     /**
      * Prepares the events for dispatching.
      */
-    public void prepare() throws RepositoryException {
+    public void prepare() {
         dispatcher.prepareEvents(this);
     }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerFactory.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerFactory.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerFactory.java Sat Feb 26 12:51:46 2005
@@ -19,16 +19,11 @@
 import org.apache.commons.collections.Buffer;
 import org.apache.commons.collections.BufferUtils;
 import org.apache.commons.collections.UnboundedFifoBuffer;
-import org.apache.jackrabbit.core.*;
-import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
-import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
-import org.apache.jackrabbit.core.state.ItemStateManager;
 import org.apache.log4j.Logger;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.core.ItemManager;
 
-import javax.jcr.RepositoryException;
-import javax.jcr.observation.EventListener;
-import javax.jcr.observation.EventListenerIterator;
-import javax.jcr.observation.ObservationManager;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -119,7 +114,7 @@
      *
      * @return <code>Set</code> of <code>EventConsumer</code>s.
      */
-    private Set getAsynchronousConsumers() {
+    Set getAsynchronousConsumers() {
         synchronized (consumerChange) {
             if (readOnlyConsumers == null) {
                 readOnlyConsumers = Collections.unmodifiableSet(new HashSet(activeConsumers));
@@ -128,7 +123,7 @@
         }
     }
 
-    private Set getSynchronousConsumers() {
+    Set getSynchronousConsumers() {
         synchronized (consumerChange) {
             if (synchronousReadOnlyConsumers == null) {
                 synchronousReadOnlyConsumers = Collections.unmodifiableSet(new HashSet(synchronousConsumers));
@@ -145,15 +140,10 @@
      * @param itemMgr the <code>ItemManager</code> of the <code>session</code>.
      * @return an <code>ObservationManager</code>.
      */
-    public ObservationManager createObservationManager(SessionImpl session,
-                                                       ItemManager itemMgr) {
-        return new SessionLocalObservationManager(session, itemMgr);
-    }
-
-    public EventStateCollection createEventStateCollection(SessionImpl session,
-                                                           ItemStateManager provider,
-                                                           HierarchyManager hmgr) {
-        return new EventStateCollection(this, session, provider, hmgr);
+    public ObservationManagerImpl createObservationManager(SessionImpl session,
+                                                           HierarchyManager hmgr,
+                                                           ItemManager itemMgr) {
+        return new ObservationManagerImpl(this, session, hmgr, itemMgr);
     }
 
     /**
@@ -187,8 +177,7 @@
      *
      * @param events the {@link EventState}s to prepare.
      */
-    void prepareEvents(EventStateCollection events)
-            throws RepositoryException {
+    void prepareEvents(EventStateCollection events) {
         Set consumers = new HashSet();
         consumers.addAll(getSynchronousConsumers());
         consumers.addAll(getAsynchronousConsumers());
@@ -222,142 +211,46 @@
         eventQueue.add(new DispatchAction(events, getAsynchronousConsumers()));
     }
 
-    //----------------------------< adapter class >-----------------------------
-
     /**
-     * Each <code>Session</code> instance has its own <code>ObservationManager</code>
-     * instance. The class <code>SessionLocalObservationManager</code> implements
-     * this behaviour.
-     */
-    class SessionLocalObservationManager implements ObservationManager {
-
-        /**
-         * The <code>Session</code> this <code>ObservationManager</code>
-         * belongs to.
-         */
-        private SessionImpl session;
-
-        /**
-         * The <code>ItemManager</code> for this <code>ObservationManager</code>.
-         */
-        private ItemManager itemMgr;
-
-        /**
-         * Creates an <code>ObservationManager</code> instance.
-         *
-         * @param session the <code>Session</code> this ObservationManager
-         *                belongs to.
-         * @param itemMgr {@link org.apache.jackrabbit.core.ItemManager} of the passed
-         *                <code>Session</code>.
-         * @throws NullPointerException if <code>session</code> or <code>itemMgr</code>
-         *                              is <code>null</code>.
-         */
-        SessionLocalObservationManager(SessionImpl session,
-                                       ItemManager itemMgr) {
-            if (session == null) {
-                throw new NullPointerException("session");
-            }
-            if (itemMgr == null) {
-                throw new NullPointerException("itemMgr");
-            }
-
-            this.session = session;
-            this.itemMgr = itemMgr;
-        }
-
-        /**
-         * @see ObservationManager#addEventListener
-         */
-        public void addEventListener(EventListener listener,
-                                     int eventTypes,
-                                     String absPath,
-                                     boolean isDeep,
-                                     String[] uuid,
-                                     String[] nodeTypeName,
-                                     boolean noLocal)
-                throws RepositoryException {
-
-            // create NodeType instances from names
-            NodeTypeImpl[] nodeTypes;
-            if (nodeTypeName == null) {
-                nodeTypes = null;
+     * Adds or replaces an event consumer.
+     * @param consumer the <code>EventConsumer</code> to add or replace.
+     */
+    void addConsumer(EventConsumer consumer) {
+        synchronized (consumerChange) {
+            if (consumer.getEventListener() instanceof SynchronousEventListener) {
+                // remove existing if any
+                synchronousConsumers.remove(consumer);
+                // re-add it
+                synchronousConsumers.add(consumer);
+                // reset read only consumer set
+                synchronousReadOnlyConsumers = null;
             } else {
-                NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
-                nodeTypes = new NodeTypeImpl[nodeTypeName.length];
-                for (int i = 0; i < nodeTypes.length; i++) {
-                    nodeTypes[i] = (NodeTypeImpl) ntMgr.getNodeType(nodeTypeName[i]);
-                }
-            }
-
-            Path path;
-            try {
-                path = Path.create(absPath, session.getNamespaceResolver(), true);
-            } catch (MalformedPathException mpe) {
-                String msg = "invalid path syntax: " + absPath;
-                log.debug(msg);
-                throw new RepositoryException(msg, mpe);
-            }
-            // create filter
-            EventFilter filter = new EventFilter(itemMgr,
-                    session,
-                    eventTypes,
-                    path,
-                    isDeep,
-                    uuid,
-                    nodeTypes,
-                    noLocal);
-
-            EventConsumer consumer =
-                    new EventConsumer(session, listener, filter);
-
-            synchronized (consumerChange) {
-                if (listener instanceof SynchronousEventListener) {
-                    // remove existing if any
-                    synchronousConsumers.remove(consumer);
-                    // re-add it
-                    synchronousConsumers.add(consumer);
-                    // reset read only consumer set
-                    synchronousReadOnlyConsumers = null;
-                } else {
-                    // remove existing if any
-                    activeConsumers.remove(consumer);
-                    // re-add it
-                    activeConsumers.add(consumer);
-                    // reset read only consumer set
-                    readOnlyConsumers = null;
-                }
+                // remove existing if any
+                activeConsumers.remove(consumer);
+                // re-add it
+                activeConsumers.add(consumer);
+                // reset read only consumer set
+                readOnlyConsumers = null;
             }
         }
+    }
 
-        /**
-         * @see ObservationManager#removeEventListener(javax.jcr.observation.EventListener)
-         */
-        public void removeEventListener(EventListener listener)
-                throws RepositoryException {
-            EventConsumer consumer =
-                    new EventConsumer(session, listener, EventFilter.BLOCK_ALL);
-
-            synchronized (consumerChange) {
-                if (listener instanceof SynchronousEventListener) {
-                    synchronousConsumers.remove(consumer);
-                    // reset read only listener set
-                    synchronousReadOnlyConsumers = null;
-                } else {
-                    activeConsumers.remove(consumer);
-                    // reset read only listener set
-                    readOnlyConsumers = null;
-                }
+    /**
+     * Unregisters an event consumer from event notification.
+     * @param consumer the consumer to deregister.
+     */
+    void removeConsumer(EventConsumer consumer) {
+        synchronized (consumerChange) {
+            if (consumer.getEventListener() instanceof SynchronousEventListener) {
+                synchronousConsumers.remove(consumer);
+                // reset read only listener set
+                synchronousReadOnlyConsumers = null;
+            } else {
+                activeConsumers.remove(consumer);
+                // reset read only listener set
+                readOnlyConsumers = null;
             }
         }
-
-        /**
-         * @see ObservationManager#getRegisteredEventListeners()
-         */
-        public EventListenerIterator getRegisteredEventListeners()
-                throws RepositoryException {
-            return new EventListenerIteratorImpl(session,
-                    getSynchronousConsumers(),
-                    getAsynchronousConsumers());
-        }
     }
+
 }

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java?view=auto&rev=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java Sat Feb 26 12:51:46 2005
@@ -0,0 +1,165 @@
+/*
+ * $Id: $
+ *
+ * Copyright 1997-2004 Day Management AG
+ * Barfuesserplatz 6, 4001 Basel, Switzerland
+ * All Rights Reserved.
+ *
+ * This software is the confidential and proprietary information of
+ * Day Management AG, ("Confidential Information"). You shall not
+ * disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into
+ * with Day.
+ */
+
+package org.apache.jackrabbit.core.observation;
+
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.ItemManager;
+import org.apache.jackrabbit.core.Path;
+import org.apache.jackrabbit.core.MalformedPathException;
+import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.log4j.Logger;
+
+import javax.jcr.observation.ObservationManager;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.EventListenerIterator;
+import javax.jcr.RepositoryException;
+
+/**
+ * Each <code>Session</code> instance has its own <code>ObservationManager</code>
+ * instance. The class <code>SessionLocalObservationManager</code> implements
+ * this behaviour.
+ */
+public class ObservationManagerImpl implements ObservationManager {
+
+    /** The logger instance of this class */
+    private static final Logger log = Logger.getLogger(ObservationManagerImpl.class);
+
+    /**
+     * The <code>Session</code> this <code>ObservationManager</code>
+     * belongs to.
+     */
+    private final SessionImpl session;
+
+    /**
+     * The <code>HierarchyManager</code> of the session.
+     */
+    private final HierarchyManager hmgr;
+
+    /**
+     * The <code>ItemManager</code> for this <code>ObservationManager</code>.
+     */
+    private final ItemManager itemMgr;
+
+    /** The <code>ObservationManagerFactory</code> */
+    private final ObservationManagerFactory obsMgrFactory;
+
+    /**
+     * Creates an <code>ObservationManager</code> instance.
+     *
+     * @param session the <code>Session</code> this ObservationManager
+     *                belongs to.
+     * @param hmgr    the <code>HierarchyManager</code> of the <code>session</code>.
+     * @param itemMgr {@link org.apache.jackrabbit.core.ItemManager} of the passed
+     *                <code>Session</code>.
+     * @throws NullPointerException if <code>session</code> or <code>itemMgr</code>
+     *                              is <code>null</code>.
+     */
+    ObservationManagerImpl(ObservationManagerFactory obsMgrFactory,
+                           SessionImpl session,
+                           HierarchyManager hmgr,
+                           ItemManager itemMgr) {
+        if (session == null) {
+            throw new NullPointerException("session");
+        }
+        if (itemMgr == null) {
+            throw new NullPointerException("itemMgr");
+        }
+
+        this.obsMgrFactory = obsMgrFactory;
+        this.session = session;
+        this.hmgr = hmgr;
+        this.itemMgr = itemMgr;
+    }
+
+    /**
+     * @see javax.jcr.observation.ObservationManager#addEventListener
+     */
+    public void addEventListener(EventListener listener,
+                                 int eventTypes,
+                                 String absPath,
+                                 boolean isDeep,
+                                 String[] uuid,
+                                 String[] nodeTypeName,
+                                 boolean noLocal)
+            throws RepositoryException {
+
+        // create NodeType instances from names
+        NodeTypeImpl[] nodeTypes;
+        if (nodeTypeName == null) {
+            nodeTypes = null;
+        } else {
+            NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
+            nodeTypes = new NodeTypeImpl[nodeTypeName.length];
+            for (int i = 0; i < nodeTypes.length; i++) {
+                nodeTypes[i] = (NodeTypeImpl) ntMgr.getNodeType(nodeTypeName[i]);
+            }
+        }
+
+        Path path;
+        try {
+            path = Path.create(absPath, session.getNamespaceResolver(), true);
+        } catch (MalformedPathException mpe) {
+            String msg = "invalid path syntax: " + absPath;
+            log.debug(msg);
+            throw new RepositoryException(msg, mpe);
+        }
+        // create filter
+        EventFilter filter = new EventFilter(itemMgr,
+                session,
+                eventTypes,
+                path,
+                isDeep,
+                uuid,
+                nodeTypes,
+                noLocal);
+
+        EventConsumer consumer =
+                new EventConsumer(session, listener, filter);
+        obsMgrFactory.addConsumer(consumer);
+    }
+
+    /**
+     * @see javax.jcr.observation.ObservationManager#removeEventListener(javax.jcr.observation.EventListener)
+     */
+    public void removeEventListener(EventListener listener)
+            throws RepositoryException {
+        EventConsumer consumer =
+                new EventConsumer(session, listener, EventFilter.BLOCK_ALL);
+        obsMgrFactory.removeConsumer(consumer);
+
+    }
+
+    /**
+     * @see javax.jcr.observation.ObservationManager#getRegisteredEventListeners()
+     */
+    public EventListenerIterator getRegisteredEventListeners()
+            throws RepositoryException {
+        return new EventListenerIteratorImpl(session,
+                obsMgrFactory.getSynchronousConsumers(),
+                obsMgrFactory.getAsynchronousConsumers());
+    }
+
+    /**
+     * Creates an <code>EventStateCollection</code> tied to the session
+     * which is attached this <code>ObservationManager</code> instance.
+     * @return a new <code>EventStateCollection</code>.
+     */
+    public EventStateCollection createEventStateCollection() {
+        return new EventStateCollection(obsMgrFactory, session, hmgr);
+    }
+
+}

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java Sat Feb 26 12:51:46 2005
@@ -20,8 +20,10 @@
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
 import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.log4j.Logger;
 
+import javax.jcr.RepositoryException;
 import java.io.PrintStream;
 
 /**
@@ -42,6 +44,11 @@
     protected final SharedItemStateManager sharedStateMgr;
 
     /**
+     * Local WorkspaceImpl instance.
+     */
+    protected final WorkspaceImpl wspImpl;
+
+    /**
      * Flag indicating whether this item state manager is in edit mode
      */
     private boolean editMode;
@@ -53,11 +60,18 @@
 
     /**
      * Creates a new <code>LocalItemStateManager</code> instance.
+     * todo LocalItemStateManager without a wspImpl will not generate observation events!
      *
      * @param sharedStateMgr shared state manager
+     * @param wspImpl the workspace instance where this item state manager
+     * belongs to, or <code>null</code> if this item state manager is not
+     * associated with a workspace. This is the case for the version item state
+     * manager. Version item states are not associated with a specific workspace
+     * instance.
      */
-    public LocalItemStateManager(SharedItemStateManager sharedStateMgr) {
+    public LocalItemStateManager(SharedItemStateManager sharedStateMgr, WorkspaceImpl wspImpl) {
         this.sharedStateMgr = sharedStateMgr;
+        this.wspImpl = wspImpl;
     }
 
     /**
@@ -304,7 +318,14 @@
     protected void update(ChangeLog changeLog)
             throws ItemStateException {
 
-        sharedStateMgr.store(changeLog);
+        try {
+            sharedStateMgr.store(changeLog, (wspImpl != null) ? wspImpl.getObservationManagerImpl() : null);
+        } catch (RepositoryException e) {
+            // should never get here
+            String msg = "ObservationManager unavailable";
+            log.error(msg);
+            throw new ItemStateException(msg, e);
+        }
 
         changeLog.persisted();
     }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java Sat Feb 26 12:51:46 2005
@@ -17,6 +17,8 @@
 package org.apache.jackrabbit.core.state;
 
 import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.observation.ObservationManagerImpl;
+import org.apache.jackrabbit.core.observation.EventStateCollection;
 import org.apache.jackrabbit.core.nodetype.NodeDefId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.nodetype.PropDefId;
@@ -293,11 +295,15 @@
      * Store modifications registered in a <code>ChangeLog</code>. The items
      * contained in the <tt>ChangeLog</tt> are not states returned by this
      * item state manager but rather must be reconnected to items provided
-     * by this state manager.
+     * by this state manager.<p/>
+     * After successfully storing the states the observation manager is informed
+     * about the changes, if an observation manager is passed to this method.
      * @param local change log containing local items
+     * @param obsMgr the observation manager to inform, or <code>null</code> if
+     *  no observation manager should be informed.
      * @throws ItemStateException if an error occurs
      */
-    public synchronized void store(ChangeLog local) throws ItemStateException {
+    public synchronized void store(ChangeLog local, ObservationManagerImpl obsMgr) throws ItemStateException {
         ChangeLog shared = new ChangeLog();
 
         /**
@@ -346,6 +352,14 @@
             shared.deleted(state.getOverlayedState());
         }
 
+        /* prepare the events */
+        EventStateCollection events = null;
+        if (obsMgr != null) {
+            events = obsMgr.createEventStateCollection();
+            events.createEventStates(local, this);
+            events.prepare();
+        }
+
         /* Push all changes from the local items to the shared items */
         local.push();
 
@@ -354,6 +368,11 @@
 
         /* Let the shared item listeners know about the change */
         shared.persisted();
+
+        /* dispatch the events */
+        if (events != null) {
+            events.dispatch();
+        }
     }
 
     //----------------------------------------------------< ItemStateListener >

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java Sat Feb 26 12:51:46 2005
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.core.state;
 
 import org.apache.jackrabbit.core.ItemId;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.log4j.Logger;
 
 /**
@@ -37,6 +38,16 @@
     private static final String ATTRIBUTE_CHANGE_LOG = "ChangeLog";
 
     /**
+     * ThreadLocal that holds the ChangeLog while this item state manager
+     * is in commit().
+     */
+    private static ThreadLocal commitLog = new ThreadLocal() {
+        protected synchronized Object initialValue() {
+            return new CommitLog();
+        }
+    };
+
+    /**
      * Current transactional change log
      */
     private transient ChangeLog txLog;
@@ -46,8 +57,8 @@
      *
      * @param sharedStateMgr shared state manager
      */
-    public TransactionalItemStateManager(SharedItemStateManager sharedStateMgr) {
-        super(sharedStateMgr);
+    public TransactionalItemStateManager(SharedItemStateManager sharedStateMgr, WorkspaceImpl wspImpl) {
+        super(sharedStateMgr, wspImpl);
     }
 
     /**
@@ -75,10 +86,15 @@
         ChangeLog changeLog = (ChangeLog) tx.getAttribute(ATTRIBUTE_CHANGE_LOG);
         if (changeLog != null) {
             try {
+                // set changeLog in ThreadLocal
+                ((CommitLog) commitLog.get()).setChanges(changeLog);
                 super.update(changeLog);
             } catch (ItemStateException e) {
+                log.error(e);
                 changeLog.undo(sharedStateMgr);
                 throw new TransactionException("Unable to end update.", e);
+            } finally {
+                ((CommitLog) commitLog.get()).setChanges(null);
             }
             changeLog.reset();
             tx.notifyCommitted();
@@ -102,13 +118,22 @@
     /**
      * @see ItemStateManager#getItemState(org.apache.jackrabbit.core.ItemId)
      *
-     * If associated to a transaction, check our transactional
-     * change log first.
+     * If this state manager is committing changes, this method first checks
+     * the commitLog ThreadLocal. Else if associated to a transaction check
+     * the transactional change log. Fallback is always the call to the base
+     * class.
      */
     public ItemState getItemState(ItemId id)
             throws NoSuchItemStateException, ItemStateException {
 
-        if (txLog != null) {
+        ChangeLog changeLog = ((CommitLog) commitLog.get()).getChanges();
+        if (changeLog != null) {
+            // check items in commit log
+            ItemState state = changeLog.get(id);
+            if (state != null) {
+                return state;
+            }
+        } else if (txLog != null) {
             // check items in change log
             ItemState state = txLog.get(id);
             if (state != null) {
@@ -121,11 +146,24 @@
     /**
      * @see ItemStateManager#hasItemState(org.apache.jackrabbit.core.ItemId)
      *
-     * If associated to a transaction, check our transactional
-     * change log first.
+     * If this state manager is committing changes, this method first checks
+     * the commitLog ThreadLocal. Else if associated to a transaction check
+     * the transactional change log. Fallback is always the call to the base
+     * class.
      */
     public boolean hasItemState(ItemId id) {
-        if (txLog != null) {
+        ChangeLog changeLog = ((CommitLog) commitLog.get()).getChanges();
+        if (changeLog != null) {
+            // check items in commit log
+            try {
+                ItemState state = changeLog.get(id);
+                if (state != null) {
+                    return true;
+                }
+            } catch (NoSuchItemStateException e) {
+                return false;
+            }
+        } else if (txLog != null) {
             // check items in change log
             try {
                 ItemState state = txLog.get(id);
@@ -142,13 +180,22 @@
     /**
      * @see ItemStateManager#getNodeReferences
      *
-     * If associated to a transaction, check our transactional
-     * change log first.
+     * If this state manager is committing changes, this method first
+     * checks the commitLog ThreadLocal. Else if associated to a transaction
+     * check the transactional change log. Fallback is always the call to
+     * the base class.
      */
     public NodeReferences getNodeReferences(NodeReferencesId id)
             throws NoSuchItemStateException, ItemStateException {
 
-        if (txLog != null) {
+        ChangeLog changeLog = ((CommitLog) commitLog.get()).getChanges();
+        if (changeLog != null) {
+            // check commit log
+            NodeReferences refs = changeLog.get(id);
+            if (refs != null) {
+                return refs;
+            }
+        } else if (txLog != null) {
             // check change log
             NodeReferences refs = txLog.get(id);
             if (refs != null) {
@@ -170,6 +217,39 @@
             txLog.merge(changeLog);
         } else {
             super.update(changeLog);
+        }
+    }
+
+    //--------------------------< inner classes >-------------------------------
+
+    /**
+     * Helper class that serves as a container for a ChangeLog in a ThreadLocal.
+     * The <code>CommitLog</code> is associated with a <code>ChangeLog</code>
+     * while the <code>TransactionalItemStateManager</code> is in the commit
+     * method.
+     */
+    private static class CommitLog {
+
+        /** The changes that are about to be committed */
+        private ChangeLog changes;
+
+        /**
+         * Sets changes that are about to be committed.
+         * @param changes that are about to be committed, or <code>null</code>
+         * if changes have been committed and the commit log should be reset.
+         */
+        private void setChanges(ChangeLog changes) {
+            this.changes = changes;
+        }
+
+        /**
+         * The changes that are about to be committed, or <code>null</code> if
+         * the <code>TransactionalItemStateManager</code> is currently not
+         * committing any changes.
+         * @return the changes about to be committed.
+         */
+        private ChangeLog getChanges() {
+            return changes;
         }
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/NativePVM.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/NativePVM.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/NativePVM.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/NativePVM.java Sat Feb 26 12:51:46 2005
@@ -18,6 +18,7 @@
 
 import org.apache.commons.collections.ReferenceMap;
 import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.observation.ObservationManagerImpl;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.state.*;
 import org.apache.jackrabbit.core.util.uuid.UUID;
@@ -165,7 +166,8 @@
             //this.stateMgr = new NativeItemStateManager(pMgr, PERSISTENT_ROOT_ID.getUUID(), ntReg);
             this.pMgr = pMgr;
             SharedItemStateManager sharedStateMgr = new SharedItemStateManager(pMgr, PERSISTENT_ROOT_ID.getUUID(), ntReg);
-            stateMgr = new LocalItemStateManager(sharedStateMgr);
+            // todo versioning is not attached to any workspace!! how do we trigger observation?
+            stateMgr = new LocalItemStateManager(sharedStateMgr, null);
             NodeState nodeState = (NodeState) stateMgr.getItemState(PERSISTENT_ROOT_ID);
             historyRoot = new PersistentNode(stateMgr, nodeState);
             initVirtualIds(historyRoot.getState());

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java?view=diff&r1=155582&r2=155583
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java Sat Feb 26 12:51:46 2005
@@ -76,6 +76,16 @@
     protected String jcrUUID;
 
     /**
+     * JCR Name jcr:lockOwner using the namespace resolver of the current session.
+     */
+    protected String jcrLockOwner;
+
+    /**
+     * JCR Name jcr:lockIsDeep using the namespace resolver of the current session.
+     */
+    protected String jcrlockIsDeep;
+
+    /**
      * JCR Name nt:base using the namespace resolver of the current session.
      */
     protected String ntBase;
@@ -212,6 +222,8 @@
         jcrPredecessors = superuser.getNamespacePrefix(NS_JCR_URI) + ":predecessors";
         jcrBaseVersion = superuser.getNamespacePrefix(NS_JCR_URI) + ":baseVersion";
         jcrUUID = superuser.getNamespacePrefix(NS_JCR_URI) + ":uuid";
+        jcrLockOwner = superuser.getNamespacePrefix(NS_JCR_URI) + ":lockOwner";
+        jcrlockIsDeep = superuser.getNamespacePrefix(NS_JCR_URI) + ":lockIsDeep";
         ntBase = superuser.getNamespacePrefix(NS_NT_URI) + ":base";
         mixReferenceable = superuser.getNamespacePrefix(NS_MIX_URI) + ":referenceable";
         mixVersionable = superuser.getNamespacePrefix(NS_MIX_URI) + ":versionable";
@@ -284,6 +296,8 @@
                         root.save();
                     }
                 }
+            } catch (Exception e) {
+                log.println("Exception in tearDown: " + e.toString());
             } finally {
                 superuser.logout();
             }