You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2006/10/09 18:46:18 UTC

svn commit: r454423 [1/3] - in /jackrabbit/trunk/contrib/spi: jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/ jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ jcr2spi/src/main/jav...

Author: angela
Date: Mon Oct  9 09:46:16 2006
New Revision: 454423

URL: http://svn.apache.org/viewvc?view=rev&rev=454423
Log:
work in progress

JCR2SPI
--------------------------------------------------------------

- reorder ItemState/NodeState/PropertyState in order to group
  methods by state types (overlayed workspace state vs. session/transient states)
- add utility methods that allow to determine and validate the
  type of ItemState.
- move childitementry classes to separate package and force usage
  of interface methods
- add checks for state type to ItemManager implementation
- add checks for state type to LockManager
- fix Node.getMixinTypes()
- rename ItemState.pull to 'reset'. remove todo asking for a careful
  merging of wsp-State and introduce a new method 'merge'.

SPI
--------------------------------------------------------------------

- rename login as suggested by julian
- add method dispose(SessionInfo) 
- rename ItemId.getRelativePath to getPath

Added:
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java   (with props)
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemReference.java   (with props)
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeEntry.java   (with props)
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeReference.java   (with props)
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildPropertyEntry.java   (with props)
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/PathElementReference.java   (with props)
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/PropertyReference.java   (with props)
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/UUIDReference.java   (with props)
Removed:
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChildItemReference.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChildNodeEntry.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChildNodeReference.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChildPropertyEntry.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathElementReference.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyReference.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UUIDReference.java
Modified:
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/RepositoryImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/LockManagerImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateValidator.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java
    jackrabbit/trunk/contrib/spi/spi/src/main/java/org/apache/jackrabbit/spi/IdFactory.java
    jackrabbit/trunk/contrib/spi/spi/src/main/java/org/apache/jackrabbit/spi/ItemId.java
    jackrabbit/trunk/contrib/spi/spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java
    jackrabbit/trunk/contrib/spi/spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdFactoryImpl.java
    jackrabbit/trunk/contrib/spi/spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/NodeInfoImpl.java
    jackrabbit/trunk/contrib/spi/spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
    jackrabbit/trunk/contrib/spi/spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/SubscriptionManager.java
    jackrabbit/trunk/contrib/spi/spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/URIResolverImpl.java

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java Mon Oct  9 09:46:16 2006
@@ -20,7 +20,7 @@
 import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
 import org.apache.jackrabbit.jcr2spi.state.ItemStateManager;
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
-import org.apache.jackrabbit.jcr2spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
 import org.apache.jackrabbit.jcr2spi.util.LogUtil;
 import org.apache.jackrabbit.name.NamespaceResolver;
 import org.apache.jackrabbit.name.QName;

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java Mon Oct  9 09:46:16 2006
@@ -24,6 +24,7 @@
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
 import org.apache.jackrabbit.jcr2spi.state.PropertyState;
 import org.apache.jackrabbit.jcr2spi.state.ItemStateLifeCycleListener;
+import org.apache.jackrabbit.jcr2spi.state.Status;
 import org.apache.jackrabbit.jcr2spi.operation.Remove;
 import org.apache.jackrabbit.jcr2spi.operation.Operation;
 import org.apache.jackrabbit.jcr2spi.util.LogUtil;
@@ -32,7 +33,6 @@
 import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.name.PathFormat;
-import org.apache.jackrabbit.spi.ItemId;
 import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
 
@@ -164,14 +164,14 @@
      * @see javax.jcr.Item#isNew()
      */
     public boolean isNew() {
-        return state.getStatus() == ItemState.STATUS_NEW;
+        return state.getStatus() == Status.NEW;
     }
 
     /**
      * @see javax.jcr.Item#isModified()
      */
     public boolean isModified() {
-        return state.getStatus() == ItemState.STATUS_EXISTING_MODIFIED;
+        return state.getStatus() == Status.EXISTING_MODIFIED;
     }
 
     /**
@@ -192,9 +192,21 @@
             if (session.getWorkspace().getName().equals(otherWspName)) {
                 // in addition they must provide the same id irrespective of
                 // any transient modifications.
-                ItemId thisId = state.getOverlayedState().getId();
-                ItemId otherId = other.state.getOverlayedState().getId();
-                return thisId.equals(otherId);
+                ItemState wspState = state.getWorkspaceState();
+                ItemState otherWspState = other.state.getWorkspaceState();
+
+                if (wspState != null && otherWspState != null) {
+                    return wspState.getId().equals(otherWspState.getId());
+                }
+                /* else:
+                - if both wsp-states are null, the items are both transiently
+                  added and are only the same if they are obtained from the same
+                  session. in this case, their states must be the same object,
+                  which is covered above.
+                - either of the two items does not have a workspace state.
+                  therefore the items cannot be the same, since one has been
+                  transiently added in one but not the other session.
+                  */
             }
         }
         return false;
