jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r552873 [1/2] - in /jackrabbit/trunk/contrib/spi: jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/ jcr2spi/src/main...
Date Tue, 03 Jul 2007 15:19:04 GMT
Author: angela
Date: Tue Jul  3 08:19:01 2007
New Revision: 552873

URL: http://svn.apache.org/viewvc?view=rev&rev=552873
Log:
JCR-999  SPI: provide batch read functionality
JCR-1000 JCR2SPI: remove duplicate item states

Added:
    jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/BatchReadConfig.java   (with props)
Modified:
    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/WorkspaceManager.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.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/operation/AddLabel.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkin.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkout.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Merge.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.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/NodeState.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/Status.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/util/StateUtility.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.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/VersionManager.java
    jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java
    jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/client/ClientRepositoryService.java
    jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/remote/RemoteRepositoryService.java
    jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/server/ServerRepositoryService.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/RepositoryServiceImpl.java
    jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java

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=552873&r1=552872&r2=552873
==============================================================================
--- 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 Tue Jul  3 08:19:01 2007
@@ -203,11 +203,8 @@
             if (session.getWorkspace().getName().equals(otherWspName)) {
                 // in addition they must provide the same id irrespective of
                 // any transient modifications.
-                ItemState wspState = state.getWorkspaceState();
-                ItemState otherWspState = other.state.getWorkspaceState();
-
-                if (wspState != null && otherWspState != null) {
-                    return wspState.getId().equals(otherWspState.getId());
+                if (state.getStatus() != Status.NEW && other.state.getStatus() != Status.NEW ) {
+                    return state.getWorkspaceId().equals(other.state.getWorkspaceId());
                 }
                 /* else:
                 - if both wsp-states are null, the items are both transiently

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=552873&r1=552872&r2=552873
==============================================================================
--- 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 Tue Jul  3 08:19:01 2007
@@ -123,7 +123,6 @@
      * @return
      */
     private boolean itemExists(ItemState itemState) {
-        itemState.checkIsSessionState();
         try {
             // check sanity of session
             session.checkIsAlive();
@@ -168,7 +167,6 @@
      */
     private Item getItem(ItemState itemState) throws ItemNotFoundException, AccessDeniedException, RepositoryException {
         session.checkIsAlive();
-        itemState.checkIsSessionState();
         if (!itemState.isValid()) {
             throw new ItemNotFoundException();
         }

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=552873&r1=552872&r2=552873
==============================================================================
--- 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 Tue Jul  3 08:19:01 2007
@@ -885,7 +885,7 @@
             return;
         }
 
-        Operation op = Update.create((NodeState) getNodeState().getWorkspaceState(), srcWorkspaceName);
+        Operation op = Update.create(getNodeState(), srcWorkspaceName);
         ((WorkspaceImpl)session.getWorkspace()).getUpdatableItemStateManager().execute(op);
     }
 

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=552873&r1=552872&r2=552873
==============================================================================
--- 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 Tue Jul  3 08:19:01 2007
@@ -524,7 +524,7 @@
         // identified by the resulting id.
         // the server must be able to deal with paths and with proper ids anyway.
         // TODO: 'createNodeId' is basically wrong since isGranted is unspecific for any item.
-        ItemId id = getIdFactory().createNodeId(parentState.getNodeId(), relPath);
+        ItemId id = getIdFactory().createNodeId((NodeId) parentState.getWorkspaceId(), relPath);
         return service.isGranted(sessionInfo, id, actions);
     }
 
@@ -536,8 +536,7 @@
         if (itemState.getStatus() == Status.NEW) {
             return true;
         }
-        ItemState wspState = itemState.getWorkspaceState();
-        return service.isGranted(sessionInfo, wspState.getId(), actions);
+        return service.isGranted(sessionInfo, itemState.getWorkspaceId(), actions);
     }
 
     /**
@@ -548,8 +547,7 @@
         if (itemState.getStatus() == Status.NEW) {
             return true;
         }
-        ItemState wspState = itemState.getWorkspaceState();
-        return service.isGranted(sessionInfo, wspState.getId(), AccessManager.READ);
+        return service.isGranted(sessionInfo, itemState.getWorkspaceId(), AccessManager.READ);
     }
 
     /**
@@ -560,8 +558,7 @@
         if (itemState.getStatus() == Status.NEW) {
             return true;
         }
-        ItemState wspState = itemState.getWorkspaceState();
-        return service.isGranted(sessionInfo, wspState.getId(), AccessManager.REMOVE);
+        return service.isGranted(sessionInfo, itemState.getWorkspaceId(), AccessManager.REMOVE);
     }
 
     /**
@@ -936,7 +933,7 @@
         public void visit(RemoveVersion operation) throws VersionException, AccessDeniedException, ReferentialIntegrityException, RepositoryException {
             NodeId versionId = (NodeId) operation.getRemoveId();
             NodeState vhState = operation.getParentState();
-            service.removeVersion(sessionInfo, vhState.getNodeId(), versionId);
+            service.removeVersion(sessionInfo, (NodeId) vhState.getWorkspaceId(), versionId);
         }
 
         /**

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java Tue Jul  3 08:19:01 2007
@@ -103,6 +103,14 @@
     public ItemState getItemState() throws ItemNotFoundException, RepositoryException;
 
     /**
+     * Set the ItemState this hierarchyEntry will be resolved to.
+     *
+     * @param state
+     * @throws IllegalStateException If the entry has already been resolved.
+     */
+    public void setItemState(ItemState state) throws IllegalStateException;
+
+    /**
      * Invalidates the underlying <code>ItemState</code> if available. If the
      * <code>recursive</code> flag is true, the hierarchy is traverses and
      * {@link #invalidate(boolean)} is called on all child entries.<br>

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java Tue Jul  3 08:19:01 2007
@@ -93,7 +93,10 @@
         if (state == null) {
             try {
                 state = doResolve();
-                target = new WeakReference(state);
+                // only set 'target' if not already by upon resolution
+                if (!isAvailable()) {
+                    setItemState(state);
+                }
             } catch (ItemNotFoundException e) {
                 remove();
                 throw e;
@@ -130,42 +133,21 @@
      * @return
      */
     ItemState internalGetItemState() {
+        ItemState state = null;
         if (target != null) {
-            ItemState state = (ItemState) target.get();
-            if (state != null) {
-                return state;
-            }
+            state = (ItemState) target.get();
         }
-        return null;
+        return state;
     }
 
     /**
-     * Set the target of this HierarchyEntry to the given new ItemState.
      *
-     * @throws IllegalStateException if this entry has already been resolved.
-     * @throws IllegalArgumentException if the given state is <code>null</code>
-     * or has another Status than {@link Status#NEW} or in case of class mismatch.
+     * @param entry
      */
-    void internalSetItemState(ItemState newItemState) {
-        if (target != null || newItemState == null) {
-            throw new IllegalStateException();
-        }
-
-        if ((denotesNode() && newItemState.isNode()) || (!denotesNode() && !newItemState.isNode())) {
-            target = new WeakReference(newItemState);
-        } else {
-            throw new IllegalArgumentException();
-        }
-    }
-
     static void removeEntry(HierarchyEntryImpl entry) {
         ItemState state = entry.internalGetItemState();
         if (state != null) {
-            if (state.getStatus() == Status.NEW) {
-                state.setStatus(Status.REMOVED);
-            } else {
-                state.getWorkspaceState().setStatus(Status.REMOVED);
-            }
+            state.setStatus(Status.REMOVED);
         }
     }
     //-----------------------------------------------------< HierarchyEntry >---
@@ -219,11 +201,7 @@
      * @see HierarchyEntry#isAvailable()
      */
     public boolean isAvailable() {
-        ItemState state = null;
-        if (target != null) {
-            state = (ItemState) target.get();
-        }
-        return state != null;
+        return internalGetItemState() != null;
     }
 
     /**
@@ -237,6 +215,20 @@
 
     /**
      * {@inheritDoc}<br>
+     * @see HierarchyEntry#setItemState(ItemState)
+     */
+    public synchronized void setItemState(ItemState state) {
+        if (state == null || (denotesNode() && !state.isNode()) || (!denotesNode() && state.isNode())) {
+            throw new IllegalArgumentException();
+        }
+        if (isAvailable()) {
+            throw new IllegalStateException("HierarchyEntry has already been resolved.");
+        }
+        target = new WeakReference(state);
+    }
+
+    /**
+     * {@inheritDoc}<br>
      * @see HierarchyEntry#invalidate(boolean)
      */
     public void invalidate(boolean recursive) {
@@ -265,12 +257,12 @@
             case Status.EXISTING_MODIFIED:
             case Status.STALE_MODIFIED:
                 // revert state from overlayed
-                state.merge(state.getWorkspaceState(), false);
+                state.revert();
                 state.setStatus(Status.EXISTING);
                 break;
             case Status.EXISTING_REMOVED:
                 // revert state from overlayed
-                state.merge(state.getWorkspaceState(), false);
+                state.revert();
                 state.setStatus(Status.EXISTING);
                 if (!denotesNode()) {
                     parent.revertPropertyRemoval((PropertyEntry) this);
@@ -306,21 +298,11 @@
         updated. otherwise the state gets updated and might be marked 'Stale'
         if transient changes are present and the workspace-state is modified.
         */
-        // TODO: check again if 'reconnect' is not possible for transiently-modified state
+        // TODO: check again if 'reload' is not possible for transiently-modified state
         if (!keepChanges || state.getStatus() == Status.EXISTING
             || state.getStatus() == Status.INVALIDATED) {
             // reload the workspace state from the persistent layer
-            try {
-                state.reconnect(keepChanges);
-            } catch (ItemNotFoundException e) {
-                // remove hierarchyEntry (including all children and set
-                // state-status to REMOVED (or STALE_DESTROYED)
-                remove();
-            } catch (RepositoryException e) {
-                // TODO: rather throw? remove from parent?
-                log.warn("Exception while reloading item state: " + e);
-                log.debug("Stacktrace: ", e);
-            }
+            state.reload(keepChanges);
         }
     }
 
@@ -334,8 +316,6 @@
             // nothing to do -> correct status must be set upon resolution.
             return;
         }
-
-        state.checkIsSessionState();
         // if during recursive removal an invalidated entry is found, reload
         // it in order to determine the current status.
         if (state.getStatus() == Status.INVALIDATED) {

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java Tue Jul  3 08:19:01 2007
@@ -216,7 +216,7 @@
 
         revertTransientChanges();
 
-        // now make sure the underlying state is reverted to the original state
+        // now make sure the attached state is reverted to the original state
         super.revert();
     }
 
@@ -529,6 +529,7 @@
      * @see NodeEntry#getNodeEntry(QName, int, boolean)
      */
     public NodeEntry getNodeEntry(QName nodeName, int index, boolean loadIfNotFound) throws RepositoryException {
+        // TODO: avoid loading the child-infos if childNodeEntries == null
         List entries = childNodeEntries().get(nodeName);
         NodeEntry cne = null;
         if (entries.size() >= index) {
@@ -600,7 +601,9 @@
                                      QName primaryNodeType, QNodeDefinition definition) throws RepositoryException {
         NodeEntry entry = internalAddNodeEntry(nodeName, uniqueID, Path.INDEX_UNDEFINED, childNodeEntries());
         NodeState state = factory.getItemStateFactory().createNewNodeState(entry, primaryNodeType, definition);
-        ((NodeEntryImpl) entry).internalSetItemState(state);
+        if (!entry.isAvailable()) {
+            entry.setItemState(state);
+        }
         return state;
     }
 
@@ -778,7 +781,9 @@
         properties.add(entry);
 
         PropertyState state = factory.getItemStateFactory().createNewPropertyState(entry, definition);
-        ((PropertyEntryImpl) entry).internalSetItemState(state);
+        if (!entry.isAvailable()) {
+            entry.setItemState(state);
+        }
 
         return state;
     }
@@ -1113,14 +1118,7 @@
         if (child == null) {
             child = childNodeAttic.get(childName, index);
             if (child == null && childNodeEntries != null) {
-                List namedChildren = childNodeEntries.get(childName);
-                for (Iterator it = namedChildren.iterator(); it.hasNext(); ) {
-                    NodeEntryImpl c = (NodeEntryImpl) it.next();
-                    if (c.matches(childName, index)) {
-                        child = c;
-                        break;
-                    }
-                }
+                child = childNodeEntries.get(childName, index);
             }
         }
         return child;

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=552873&r1=552872&r2=552873
==============================================================================
--- 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 Tue Jul  3 08:19:01 2007
@@ -89,7 +89,6 @@
      * @see LockManager#lock(NodeState,boolean,boolean)
      */
     public Lock lock(NodeState nodeState, boolean isDeep, boolean isSessionScoped) throws LockException, RepositoryException {
-        nodeState.checkIsSessionState();
         // retrieve node first
         Node lhNode;
         // NOTE: Node must be retrieved from the given NodeState and not from
@@ -156,8 +155,6 @@
      * @param nodeState
      */
     public boolean isLocked(NodeState nodeState) throws RepositoryException {
-        nodeState.checkIsSessionState();
-
         LockImpl l = getLockImpl(nodeState, false);
         return l != null;
     }
@@ -167,8 +164,6 @@
      * @param nodeState
      */
     public void checkLock(NodeState nodeState) throws LockException, RepositoryException {
-        nodeState.checkIsSessionState();
-
         // shortcut: new status indicates that a new state was already added
         // thus, the parent state is not locked by foreign lock.
         if (nodeState.getStatus() == Status.NEW) {
@@ -366,7 +361,6 @@
      * @throws RepositoryException
      */
     private LockImpl getLockImpl(NodeState nodeState, boolean lazyLockDiscovery) throws RepositoryException {
-        nodeState.checkIsSessionState();
         NodeState nState = nodeState;
         // access first non-NEW state
         while (nState.getStatus() == Status.NEW) {
@@ -478,8 +472,6 @@
         private boolean isLive = true;
 
         private LockState(NodeState lockHoldingState, LockInfo lockInfo) {
-            lockHoldingState.checkIsSessionState();
-
             this.lockHoldingState = lockHoldingState;
             this.lockInfo = lockInfo;
         }
@@ -519,7 +511,8 @@
          * @throws RepositoryException
          */
         private void reloadLockInfo() throws LockException, RepositoryException {
-            lockInfo = wspManager.getLockInfo(lockHoldingState.getNodeId());
+            NodeId nId = lockHoldingState.getNodeEntry().getWorkspaceId();
+            lockInfo = wspManager.getLockInfo(nId);
         }
 
         /**

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java Tue Jul  3 08:19:01 2007
@@ -88,11 +88,11 @@
     }
     //----------------------------------------< Access Operation Parameters >---
     public NodeId getVersionHistoryId() {
-        return versionHistoryState.getNodeId();
+        return versionHistoryState.getNodeEntry().getWorkspaceId();
     }
 
     public NodeId getVersionId() {
-        return versionState.getNodeId();
+        return versionState.getNodeEntry().getWorkspaceId();
     }
 
     public QName getLabel() {

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkin.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkin.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkin.java Tue Jul  3 08:19:01 2007
@@ -65,7 +65,7 @@
      */
     public void persisted() {
         try {
-            mgr.getVersionHistoryNodeState(nodeState).invalidate(true);
+            mgr.getVersionHistoryEntry(nodeState).invalidate(true);
         } catch (RepositoryException e) {
             log.warn("Internal error", e);
         }
@@ -82,7 +82,7 @@
      * @return The nodeState to be checked in.
      */
     public NodeId getNodeId() {
-        return nodeState.getNodeId();
+        return nodeState.getNodeEntry().getWorkspaceId();
     }
 
     //------------------------------------------------------------< Factory >---

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkout.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkout.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkout.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkout.java Tue Jul  3 08:19:01 2007
@@ -61,7 +61,7 @@
      */
     public void persisted() {
         try {
-            mgr.getVersionHistoryNodeState(nodeState).invalidate(true);
+            mgr.getVersionHistoryEntry(nodeState).invalidate(true);
         } catch (RepositoryException e) {
             log.warn("Internal error", e);
         }
@@ -81,7 +81,7 @@
      * @return
      */
     public NodeId getNodeId() {
-        return nodeState.getNodeId();
+        return nodeState.getNodeEntry().getWorkspaceId();
     }
 
     //------------------------------------------------------------< Factory >---

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Merge.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Merge.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Merge.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Merge.java Tue Jul  3 08:19:01 2007
@@ -69,7 +69,7 @@
      */
     public void persisted() {
         try {
-            mgr.getVersionHistoryNodeState(nodeState).invalidate(true);
+            mgr.getVersionHistoryEntry(nodeState).invalidate(true);
         } catch (RepositoryException e) {
             log.warn("Error while retrieving VersionHistory state:", e.getMessage());
         }
@@ -78,7 +78,7 @@
 
     //----------------------------------------< Access Operation Parameters >---
     public NodeId getNodeId() {
-        return nodeState.getNodeId();
+        return nodeState.getNodeEntry().getWorkspaceId();
     }
 
     public String getSourceWorkspaceName() {

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java Tue Jul  3 08:19:01 2007
@@ -86,11 +86,11 @@
 
     //----------------------------------------< Access Operation Parameters >---
     public NodeId getVersionHistoryId() {
-        return versionHistoryState.getNodeId();
+        return versionHistoryState.getNodeEntry().getWorkspaceId();
     }
 
     public NodeId getVersionId() {
-        return versionState.getNodeId();
+        return versionState.getNodeEntry().getWorkspaceId();
     }
 
     public QName getLabel() {

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java Tue Jul  3 08:19:01 2007
@@ -21,6 +21,7 @@
 import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
 import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
 import org.apache.jackrabbit.jcr2spi.version.VersionManager;
+import org.apache.jackrabbit.spi.ItemId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,7 +43,7 @@
     protected RemoveVersion(ItemState removeState, NodeState parent, VersionManager mgr) {
         super(removeState, parent);
         try {
-            versionableEntry = mgr.getVersionableNodeState((NodeState) removeState);
+            versionableEntry = mgr.getVersionableNodeEntry((NodeState) removeState);
         } catch (RepositoryException e) {
             log.warn("Internal error", e);
         }
@@ -76,6 +77,11 @@
         // invalidate the versionhistory entry and all its children
         // in order to the the v-graph recalculated
         removeState.getHierarchyEntry().getParent().invalidate(true);
+    }
+
+    //----------------------------------------< Access Operation Parameters >---
+    public ItemId getRemoveId() {
+        return removeState.getWorkspaceId();
     }
 
     //------------------------------------------------------------< Factory >---

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java Tue Jul  3 08:19:01 2007
@@ -75,7 +75,7 @@
     }
     //----------------------------------------< Access Operation Parameters >---
     public NodeId getNodeId() {
-        return nodeState.getNodeId();
+        return nodeState.getNodeEntry().getWorkspaceId();
     }
 
     public NodeId[] getMergeFailedIds() {

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java Tue Jul  3 08:19:01 2007
@@ -80,8 +80,8 @@
         }
         entry.invalidate(true);
     }
-    //----------------------------------------< Access Operation Parameters >---
 
+    //----------------------------------------< Access Operation Parameters >---
     /**
      * Returns id of state or the closest existing state of the restore target or
      * <code>null</code> in case of a {@link javax.jcr.Workspace#restore(Version[], boolean)}
@@ -89,7 +89,7 @@
      * @return
      */
     public NodeId getNodeId() {
-        return (nodeState == null) ? null : nodeState.getNodeId();
+        return (nodeState == null) ? null : nodeState.getNodeEntry().getWorkspaceId();
     }
 
     /**
@@ -106,7 +106,7 @@
     public NodeId[] getVersionIds() {
         NodeId[] versionIds = new NodeId[versionStates.length];
         for (int i = 0; i < versionStates.length; i++) {
-            versionIds[i] = versionStates[i].getNodeId();
+            versionIds[i] = versionStates[i].getNodeEntry().getWorkspaceId();
         }
         return versionIds;
     }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java Tue Jul  3 08:19:01 2007
@@ -44,7 +44,7 @@
     private SetPropertyValue(PropertyState propertyState, int valueType, QValue[] values) {
         this.propertyState = propertyState;
 
-        propertyId = propertyState.getPropertyId();
+        propertyId = (PropertyId) propertyState.getId();
         this.valueType = valueType;
         this.values = values;
 

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.java Tue Jul  3 08:19:01 2007
@@ -62,7 +62,7 @@
 
     //----------------------------------------< Access Operation Parameters >---
     public NodeId getNodeId() {
-        return nodeState.getNodeId();
+        return nodeState.getNodeEntry().getWorkspaceId();
     }
 
     public String getSourceWorkspaceName() {

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=552873&r1=552872&r2=552873
==============================================================================
--- 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 Tue Jul  3 08:19:01 2007
@@ -38,7 +38,7 @@
 /**
  * <code>ItemState</code> represents the state of an <code>Item</code>.
  */
-public abstract class ItemState implements ItemStateLifeCycleListener {
+public abstract class ItemState {
 
     /**
      * Logger instance
@@ -46,13 +46,6 @@
     private static Logger log = LoggerFactory.getLogger(ItemState.class);
 
     /**
-     * Flag used to distinguish workspace states from session states. The latter
-     * will be able to handle the various methods related to transient
-     * modifications.
-     */
-    private final boolean isWorkspaceState;
-
-    /**
      * the internal status of this item state
      */
     private int status;
@@ -76,22 +69,34 @@
     final ItemDefinitionProvider definitionProvider;
 
     /**
-     * the backing persistent item state (may be null)
+     * Constructs an item state
+     *
+     * @param entry
+     * @param isf
+     * @param definitionProvider
      */
-    transient ItemState overlayedState;
+    protected ItemState(HierarchyEntry entry, ItemStateFactory isf,
+                        ItemDefinitionProvider definitionProvider) {
+        this(getInitialStatus(entry.getParent()), entry, isf, definitionProvider);
+    }
 
     /**
-     * Constructs a new unconnected item state
+     * Constructs an item state
      *
-     * @param initialStatus
-     * @param isWorkspaceState
+     * @param entry
+     * @param isf
+     * @param definitionProvider
      */
-    protected ItemState(int initialStatus, boolean isWorkspaceState,
-                        HierarchyEntry entry, ItemStateFactory isf,
+    protected ItemState(int initialStatus, HierarchyEntry entry,
+                        ItemStateFactory isf,
                         ItemDefinitionProvider definitionProvider) {
+        if (entry == null) {
+            throw new IllegalArgumentException("Cannot build ItemState from 'null' HierarchyEntry");
+        }
         switch (initialStatus) {
             case Status.EXISTING:
             case Status.NEW:
+            case Status.EXISTING_REMOVED:
                 status = initialStatus;
                 break;
             default:
@@ -99,44 +104,32 @@
                 log.debug(msg);
                 throw new IllegalArgumentException(msg);
         }
-        if (entry == null) {
-            throw new IllegalArgumentException("Cannot build ItemState from 'null' HierarchyEntry");
-        }
         this.hierarchyEntry = entry;
         this.isf = isf;
         this.definitionProvider = definitionProvider;
-        this.isWorkspaceState = isWorkspaceState;
 
-        overlayedState = null;
+        if (!entry.isAvailable()) {
+            entry.setItemState(this);
+        }
     }
 
     /**
-     * Constructs a new item state that is initially connected to an overlayed
-     * state.
      *
-     * @param overlayedState
-     * @param initialStatus
+     * @param parent
+     * @return
      */
-    protected ItemState(ItemState overlayedState, int initialStatus, ItemStateFactory isf) {
-        switch (initialStatus) {
-            case Status.EXISTING:
-            case Status.EXISTING_MODIFIED:
-            case Status.EXISTING_REMOVED:
-                status = initialStatus;
+    private static int getInitialStatus(NodeEntry parent) {
+        int status = Status.EXISTING;
+        // walk up hiearchy and check if any of the parents is transiently
+        // removed, in which case the status must be set to EXISTING_REMOVED.
+        while (parent != null) {
+            if (parent.getStatus() == Status.EXISTING_REMOVED) {
+                status = Status.EXISTING_REMOVED;
                 break;
-            default:
-                String msg = "illegal status: " + initialStatus;
-                log.debug(msg);
-                throw new IllegalArgumentException(msg);
-        }
-        if (overlayedState.getHierarchyEntry() == null) {
-            throw new IllegalArgumentException("Cannot build ItemState from 'null' HierarchyEntry");
+            }
+            parent = parent.getParent();
         }
-        this.hierarchyEntry = overlayedState.getHierarchyEntry();
-        this.isf = isf;
-        this.isWorkspaceState = false;
-        this.definitionProvider = overlayedState.definitionProvider;
-        connect(overlayedState);
+        return status;
     }
 
     //----------------------------------------------------------< ItemState >---
@@ -193,6 +186,15 @@
 
     /**
      * Utility method:
+     * Returns the identifier of this item state. Shortcut for calling 'getWorkspaceId'
+     * on the NodeEntry or PropertyEntry respectively.
+     *
+     * @return the identifier of this item state..
+     */
+    public abstract ItemId getWorkspaceId();
+
+    /**
+     * Utility method:
      * Returns the qualified path of this item state. Shortcut for calling
      * 'getPath' on the {@link ItemState#getHierarchyEntry() hierarchy entry}.
      *
@@ -239,8 +241,8 @@
         if (Status.isTerminal(oldStatus)) {
             throw new IllegalStateException("State is already in terminal status " + Status.getName(oldStatus));
         }
-        if (Status.isValidStatusChange(oldStatus, newStatus, isWorkspaceState)) {
-            status = newStatus;
+        if (Status.isValidStatusChange(oldStatus, newStatus)) {
+            status = Status.getNewStatus(oldStatus, newStatus);
         } else {
             throw new IllegalArgumentException("Invalid new status " + Status.getName(newStatus) + " for state with status " + Status.getName(oldStatus));
         }
@@ -257,9 +259,8 @@
         }
         if (status == Status.MODIFIED) {
             /*
-            change back tmp MODIFIED status, that is used as marker only to
-            force the overlaying state to synchronize as well as to inform
-            other listeners about changes.
+            change back tmp MODIFIED status, that is used as marker only
+            inform listeners about (external) changes.
             */
             status = Status.EXISTING;
         }
@@ -275,7 +276,15 @@
      * @param keepChanges
      * @return true if this state has been modified
      */
-     public abstract boolean merge(ItemState another, boolean keepChanges);
+    public abstract boolean merge(ItemState another, boolean keepChanges);
+
+    /**
+     * Revert all transient modifications made to this ItemState.
+     *
+     * @return true if this state has been modified i.e. if there was anything
+     * to revert.
+     */
+    public abstract boolean revert();
 
     /**
      * Add an <code>ItemStateLifeCycleListener</code>
@@ -308,102 +317,6 @@
         return Collections.unmodifiableCollection(listeners).iterator();
     }
 
-    //-----------------------------------------< ItemStateLifeCycleListener >---
-    /**
-     *
-     * @param overlayed
-     * @param previousStatus
-     */
-    public void statusChanged(ItemState overlayed, int previousStatus) {
-        checkIsSessionState();
-        overlayed.checkIsWorkspaceState();
-
-        // the given state is the overlayed state this state (session) is listening to.
-        if (overlayed == overlayedState) {
-            switch (overlayed.getStatus()) {
-                case Status.MODIFIED:
-                    // underlying state has been modified by external changes
-                    if (status == Status.EXISTING || status == Status.INVALIDATED) {
-                        // temporarily set the state to MODIFIED in order to inform listeners.
-                        setStatus(Status.MODIFIED);
-                    } else if (status == Status.EXISTING_MODIFIED) {
-                        // TODO: try to merge changes
-                        setStatus(Status.STALE_MODIFIED);
-                    }
-                    // else: this status is EXISTING_REMOVED => ignore.
-                    // no other status is possible.
-                    break;
-                case Status.REMOVED:
-                    if (status == Status.EXISTING_MODIFIED) {
-                        setStatus(Status.STALE_DESTROYED);
-                    } else {
-                        setStatus(Status.REMOVED);
-                    }
-                    break;
-                case Status.INVALIDATED:
-                    // invalidate this session state if it is EXISTING.
-                    if (status == Status.EXISTING) {
-                        setStatus(Status.INVALIDATED);
-                    }
-                    break;
-                default:
-                    // Should never occur, since 'setStatus(int)' already validates
-                    log.error("Workspace state cannot have its state changed to " + overlayed.getStatus());
-                    break;
-            }
-        }
-    }
-
-    //--------------------------------------------------------< 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.");
-        }
-    }
-
-    /**
-     * @return true, if this state is overlaying a workspace state.
-     */
-    public boolean hasOverlayedState() {
-        return overlayedState != null;
-    }
-
-    //----------------------------------------------------< Session - State >---
-
     /**
      * Used on the target state of a save call AFTER the changelog has been
      * successfully submitted to the SPI..
@@ -414,74 +327,49 @@
     abstract void persisted(ChangeLog changeLog) throws IllegalStateException;
 
     /**
-     * Connect this state to some underlying overlayed state.
-     */
-    private void connect(ItemState overlayedState) {
-        checkIsSessionState();
-        overlayedState.checkIsWorkspaceState();
-
-        if (this.overlayedState == null) {
-            setOverLayedState(overlayedState);
-        } else if (this.overlayedState != overlayedState) {
-            throw new IllegalStateException("Item state already connected to another underlying state: " + this);
-        } // attempt to connect state to its ol-state again -> nothing to do.
-    }
-
-    /**
-     * Replaces the overlayedState with a new instance retrieved from the
-     * persistent layer thus forcing a reload of this ItemState or in case
-     * of a NEW state, retrieves the overlayed state after the state has been
-     * persisted and connects the NEW state. Note, that in the latter case,
-     * the parent must already be connected to its overlayed state.
+     * Retrieved a fresh ItemState from the persistent layer and merge its
+     * data with this state in order to reload it. In case of a NEW state retrieving
+     * the state from the persistent layer is only possible if the state has
+     * been persisted.
      *
      * @param keepChanges
-     * @throws ItemNotFoundException
-     * @throws RepositoryException
      */
-    public void reconnect(boolean keepChanges) throws ItemNotFoundException, RepositoryException {
-        checkIsSessionState();
-        // Need to use the workspace-ISF in order not to create a session-state.
-        ItemStateFactory wspIsf;
-        if (overlayedState != null) {
-            wspIsf = overlayedState.isf;
-        } else {
-            wspIsf = getParent().overlayedState.isf;
-        }
-        ItemId id = (overlayedState == null) ? getId() : overlayedState.getId();
-        ItemState overlayed;
-        if (isNode()) {
-            overlayed = wspIsf.createNodeState((NodeId) id, (NodeEntry) getHierarchyEntry());
-        } else {
-            overlayed = wspIsf.createPropertyState((PropertyId) id, (PropertyEntry) getHierarchyEntry());
+    public void reload(boolean keepChanges) {
+        ItemId id = getWorkspaceId();
+        ItemState tmp;
+        try {
+            if (isNode()) {
+                tmp = isf.createNodeState((NodeId) id, (NodeEntry) getHierarchyEntry());
+            } else {
+                tmp = isf.createPropertyState((PropertyId) id, (PropertyEntry) getHierarchyEntry());
+            }
+        } catch (ItemNotFoundException e) {
+            // TODO: deal with moved items separately
+            // remove hierarchyEntry (including all children and set
+            // state-status to REMOVED (or STALE_DESTROYED)
+            log.debug("Item '" + id + "' cannot be found on the persistent layer -> remove.");
+            getHierarchyEntry().remove();
+            return;
+        } catch (RepositoryException e) {
+            // TODO: rather throw? remove from parent?
+            log.warn("Exception while reloading item state: " + e);
+            log.debug("Stacktrace: ", e);
+            return;
         }
-        setOverLayedState(overlayed);
-        boolean modified = merge(overlayed, keepChanges);
+
+        boolean modified = merge(tmp, keepChanges);
         if (status == Status.NEW || status == Status.INVALIDATED) {
             setStatus(Status.EXISTING);
         } else if (modified) {
-            // start notification by marking ol-state modified.
-            overlayed.setStatus(Status.MODIFIED);
+            // start notification by marking this state modified.
+            setStatus(Status.MODIFIED);
         }
     }
 
     /**
-     *
-     * @param overlayedState
-     */
-    private void setOverLayedState(ItemState overlayedState) {
-        if (this.overlayedState != null) {
-           this.overlayedState.removeListener(this);
-        }
-        this.overlayedState = overlayedState;
-        this.overlayedState.addListener(this);
-    }
-
-    /**
      * Marks this item state as modified.
      */
     void markModified() {
-        checkIsSessionState();
-
         switch (status) {
             case Status.EXISTING:
                 setStatus(Status.EXISTING_MODIFIED);

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java Tue Jul  3 08:19:01 2007
@@ -25,6 +25,7 @@
 import org.apache.jackrabbit.spi.NodeId;
 import org.apache.jackrabbit.spi.ItemId;
 import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.NodeInfo;
 import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
 
@@ -61,39 +62,40 @@
     private QName[] mixinTypeNames = QName.EMPTY_ARRAY;
 
     /**
-     * Constructs a new node state that is not connected.
+     * Constructs a NEW NodeState
      *
-     * @param nodeTypeName  node type of this node
      * @param entry
-     * @param initialStatus the initial status of the node state object
+     * @param nodeTypeName
+     * @param mixinTypeNames
+     * @param isf
+     * @param definition
+     * @param definitionProvider
      */
     protected NodeState(NodeEntry entry, QName nodeTypeName, QName[] mixinTypeNames,
-                        QNodeDefinition definition, int initialStatus,
-                        boolean isWorkspaceState,
-                        ItemStateFactory isf, ItemDefinitionProvider definitionProvider) {
-        super(initialStatus, isWorkspaceState, entry, isf, definitionProvider);
+                        ItemStateFactory isf, QNodeDefinition definition,
+                        ItemDefinitionProvider definitionProvider) {
+        super(Status.NEW, entry, isf, definitionProvider);
         this.nodeTypeName = nodeTypeName;
         setMixinTypeNames(mixinTypeNames);
         this.definition = definition;
     }
 
     /**
-     * Constructs a new <code>NodeState</code> that is initially connected to an
-     * overlayed state.
+     * Constructs an EXISTING NodeState
      *
-     * @param overlayedState the backing node state being overlayed
-     * @param initialStatus  the initial status of the node state object
-     */
-    protected NodeState(NodeState overlayedState, int initialStatus, ItemStateFactory isf) {
-        super(overlayedState, initialStatus, isf);
-
-        synchronized (overlayedState) {
-            nodeTypeName = overlayedState.nodeTypeName;
-            definition = overlayedState.definition;
-            if (mixinTypeNames != null) {
-                this.mixinTypeNames = overlayedState.mixinTypeNames;
-            }
-        }
+     * @param entry
+     * @param nInfo
+     * @param isf
+     * @param definition
+     * @param definitionProvider
+     */
+    protected NodeState(NodeEntry entry, NodeInfo nInfo, ItemStateFactory isf,
+                        QNodeDefinition definition,
+                        ItemDefinitionProvider definitionProvider) {
+        super(entry, isf, definitionProvider);
+        this.nodeTypeName = nInfo.getNodetype();
+        setMixinTypeNames(nInfo.getMixins());
+        this.definition = definition;
     }
 
     //----------------------------------------------------------< ItemState >---
@@ -116,6 +118,14 @@
     }
 
     /**
+     * {@inheritDoc}
+     * @see ItemState#getWorkspaceId()
+     */
+    public ItemId getWorkspaceId() {
+        return getNodeEntry().getWorkspaceId();
+    }
+
+    /**
      * @see ItemState#merge(ItemState, boolean)
      */
     public boolean merge(ItemState another, boolean keepChanges) {
@@ -145,6 +155,146 @@
         return modified;
     }
 
+    /**
+     * @see ItemState#revert()
+     * @return Always returns false unless the definition has been modified
+     * along with a move operation.
+     */
+    public boolean revert() {
+        // TODO: ev. reset the 'markModified' flag
+        if (StateUtility.isMovedState(this)) {
+            try {
+                QNodeDefinition def = definitionProvider.getQNodeDefinition(this);
+                if (!def.equals(definition)) {
+                    definition = def;
+                    return true;
+                }
+            } catch (RepositoryException e) {
+                // should never get here
+                log.warn("Internal error", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @see ItemState#persisted(ChangeLog)
+     */
+    void persisted(ChangeLog changeLog) throws IllegalStateException {
+        // remember parent states that have need to adjust their uniqueID/mixintypes
+        // or that got a new child entry added or existing entries removed.
+        Map modParents = new HashMap();
+
+        // process deleted states from the changelog
+        for (Iterator it = changeLog.deletedStates(); it.hasNext();) {
+            ItemState delState = (ItemState) it.next();
+            if (Status.isTerminal(delState.getStatus())) {
+                log.debug("Removal of State " + delState + " has already been completed.");
+                continue;
+            }
+            delState.getHierarchyEntry().remove();
+
+            // adjust parent states unless the parent is removed as well
+            if (delState.getHierarchyEntry().getParent().isAvailable()) {
+                try {
+                    NodeState parent = delState.getParent();
+                    if (!changeLog.containsDeletedState(parent)) {
+                        modifiedParent(parent, delState, modParents);
+                    }
+                } catch (RepositoryException e) {
+                    // ignore. if parent state cannot be retrieved for whatever
+                    // reason, it doesn't need to be adjusted
+                }
+            }
+        }
+
+        // process added states from the changelog. since the changlog maintains
+        // LinkedHashSet for its entries, the iterator will not return a added
+        // entry before its NEW parent.
+        for (Iterator it = changeLog.addedStates(); it.hasNext();) {
+            ItemState addedState = (ItemState) it.next();
+            NodeState parent;
+            try {
+                parent = addedState.getParent();
+            } catch (RepositoryException e) {
+                // TODO: handle properly
+                log.error("Internal error:", e.getMessage());
+                continue;
+            }
+            // if parent is modified -> remember for final status reset
+            if (parent.getStatus() == Status.EXISTING_MODIFIED) {
+                modifiedParent(parent, addedState, modParents);
+            }
+            if (addedState.getStatus() == Status.EXISTING) {
+                log.debug("Adding new state " + addedState + " has already been completed.");
+            } else {
+                // connect the new state to its overlayed state (including update
+                // via merging in order to be aware of autocreated values,
+                // changed definition etc.
+                addedState.reload(false);
+            }
+        }
+
+        for (Iterator it = changeLog.modifiedStates(); it.hasNext();) {
+            ItemState modState = (ItemState) it.next();
+            if (modState.getStatus() == Status.EXISTING) {
+                log.debug("Modified state has already been processed");
+                continue;
+            }
+            if (modState.isNode()) {
+                if (StateUtility.isMovedState((NodeState) modState)) {
+                    // and mark the moved state existing
+                    modState.setStatus(Status.EXISTING);
+                } else {
+                    // remember state as modified only for later processing
+                    if (!modParents.containsKey(modState)) {
+                        modParents.put(modState, new ArrayList(2));
+                    }
+                }
+            } else {
+                // peristed prop-state has status EXISTING now
+                modState.setStatus(Status.EXISTING);
+
+                // if property state defines a modified jcr:mixinTypes the parent
+                // is listed as modified state and needs to be processed at the end.
+                if (QName.JCR_MIXINTYPES.equals(modState.getQName())) {
+                    try {
+                        modifiedParent(modState.getParent(), modState, modParents);
+                    } catch (RepositoryException e) {
+                        // should never occur. since parent must be available otherwise
+                        // the mixin could not been added/removed.
+                        log.warn("Internal error:", e.getMessage());
+                    }
+                }
+            }
+        }
+
+        /* process all parent states that are marked modified and eventually
+           need their uniqueID or mixin-types being adjusted because that property
+           has been added, modified or removed */
+        for (Iterator it = modParents.keySet().iterator(); it.hasNext();) {
+            NodeState parent = (NodeState) it.next();
+            List l = (List) modParents.get(parent);
+            adjustNodeState(parent, (PropertyState[]) l.toArray(new PropertyState[l.size()]));
+        }
+
+        /* finally check if all entries in the changelog have been processed
+           and eventually force a reload in order not to have any states with
+           wrong transient status floating around. */
+        Iterator[] its = new Iterator[] {changeLog.addedStates(), changeLog.deletedStates(), changeLog.modifiedStates()};
+        IteratorChain chain = new IteratorChain(its);
+        while (chain.hasNext()) {
+            ItemState state = (ItemState) chain.next();
+            if (!(state.getStatus() == Status.EXISTING ||
+                  state.getStatus() == Status.REMOVED ||
+                  state.getStatus() == Status.INVALIDATED)) {
+                log.info("State " + state + " with Status " + Status.getName(state.getStatus()) + " has not been processed upon ChangeLog.persisted => invalidate");
+                state.setStatus(Status.EXISTING);
+            }
+        }
+    }
+
     //----------------------------------------------------------< NodeState >---
     /**
      * @return The <code>NodeEntry</code> associated with this state.
@@ -159,11 +309,7 @@
      * @return the id of this node state.
      */
     public NodeId getNodeId() {
-        if (isWorkspaceState()) {
-            return getNodeEntry().getWorkspaceId();
-        } else {
-            return getNodeEntry().getId();
-        }
+        return getNodeEntry().getId();
     }
 
     /**
@@ -324,129 +470,6 @@
     }
 
     /**
-     * {@inheritDoc}
-     * @see ItemState#persisted(ChangeLog)
-     */
-    void persisted(ChangeLog changeLog) throws IllegalStateException {
-        checkIsSessionState();
-
-        // remember parent states that have need to adjust their uniqueID/mixintypes
-        // or that got a new child entry added or existing entries removed.
-        Map modParents = new HashMap();
-
-        // process deleted states from the changelog
-        for (Iterator it = changeLog.deletedStates(); it.hasNext();) {
-            ItemState delState = (ItemState) it.next();
-            if (Status.isTerminal(delState.getStatus())) {
-                log.debug("Removal of State " + delState + " has already been completed.");
-                continue;
-            }
-            delState.getHierarchyEntry().remove();
-
-            // adjust parent states unless the parent is removed as well
-            if (delState.getHierarchyEntry().getParent().isAvailable()) {
-                try {
-                    NodeState parent = delState.getParent();
-                    if (!changeLog.containsDeletedState(parent)) {
-                        modifiedParent(parent, delState, modParents);
-                    }
-                } catch (RepositoryException e) {
-                    // ignore. if parent state cannot be retrieved for whatever
-                    // reason, it doesn't need to be adjusted
-                }
-            }
-        }
-
-        // process added states from the changelog. since the changlog maintains
-        // LinkedHashSet for its entries, the iterator will not return a added
-        // entry before its NEW parent.
-        for (Iterator it = changeLog.addedStates(); it.hasNext();) {
-            ItemState addedState = (ItemState) it.next();
-            try {
-                NodeState parent = addedState.getParent();
-                // if parent is modified -> remember for final status reset
-                if (parent.getStatus() == Status.EXISTING_MODIFIED) {
-                    modifiedParent(parent, addedState, modParents);
-                }
-                if (addedState.getStatus() == Status.EXISTING) {
-                    log.debug("Adding new state " + addedState + " has already been completed.");
-                } else {
-                    // connect the new state to its overlayed state (including update
-                    // via merging in order to be aware of autocreated values,
-                    // changed definition etc.
-                    addedState.reconnect(false);
-                }
-            } catch (RepositoryException e) {
-                // should never occur
-                log.error("Internal error:", e.getMessage());
-            }
-        }
-
-        for (Iterator it = changeLog.modifiedStates(); it.hasNext();) {
-            ItemState modState = (ItemState) it.next();
-            if (modState.getStatus() == Status.EXISTING) {
-                log.debug("Modified state has already been processed");
-                continue;
-            }
-            if (modState.isNode()) {
-                if (StateUtility.isMovedState((NodeState) modState)) {
-                    // set definition of overlayed according to session-state
-                    NodeState overlayed = (NodeState) modState.overlayedState;
-                    overlayed.definition = ((NodeState) modState).definition;
-
-                    // and mark the moved state existing
-                    modState.setStatus(Status.EXISTING);
-                } else {
-                    // remember state as modified only for later processing
-                    if (!modParents.containsKey(modState)) {
-                        modParents.put(modState, new ArrayList(2));
-                    }
-                }
-            } else {
-                // Properties: push changes down to overlayed state
-                modState.overlayedState.merge(modState, false);
-                modState.setStatus(Status.EXISTING);
-
-                // if property state defines a modified jcr:mixinTypes the parent
-                // is listed as modified state and needs to be processed at the end.
-                if (QName.JCR_MIXINTYPES.equals(modState.getQName())) {
-                    try {
-                        modifiedParent(modState.getParent(), modState, modParents);
-                    } catch (RepositoryException e) {
-                        // should never occur. since parent must be available otherwise
-                        // the mixin could not been added/removed.
-                        log.warn("Internal error:", e.getMessage());
-                    }
-                }
-            }
-        }
-
-        /* process all parent states that are marked modified and eventually
-           need their uniqueID or mixin-types being adjusted because that property
-           has been added, modified or removed */
-        for (Iterator it = modParents.keySet().iterator(); it.hasNext();) {
-            NodeState parent = (NodeState) it.next();
-            List l = (List) modParents.get(parent);
-            adjustNodeState(parent, (PropertyState[]) l.toArray(new PropertyState[l.size()]));
-        }
-
-        /* finally check if all entries in the changelog have been processed
-           and eventually force a reload in order not to have any states with
-           wrong transient status floating around. */
-        Iterator[] its = new Iterator[] {changeLog.addedStates(), changeLog.deletedStates(), changeLog.modifiedStates()};
-        IteratorChain chain = new IteratorChain(its);
-        while (chain.hasNext()) {
-            ItemState state = (ItemState) chain.next();
-            if (!(state.getStatus() == Status.EXISTING ||
-                  state.getStatus() == Status.REMOVED ||
-                  state.getStatus() == Status.INVALIDATED)) {
-                log.info("State " + state + " with Status " + Status.getName(state.getStatus()) + " has not been processed upon ChangeLog.persisted => invalidate");
-                state.setStatus(Status.EXISTING);
-            }
-        }
-    }
-
-    /**
      * Reorders the child node <code>insertNode</code> before the child node
      * <code>beforeNode</code>.
      *
@@ -459,7 +482,6 @@
      */
     synchronized void reorderChildNodeEntries(NodeState insertNode, NodeState beforeNode)
         throws ItemNotFoundException, RepositoryException {
-        checkIsSessionState();
 
         NodeEntry before = (beforeNode == null) ? null : beforeNode.getNodeEntry();
         insertNode.getNodeEntry().orderBefore(before);
@@ -482,8 +504,6 @@
     synchronized void moveChildNodeEntry(NodeState newParent, NodeState childState,
                                          QName newName, QNodeDefinition newDefinition)
         throws RepositoryException {
-        checkIsSessionState();
-
         // move child entry
         childState.getNodeEntry().move(newName, newParent.getNodeEntry(), true);
         childState.definition = newDefinition;
@@ -518,40 +538,23 @@
      * @param props
      */
     private static void adjustNodeState(NodeState parent, PropertyState[] props) {
-        NodeState overlayed = (NodeState) parent.overlayedState;
-        if (overlayed != null) {
-            for (int i = 0; i < props.length; i++) {
-                PropertyState propState = props[i];
-                if (QName.JCR_UUID.equals(propState.getQName())) {
-                    if (propState.getStatus() == Status.REMOVED) {
-                        parent.getNodeEntry().setUniqueID(null);
-                    } else {
-                        // retrieve uuid from persistent layer
-                        try {
-                            propState.reconnect(false);
-                        } catch (RepositoryException e) {
-                            // TODO: handle properly
-                            log.error("Internal error", e);
-                        }
-                    }
-                } else if (QName.JCR_MIXINTYPES.equals(propState.getQName())) {
-                    QName[] mixins = StateUtility.getMixinNames(propState);
-                    parent.setMixinTypeNames(mixins);
-                    overlayed.setMixinTypeNames(mixins);
-                } // else: ignore.
-            }
-
-            // set parent status to 'existing'
-            parent.setStatus(Status.EXISTING);
-            try {
-                parent.reconnect(false);
-            } catch (RepositoryException e) {
-                // TODO: handle properly
-                log.error("Internal error", e);
-            }
-        } else {
-            // should never occur.
-            log.warn("Error while adjusting nodestate: Overlayed state is missing.");
+        for (int i = 0; i < props.length; i++) {
+            PropertyState propState = props[i];
+            if (QName.JCR_UUID.equals(propState.getQName())) {
+                if (propState.getStatus() == Status.REMOVED) {
+                    parent.getNodeEntry().setUniqueID(null);
+                } else {
+                    // retrieve uuid from persistent layer
+                    propState.reload(false);
+                }
+            } else if (QName.JCR_MIXINTYPES.equals(propState.getQName())) {
+                QName[] mixins = StateUtility.getMixinNames(propState);
+                parent.setMixinTypeNames(mixins);
+            } // else: ignore.
         }
+
+        // set parent status to 'existing'
+        parent.setStatus(Status.EXISTING);
+        parent.reload(false);
     }
 }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java Tue Jul  3 08:19:01 2007
@@ -16,21 +16,20 @@
  */
 package org.apache.jackrabbit.jcr2spi.state;
 
-import javax.jcr.PropertyType;
-import javax.jcr.ValueFormatException;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.ConstraintViolationException;
-
-import org.apache.jackrabbit.spi.QPropertyDefinition;
-import org.apache.jackrabbit.spi.PropertyId;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
+import org.apache.jackrabbit.jcr2spi.nodetype.ItemDefinitionProvider;
+import org.apache.jackrabbit.jcr2spi.nodetype.ValueConstraint;
 import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.PropertyInfo;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.spi.QValue;
-import org.apache.jackrabbit.jcr2spi.nodetype.ValueConstraint;
-import org.apache.jackrabbit.jcr2spi.nodetype.ItemDefinitionProvider;
-import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.ConstraintViolationException;
 import java.util.Iterator;
 
 /**
@@ -46,77 +45,58 @@
     private QPropertyDefinition definition;
 
     /**
-     * The internal value(s)
-     */
-    private QValue[] values;
-
-    /**
-     * The type of this property state
-     */
-    private int type;
-
-    /**
      * True if this Property is multiValued
      */
     private final boolean multiValued;
 
     /**
-     * Constructs a new property state that is initially connected to an
-     * overlayed state.
      *
-     * @param overlayedState
-     * @param initialStatus
      */
-    protected PropertyState(PropertyState overlayedState, int initialStatus,
-                            ItemStateFactory isf) {
-        super(overlayedState, initialStatus, isf);
-
-        this.definition = overlayedState.definition;
-        this.multiValued = overlayedState.multiValued;
+    private TransientData transientData;
 
-        init(overlayedState.getType(), overlayedState.getValues());
-    }
+    /**
+     *
+     */
+    private PropertyInfo pInfo;
 
     /**
-     * Create a new <code>PropertyState</code>
+     * Create a NEW PropertyState
      *
      * @param entry
-     * @param initialStatus
-     * @param isWorkspaceState
+     * @param isf
+     * @param definition
+     * @param definitionProvider
      */
-    protected PropertyState(PropertyEntry entry, boolean multiValued, QPropertyDefinition definition,
-                            int initialStatus, boolean isWorkspaceState,
-                            ItemStateFactory isf, ItemDefinitionProvider definitionProvider) {
-        super(initialStatus, isWorkspaceState, entry, isf, definitionProvider);
-
+    protected PropertyState(PropertyEntry entry, ItemStateFactory isf,
+                            QPropertyDefinition definition,
+                            ItemDefinitionProvider definitionProvider) {
+        super(Status.NEW, entry, isf, definitionProvider);
+        this.multiValued = definition.isMultiple();
         this.definition = definition;
-        this.multiValued = multiValued;
-        init(PropertyType.UNDEFINED, QValue.EMPTY_ARRAY);
+        this.transientData = null; // TODO: maybe type/values should be passed to constructor
+        this.pInfo = null;
     }
 
     /**
+     * Create an EXISTING PropertyState
      *
-     * @param type
-     * @param values
+     * @param entry
+     * @param pInfo
+     * @param isf
+     * @param definition
+     * @param definitionProvider
      */
-    void init(int type, QValue[] values) {
-        // free old values as necessary
-        QValue[] oldValues = this.values;
-        if (oldValues != null) {
-            for (int i = 0; i < oldValues.length; i++) {
-                QValue old = oldValues[i];
-                if (old != null) {
-                    // make sure temporarily allocated data is discarded
-                    // before overwriting it (see QValue#discard())
-                    old.discard();
-                }
-            }
-        }
-        this.type = type;
-        this.values = (values == null) ? QValue.EMPTY_ARRAY : values;
+    protected PropertyState(PropertyEntry entry, PropertyInfo pInfo,
+                            ItemStateFactory isf,
+                            QPropertyDefinition definition,
+                            ItemDefinitionProvider definitionProvider) {
+        super(entry, isf, definitionProvider);
+        this.multiValued = pInfo.isMultiValued();
+        this.definition = definition;
+        this.transientData = null;
+        this.pInfo = pInfo;
     }
 
-
     //----------------------------------------------------------< ItemState >---
     /**
      * Always returns false.
@@ -133,7 +113,15 @@
      * @see ItemState#getId()
      */
     public ItemId getId() {
-        return getPropertyId();
+        return ((PropertyEntry) getHierarchyEntry()).getId();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @see ItemState#getWorkspaceId()
+     */
+    public ItemId getWorkspaceId() {
+        return ((PropertyEntry) getHierarchyEntry()).getWorkspaceId();
     }
 
     /**
@@ -151,32 +139,54 @@
         if (another.isNode()) {
             throw new IllegalArgumentException("Attempt to merge property state with node state.");
         }
-        if (keepChanges || !diff(this, (PropertyState) another)) {
-            // nothing to do.
-            return false;
+        boolean modified = diff(this, (PropertyState) another);
+        this.pInfo = ((PropertyState) another).pInfo;
+        if (!keepChanges && transientData != null) {
+            modified = true;
+            transientData.discardValues();
+            transientData = null;
         }
+        return modified;
+    }
 
-        synchronized (another) {
-            PropertyState pState = (PropertyState) another;
-            init(pState.type, pState.values);
+    /**
+     * @see ItemState#revert()
+     * @return true if
+     */
+    public boolean revert() {
+        if (getStatus() == Status.NEW) {
+            throw new IllegalStateException("Cannot call revert on a NEW property state.");
+        }
+        if (transientData == null) {
+            return false;
+        } else {
+            transientData.discardValues();
+            transientData = null;
+            return true;
         }
-        return true;
     }
 
-    //------------------------------------------------------< PropertyState >---
+
     /**
-     * Returns the identifier of this property.
-     *
-     * @return the id of this property.
+     * {@inheritDoc}
+     * @see ItemState#persisted(ChangeLog)
      */
-    public PropertyId getPropertyId() {
-        if (isWorkspaceState()) {
-            return getPropertyEntry().getWorkspaceId();
-        } else {
-            return getPropertyEntry().getId();
+    void persisted(ChangeLog changeLog)
+        throws IllegalStateException {
+        for (Iterator it = changeLog.modifiedStates(); it.hasNext();) {
+            ItemState modState = (ItemState) it.next();
+            if (modState == this) {
+                /*
+                NOTE: Property can only be the changelog target, if it was
+                existing and has been modified. removal, add and implicit modification
+                of protected properties must be persisted by save on parent.
+                */
+                setStatus(Status.EXISTING);
+            }
         }
     }
 
+    //------------------------------------------------------< PropertyState >---
     /**
      * Returns the type of the property value(s).
      *
@@ -187,7 +197,7 @@
      * type if the latter is {@link PropertyType#UNDEFINED}.
      */
     public int getType() {
-        return type;
+        return (transientData == null) ? pInfo.getType() : transientData.type;
     }
 
     /**
@@ -219,7 +229,8 @@
      * @return the value(s) of this property.
      */
     public QValue[] getValues() {
-        return values;
+        // if transientData are null the pInfo MUST be present (ev. add check)
+        return (transientData == null) ? pInfo.getValues() : transientData.values;
     }
 
     /**
@@ -232,35 +243,13 @@
         if (isMultiValued()) {
             throw new ValueFormatException("'getValue' may not be called on a multi-valued state.");
         }
+        QValue[] values = getValues();
         if (values == null || values.length == 0) {
             return null;
         } else {
             return values[0];
         }
     }
-
-    /**
-     * {@inheritDoc}
-     * @see ItemState#persisted(ChangeLog)
-     */
-    void persisted(ChangeLog changeLog)
-        throws IllegalStateException {
-        checkIsSessionState();
-        for (Iterator it = changeLog.modifiedStates(); it.hasNext();) {
-            ItemState modState = (ItemState) it.next();
-            if (modState == this) {
-                /*
-                NOTE: overlayedState must be existing, otherwise save was not
-                possible on prop. Similarly a property can only be the changelog
-                target, if it was modified. removal, add and implicit modification
-                of protected properties must be persisted by save on parent.
-                */
-                // push changes to overlayed state and reset status
-                ((PropertyState) overlayedState).init(getType(), getValues());
-                setStatus(Status.EXISTING);
-            }
-        }
-    }
     
     /**
      * Sets the value(s) of this property.
@@ -268,25 +257,16 @@
      * @param values the new values
      */
     void setValues(QValue[] values, int type) throws RepositoryException {
-        checkIsSessionState();
-        // make sure the arguements are consistent and do not violate the
-        // given property definition.
-        validate(values, type, getDefinition());
-        init(type, values);
-
+        if (transientData == null) {
+            transientData = new TransientData(type, values);
+        } else {
+            transientData.setValues(type, values);
+        }
         markModified();
     }
 
     //------------------------------------------------------------< private >---
     /**
-     *
-     * @return
-     */
-    private PropertyEntry getPropertyEntry() {
-        return (PropertyEntry) getHierarchyEntry();
-    }
-
-    /**
      * Checks whether the given property parameters are consistent and satisfy
      * the constraints specified by the given definition. The following
      * validations/checks are performed:
@@ -350,5 +330,42 @@
         }
         // no difference
         return false;
+    }
+
+    //--------------------------------------------------------< inner class >---
+    /**
+     * Inner class storing transient property values an their type.
+     */
+    private class TransientData {
+
+        private int type;
+        private QValue[] values;
+
+        private TransientData(int type, QValue[] values) throws RepositoryException {
+            setValues(type, values);
+        }
+
+        private void setValues(int type, QValue[] values) throws RepositoryException {
+            // make sure the arguements are consistent and do not violate the
+            // given property definition.
+            validate(values, type, getDefinition());
+            // free old values if existing
+            discardValues();
+
+            this.type = type;
+            this.values = (values == null) ? QValue.EMPTY_ARRAY : values;
+        }
+
+        private void discardValues() {
+            if (values != null) {
+                for (int i = 0; i < values.length; i++) {
+                    if (values[i] != null) {
+                        // make sure temporarily allocated data is discarded
+                        // before overwriting it (see QValue#discard())
+                        values[i].discard();
+                    }
+                }
+            }
+        }
     }
 }



Mime
View raw message