@@ -239,11 +251,11 @@
 
         // check status of this item's state
         switch (state.getStatus()) {
-            case ItemState.STATUS_NEW:
+            case Status.NEW:
                 String msg = "Cannot refresh a new item (" + safeGetJCRPath() + ").";
                 log.debug(msg);
                 throw new RepositoryException(msg);
-            case ItemState.STATUS_STALE_DESTROYED:
+            case Status.STALE_DESTROYED:
                 msg = "Cannot refresh on a deleted item (" + safeGetJCRPath() + ").";
                 log.debug(msg);
                 throw new InvalidItemStateException(msg);
@@ -283,28 +295,28 @@
         switch (state.getStatus()) {
             /**
              * Nothing to do for
-             * - ItemState.STATUS_EXISTING : modifications reverted or saved
-             * - ItemState.STATUS_EXISTING_MODIFIED : transient modification
-             * - ItemState.STATUS_STALE_MODIFIED : external modifications while transient changes pending
-             * - ItemState.MODIFIED : externaly modified -> marker for sessionISM states only
+             * - Status#EXISTING : modifications reverted or saved
+             * - Status#EXISTING_MODIFIED : transient modification
+             * - Status#STALE_MODIFIED : external modifications while transient changes pending
+             * - Status#MODIFIED : externaly modified -> marker for sessionISM states only
              */
-            case ItemState.STATUS_EXISTING:
-            case ItemState.STATUS_EXISTING_MODIFIED:
-            case ItemState.STATUS_STALE_MODIFIED:
-            case ItemState.STATUS_MODIFIED:
+            case Status.EXISTING:
+            case Status.EXISTING_MODIFIED:
+            case Status.STALE_MODIFIED:
+            case Status.MODIFIED:
                 break;
             /**
              * Notify listeners that this item is transiently or permanently
              * destroyed.
-             * - STATUS_EXISTING_REMOVED : transient removal
-             * - STATUS_REMOVED : permanent removal. item will never get back to life
-             * - STATUS_STALE_DESTROYED : permanent removal. item will never get back to life
+             * - Status#EXISTING_REMOVED : transient removal
+             * - Status#REMOVED : permanent removal. item will never get back to life
+             * - Status#STALE_DESTROYED : permanent removal. item will never get back to life
              */
-            case ItemState.STATUS_EXISTING_REMOVED:
+            case Status.EXISTING_REMOVED:
                 notifyDestroyed();
                 break;
-            case ItemState.STATUS_REMOVED:
-            case ItemState.STATUS_STALE_DESTROYED:
+            case Status.REMOVED:
+            case Status.STALE_DESTROYED:
                 state.removeListener(this);
                 this.state = null;
                 notifyDestroyed();
@@ -312,7 +324,7 @@
             /**
              * Invalid status. A state can never change its state to 'New'.
              */
-            case ItemState.STATUS_NEW:
+            case Status.NEW:
                 // should never happen.
                 log.error("invalid state change to STATUS_NEW");
                 break;

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java Mon Oct  9 09:46:16 2006
@@ -19,8 +19,8 @@
 import org.apache.jackrabbit.jcr2spi.state.ItemState;
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
 import org.apache.jackrabbit.jcr2spi.state.PropertyState;
-import org.apache.jackrabbit.jcr2spi.state.ChildNodeEntry;
-import org.apache.jackrabbit.jcr2spi.state.ChildPropertyEntry;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildPropertyEntry;
 import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
 import org.apache.jackrabbit.jcr2spi.util.Dumpable;
 import org.apache.jackrabbit.jcr2spi.util.LogUtil;
@@ -75,9 +75,6 @@
  */
 public class ItemManagerImpl implements Dumpable, ItemManager {
 
-    // TODO: needs to be fixed, either by modifying interface or impl. items can be created from item states obtained from WorkspaceManager.
-    // -->> see LockManagerImpl
-
     private static Logger log = LoggerFactory.getLogger(ItemManagerImpl.class);
 
     private final SessionImpl session;
@@ -138,6 +135,7 @@
      * @see ItemManager#itemExists(ItemState)
      */
     public boolean itemExists(ItemState itemState) {
+        itemState.checkIsSessionState();
         try {
             // check sanity of session
             session.checkIsAlive();
@@ -171,6 +169,8 @@
      * @see ItemManager#getItem(ItemState)
      */
     public Item getItem(ItemState itemState) throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+        itemState.checkIsSessionState();
+
         // first try to access item from cache
         Item item = retrieveItem(itemState);
         // not yet in cache, need to create instance
@@ -194,6 +194,7 @@
             throws ItemNotFoundException, AccessDeniedException, RepositoryException {
         // check sanity of session
         session.checkIsAlive();
+        parentState.checkIsSessionState();
         checkAccess(parentState, true);
 
         Iterator iter = parentState.getChildNodeEntries().iterator();
@@ -219,6 +220,7 @@
             throws ItemNotFoundException, AccessDeniedException, RepositoryException {
         // check sanity of session
         session.checkIsAlive();
+        parentState.checkIsSessionState();
         checkAccess(parentState, true);
 
         Collection nodeEntries = parentState.getChildNodeEntries();
@@ -241,6 +243,7 @@
             throws ItemNotFoundException, AccessDeniedException, RepositoryException {
         // check sanity of session
         session.checkIsAlive();
+        parentState.checkIsSessionState();
         checkAccess(parentState, true);
 
         Iterator iter = parentState.getPropertyEntries().iterator();
@@ -266,6 +269,7 @@
             throws ItemNotFoundException, AccessDeniedException, RepositoryException {
         // check sanity of session
         session.checkIsAlive();
+        parentState.checkIsSessionState();
         checkAccess(parentState, true);
 
         Collection propEntries = parentState.getPropertyEntries();

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java Mon Oct  9 09:46:16 2006
@@ -33,7 +33,7 @@
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
 import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
 import org.apache.jackrabbit.jcr2spi.state.ItemStateValidator;
-import org.apache.jackrabbit.jcr2spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
 import org.apache.jackrabbit.jcr2spi.state.PropertyState;
 import org.apache.jackrabbit.jcr2spi.state.NoSuchItemStateException;
 import org.apache.jackrabbit.jcr2spi.state.ItemState;
@@ -649,7 +649,7 @@
         QName[] mixinNames = getNodeState().getMixinTypeNames();
         NodeType[] nta = new NodeType[mixinNames.length];
         for (int i = 0; i < mixinNames.length; i++) {
-            nta[i++] = session.getNodeTypeManager().getNodeType(mixinNames[i]);
+            nta[i] = session.getNodeTypeManager().getNodeType(mixinNames[i]);
         }
         return nta;
     }
@@ -864,7 +864,7 @@
         // make sure the specified workspace is visible for the current session.
         session.checkAccessibleWorkspace(srcWorkspaceName);
 
-        Operation op = Update.create((NodeState) getNodeState().getOverlayedState(), srcWorkspaceName);
+        Operation op = Update.create((NodeState) getNodeState().getWorkspaceState(), srcWorkspaceName);
         ((WorkspaceImpl)session.getWorkspace()).getUpdatableItemStateManager().execute(op);
     }
 
@@ -1218,7 +1218,7 @@
             return QName.ROOT;
         }
 
-        return getNodeState().getName();
+        return getNodeState().getQName();
     }
 
 
@@ -1240,7 +1240,7 @@
      */
     private void checkHasPendingChanges() throws InvalidItemStateException, RepositoryException {
         if (hasPendingChanges()) {
-            String msg = "Unable to lock node. Node has pending changes: " + getPath();
+            String msg = "Node has pending changes: " + getPath();
             log.debug(msg);
             throw new InvalidItemStateException(msg);
         }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/RepositoryImpl.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/RepositoryImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/RepositoryImpl.java Mon Oct  9 09:46:16 2006
@@ -71,7 +71,7 @@
      */
     public Session login(Credentials credentials, String workspaceName) throws LoginException, NoSuchWorkspaceException, RepositoryException {
         String wspName = (workspaceName == null) ? config.getDefaultWorkspaceName() : workspaceName;
-        SessionInfo info = config.getRepositoryService().login(credentials, wspName);
+        SessionInfo info = config.getRepositoryService().obtain(credentials, wspName);
         if (info instanceof XASessionInfo) {
             return new XASessionImpl((XASessionInfo) info, this, config);
         } else {

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java Mon Oct  9 09:46:16 2006
@@ -568,30 +568,10 @@
         // dispose item manager
         itemManager.dispose();
         // dispose workspace
-
-        // TODO
-        // wsp.dispose();
+        workspace.dispose();
 
         // invalidate session
         alive = false;
-        /*
-        // TODO
-        // logout JAAS subject
-        if (loginContext != null) {
-        try {
-        loginContext.logout();
-        } catch (javax.security.auth.login.LoginException le) {
-        log.warn("failed to logout current subject: " + le.getMessage());
-        }
-        loginContext = null;
-        }
-
-        try {
-        accessMgr.close();
-        } catch (Exception e) {
-        log.warn("error while closing AccessManager", e);
-        }
-        */
         // finally notify listeners that session has been closed
         notifyLoggedOut();
     }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceImpl.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceImpl.java Mon Oct  9 09:46:16 2006
@@ -408,6 +408,12 @@
     }
 
     //------------------------------------< implementation specific methods >---
+    void dispose() {
+        // TODO.
+        // NOTE: wspManager has already been disposed upon SessionItemStateManager.dispose()
+    }
+
+
     IdFactory getIdFactory() {
         return wspManager.getIdFactory();
     }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java Mon Oct  9 09:46:16 2006
@@ -387,6 +387,11 @@
                 log.warn("Exception while disposing workspace manager: " + e);
             }
         }
+        try {
+            service.dispose(sessionInfo);
+        } catch (RepositoryException e) {
+            log.warn("Exception while disposing session info: " + e);            
+        }
     }
     //------------------------------------------------------< AccessManager >---
     /**
@@ -394,15 +399,15 @@
      */
     public boolean isGranted(NodeState parentState, Path relPath, String[] actions) throws ItemNotFoundException, RepositoryException {
         // TODO: TOBEFIXED. 
-        ItemState wspState = parentState.getOverlayedState();
+        ItemState wspState = parentState.getWorkspaceState();
         if (wspState == null) {
             Path.PathBuilder pb = new Path.PathBuilder();
             pb.addAll(relPath.getElements());
             while (wspState == null) {
-                pb.addFirst(parentState.getName());
+                pb.addFirst(parentState.getQName());
 
                 parentState = parentState.getParent();
-                wspState = parentState.getOverlayedState();
+                wspState = parentState.getWorkspaceState();
             }
             try {
                 relPath = pb.getPath();
@@ -427,7 +432,7 @@
      * @see AccessManager#isGranted(ItemState, String[])
      */
     public boolean isGranted(ItemState itemState, String[] actions) throws ItemNotFoundException, RepositoryException {
-        ItemState wspState = itemState.getOverlayedState();
+        ItemState wspState = itemState.getWorkspaceState();
         // a 'new' state can always be read, written and removed
         // TODO: correct?
         if (wspState == null) {
@@ -440,7 +445,7 @@
      * @see AccessManager#canRead(ItemState)
      */
     public boolean canRead(ItemState itemState) throws ItemNotFoundException, RepositoryException {
-        ItemState wspState = itemState.getOverlayedState();
+        ItemState wspState = itemState.getWorkspaceState();
         // a 'new' state can always be read
         if (wspState == null) {
             return true;
@@ -452,7 +457,7 @@
      * @see AccessManager#canRemove(ItemState)
      */
     public boolean canRemove(ItemState itemState) throws ItemNotFoundException, RepositoryException {
-        ItemState wspState = itemState.getOverlayedState();
+        ItemState wspState = itemState.getWorkspaceState();
         // a 'new' state can always be removed again
         if (wspState == null) {
             return true;
@@ -587,7 +592,7 @@
          */
         private void execute(ChangeLog changeLog) throws RepositoryException, ConstraintViolationException, AccessDeniedException, ItemExistsException, NoSuchNodeTypeException, UnsupportedRepositoryOperationException, VersionException {
             try {
-                ItemState target = changeLog.getTarget().getOverlayedState();
+                ItemState target = changeLog.getTarget();
                 batch = service.createBatch(target.getId(), sessionInfo);
                 Iterator it = changeLog.getOperations();
                 while (it.hasNext()) {

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/LockManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/LockManagerImpl.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/LockManagerImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/LockManagerImpl.java Mon Oct  9 09:46:16 2006
@@ -25,8 +25,8 @@
 import org.apache.jackrabbit.jcr2spi.operation.LockRelease;
 import org.apache.jackrabbit.jcr2spi.operation.LockRefresh;
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
-import org.apache.jackrabbit.jcr2spi.state.ItemState;
 import org.apache.jackrabbit.jcr2spi.state.ChangeLog;
+import org.apache.jackrabbit.jcr2spi.state.Status;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.spi.EventIterator;
 import org.apache.jackrabbit.spi.Event;
@@ -81,11 +81,14 @@
      * @see LockManager#lock(NodeState,boolean,boolean)
      */
     public Lock lock(NodeState nodeState, boolean isDeep, boolean isSessionScoped) throws LockException, RepositoryException {
+        // TODO: TOBEFIXED
+        if (nodeState.isWorkspaceState()) {
+            throw new RepositoryException("Internal error: Cannot create Lock for 'workspace' state.");
+        }
         // retrieve node first
         Node lhNode;
         // NOTE: Node must be retrieved from the given NodeState and not from
         // the overlayed workspace nodestate. See below.
-        // TODO: don't rely on state being obtained from SessionISM. see ItemManagerImpl
         Item item = itemManager.getItem(nodeState);
         if (item.isNode()) {
             lhNode = (Node) item;
@@ -98,7 +101,7 @@
         Operation op = LockOperation.create(wspNodeState, isDeep, isSessionScoped);
         wspManager.execute(op);
 
-        Lock lock = new LockImpl(wspNodeState, lhNode, isSessionScoped);
+        Lock lock = new LockImpl(new LockState(wspNodeState), lhNode, isSessionScoped);
         return lock;
     }
 
@@ -119,7 +122,7 @@
         // added to the map.
         if (lockMap.containsKey(wspNodeState)) {
             LockImpl l = (LockImpl) lockMap.remove(wspNodeState);
-            l.unlocked();
+            l.lockState.unlocked();
         }
     }
 
@@ -134,15 +137,7 @@
      * @param nodeState
      */
     public Lock getLock(NodeState nodeState) throws LockException, RepositoryException {
-        NodeState wspNodeState;
-        // a lock can never exist on a new state -> access parent
-        if (nodeState.getStatus() == ItemState.STATUS_NEW) {
-            wspNodeState = getWorkspaceState(nodeState.getParent());
-        } else {
-            wspNodeState = getWorkspaceState(nodeState);
-        }
-
-        LockImpl l = internalGetLock(wspNodeState);
+        LockImpl l = getLockImpl(nodeState);
         // no-lock found or lock doesn't apply to this state -> throw
         if (l == null) {
             throw new LockException("Node with id '" + nodeState.getNodeId() + "' is not locked.");
@@ -158,16 +153,13 @@
      * @param nodeState
      */
     public boolean isLocked(NodeState nodeState) throws RepositoryException {
-        NodeState wspNodeState;
-        // a lock can never exist on a new state -> access parent
-        if (nodeState.getStatus() == ItemState.STATUS_NEW) {
-            wspNodeState = getWorkspaceState(nodeState.getParent());
+        if (nodeState.isWorkspaceState()) {
+            LockState lSt = getLockState(nodeState);
+            return lSt != null;
         } else {
-            wspNodeState = getWorkspaceState(nodeState);
+            LockImpl l = getLockImpl(nodeState);
+            return l != null;
         }
-
-        LockImpl l = internalGetLock(wspNodeState);
-        return l != null;
     }
 
     /**
@@ -177,16 +169,23 @@
     public void checkLock(NodeState nodeState) throws LockException, RepositoryException {
         // shortcut: new status indicates that a new state was already added
         // thus, the parent state is not locked by foreign lock.
-        if (nodeState.getStatus() == ItemState.STATUS_NEW) {
+        if (nodeState.getStatus() == Status.NEW) {
             return;
         }
 
-        NodeState wspNodeState = getWorkspaceState(nodeState);
-        LockImpl l = internalGetLock(wspNodeState);
-        if (l != null && l.lockInfo.getLockToken() == null) {
-            // lock is present and token is null -> session is not lock-holder.
-            throw new LockException("Node with id '" + nodeState + "' is locked.");
-        } // else: state is not locked at all || session is lock-holder
+        if (nodeState.isWorkspaceState()) {
+            LockState lSt = getLockState(nodeState);
+            if (lSt != null && lSt.lockInfo.getLockToken() == null) {
+                // lock is present and token is null -> session is not lock-holder.
+                throw new LockException("Node with id '" + nodeState + "' is locked.");
+            } // else: state is not locked at all || session is lock-holder
+        } else {
+            LockImpl l = getLockImpl(nodeState);
+            if (l != null && l.getLockToken() == null) {
+                // lock is present and token is null -> session is not lock-holder.
+                throw new LockException("Node with id '" + nodeState + "' is locked.");
+            } // else: state is not locked at all || session is lock-holder
+        }
     }
 
     /**
@@ -270,7 +269,7 @@
                 } catch (RepositoryException e) {
                     log.error("Error while unlocking session scoped lock. Cleaning up local lock status.");
                     // at least clean up local lock map and the locks life cycle
-                    l.unlocked();
+                    l.lockState.unlocked();
                 }
             }
         }
@@ -285,27 +284,26 @@
         // release all remaining locks without modifying their lock status
         LockImpl[] locks = (LockImpl[]) lockMap.values().toArray(new LockImpl[lockMap.size()]);
         for (int i = 0; i < locks.length; i++) {
-            locks[i].release();
+            locks[i].lockState.release();
         }
     }
 
     //------------------------------------------------------------< private >---
     /**
-     * If the given <code>NodeState</code> has an overlayed state, the overlayed
-     * (workspace) state will be returned. Otherwise the given state is returned.
+     * The workspace state of the given node is returned. If the state is a new
+     * state (no overlayed state and not being workspace state itself), an
+     * <code>IllegalArgumentException</code> is thrown.
      *
      * @param nodeState
      * @return The overlayed state or the given state, if this one does not have
      * an overlayed state.
      */
     private NodeState getWorkspaceState(NodeState nodeState) {
-        if (nodeState.hasOverlayedState()) {
-            // nodestate has been obtained from  Session-ISM
-            return (NodeState) nodeState.getOverlayedState();
-        } else {
-            // nodestate has been obtained from Workspace-ISM already
-            return nodeState;
+        NodeState wspState = (NodeState) nodeState.getWorkspaceState();
+        if (wspState == null) {
+            throw new IllegalArgumentException("NodeState " + nodeState + " has no overlayed state.");
         }
+        return wspState;
     }
 
     /**
@@ -314,26 +312,56 @@
      * Note, that this methods does NOT check if the given node state would
      * be affected by the lock present on an ancestor state.
      *
-     * @param wspNodeState <code>NodeState</code> from which searching starts.
+     * @param nodeState <code>NodeState</code> from which searching starts.
      * Note, that the given state must not have an overlayed state.
      * @return a state holding a lock or <code>null</code> if neither the
      * given state nor any of its ancestors is locked.
      */
-    private NodeState getLockHoldingState(NodeState wspNodeState) {
+    private NodeState getLockHoldingState(NodeState nodeState) {
         /**
          * TODO: should not only rely on existence of jcr:lockIsDeep property
          * but also verify that node.isNodeType("mix:lockable")==true;
          * this would have a negative impact on performance though...
          */
-        while (!wspNodeState.hasPropertyName(QName.JCR_LOCKISDEEP)) {
-            NodeState parentState = wspNodeState.getParent();
+        while (!nodeState.hasPropertyName(QName.JCR_LOCKISDEEP)) {
+            NodeState parentState = nodeState.getParent();
             if (parentState == null) {
                 // reached root state without finding a locked node
                 return null;
             }
-            wspNodeState = parentState;
+            nodeState = parentState;
+        }
+        return nodeState;
+    }
+
+    private LockState getLockState(NodeState wspState) throws LockException, RepositoryException {
+        wspState.checkIsWorkspaceState();
+
+        if (lockMap.containsKey(wspState)) {
+            LockImpl lock = (LockImpl) lockMap.get(wspState);
+            return lock.lockState;
+        }
+
+        // try to retrieve a state (ev. a parent state) that holds a lock.
+        NodeState lockHoldingWspState = getLockHoldingState(wspState);
+        if (lockHoldingWspState == null) {
+            // no lock
+            return null;
+        } else {
+            if (lockMap.containsKey(lockHoldingWspState)) {
+                LockImpl lock = (LockImpl) lockMap.get(lockHoldingWspState);
+                return lock.lockState;
+            }
+
+            LockState st = new LockState(lockHoldingWspState);
+            if (st.appliesToNodeState(wspState)) {
+                return st;
+            } else {
+                // lock exists but does not apply to the workspace node state
+                // passed to this method.
+                return null;
+            }
         }
-        return wspNodeState;
     }
 
     /**
@@ -341,40 +369,46 @@
      * by an inherited deep lock) or <code>null</code> if the state is not
      * locked at all.
      *
-     * @param wspNodeState
+     * @param nodeState
      * @return LockImpl that applies to the given state or <code>null</code>.
      * @throws RepositoryException
      */
-    private LockImpl internalGetLock(NodeState wspNodeState) throws RepositoryException {
+    private LockImpl getLockImpl(NodeState nodeState) throws RepositoryException {
         // shortcut: check if a given state holds a lock, which has been
         // accessed before (thus is known to the manager) irrespective if the
         // current session is the lock holder or not.
-        if (lockMap.containsKey(wspNodeState)) {
-            return (LockImpl) lockMap.get(wspNodeState);
+        NodeState wspSt = (NodeState) nodeState.getWorkspaceState();
+        if (wspSt != null && lockMap.containsKey(nodeState)) {
+            return (LockImpl) lockMap.get(nodeState);
         }
 
         // try to retrieve a state (ev. a parent state) that holds a lock.
-        NodeState lockHoldingState = getLockHoldingState(wspNodeState);
+        NodeState lockHoldingState = getLockHoldingState(nodeState);
         if (lockHoldingState == null) {
             // no lock
             return null;
         } else {
+            NodeState lockHoldingWspState = getWorkspaceState(lockHoldingState);
             // check lockMap again with the lockholding state
-            if (lockMap.containsKey(lockHoldingState)) {
-                return (LockImpl) lockMap.get(lockHoldingState);
+            if (lockMap.containsKey(lockHoldingWspState)) {
+                return (LockImpl) lockMap.get(lockHoldingWspState);
             }
 
+            if (lockHoldingWspState == lockHoldingState) {
+                // TODO: TOBEFIXED the Lock cannot be builded from a wsp-state since the Node cannot be retrieved.
+                throw new RepositoryException("Internal error: Cannot retrieve Lock for 'workspace' state " + nodeState);
+            }
+            LockState lstate = new LockState(lockHoldingWspState);
             // Lock has never been access -> build the lock object
             // retrieve lock holding node. note that this may fail if the session
             // does not have permission to see this node.
-            // TODO: TO_BE_FIXED. not correct to build Item from state obtained from WorkspaceISM. see ItemManagerImpl
             Item lockHoldingNode = itemManager.getItem(lockHoldingState);
 
             // TODO: we don;t know if lock is session scoped -> set flag to false
             // TODO: ev. add 'isSessionScoped' to RepositoryService lock-call.
-            LockImpl l = new LockImpl(lockHoldingState, (Node)lockHoldingNode, false);
+            LockImpl l = new LockImpl(lstate, (Node)lockHoldingNode, false);
 
-            if (l.appliesToNodeState(wspNodeState)) {
+            if (l.lockState.appliesToNodeState(nodeState)) {
                 return l;
             } else {
                 // lock exists but does not apply to the workspace node state
@@ -416,59 +450,160 @@
         }
     }
 
+    //--------------------------------------------------------------------------
+    private class LockState implements InternalEventListener{
+
+        private final NodeState lockHoldingState;
+        private LockInfo lockInfo;
+        private boolean isLive = true;
+
+        private LockState(NodeState lockHoldingState) throws LockException, RepositoryException {
+            lockHoldingState.checkIsWorkspaceState();
+
+            this.lockHoldingState = lockHoldingState;
+            // retrieve lock info from wsp-manager, in order to get the complete
+            // lockInfo including lock-token, which is not available from the
+            // child properties nor from the original lock request.
+            this.lockInfo = wspManager.getLockInfo(lockHoldingState.getNodeId());
+
+            // register as internal listener to the wsp manager in order to get
+            // informed if this lock ends his life.
+            wspManager.addEventListener(this);
+        }
+
+        private void refresh() throws RepositoryException {
+            // lock is still alive -> send refresh-lock operation.
+            Operation op = LockRefresh.create(lockHoldingState);
+            wspManager.execute(op);
+        }
+
+        /**
+         * Returns true, if the given node state is the lockholding state of
+         * this Lock object OR if this Lock is deep.
+         * Note, that in the latter case this method does not assert, that the
+         * given node state is a child state of the lockholding state.
+         *
+         * @param nodeState that must be the same or a child of the lock holding
+         * state stored within this lock object.
+         * @return true if this lock applies to the given node state.
+         */
+        private boolean appliesToNodeState(NodeState nodeState) {
+            if (nodeState.getStatus() == Status.NEW) {
+                return lockInfo.isDeep();
+            } else {
+                NodeState wspState = getWorkspaceState(nodeState);
+                if (lockHoldingState == wspState) {
+                    return true;
+                } else {
+                    return lockInfo.isDeep();
+                }
+            }
+        }
+
+        /**
+         * Reload the lockInfo from the server.
+         *
+         * @throws LockException
+         * @throws RepositoryException
+         */
+        private void reloadLockInfo() throws LockException, RepositoryException {
+            lockInfo = wspManager.getLockInfo(lockHoldingState.getNodeId());
+        }
+
+        /**
+         * Release this lock by removing from the lock map and unregistering
+         * it from event listening
+         */
+        private void release() {
+            if (lockMap.containsKey(lockHoldingState)) {
+                lockMap.remove(lockHoldingState);
+            }
+            wspManager.removeEventListener(this);
+        }
+
+        /**
+         * This lock has been removed by the current Session or by an external
+         * unlock request. Since a lock will never come back to life after
+         * unlocking, it is released an its status is reset accordingly.
+         */
+        private void unlocked() {
+            if (isLive) {
+                isLive = false;
+                release();
+            }
+        }
+
+        //------------------------------------------< InternalEventListener >---
+        public void onEvent(EventIterator events, boolean isLocal) {
+            if (!isLive) {
+                // since we only monitor the removal of the lock (by means
+                // of deletion of the jcr:lockIsDeep property, we are not interested
+                // if the lock is not active any more.
+                return;
+            }
+
+            while (events.hasNext()) {
+                Event ev = events.nextEvent();
+                // if the jcr:lockIsDeep property related to this Lock got removed,
+                // we assume that the lock has been released.
+                // TODO: not correct to compare nodeIds
+                if (ev.getType() == Event.PROPERTY_REMOVED
+                    && QName.JCR_LOCKISDEEP.equals(ev.getQPath().getNameElement().getName())
+                    && lockHoldingState.getNodeId().equals(ev.getParentId())) {
+
+                    // this lock has been release by someone else (and not by
+                    // a call to LockManager#unlock -> clean up and set isLive
+                    // flag to false.
+                    unlocked();
+                    break;
+                }
+            }
+        }
+
+        public void onEvent(EventIterator events, ChangeLog changeLog) {
+            // nothing to do. not interested in transient modifications
+        }
+    }
+
     //---------------------------------------------------------------< Lock >---
     /**
      * Inner class implementing the {@link Lock} interface.
      */
-    private class LockImpl implements Lock, InternalEventListener, LockTokenListener {
+    private class LockImpl implements Lock, LockTokenListener {
 
-        private final NodeState lockHoldingState;
+        private final LockState lockState;
         private final Node node;
         private final boolean isSessionScoped;
 
-        private LockInfo lockInfo;
-        private boolean isLive = true;
-
         /**
          *
-         * @param lockHoldingState The NodeState of the lock holding <code>Node</code>.
+         * @param lockState
          * Note, that the given state must not have an overlayed state.
          * @param lockHoldingNode the lock holding <code>Node</code> itself.
          * @param lockHoldingNode
          */
-        public LockImpl(NodeState lockHoldingState, Node lockHoldingNode, boolean isSessionScoped) throws LockException, RepositoryException {
-            if (lockHoldingState.hasOverlayedState()) {
-                throw new IllegalArgumentException("Cannot build Lock object from a node state that has an overlayed state.");
-            }
+        public LockImpl(LockState lockState, Node lockHoldingNode, boolean isSessionScoped) {
+            this.lockState = lockState;
 
-            this.lockHoldingState = lockHoldingState;
             this.node = lockHoldingNode;
             this.isSessionScoped = isSessionScoped;
 
-            // retrieve lock info from wsp-manager, in order to get the complete
-            // lockInfo including lock-token, which is not available from the
-            // child properties nor from the original lock request.
-            this.lockInfo = wspManager.getLockInfo(lockHoldingState.getNodeId());
-
-            // register as internal listener to the wsp manager in order to get
-            // informed if this lock ends his life.
-            wspManager.addEventListener(this);
             // store lock in the map
-            lockMap.put(lockHoldingState, this);
+            lockMap.put(lockState.lockHoldingState, this);
         }
 
         /**
          * @see Lock#getLockOwner()
          */
         public String getLockOwner() {
-            return lockInfo.getOwner();
+            return getLockInfo().getOwner();
         }
 
         /**
          * @see Lock#isDeep()
          */
         public boolean isDeep() {
-            return lockInfo.isDeep();
+            return getLockInfo().isDeep();
         }
 
         /**
@@ -482,14 +617,14 @@
          * @see Lock#getLockToken()
          */
         public String getLockToken() {
-            return lockInfo.getLockToken();
+            return getLockInfo().getLockToken();
         }
 
         /**
          * @see Lock#isLive()
          */
         public boolean isLive() throws RepositoryException {
-            return isLive;
+            return lockState.isLive;
         }
 
         /**
@@ -512,48 +647,10 @@
                 // lock-holder of a foreign lock.
                 throw new LockException("Session does not hold lock.");
             } else {
-                // lock is still alive -> send refresh-lock operation.
-                Operation op = LockRefresh.create(lockHoldingState);
-                wspManager.execute(op);
+                lockState.refresh();
             }
         }
 
-        //------------------------------------------< InternalEventListener >---
-        /**
-         *
-         * @param events
-         * @param isLocal
-         */
-        public void onEvent(EventIterator events, boolean isLocal) {
-            if (!isLive) {
-                // since we only monitor the removal of the lock (by means
-                // of deletion of the jcr:lockIsDeep property, we are not interested
-                // if the lock is not active any more.
-                return;
-            }
-
-            while (events.hasNext()) {
-                Event ev = events.nextEvent();
-                // if the jcr:lockIsDeep property related to this Lock got removed,
-                // we assume that the lock has been released.
-                // TODO: not correct to compare nodeIds
-                if (ev.getType() == Event.PROPERTY_REMOVED
-                    && QName.JCR_LOCKISDEEP.equals(ev.getQPath().getNameElement().getName())
-                    && lockHoldingState.getNodeId().equals(ev.getParentId())) {
-
-                    // this lock has been release by someone else (and not by
-                    // a call to LockManager#unlock -> clean up and set isLive
-                    // flag to false.
-                    unlocked();
-                    break;
-                }
-            }
-        }
-
-        public void onEvent(EventIterator events, ChangeLog changeLog) {
-            // nothing to do. we are not interested in transient modifications
-        }
-
         //----------------------------------------------< LockTokenListener >---
         /**
          * A lock token as been added to the current Session. If this Lock
@@ -570,7 +667,7 @@
             if (getLockToken() == null) {
                 // could be that this affects this lock and session became
                 // lock holder -> releoad info to assert.
-                reloadLockInfo();
+                lockState.reloadLockInfo();
             }
         }
 
@@ -585,60 +682,12 @@
             // reload lock info, if session gave away its lock-holder status
             // for this lock.
             if (lockToken.equals(getLockToken())) {
-                reloadLockInfo();
+                lockState.reloadLockInfo();
             }
         }
 
-        //--------------------------------------------------------< private >---
-        /**
-         * Reload the lockInfo from the server.
-         *
-         * @throws LockException
-         * @throws RepositoryException
-         */
-        private void reloadLockInfo() throws LockException, RepositoryException {
-            lockInfo = wspManager.getLockInfo(lockHoldingState.getNodeId());
-        }
-
-        /**
-         * Release this lock by removing from the lock map and unregistering
-         * it from event listening
-         */
-        private void release() {
-            if (lockMap.containsKey(lockHoldingState)) {
-                lockMap.remove(lockHoldingState);
-            }
-            wspManager.removeEventListener(this);
-        }
-
-        /**
-         * This lock has been removed by the current Session or by an external
-         * unlock request. Since a lock will never come back to life after
-         * unlocking, it is released an its status is reset accordingly.
-         */
-        private void unlocked() {
-            if (isLive) {
-                isLive = false;
-                release();
-            }
-        }
-
-        /**
-         * Returns true, if the given node state is the lockholding state of
-         * this Lock object OR if this Lock is deep.
-         * Note, that in the latter case this method does not assert, that the
-         * given node state is a child state of the lockholding state.
-         *
-         * @param nodeState that must be the same or a child of the lock holding
-         * state stored within this lock object.
-         * @return true if this lock applies to the given node state.
-         */
-        private boolean appliesToNodeState(NodeState nodeState) {
-            if (lockHoldingState.equals(nodeState)) {
-                return true;
-            } else {
-                return isDeep();
-            }
+        private LockInfo getLockInfo() {
+            return lockState.lockInfo;
         }
     }
 

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java Mon Oct  9 09:46:16 2006
@@ -96,6 +96,9 @@
     public NodeState getRootState() throws ItemStateException {
         if (root == null) {
             root = isf.createRootState(this);
+            if (root.getUUID() != null) {
+                uuid2NodeState.put(root.getUUID(), root);
+            }
             root.addListener(lifeCycleListener);
         }
         return root;
@@ -181,7 +184,7 @@
      */
     private ItemState resolve(ItemId id) throws NoSuchItemStateException, ItemStateException {
         String uuid = id.getUUID();
-        Path relPath = id.getRelativePath();
+        Path path = id.getPath();
 
         NodeState nodeState;
         // resolve uuid part
@@ -189,7 +192,7 @@
             nodeState = (NodeState) uuid2NodeState.get(uuid);
             if (nodeState == null) {
                 // state identified by the uuid is not yet cached -> get from ISM
-                NodeId refId = (relPath == null) ? (NodeId) id : idFactory.createNodeId(uuid);
+                NodeId refId = (path == null) ? (NodeId) id : idFactory.createNodeId(uuid);
                 nodeState = isf.createNodeState(refId, this);
                 nodeState.addListener(lifeCycleListener);
                 uuid2NodeState.put(uuid, nodeState);
@@ -200,8 +203,8 @@
         }
 
         ItemState s = nodeState;
-        if (relPath != null) {
-            s = PathResolver.resolve(nodeState, relPath);
+        if (path != null) {
+            s = PathResolver.resolve(nodeState, path);
         }
         touch(s);
         return s;
@@ -235,9 +238,9 @@
         }
 
         // resolve relative path
-        if (id.getRelativePath() != null) {
+        if (id.getPath() != null) {
             try {
-                state = PathResolver.lookup(state, id.getRelativePath());
+                state = PathResolver.lookup(state, id.getPath());
             } catch (ItemStateException e) {
                 log.warn("exception while looking up state with id: " + id);
                 return null;
@@ -252,8 +255,8 @@
     private class ISLifeCycleListener implements ItemStateLifeCycleListener {
 
         public void statusChanged(ItemState state, int previousStatus) {
-            if (state.getStatus() == ItemState.STATUS_REMOVED ||
-                state.getStatus() == ItemState.STATUS_STALE_DESTROYED) {
+            if (state.getStatus() == Status.REMOVED ||
+                state.getStatus() == Status.STALE_DESTROYED) {
                 recentlyUsed.remove(state);
                 if (state.isNode()) {
                     NodeState nodeState = (NodeState) state;

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java Mon Oct  9 09:46:16 2006
@@ -109,7 +109,7 @@
         if (!addedStates.remove(state)) {
             modifiedStates.remove(state);
             deletedStates.add(state);
-        }       
+        }
     }
 
     /**
@@ -220,6 +220,7 @@
      */
     public void collectOperations(Iterator operations) {
         Set affectedStates = new HashSet();
+        affectedStates.addAll(addedStates);
         affectedStates.addAll(deletedStates);
         affectedStates.addAll(modifiedStates);
         while (operations.hasNext()) {
@@ -244,17 +245,17 @@
         Iterator iter = modifiedStates();
         while (iter.hasNext()) {
             ItemState state = (ItemState) iter.next();
-            state.setStatus(ItemState.STATUS_EXISTING);
+            state.setStatus(Status.EXISTING);
         }
         iter = deletedStates();
         while (iter.hasNext()) {
             ItemState state = (ItemState) iter.next();
-            state.setStatus(ItemState.STATUS_REMOVED);
+            state.setStatus(Status.REMOVED);
         }
         iter = addedStates();
         while (iter.hasNext()) {
             ItemState state = (ItemState) iter.next();
-            state.setStatus(ItemState.STATUS_EXISTING);
+            state.setStatus(Status.EXISTING);
         }
     }
 

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java Mon Oct  9 09:46:16 2006
@@ -23,6 +23,7 @@
 import org.apache.jackrabbit.name.Path;
 import org.apache.jackrabbit.name.MalformedPathException;
 import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,45 +42,13 @@
      */
     private static Logger log = LoggerFactory.getLogger(ItemState.class);
 
-     //----------------< flags defining the current status of this instance >---
     /**
-     * 'existing', i.e. persistent state
+     * Flag used to distinguish workspace states from session states. The first
+     * accepts call to {@link #refresh(Event, ChangeLog)}, while the latter
+     * will be able to handle the various methods related to transient
+     * modifications.
      */
-    public static final int STATUS_EXISTING = 1;
-    /**
-     * 'existing', i.e. persistent state that has been transiently modified (copy-on-write)
-     */
-    public static final int STATUS_EXISTING_MODIFIED = 2;
-    /**
-     * 'existing', i.e. persistent state that has been transiently removed (copy-on-write)
-     */
-    public static final int STATUS_EXISTING_REMOVED = 3;
-    /**
-     * 'new' state
-     */
-    public static final int STATUS_NEW = 4;
-    /**
-     * 'existing', i.e. persistent state that has been persistently modified by somebody else
-     */
-    public static final int STATUS_STALE_MODIFIED = 5;
-    /**
-     * 'existing', i.e. persistent state that has been destroyed by somebody else
-     */
-    public static final int STATUS_STALE_DESTROYED = 6;
-
-    /**
-     * a state is permanently modified either by saving transient changes or
-     * by wsp operations or be external modification
-     * TODO: improve. status only temporarily used to indicate to a SessionISM-state to pull changes
-     */
-    public static final int STATUS_MODIFIED = 7;
-
-    /**
-     * a new state was deleted and is now 'removed'
-     * or an existing item has been removed by a workspace operation or
-     * by an external modification.
-     */
-    public static final int STATUS_REMOVED = 8;
+    private final boolean isWorkspaceState;
 
     /**
      * the internal status of this item state
@@ -114,10 +83,11 @@
      * @param parent
      * @param initialStatus the initial status of the item state object
      */
-    protected ItemState(NodeState parent, int initialStatus, IdFactory idFactory) {
+    protected ItemState(NodeState parent, int initialStatus, IdFactory idFactory,
+                        boolean isWorkspaceState) {
         switch (initialStatus) {
-            case STATUS_EXISTING:
-            case STATUS_NEW:
+            case Status.EXISTING:
+            case Status.NEW:
                 status = initialStatus;
                 break;
             default:
@@ -127,7 +97,9 @@
         }
         this.parent = parent;
         overlayedState = null;
+
         this.idFactory = idFactory;
+        this.isWorkspaceState = isWorkspaceState;
     }
 
     /**
@@ -140,9 +112,9 @@
     protected ItemState(ItemState overlayedState, NodeState parent,
                         int initialStatus, IdFactory idFactory) {
         switch (initialStatus) {
-            case STATUS_EXISTING:
-            case STATUS_EXISTING_MODIFIED:
-            case STATUS_EXISTING_REMOVED:
+            case Status.EXISTING:
+            case Status.EXISTING_MODIFIED:
+            case Status.EXISTING_REMOVED:
                 status = initialStatus;
                 break;
             default:
@@ -152,79 +124,26 @@
         }
         this.parent = parent;
         this.idFactory = idFactory;
-        connect(overlayedState);
-    }
+        this.isWorkspaceState = false;
 
-    /**
-     * Copy state information from overlayed state to this state
-     */
-    protected abstract void pull();
-
-    /**
-     * Connect this state to some underlying overlayed state.
-     */
-    protected void connect(ItemState overlayedState) {
-        if (this.overlayedState != null) {
-            if (this.overlayedState != overlayedState) {
-                throw new IllegalStateException("Item state already connected to another underlying state: " + this);
-            }
-        }
-        this.overlayedState = overlayedState;
-        this.overlayedState.addListener(this);
-    }
-
-
-    protected abstract void refresh(Event event, ChangeLog changeLog);
-
-    /**
-     * Notify the life cycle listeners that this state has changed its status.
-     */
-    private void notifyStatusChanged(int oldStatus) {
-        // copy listeners to array to avoid ConcurrentModificationException
-        ItemStateLifeCycleListener[] la;
-        synchronized (listeners) {
-            la = (ItemStateLifeCycleListener[]) listeners.toArray(new ItemStateLifeCycleListener[listeners.size()]);
-        }
-        for (int i = 0; i < la.length; i++) {
-            if (la[i] instanceof ItemStateLifeCycleListener) {
-                ((ItemStateLifeCycleListener) la[i]).statusChanged(this, oldStatus);
-            }
-        }
+        connect(overlayedState);
     }
 
+    //----------------------------------------------------------< ItemState >---
     /**
-     * Marks this item state as modified.
+     * Returns <code>true</code> if this item state is valid, that is its status
+     * is one of:
+     * <ul>
+     * <li>{@link Status#EXISTING}</li>
+     * <li>{@link Status#EXISTING_MODIFIED}</li>
+     * <li>{@link Status#NEW}</li>
+     * </ul>
+     * @return
      */
-    protected void markModified() {
-        // only transient states can be marked-modified
-        if (getStatus() != STATUS_NEW && overlayedState == null) {
-            throw new IllegalStateException("persisted cannot be called on workspace state");
-        }
-
-        switch (status) {
-            case STATUS_EXISTING:
-                setStatus(STATUS_EXISTING_MODIFIED);
-                break;
-            case STATUS_EXISTING_MODIFIED:
-                // already modified, do nothing
-                break;
-            case STATUS_NEW:
-                // still new, do nothing
-                break;
-            case STATUS_STALE_DESTROYED:
-            case STATUS_STALE_MODIFIED:
-                // should actually not get here because item should check before
-                // it modifies an item state.
-                throw new IllegalStateException("Cannot mark stale state modified.");
-
-            case STATUS_EXISTING_REMOVED:
-            default:
-                String msg = "Cannot mark item state with status " + status + " modified.";
-                throw new IllegalStateException(msg);
-        }
+    public boolean isValid() {
+        return status == Status.EXISTING || status == Status.EXISTING_MODIFIED || status == Status.NEW;
     }
 
-    //--------------------< public READ methods and package private Setters >---
     /**
      * Determines if this item state represents a node.
      *
@@ -233,6 +152,13 @@
     public abstract boolean isNode();
 
     /**
+     * Returns the name of this state.
+     *
+     * @return name of this state
+     */
+    public abstract QName getQName();
+
+    /**
      * Returns the identifier of this item state.
      *
      * @return the identifier of this item state..
@@ -313,31 +239,6 @@
     }
 
     /**
-     * Returns <code>true</code> if this item state represents new or modified
-     * state or <code>false</code> if it represents existing, unmodified state.
-     *
-     * @return <code>true</code> if this item state is modified or new,
-     *         otherwise <code>false</code>
-     */
-    public boolean isTransient() {
-        return status == STATUS_EXISTING_MODIFIED || status == STATUS_NEW;
-    }
-
-    /**
-     * Returns <code>true</code> if this item state is valid, that is its status
-     * is one of:
-     * <ul>
-     * <li>{@link #STATUS_EXISTING}</li>
-     * <li>{@link #STATUS_EXISTING_MODIFIED}</li>
-     * <li>{@link #STATUS_NEW}</li>
-     * </ul>
-     * @return
-     */
-    public boolean isValid() {
-        return status == STATUS_EXISTING || status == STATUS_EXISTING_MODIFIED || status == STATUS_NEW;
-    }
-
-    /**
      * Returns the parent <code>NodeState</code> or <code>null</code>
      * if either this item state represents the root node or this item state is
      * 'free floating', i.e. not attached to the repository's hierarchy.
@@ -363,61 +264,189 @@
      * @param newStatus the new status
      */
     void setStatus(int newStatus) {
-        if (status == newStatus) {
+        int oldStatus = status;
+        if (oldStatus == newStatus) {
             return;
         }
-        int oldStatus = status;
-        switch (newStatus) {
-            case STATUS_NEW:
-            case STATUS_EXISTING:
-            case STATUS_EXISTING_REMOVED:
-            case STATUS_EXISTING_MODIFIED:
-            case STATUS_STALE_MODIFIED:
-            case STATUS_STALE_DESTROYED:
-            case STATUS_MODIFIED:
-            case STATUS_REMOVED:
-                status = newStatus;
-                break;
-            default:
-                String msg = "illegal status: " + newStatus;
-                log.debug(msg);
-                throw new IllegalArgumentException(msg);
+
+        if (Status.isTerminalStatus(oldStatus)) {
+            throw new IllegalStateException("State is already in terminal status " + oldStatus);
+        }
+
+        if (isWorkspaceState()) {
+            switch (newStatus) {
+                case Status.EXISTING:
+                case Status.MODIFIED:
+                case Status.REMOVED:
+                    status = newStatus;
+                    break;
+
+                case Status.NEW:
+                case Status.EXISTING_REMOVED:
+                case Status.EXISTING_MODIFIED:
+                case Status.STALE_MODIFIED:
+                case Status.STALE_DESTROYED:
+                default:
+                    String msg = "Illegal status " + newStatus + " for 'workspace' state.";
+                    log.debug(msg);
+                    throw new IllegalArgumentException(msg);
+            }
+        } else {
+            switch (newStatus) {
+                case Status.NEW:
+                case Status.EXISTING:
+                case Status.EXISTING_REMOVED:
+                case Status.EXISTING_MODIFIED:
+                case Status.STALE_MODIFIED:
+                case Status.STALE_DESTROYED:
+                case Status.REMOVED:
+                    status = newStatus;
+                    break;
+
+                case Status.MODIFIED:
+                default:
+                    String msg = "Illegal status " + newStatus + " for 'session' state.";
+                    log.debug(msg);
+                    throw new IllegalArgumentException(msg);
+            }
+        }
+
+        // notifiy listeners about status change
+        // copy listeners to array to avoid ConcurrentModificationException
+        ItemStateLifeCycleListener[] la;
+        synchronized (listeners) {
+            la = (ItemStateLifeCycleListener[]) listeners.toArray(new ItemStateLifeCycleListener[listeners.size()]);
+        }
+        for (int i = 0; i < la.length; i++) {
+            if (la[i] instanceof ItemStateLifeCycleListener) {
+                ((ItemStateLifeCycleListener) la[i]).statusChanged(this, oldStatus);
+            }
+        }
+    }
+
+    /**
+     * Add an <code>ItemStateLifeCycleListener</code>
+     *
+     * @param listener the new listener to be informed on modifications
+     */
+    public void addListener(ItemStateLifeCycleListener listener) {
+        synchronized (listeners) {
+            assert (!listeners.contains(listener));
+            listeners.add(listener);
+        }
+    }
+
+    /**
+     * Remove an <code>ItemStateLifeCycleListener</code>
+     *
+     * @param listener an existing listener
+     */
+    public void removeListener(ItemStateLifeCycleListener listener) {
+        synchronized (listeners) {
+            listeners.remove(listener);
+        }
+    }
+
+    //--------------------------------------------------------< State types >---
+    /**
+     * @return true if this state is a workspace state.
+     */
+    public boolean isWorkspaceState() {
+        return isWorkspaceState;
+    }
+
+    /**
+     * Returns <i>this</i>, if {@link #isWorkspaceState()} returns <code>true</code>.
+     * Otherwise this method returns the workspace state backing <i>this</i>
+     * 'session' state or <code>null</code> if this state is new.
+     *
+     * @return the workspace state or <code>null</code> if this state is new.
+     */
+    public ItemState getWorkspaceState() {
+        if (isWorkspaceState) {
+            return this;
+        } else {
+            return overlayedState;
+        }
+    }
+
+    /**
+     * @throws IllegalStateException if this state is a 'session' state.
+     */
+    public void checkIsWorkspaceState() {
+        if (!isWorkspaceState) {
+            throw new IllegalStateException("State " + this + " is not a 'workspace' state.");
+        }
+    }
+
+    /**
+     * @throws IllegalStateException if this state is a 'workspace' state.
+     */
+    public void checkIsSessionState() {
+        if (isWorkspaceState) {
+            throw new IllegalStateException("State " + this + " is not a 'session' state.");
         }
-        notifyStatusChanged(oldStatus);
     }
 
+    //--------------------------------------------------< Workspace - State >---
     /**
-     * Determines if this item state is overlying persistent state.
+     * Used on 'workspace' states in order to update the state according to
+     * the given event (and ev. changelog).
      *
-     * @return <code>true</code> if this item state is overlying persistent
-     *         state, otherwise <code>false</code>.
+     * @param event
+     * @param changeLog
+     * @throws IllegalStateException if this state is a 'session' state.
      */
-    public boolean hasOverlayedState() {
-        return overlayedState != null;
+    abstract void refresh(Event event, ChangeLog changeLog);
+
+
+    //----------------------------------------------------< Session - State >---
+    /**
+     * Copy all state information from overlayed state to this state
+     */
+    abstract void reset();
+
+    /**
+     * Merge the state information from the overlayed state into this state
+     */
+    abstract void merge();
+
+    /**
+     * Connect this state to some underlying overlayed state.
+     */
+    void connect(ItemState overlayedState) {
+        checkIsSessionState();
+        overlayedState.checkIsWorkspaceState();
+
+        if (this.overlayedState != null && this.overlayedState != overlayedState) {
+            throw new IllegalStateException("Item state already connected to another underlying state: " + this);
+        }
+        this.overlayedState = overlayedState;
+        this.overlayedState.addListener(this);
     }
 
     /**
-     * Returns the persistent state backing <i>this</i> transient state or
-     * <code>null</code> if there is no persistent state (i.e.. <i>this</i>
-     * state is purely transient).
+     * Returns <code>true</code> if this item state represents new or modified
+     * state or <code>false</code> if it represents existing, unmodified state.
      *
-     * @return the persistent item state or <code>null</code> if there is
-     *         no persistent state.
+     * @return <code>true</code> if this item state is modified or new,
+     *         otherwise <code>false</code>
      */
-    public ItemState getOverlayedState() {
-        return overlayedState;
+    private boolean isTransient() {
+        checkIsSessionState();
+        return status == Status.EXISTING_MODIFIED || status == Status.NEW;
     }
 
     /**
      * Removes this item state. This will change the status of this property
-     * state to either {@link #STATUS_EXISTING_REMOVED} or {@link
-     * #STATUS_REMOVED} depending on the current status.
+     * state to either {@link Status#EXISTING_REMOVED} or {@link
+     * Status#REMOVED} depending on the current status.
      *
      * @throws ItemStateException if an error occurs while removing this item
      *                            state. e.g. this item state is not valid
      *                            anymore.
      */
-    public abstract void remove() throws ItemStateException;
+    abstract void remove() throws ItemStateException;
 
     /**
      * Reverts this item state to its initial status and adds itself to the Set
@@ -426,7 +455,7 @@
      * @param affectedItemStates the set of affected item states that reverted
      *                           themselfes.
      */
-    public abstract void revert(Set affectedItemStates);
+    abstract void revert(Set affectedItemStates);
 
     /**
      * Checks if this <code>ItemState</code> is transiently modified or new and
@@ -439,31 +468,36 @@
      *                        collected while the <code>ItemState</code>
      *                        hierarchy is traversed.
      */
-    public abstract void collectTransientStates(Set transientStates);
+    abstract void collectTransientStates(Set transientStates);
 
     /**
-     * Add an <code>ItemStateLifeCycleListener</code>
-     *
-     * @param listener the new listener to be informed on modifications
+     * Marks this item state as modified.
      */
-    public void addListener(ItemStateLifeCycleListener listener) {
-        synchronized (listeners) {
-            assert (!listeners.contains(listener));
-            listeners.add(listener);
-        }
-    }
+    void markModified() {
+        checkIsSessionState();
 
-    /**
-     * Remove an <code>ItemStateLifeCycleListener</code>
-     *
-     * @param listener an existing listener
-     */
-    public void removeListener(ItemStateLifeCycleListener listener) {
-        synchronized (listeners) {
-            listeners.remove(listener);
+        switch (status) {
+            case Status.EXISTING:
+                setStatus(Status.EXISTING_MODIFIED);
+                break;
+            case Status.EXISTING_MODIFIED:
+                // already modified, do nothing
+                break;
+            case Status.NEW:
+                // still new, do nothing
+                break;
+            case Status.STALE_DESTROYED:
+            case Status.STALE_MODIFIED:
+                // should actually not get here because item should check before
+                // it modifies an item state.
+                throw new IllegalStateException("Cannot mark stale state modified.");
+
+            case Status.EXISTING_REMOVED:
+            default:
+                String msg = "Cannot mark item state with status " + status + " modified.";
+                throw new IllegalStateException(msg);
         }
     }
-
     //-----------------------------------------< ItemStateLifeCycleListener >---
     /**
      *
@@ -472,26 +506,25 @@
      */
     public void statusChanged(ItemState state, int previousStatus) {
         // workspace-states never are listening to another state
-        if (getStatus() != STATUS_NEW && overlayedState == null) {
-            throw new IllegalStateException("statusChanged cannot be called on workspace state");
-        }
+        checkIsSessionState();
+        state.checkIsWorkspaceState();
 
         switch (state.getStatus()) {
-            case STATUS_EXISTING:
+            case Status.EXISTING:
                 // nothing to do
                 break;
-            case STATUS_MODIFIED:
-                if (previousStatus == STATUS_EXISTING) {
-                    // change back
-                    state.status = STATUS_EXISTING;
+            case Status.MODIFIED:
+                if (previousStatus == Status.EXISTING) {
+                    // change back // TODO: improve...
+                    state.status = Status.EXISTING;
                     // underlying state has been modified
                     if (isTransient()) {
-                        setStatus(STATUS_STALE_MODIFIED);
+                        setStatus(Status.STALE_MODIFIED);
                     } else {
                         synchronized (this) {
                             // this instance represents existing state, update it
-                            pull();
-                            setStatus(STATUS_EXISTING);
+                            merge();
+                            setStatus(Status.EXISTING);
                         }
                     }
                 } else {
@@ -499,18 +532,15 @@
                     throw new IllegalArgumentException();
                 }
                 break;
-            case STATUS_REMOVED:
+            case Status.REMOVED:
                 if (isTransient()) {
-                    setStatus(STATUS_STALE_DESTROYED);
+                    setStatus(Status.STALE_DESTROYED);
                 } else {
-                    setStatus(STATUS_REMOVED);
+                    setStatus(Status.REMOVED);
                 }
                 break;
-            case STATUS_STALE_MODIFIED:
-            case STATUS_STALE_DESTROYED:
-            case STATUS_EXISTING_REMOVED:
-            case STATUS_EXISTING_MODIFIED:
-            case STATUS_NEW:
+            default:
+                // Should never occur, since 'setStatus(int)' already validates
                 log.error("Workspace state cannot have its state changed to " + state.getStatus());
                 break;
         }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateValidator.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateValidator.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateValidator.java Mon Oct  9 09:46:16 2006
@@ -20,6 +20,7 @@
 import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.jcr2spi.nodetype.EffectiveNodeType;
 import org.apache.jackrabbit.jcr2spi.ManagerProvider;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
 import org.apache.jackrabbit.jcr2spi.util.LogUtil;
 import org.apache.jackrabbit.jcr2spi.security.AccessManager;
 import org.slf4j.LoggerFactory;