jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r506927 [7/8] - in /jackrabbit/trunk/contrib/spi: jcr2spi/ 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...
Date Tue, 13 Feb 2007 09:31:53 GMT
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java Tue Feb 13 01:31:36 2007
@@ -42,14 +42,14 @@
 import org.apache.jackrabbit.jcr2spi.operation.AddLabel;
 import org.apache.jackrabbit.jcr2spi.operation.RemoveLabel;
 import org.apache.jackrabbit.jcr2spi.operation.RemoveVersion;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
 import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
 
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.spi.QNodeDefinition;
-import org.apache.jackrabbit.spi.ItemId;
-import org.apache.jackrabbit.spi.IdFactory;
 import org.apache.jackrabbit.spi.QValue;
 import org.apache.jackrabbit.spi.QValueFactory;
 import org.apache.jackrabbit.uuid.UUID;
@@ -73,11 +73,7 @@
 import javax.jcr.nodetype.NoSuchNodeTypeException;
 import javax.jcr.lock.LockException;
 import java.util.Iterator;
-import java.util.Set;
-import java.util.HashSet;
 import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
 import java.io.InputStream;
 
 /**
@@ -107,145 +103,21 @@
      * @param workspaceItemStateMgr
      */
     public SessionItemStateManager(UpdatableItemStateManager workspaceItemStateMgr,
-                                   IdFactory idFactory,
                                    ItemStateValidator validator,
-                                   QValueFactory qValueFactory) {
+                                   QValueFactory qValueFactory,
+                                   ItemStateFactory isf) {
+        
         this.workspaceItemStateMgr = workspaceItemStateMgr;
-        this.transientStateMgr = new TransientItemStateManager(idFactory, workspaceItemStateMgr);
+        this.transientStateMgr = new TransientItemStateManager();
+        isf.addCreationListener(transientStateMgr);
+
         this.validator = validator;
         this.qValueFactory = qValueFactory;
     }
 
-    //---------------------------------------------------< ItemStateManager >---
-    /**
-     * {@inheritDoc}
-     * @see ItemStateManager#getRootState()
-     */
-    public NodeState getRootState() throws ItemStateException {
-        // always retrieve from transientStateMgr
-        return transientStateMgr.getRootState();
-    }
-
-    /**
-     * {@inheritDoc}
-     * @see ItemStateManager#getItemState(ItemId)
-     */
-    public ItemState getItemState(ItemId id)
-            throws NoSuchItemStateException, ItemStateException {
-
-        ItemState itemState = transientStateMgr.getItemState(id);
-        // check status of ItemState. Transient ISM also returns removed ItemStates
-        if (itemState.isValid()) {
-            return itemState;
-        } else {
-            throw new NoSuchItemStateException(id.toString());
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     * @see ItemStateManager#hasItemState(ItemId)
-     */
-    public boolean hasItemState(ItemId id) {
-        // first check if the specified item exists at all in the transient ISM
-        if (transientStateMgr.hasItemState(id)) {
-            // retrieve item and check state
-            try {
-                ItemState itemState = transientStateMgr.getItemState(id);
-                if (itemState.isValid()) {
-                    return true;
-                }
-            } catch (ItemStateException e) {
-                // has been removed in the meantime
-            }
-        }
-        return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     * Since node references cannot be managed within the transient space,
-     * this call is delegated to the workspace itemstate manager.
-     *
-     * @see ItemStateManager#getReferingStates(NodeState)
-     * @param nodeState
-     */
-    public Collection getReferingStates(NodeState nodeState) throws ItemStateException {
-        NodeState wspState = (NodeState) nodeState.getWorkspaceState();
-        if (wspState == null) {
-            // new state => unable to determine references
-            return Collections.EMPTY_SET;
-        }
-
-        Collection rs = workspaceItemStateMgr.getReferingStates(wspState);
-        if (rs.isEmpty()) {
-            return rs;
-        } else {
-            // retrieve session-propertystates
-            Set refStates = new HashSet();
-            for (Iterator it =  rs.iterator(); it.hasNext();) {
-                PropertyState wState = (PropertyState) it.next();
-                ItemState sState = wState.getSessionState();
-                if (sState == null) {
-                    // overlaying state has not been build up to now
-                   sState = getItemState(wState.getPropertyId());
-                }
-                // add property state to list of refering states unless it has
-                // be removed in the transient layer.
-                if (sState.isValid()) {
-                   refStates.add(sState);
-                }
-            }
-            return Collections.unmodifiableCollection(refStates);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     * Since node references cannot be managed within the transient space,
-     * this call is delegated to the workspace itemstate manager.
-     *
-     * @see ItemStateManager#hasReferingStates(NodeState)
-     * @param nodeState
-     */
-    public boolean hasReferingStates(NodeState nodeState) {
-        try {
-            return !getReferingStates(nodeState).isEmpty();
-        } catch (ItemStateException e) {
-            log.warn("Internal error", e);
-            return false;
-        }
-    }
-
-    //------------------------------------------< UpdatableItemStateManager >---
-    /**
-     * {@inheritDoc}
-     */
-    public void execute(Operation operation) throws RepositoryException {
-        operation.accept(this);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void execute(ChangeLog changes) throws RepositoryException {
-        throw new UnsupportedOperationException("Not implemented for SessionItemStateManager");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void dispose() {
-        // discard all transient changes
-        transientStateMgr.dispose();
-        // dispose our (i.e. 'local') state manager
-        workspaceItemStateMgr.dispose();
-    }
-
-    //--------------------------------------------------------------------------
     /**
      * @return <code>true</code> if this manager has any transient state;
-     *         <code>false</code> otherwise.
+     * <code>false</code> otherwise.
      */
     public boolean hasPendingChanges() {
         return transientStateMgr.hasPendingChanges();
@@ -285,9 +157,8 @@
      *
      * @param itemState the root state of the cancel operation.
      * @throws ItemStateException if undoing changes made to <code>state</code>
-     *                            and descendant items is not a closed set of
-     *                            changes. That is, at least another item needs
-     *                            to be canceled as well in another sub-tree.
+     * and descendant items is not a closed set of changes. That is, at least
+     * another item needs to be canceled as well in another sub-tree.
      */
     public void undo(ItemState itemState) throws ItemStateException, ConstraintViolationException {
         ChangeLog changeLog = getChangeLog(itemState, false);
@@ -298,7 +169,7 @@
             IteratorChain chain = new IteratorChain(its);
             while (chain.hasNext()) {
                 ItemState state = (ItemState) chain.next();
-                state.revert();
+                state.getHierarchyEntry().revert();
             }
 
             // remove transient states and related operations from the t-statemanager
@@ -308,7 +179,8 @@
     }
 
     /**
-     * Adjust references at the end of a successful {@link Session#importXML(String, InputStream, int) XML import}.
+     * Adjust references at the end of a successful
+     * {@link Session#importXML(String, InputStream, int) XML import}.
      *
      * @param refTracker
      * @throws ConstraintViolationException
@@ -343,46 +215,38 @@
         refTracker.clear();
     }
 
-    //-------------------------------------------< Transient state handling >---
-
+    //------------------------------------------< UpdatableItemStateManager >---
     /**
-     *
-     * @param itemState
-     * @param throwOnStale Throws StaleItemStateException if either the given
-     * <code>ItemState</code> or any of its decendants is stale and the flag is true.
-     * @return
-     * @throws StaleItemStateException if a stale <code>ItemState</code> is
-     * encountered while traversing the state hierarchy. The <code>changeLog</code>
-     * might have been populated with some transient item states. A client should
-     * therefore not reuse the <code>changeLog</code> if such an exception is thrown.
-     * @throws ItemStateException if <code>state</code> is a new item state.
+     * {@inheritDoc}
+     * @see UpdatableItemStateManager#execute(Operation)
      */
-    private ChangeLog getChangeLog(ItemState itemState, boolean throwOnStale) throws StaleItemStateException, ItemStateException, ConstraintViolationException {
-        // build changelog for affected and decendant states only
-        ChangeLog changeLog = new ChangeLog(itemState);
-        // fail-fast test: check status of this item's state
-        if (itemState.getStatus() == Status.NEW) {
-            String msg = "Cannot save an item with status NEW (" +itemState+ ").";
-            log.debug(msg);
-            throw new ItemStateException(msg);
-        }
-        if (throwOnStale && Status.isStale(itemState.getStatus())) {
-            String msg =  "Attempt to save an item, that has been externally modified (" +itemState+ ").";
-            log.debug(msg);
-            throw new StaleItemStateException(msg);
-        }
-        // collect transient/stale states that should be persisted or reverted
-        itemState.collectStates(changeLog, throwOnStale);
+    public void execute(Operation operation) throws RepositoryException {
+        operation.accept(this);
+    }
 
-        changeLog.collectOperations(transientStateMgr.getOperations());
-        changeLog.checkIsSelfContained();
-        return changeLog;
+    /**
+     * {@inheritDoc}
+     * @see UpdatableItemStateManager#execute(ChangeLog)
+     */
+    public void execute(ChangeLog changes) throws RepositoryException {
+        throw new UnsupportedOperationException("Not implemented for SessionItemStateManager");
     }
 
-    //--------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     * @see UpdatableItemStateManager#dispose()
+     */
+    public void dispose() {
+        // discard all transient changes
+        transientStateMgr.dispose();
+        // dispose our (i.e. 'local') state manager
+        workspaceItemStateMgr.dispose();
+    }
 
+    //---------------------------------------------------< OperationVisitor >---
     /**
      * @inheritDoc
+     * @see OperationVisitor#visit(AddNode)
      */
     public void visit(AddNode operation) throws LockException, ConstraintViolationException, AccessDeniedException, ItemExistsException, NoSuchNodeTypeException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
         int options = ItemStateValidator.CHECK_LOCK | ItemStateValidator.CHECK_COLLISION
@@ -397,11 +261,12 @@
 
     /**
      * @inheritDoc
+     * @see OperationVisitor#visit(AddProperty)
      */
     public void visit(AddProperty operation) throws ValueFormatException, LockException, ConstraintViolationException, AccessDeniedException, ItemExistsException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
         NodeState parent = operation.getParentState();
         QName propertyName = operation.getPropertyName();
-        QPropertyDefinition pDef = validator.getApplicablePropertyDefinition(propertyName, operation.getPropertyType(), operation.isMultiValued(), parent);
+        QPropertyDefinition pDef = operation.getDefinition();
         int targetType = pDef.getRequiredType();
         if (targetType == PropertyType.UNDEFINED) {
             targetType = operation.getPropertyType();
@@ -420,6 +285,7 @@
 
     /**
      * @inheritDoc
+     * @see OperationVisitor#visit(Move)
      */
     public void visit(Move operation) throws LockException, ConstraintViolationException, AccessDeniedException, ItemExistsException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
 
@@ -453,6 +319,7 @@
 
     /**
      * @inheritDoc
+     * @see OperationVisitor#visit(Remove)
      */
     public void visit(Remove operation) throws ConstraintViolationException, AccessDeniedException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
         ItemState state = operation.getRemoveState();
@@ -460,61 +327,68 @@
             | ItemStateValidator.CHECK_VERSIONING
             | ItemStateValidator.CHECK_CONSTRAINTS;
         removeItemState(state, options);
-        // remember operation unless new state got removed
+        // unless new state got removed remember operation and mark parent modified.
         if (!Status.isTerminal(state.getStatus())) {
             transientStateMgr.addOperation(operation);
+            operation.getParentState().markModified();
         }
     }
 
     /**
      * @inheritDoc
+     * @see OperationVisitor#visit(SetMixin)
      */
     public void visit(SetMixin operation) throws ConstraintViolationException, AccessDeniedException, NoSuchNodeTypeException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
         // NOTE: nodestate is only modified upon save of the changes!
         QName[] mixinNames = operation.getMixinNames();
         NodeState nState = operation.getNodeState();
+        NodeEntry nEntry = (NodeEntry) nState.getHierarchyEntry();
 
-        // new array of mixinNames to be set on the nodestate (and corresponding property state)
-        if (mixinNames != null && mixinNames.length > 0) {
-            // update/create corresponding property state
-            if (nState.hasPropertyName(QName.JCR_MIXINTYPES)) {
-                // execute value of existing property
-                try {
-                    PropertyState pState = nState.getPropertyState(QName.JCR_MIXINTYPES);
+        try {
+            // new array of mixinNames to be set on the nodestate (and corresponding property state)
+            PropertyEntry mixinEntry = nEntry.getPropertyEntry(QName.JCR_MIXINTYPES);
+            if (mixinNames != null && mixinNames.length > 0) {
+                // update/create corresponding property state
+                if (mixinEntry != null) {
+                    // execute value of existing property
+                    PropertyState pState = mixinEntry.getPropertyState();
                     int options = ItemStateValidator.CHECK_LOCK | ItemStateValidator.CHECK_VERSIONING;
                     setPropertyStateValue(pState, getQValues(mixinNames, qValueFactory), PropertyType.NAME, options);
-                } catch (ItemStateException e) {
-                    // should not occur, since existance has been asserted before
-                    throw new RepositoryException(e);
+                } else {
+                    // create new jcr:mixinTypes property
+                    EffectiveNodeType ent = validator.getEffectiveNodeType(nState);
+                    QPropertyDefinition pd = ent.getApplicablePropertyDefinition(QName.JCR_MIXINTYPES, PropertyType.NAME, true);
+                    QValue[] mixinValue = getQValues(mixinNames, qValueFactory);
+                    int options = ItemStateValidator.CHECK_LOCK | ItemStateValidator.CHECK_VERSIONING;
+                    addPropertyState(nState, pd.getQName(), pd.getRequiredType(), mixinValue, pd, options);
                 }
+                nState.markModified();
+                transientStateMgr.addOperation(operation);
             } else {
-                // create new jcr:mixinTypes property
-                EffectiveNodeType ent = validator.getEffectiveNodeType(nState);
-                QPropertyDefinition pd = ent.getApplicablePropertyDefinition(QName.JCR_MIXINTYPES, PropertyType.NAME, true);
-                QValue[] mixinValue = getQValues(mixinNames, qValueFactory);
-                int options = ItemStateValidator.CHECK_LOCK | ItemStateValidator.CHECK_VERSIONING;
-                addPropertyState(nState, pd.getQName(), pd.getRequiredType(), mixinValue, pd, options);
-            }
-        } else {
-            // remove the jcr:mixinTypes property state if already present
-            if (nState.hasPropertyName(QName.JCR_MIXINTYPES)) {
-                try {
-                    PropertyState pState = nState.getPropertyState(QName.JCR_MIXINTYPES);
+                // remove the jcr:mixinTypes property state if already present
+                if (mixinEntry != null) {
+                    PropertyState pState = mixinEntry.getPropertyState();
+                    boolean newMixinState = pState.getStatus() == Status.NEW;
                     int options = ItemStateValidator.CHECK_LOCK | ItemStateValidator.CHECK_VERSIONING;
                     removeItemState(pState, options);
-                } catch (ItemStateException e) {
-                    // should not occur, since existance has been asserted before
-                    throw new RepositoryException(e);
+                    // only added the remove-mixin operation if it doesn't revert
+                    // a previous 'add-mixin' (which has been removed automatically
+                    // upon notification of removing the prop-state).
+                    if (!newMixinState) {
+                        nState.markModified();
+                        transientStateMgr.addOperation(operation);
+                    }
                 }
             }
+        } catch (ItemStateException e) {
+            // should not occur, since existance has been asserted before
+            throw new RepositoryException(e);
         }
-
-        nState.markModified();
-        transientStateMgr.addOperation(operation);
     }
 
     /**
      * @inheritDoc
+     * @see OperationVisitor#visit(SetPropertyValue)
      */
     public void visit(SetPropertyValue operation) throws ValueFormatException, LockException, ConstraintViolationException, AccessDeniedException, ItemExistsException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
         PropertyState pState = operation.getPropertyState();
@@ -527,6 +401,7 @@
 
     /**
      * @inheritDoc
+     * @see OperationVisitor#visit(ReorderNodes)
      */
     public void visit(ReorderNodes operation) throws ConstraintViolationException, AccessDeniedException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
         NodeState parent = operation.getParentState();
@@ -541,58 +416,114 @@
         transientStateMgr.addOperation(operation);
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(Clone)
+     */
     public void visit(Clone operation) throws NoSuchWorkspaceException, LockException, ConstraintViolationException, AccessDeniedException, ItemExistsException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: Clone cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(Clone)
+     */
     public void visit(Copy operation) throws NoSuchWorkspaceException, LockException, ConstraintViolationException, AccessDeniedException, ItemExistsException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: Copy cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(Clone)
+     */
     public void visit(Checkout operation) throws RepositoryException, UnsupportedRepositoryOperationException {
         throw new UnsupportedOperationException("Internal error: Checkout cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(Clone)
+     */
     public void visit(Checkin operation) throws UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: Checkin cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(Update)
+     */
     public void visit(Update operation) throws NoSuchWorkspaceException, AccessDeniedException, LockException, InvalidItemStateException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: Update cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(Restore)
+     */
     public void visit(Restore operation) throws VersionException, PathNotFoundException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: Restore cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(Merge)
+     */
     public void visit(Merge operation) throws NoSuchWorkspaceException, AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: Merge cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(ResolveMergeConflict)
+     */
     public void visit(ResolveMergeConflict operation) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: Update cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(LockOperation)
+     */
     public void visit(LockOperation operation) throws AccessDeniedException, InvalidItemStateException, UnsupportedRepositoryOperationException, LockException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: Lock cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(LockRefresh)
+     */
     public void visit(LockRefresh operation) throws AccessDeniedException, InvalidItemStateException, UnsupportedRepositoryOperationException, LockException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: LockRefresh cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(LockRelease)
+     */
     public void visit(LockRelease operation) throws AccessDeniedException, InvalidItemStateException, UnsupportedRepositoryOperationException, LockException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: LockRelease cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(AddLabel)
+     */
     public void visit(AddLabel operation) throws VersionException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: AddLabel cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(RemoveLabel)
+     */
     public void visit(RemoveLabel operation) throws VersionException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: RemoveLabel cannot be handled by session ItemStateManager.");
     }
 
+    /**
+     * @throws UnsupportedOperationException
+     * @see OperationVisitor#visit(RemoveVersion)
+     */
     public void visit(RemoveVersion operation) throws VersionException, AccessDeniedException, ReferentialIntegrityException, RepositoryException {
         throw new UnsupportedOperationException("Internal error: RemoveVersion cannot be handled by session ItemStateManager.");
     }
@@ -600,6 +531,40 @@
     //--------------------------------------------< Internal State Handling >---
     /**
      *
+     * @param itemState
+     * @param throwOnStale Throws StaleItemStateException if either the given
+     * <code>ItemState</code> or any of its decendants is stale and the flag is true.
+     * @return
+     * @throws StaleItemStateException if a stale <code>ItemState</code> is
+     * encountered while traversing the state hierarchy. The <code>changeLog</code>
+     * might have been populated with some transient item states. A client should
+     * therefore not reuse the <code>changeLog</code> if such an exception is thrown.
+     * @throws ItemStateException if <code>state</code> is a new item state.
+     */
+    private ChangeLog getChangeLog(ItemState itemState, boolean throwOnStale) throws StaleItemStateException, ItemStateException, ConstraintViolationException {
+        // build changelog for affected and decendant states only
+        ChangeLog changeLog = new ChangeLog(itemState);
+        // fail-fast test: check status of this item's state
+        if (itemState.getStatus() == Status.NEW) {
+            String msg = "Cannot save an item with status NEW (" +itemState+ ").";
+            log.debug(msg);
+            throw new ItemStateException(msg);
+        }
+        if (throwOnStale && Status.isStale(itemState.getStatus())) {
+            String msg =  "Attempt to save an item, that has been externally modified (" +itemState+ ").";
+            log.debug(msg);
+            throw new StaleItemStateException(msg);
+        }
+        // collect transient/stale states that should be persisted or reverted
+        itemState.getHierarchyEntry().collectStates(changeLog, throwOnStale);
+
+        changeLog.collectOperations(transientStateMgr.getOperations());
+        changeLog.checkIsSelfContained();
+        return changeLog;
+    }
+
+    /**
+     *
      * @param parent
      * @param propertyName
      * @param propertyType
@@ -685,7 +650,7 @@
         // recursively remove the given state and all child states.
         boolean success = false;
         try {
-            itemState.remove();
+            itemState.getHierarchyEntry().transientRemove();
             success = true;
         } catch (ItemStateException e) {
             throw new RepositoryException("Cannot remove item: " + e.getMessage(), e);

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java Tue Feb 13 01:31:36 2007
@@ -18,6 +18,8 @@
  */
 public final class Status {
 
+    public static final int _UNDEFINED_ = -1;
+
     /**
      * A state once read from persistent storage has been set to invalid. This
      * means that the state needs to be re-fetched from persistent storage when
@@ -221,6 +223,9 @@
      * @return Human readable status name for the given int.
      */
     public static String getName(int status) {
+        if (status == _UNDEFINED_) {
+            return "_UNDEFINED_";
+        }
         if (status < 0 || status >= STATUS_NAMES.length) {
             throw new IllegalArgumentException("Invalid status " + status);
         }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java Tue Feb 13 01:31:36 2007
@@ -18,185 +18,178 @@
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.jackrabbit.spi.IdFactory;
 import org.apache.jackrabbit.spi.QNodeDefinition;
-import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.spi.NodeId;
 import org.apache.jackrabbit.spi.PropertyId;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.name.QName;
-import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
+import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeRegistry;
+
+import java.util.Iterator;
 
 /**
  * <code>TransientISFactory</code>...
  */
-final class TransientISFactory implements TransientItemStateFactory {
+public final class TransientISFactory extends AbstractItemStateFactory implements TransientItemStateFactory  {
 
     private static Logger log = LoggerFactory.getLogger(TransientISFactory.class);
 
-    private final IdFactory idFactory;
-    private final ItemStateManager workspaceItemStateMgr;
-
-    private ItemStateCache cache;
-    private ItemStateCreationListener listener;
+    private final ItemStateFactory workspaceStateFactory;
+    private final NodeTypeRegistry ntReg;
 
-    TransientISFactory(IdFactory idFactory, ItemStateManager workspaceItemStateMgr) {
-        this.idFactory = idFactory;
-        this.workspaceItemStateMgr = workspaceItemStateMgr;
+    public TransientISFactory(ItemStateFactory workspaceStateFactory, NodeTypeRegistry ntReg) {
+        this.workspaceStateFactory = workspaceStateFactory;
+        this.ntReg = ntReg;
     }
 
     //------------------------------------------< TransientItemStateFactory >---
     /**
      * @inheritDoc
-     * @see TransientItemStateFactory#createNewNodeState(QName, String, NodeState, QName, QNodeDefinition)
+     * @see TransientItemStateFactory#createNewNodeState(NodeEntry , QName, QNodeDefinition)
      */
-    public NodeState createNewNodeState(QName name, String uniqueID,
-                                        NodeState parent, QName nodetypeName,
+    public NodeState createNewNodeState(NodeEntry entry, QName nodetypeName,
                                         QNodeDefinition definition) {
-        NodeState nodeState = new NodeState(name, uniqueID, parent, nodetypeName,
-            definition, Status.NEW, this, idFactory, false);
 
-        // notify listeners when this item state is saved or invalidated
-        nodeState.addListener(cache);
-        nodeState.addListener(listener);
+        NodeState nodeState = new NodeState(entry, nodetypeName, QName.EMPTY_ARRAY, definition, Status.NEW, false, this, ntReg);
 
         // notify listeners that a node state has been created
-        cache.created(nodeState);
-        listener.created(nodeState);
+        notifyCreated(nodeState);
 
         return nodeState;
     }
 
     /**
      * @inheritDoc
-     * @see TransientItemStateFactory#createNewPropertyState(QName, NodeState, QPropertyDefinition)
+     * @see TransientItemStateFactory#createNewPropertyState(PropertyEntry, QPropertyDefinition)
      */
-    public PropertyState createNewPropertyState(QName name, NodeState parent, QPropertyDefinition definition) {
-        PropertyState propState = new PropertyState(name, parent,
-            definition, Status.NEW, this, idFactory, false);
-
-        // get a notification when this item state is saved or invalidated
-        propState.addListener(cache);
-        propState.addListener(listener);
+    public PropertyState createNewPropertyState(PropertyEntry entry, QPropertyDefinition definition) {
+        PropertyState propState = new PropertyState(entry, definition.isMultiple(), definition, Status.NEW, false, this, ntReg);
 
         // notify listeners that a property state has been created
-        cache.created(propState);
-        listener.created(propState);
+        notifyCreated(propState);
 
         return propState;
     }
 
+    //---------------------------------------------------< ItemStateFactory >---
     /**
      * @inheritDoc
-     * @see TransientItemStateFactory#setListener(ItemStateCreationListener)
+     * @see ItemStateFactory#createRootState(NodeEntry)
+     * @param entry
      */
-    public void setListener(ItemStateCreationListener listener) {
-        this.listener = listener;
+    public NodeState createRootState(NodeEntry entry) throws ItemStateException {
+        // retrieve state to overlay
+        NodeState overlayedState = (NodeState) workspaceStateFactory.createRootState(entry);
+        return buildNodeState(overlayedState, Status.EXISTING);
     }
 
-    //---------------------------------------------------< ItemStateFactory >---
     /**
      * @inheritDoc
-     * @see ItemStateFactory#createRootState(ItemStateManager)
+     * @see ItemStateFactory#createNodeState(NodeId,NodeEntry)
      */
-    public NodeState createRootState(ItemStateManager ism) throws ItemStateException {
+    public NodeState createNodeState(NodeId nodeId, NodeEntry entry)
+        throws NoSuchItemStateException, ItemStateException {
         // retrieve state to overlay
-        NodeState overlayedState = (NodeState) workspaceItemStateMgr.getRootState();
-        NodeState nodeState = new NodeState(overlayedState, null, Status.EXISTING, this, idFactory);
+        NodeState overlayedState = (NodeState) workspaceStateFactory.createNodeState(nodeId, entry);
+        return buildNodeState(overlayedState, getInitialStatus(entry.getParent()));
+    }
 
-        nodeState.addListener(cache);
-        cache.created(nodeState);
-        return nodeState;
+    /**
+     * @inheritDoc
+     * @see ItemStateFactory#createDeepNodeState(NodeId, NodeEntry)
+     */
+    public NodeState createDeepNodeState(NodeId nodeId, NodeEntry anyParent) throws NoSuchItemStateException, ItemStateException {
+        NodeState overlayedState = (NodeState) workspaceStateFactory.createDeepNodeState(nodeId, anyParent);
+        return buildNodeState(overlayedState, getInitialStatus(anyParent));
     }
 
     /**
      * @inheritDoc
-     * @see ItemStateFactory#createNodeState(NodeId, ItemStateManager)
+     * @see ItemStateFactory#createPropertyState(PropertyId, PropertyEntry)
      */
-    public NodeState createNodeState(NodeId nodeId, ItemStateManager ism)
+    public PropertyState createPropertyState(PropertyId propertyId,
+                                             PropertyEntry entry)
         throws NoSuchItemStateException, ItemStateException {
+        // retrieve state to overlay
+        PropertyState overlayedState = (PropertyState) workspaceStateFactory.createPropertyState(propertyId, entry);
+        return buildPropertyState(overlayedState, getInitialStatus(entry.getParent()));
+    }
 
-        NodeState nodeState = cache.getNodeState(nodeId);
-        if (nodeState == null) {
-            // retrieve state to overlay
-            NodeState overlayedState = (NodeState) workspaceItemStateMgr.getItemState(nodeId);
-            NodeState overlayedParent = overlayedState.getParent();
-
-            if (overlayedParent == null) {
-                // special case root state
-                return createRootState(ism);
-            }
-            
-            NodeState parentState = (NodeState) overlayedParent.getSessionState();
-            if (parentState == null) {
-                parentState = (NodeState) ism.getItemState(overlayedParent.getId());
-            }
+    /**
+     * @see ItemStateFactory#createDeepPropertyState(PropertyId, NodeEntry)
+     */
+    public PropertyState createDeepPropertyState(PropertyId propertyId, NodeEntry anyParent) throws NoSuchItemStateException, ItemStateException {
+        PropertyState overlayedState = (PropertyState) workspaceStateFactory.createDeepPropertyState(propertyId, anyParent);
+        return buildPropertyState(overlayedState, getInitialStatus(anyParent));
+    }
 
-            ChildNodeEntry cne = parentState.getChildNodeEntry(nodeId);
-            if (cne != null) {
-                nodeState = cne.getNodeState();
-                nodeState.addListener(cache);
-                cache.created(nodeState);
-            } else {
-                throw new NoSuchItemStateException("No such item " + nodeId.toString());
-            }
-        }
-        return nodeState;
+    /**
+     * @inheritDoc
+     * @see ItemStateFactory#getChildNodeInfos(NodeId)
+     * @param nodeId
+     */
+    public Iterator getChildNodeInfos(NodeId nodeId) throws NoSuchItemStateException, ItemStateException {
+        return workspaceStateFactory.getChildNodeInfos(nodeId);
     }
 
     /**
      * @inheritDoc
-     * @see ItemStateFactory#createNodeState(NodeId, NodeState)
+     * @see ItemStateFactory#getNodeReferences(NodeState)
+     * @param nodeState
      */
-    public NodeState createNodeState(NodeId nodeId, NodeState parentState)
-        throws NoSuchItemStateException, ItemStateException {
+    public NodeReferences getNodeReferences(NodeState nodeState) {
+        if (nodeState.getStatus() == Status.NEW) {
+            return EmptyNodeReferences.getInstance();
+        }
+
+        NodeState workspaceState = (NodeState) nodeState.getWorkspaceState();
+        return workspaceStateFactory.getNodeReferences(workspaceState);
+    }
 
-        NodeState nodeState = cache.getNodeState(nodeId);
-        if (nodeState == null) {
-            // retrieve state to overlay
-            NodeState overlayedState = (NodeState) workspaceItemStateMgr.getItemState(nodeId);
-            nodeState = new NodeState(overlayedState, parentState, Status.EXISTING, this, idFactory);
+    //------------------------------------------------------------< private >---
+    /**
+     *
+     * @param overlayed
+     * @return
+     */
+    private NodeState buildNodeState(NodeState overlayed, int initialStatus) {
+        NodeState nodeState = new NodeState(overlayed, initialStatus, this);
 
-            nodeState.addListener(cache);
-            cache.created(nodeState);
-        }
+        notifyCreated(nodeState);
         return nodeState;
     }
 
+
     /**
-     * @inheritDoc
-     * @see ItemStateFactory#createPropertyState(PropertyId, NodeState)
+     *
+     * @param overlayed
+     * @return
      */
-    public PropertyState createPropertyState(PropertyId propertyId,
-                                             NodeState parentState)
-        throws NoSuchItemStateException, ItemStateException {
-
-        PropertyState propState = cache.getPropertyState(propertyId);
-        if (propState == null) {
-            // retrieve state to overlay
-            PropertyState overlayedState = (PropertyState) workspaceItemStateMgr.getItemState(propertyId);
-            propState = new PropertyState(overlayedState, parentState, Status.EXISTING, this, idFactory);
+    private PropertyState buildPropertyState(PropertyState overlayed, int initialStatus) {
+        PropertyState propState = new PropertyState(overlayed, initialStatus, this);
 
-            propState.addListener(cache);
-            cache.created(propState);
-        }
+        notifyCreated(propState);
         return propState;
     }
 
-    public ChildNodeEntries getChildNodeEntries(NodeState nodeState) throws NoSuchItemStateException, ItemStateException {
-        if (nodeState.getStatus() == Status.NEW) {
-            return new ChildNodeEntries(nodeState);
-        } else {
-            NodeState overlayed = (NodeState) nodeState.getWorkspaceState();
-            ChildNodeEntries overlayedEntries = overlayed.isf.getChildNodeEntries(overlayed);
-            return new ChildNodeEntries(nodeState, overlayedEntries);
-        }
-    }
-
     /**
-     * @inheritDoc
-     * @see ItemStateFactory#setCache(ItemStateCache)
-     */
-    public void setCache(ItemStateCache cache) {
-        this.cache = cache;
+     *
+     * @param parent
+     * @return
+     */
+    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;
+            }
+            parent = parent.getParent();
+        }
+        return status;
     }
 }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateFactory.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateFactory.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateFactory.java Tue Feb 13 01:31:36 2007
@@ -17,8 +17,10 @@
 package org.apache.jackrabbit.jcr2spi.state;
 
 import org.apache.jackrabbit.name.QName;
-import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
 import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
 
 /**
  * <code>TransientItemStateFactory</code> extends the item state factory and
@@ -30,36 +32,22 @@
      * Creates a transient child <code>NodeState</code> with the given
      * <code>name</code>.
      *
-     * @param name the name of the <code>NodeState</code> to create.
-     * @param uniqueID the unique ID of the <code>NodeState</code> to create or
-     * <code>null</code> if the created <code>NodeState</code> cannot be
-     * identified by a unique ID.
-     * @param parent the parent of the <code>NodeState</code> to create.
-     * @param nodeTypeName name of the primary nodetype
-     * @param definition the definition for this new NodeState
-     * @return the created <code>NodeState</code>.
+     * @param entry
+     * @param nodeTypeName
+     * @param definition
+     * @return the created <code>NodeState</code>
      */
-    public NodeState createNewNodeState(QName name, String uniqueID,
-                                        NodeState parent, QName nodeTypeName,
+    public NodeState createNewNodeState(NodeEntry entry,
+                                        QName nodeTypeName,
                                         QNodeDefinition definition);
 
     /**
-     * Creates a transient <code>PropertyState</code> with the given
-     * <code>name</code>.
+     * Creates a transient <code>PropertyState</code>.
      *
-     * @param name   the name of the <code>PropertyState</code> to create.
-     * @param parent the parent of the <code>PropertyState</code> to create.
-     * @param definition definition for this new property state.
+     * @param entry
+     * @param definition
      * @return the created <code>PropertyState</code>.
      */
-    public PropertyState createNewPropertyState(QName name,
-                                                NodeState parent,
+    public PropertyState createNewPropertyState(PropertyEntry entry,
                                                 QPropertyDefinition definition);
-
-    /**
-     * Set the listener that gets informed about NEW states.
-     *
-     * @param listener
-     */
-    public void setListener(ItemStateCreationListener listener);
 }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java Tue Feb 13 01:31:36 2007
@@ -17,9 +17,8 @@
 package org.apache.jackrabbit.jcr2spi.state;
 
 import org.apache.jackrabbit.jcr2spi.operation.Operation;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
 import org.apache.jackrabbit.name.QName;
-import org.apache.jackrabbit.spi.ItemId;
-import org.apache.jackrabbit.spi.IdFactory;
 import org.apache.jackrabbit.spi.QNodeDefinition;
 import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.spi.QValue;
@@ -30,21 +29,17 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import java.util.Iterator;
-import java.util.Collection;
 
 /**
- * <code>TransientItemStateManager</code> implements a {@link ItemStateManager}
- * and adds support for transient changes on {@link ItemState}s. This item
- * state manager also returns item states that are transiently deleted. It is
- * the responsiblity of the caller to check whether a certain item state is
- * still valid. This item state manager also provides methods to create new
- * item states. While all other modifications can be invoked on the item state
- * instances itself, creating a new node state is done using
+ * <code>TransientItemStateManager</code> adds support for transient changes on
+ * {@link ItemState}s and also provides methods to create new item states.
+ * While all other modifications can be invoked on the item state instances itself,
+ * creating a new node state is done using
  * {@link #createNewNodeState(QName, String, QName, QNodeDefinition, NodeState)}
- * and {@link #createNewPropertyState(QName, NodeState, QPropertyDefinition, QValue[], int)}.
+ * and
+ * {@link #createNewPropertyState(QName, NodeState, QPropertyDefinition, QValue[], int)}.
  */
-public class TransientItemStateManager extends CachingItemStateManager
-    implements ItemStateCreationListener {
+public class TransientItemStateManager implements ItemStateCreationListener {
 
     /**
      * Logger instance for this class.
@@ -58,24 +53,10 @@
     private final ChangeLog changeLog;
 
     /**
-     * The root node state or <code>null</code> if it hasn't been retrieved yet.
-     */
-    private NodeState rootNodeState;
-
-    /**
      *
-     * @param idFactory
-     * @param parent
      */
-    TransientItemStateManager(IdFactory idFactory, ItemStateManager parent) {
-        super(new TransientISFactory(idFactory, parent), idFactory);
+    TransientItemStateManager() {
         this.changeLog = new ChangeLog(null);
-        getTransientFactory().setListener(this);
-    }
-
-
-    private TransientItemStateFactory getTransientFactory() {
-        return (TransientItemStateFactory) getItemStateFactory();
     }
 
     /**
@@ -116,11 +97,15 @@
      * @return a new transient {@link NodeState}.
      */
     NodeState createNewNodeState(QName nodeName, String uniqueID, QName nodeTypeName,
-                                 QNodeDefinition definition, NodeState parent) {
-        NodeState nodeState = getTransientFactory().createNewNodeState(nodeName, uniqueID, parent, nodeTypeName, definition);
+                                 QNodeDefinition definition, NodeState parent)
+        throws ItemExistsException {
+
+        parent.checkIsSessionState();
+        NodeState nodeState = ((NodeEntry) parent.getHierarchyEntry()).addNewNodeEntry(nodeName, uniqueID, nodeTypeName, definition);
+        nodeState.addListener(this);
+
+        parent.markModified();
 
-        parent.addChildNodeState(nodeState);
-        changeLog.added(nodeState);
         return nodeState;
     }
 
@@ -141,12 +126,15 @@
                                          QPropertyDefinition definition,
                                          QValue[] values, int propertyType)
         throws ItemExistsException, ConstraintViolationException, RepositoryException {
-        PropertyState propState = getTransientFactory().createNewPropertyState(propName, parent, definition);
+
+        parent.checkIsSessionState();
+        PropertyState propState = ((NodeEntry) parent.getHierarchyEntry()).addNewPropertyEntry(propName, definition);
         // NOTE: callers must make sure, the property type is not 'undefined'
         propState.init(propertyType, values);
+        propState.addListener(this);
+
+        parent.markModified();
 
-        parent.addPropertyState(propState);
-        changeLog.added(propState);
         return propState;
     }
 
@@ -168,71 +156,6 @@
         changeLog.removeAll(subChangeLog);
     }
 
-    //---------------------------------------------------< ItemStateManager >---
-    /**
-     * Return the root node state.
-     *
-     * @return the root node state.
-     * @throws ItemStateException if an error occurs while retrieving the root
-     *                            node state.
-     * @see ItemStateManager#getRootState()
-     */
-    public NodeState getRootState() throws ItemStateException {
-        if (rootNodeState == null) {
-            rootNodeState = getItemStateFactory().createRootState(this);
-        }
-        return rootNodeState;
-    }
-
-    /**
-     * Return an item state given its id. Please note that this implementation
-     * also returns item states that are in removed state ({@link
-     * Status#EXISTING_REMOVED} but not yet saved.
-     *
-     * @return item state.
-     * @throws NoSuchItemStateException if there is no item state (not even a
-     *                                  removed item state) with the given id.
-     * @see ItemStateManager#getItemState(ItemId)
-     */
-    public ItemState getItemState(ItemId id) throws NoSuchItemStateException, ItemStateException {
-        return super.getItemState(id);
-    }
-
-    /**
-     * Return a flag indicating whether a given item state exists.
-     *
-     * @return <code>true</code> if item state exists within this item state
-     *         manager; <code>false</code> otherwise
-     * @see ItemStateManager#hasItemState(ItemId)
-     */
-    public boolean hasItemState(ItemId id) {
-        return super.hasItemState(id);
-    }
-
-    /**
-     * Always throws an {@link UnsupportedOperationException}. A transient item
-     * state manager cannot not maintain node references.
-     *
-     * @param nodeState
-     * @throws UnsupportedOperationException
-     * @see ItemStateManager#getReferingStates(NodeState)
-     */
-    public Collection getReferingStates(NodeState nodeState) {
-        throw new UnsupportedOperationException("getNodeReferences() not implemented");
-    }
-
-    /**
-     * Always throws an {@link UnsupportedOperationException}. A transient item
-     * state manager cannot not maintain node references.
-     *
-     * @param nodeState
-     * @throws UnsupportedOperationException
-     * @see ItemStateManager#hasReferingStates(NodeState)
-     */
-    public boolean hasReferingStates(NodeState nodeState) {
-        throw new UnsupportedOperationException("hasNodeReferences() not implemented");
-    }
-
     //-----------------------------------------< ItemStateLifeCycleListener >---
     /**
      * Depending on status of the given state adapt change log.
@@ -243,6 +166,9 @@
      * @see ItemStateLifeCycleListener#statusChanged(ItemState, int)
      */
     public void statusChanged(ItemState state, int previousStatus) {
+        if (changeLog.isEmpty()) {
+            return;
+        }
         switch (state.getStatus()) {
             case Status.EXISTING:
             case Status.EXISTING_MODIFIED:
@@ -258,8 +184,7 @@
                 // must not be any transient modifications for that state.
                 // we ignore it.
             case Status.INVALIDATED:
-                // only non transient states can change their status to
-                // invalidated -> nothing to do here.
+                // -> nothing to do here.
                 break;
             default:
                 log.error("ItemState has invalid status: " + state.getStatus());
@@ -267,7 +192,6 @@
     }
 
     //-----------------------------------------< ItemStateCreationListener >---
-
     /**
      * @see ItemStateCreationListener#created(ItemState)
      */

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java Tue Feb 13 01:31:36 2007
@@ -21,10 +21,9 @@
 import javax.jcr.RepositoryException;
 
 /**
- * Identifies an <code>ItemStateManager</code> that allows updating
- * items.
+ * An <code>ItemStateManager</code> that deals with state modifications.
  */
-public interface UpdatableItemStateManager extends ItemStateManager {
+public interface UpdatableItemStateManager {
 
     /**
      * Executes the given operation and modifies the affected item states accordingly.

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java Tue Feb 13 01:31:36 2007
@@ -25,29 +25,35 @@
 import org.apache.jackrabbit.spi.PropertyInfo;
 import org.apache.jackrabbit.spi.SessionInfo;
 import org.apache.jackrabbit.spi.RepositoryService;
-import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.spi.QNodeDefinition;
-import org.apache.jackrabbit.spi.ChildInfo;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.jcr2spi.WorkspaceManager;
 import org.apache.jackrabbit.jcr2spi.nodetype.EffectiveNodeType;
-import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeConflictException;
 import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeConflictException;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.HierarchyEntry;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.MalformedPathException;
 
 import javax.jcr.PathNotFoundException;
 import javax.jcr.RepositoryException;
+import javax.jcr.ItemExistsException;
 import javax.jcr.ItemNotFoundException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Collections;
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
 
 /**
  * <code>WorkspaceItemStateFactory</code>...
  */
-public class WorkspaceItemStateFactory implements ItemStateFactory {
+public class WorkspaceItemStateFactory extends AbstractItemStateFactory implements ItemStateFactory {
 
     private static Logger log = LoggerFactory.getLogger(WorkspaceItemStateFactory.class);
 
@@ -55,9 +61,8 @@
     private final SessionInfo sessionInfo;
     private final WorkspaceManager wspManager;
 
-    private ItemStateCache cache;
-
-    public WorkspaceItemStateFactory(RepositoryService service, SessionInfo sessionInfo, WorkspaceManager wspManager) {
+    public WorkspaceItemStateFactory(RepositoryService service, SessionInfo sessionInfo,
+                                     WorkspaceManager wspManager) {
         this.service = service;
         this.sessionInfo = sessionInfo;
         this.wspManager = wspManager;
@@ -65,12 +70,13 @@
 
     /**
      * @inheritDoc
-     * @see ItemStateFactory#createRootState(ItemStateManager)
+     * @see ItemStateFactory#createRootState(NodeEntry)
+     * @param entry
      */
-    public NodeState createRootState(ItemStateManager ism) throws ItemStateException {
+    public NodeState createRootState(NodeEntry entry) throws ItemStateException {
         try {
             NodeInfo info = service.getNodeInfo(sessionInfo, service.getRootId(sessionInfo));
-            return createNodeState(info, null);
+            return createNodeState(info, entry);
         } catch (RepositoryException e) {
             throw new ItemStateException("Internal error while building root state.");
         }
@@ -81,20 +87,15 @@
      * <code>RepositoryService</code>.
      *
      * @inheritDoc
-     * @see ItemStateFactory#createNodeState(NodeId, ItemStateManager)
+     * @see ItemStateFactory#createNodeState(NodeId,NodeEntry)
      */
-    public NodeState createNodeState(NodeId nodeId, ItemStateManager ism)
+    public NodeState createNodeState(NodeId nodeId, NodeEntry entry)
             throws NoSuchItemStateException, ItemStateException {
         try {
             NodeInfo info = service.getNodeInfo(sessionInfo, nodeId);
-            NodeId parentId = info.getParentId();
-            if (parentId != null) {
-                NodeState parent = (NodeState) ism.getItemState(parentId);
-                return parent.getChildNodeEntry(nodeId).getNodeState();
-            } else {
-                // special case for root state
-                return createNodeState(info, null);
-            }
+            return createNodeState(info, entry);
+        } catch (PathNotFoundException e) {
+            throw new NoSuchItemStateException(e.getMessage(), e);
         } catch (ItemNotFoundException e) {
             throw new NoSuchItemStateException(e.getMessage(), e);
         } catch (RepositoryException e) {
@@ -102,172 +103,276 @@
         }
     }
 
+    public NodeState createDeepNodeState(NodeId nodeId, NodeEntry anyParent) throws NoSuchItemStateException, ItemStateException {
+        try {
+            NodeInfo info = service.getNodeInfo(sessionInfo, nodeId);
+            // node for nodeId exists -> build missing entries in hierarchy
+            // Note, that the path contained in NodeId does not reveal which
+            // entries are missing -> calculate relative path.
+            Path anyParentPath = anyParent.getPath();
+            Path relPath = anyParentPath.computeRelativePath(info.getPath());
+            Path.PathElement[] missingElems = relPath.getElements();
+
+            NodeEntry entry = anyParent;
+            for (int i = 0; i < missingElems.length; i++) {
+                QName name = missingElems[i].getName();
+                int index = missingElems[i].getNormalizedIndex();
+                if (entry.hasNodeEntry(name, index)) {
+                    entry = entry.getNodeEntry(name, index);
+                } else {
+                    entry = entry.addNodeEntry(name, null, index);
+                }
+            }
+            if (entry == anyParent) {
+                throw new ItemStateException("Internal error while getting deep itemState");
+            }
+            return createNodeState(info, entry);
+        } catch (PathNotFoundException e) {
+            throw new NoSuchItemStateException(e.getMessage(), e);
+        } catch (ItemNotFoundException e) {
+            throw new NoSuchItemStateException(e.getMessage(), e);
+        }  catch (RepositoryException e) {
+            throw new ItemStateException(e.getMessage(), e);
+        } catch (MalformedPathException e) {
+            throw new ItemStateException(e.getMessage(), e);
+        }
+    }
+
     /**
-     * Creates the node with information retrieved from the
+     * Creates the property with information retrieved from the
      * <code>RepositoryService</code>.
      *
      * @inheritDoc
-     * @see ItemStateFactory#createNodeState(NodeId, NodeState)
+     * @see ItemStateFactory#createPropertyState(PropertyId,PropertyEntry)
      */
-    public NodeState createNodeState(NodeId nodeId, NodeState parent)
+    public PropertyState createPropertyState(PropertyId propertyId,
+                                             PropertyEntry entry)
             throws NoSuchItemStateException, ItemStateException {
         try {
-            NodeInfo info = service.getNodeInfo(sessionInfo, nodeId);
-            return createNodeState(info, parent);
+            PropertyInfo info = service.getPropertyInfo(sessionInfo, propertyId);
+            return createPropertyState(info, entry);
         } catch (PathNotFoundException e) {
             throw new NoSuchItemStateException(e.getMessage(), e);
+        } catch (ItemNotFoundException e) {
+            throw new NoSuchItemStateException(e.getMessage(), e);
         } catch (RepositoryException e) {
             throw new ItemStateException(e.getMessage(), e);
         }
     }
 
-    /**
-     * Creates the node with information retrieved from <code>info</code>.
-     *
-     * @param info the <code>NodeInfo</code> to use to create the
-     * <code>NodeState</code>.
-     * @param parent the parent <code>NodeState</code>.
-     * @return the new <code>NodeState</code>.
-     */
-    private NodeState createNodeState(NodeInfo info, NodeState parent)
-            throws NoSuchItemStateException, ItemStateException {
+    public PropertyState createDeepPropertyState(PropertyId propertyId, NodeEntry anyParent) throws NoSuchItemStateException, ItemStateException {
         try {
-            // retrieve definition
-            QNodeDefinition definition;
-            if (parent == null) {
-                // special case for root state
-                definition = wspManager.getNodeTypeRegistry().getRootNodeDef();
-            } else {
-                NodeTypeRegistry ntReg = wspManager.getNodeTypeRegistry();
-                EffectiveNodeType ent = ntReg.getEffectiveNodeType(parent.getNodeTypeNames());
-                definition = ent.getApplicableNodeDefinition(info.getQName(), info.getNodetype(), ntReg);
-            }
-
-            // build the node state
-            String uniqueID = null;
-            if (info.getId().getPath() == null) {
-                uniqueID = info.getId().getUniqueID();
+            PropertyInfo info = service.getPropertyInfo(sessionInfo, propertyId);
+            // prop for propertyId exists -> build missing entries in hierarchy
+            // Note, that the path contained in PropertyId does not reveal which
+            // entries are missing -> calculate relative path.
+            Path anyParentPath = anyParent.getPath();
+            Path relPath = anyParentPath.computeRelativePath(info.getPath());
+            Path.PathElement[] missingElems = relPath.getElements();
+            NodeEntry entry = anyParent;
+            int i = 0;
+            // NodeEntries except for the very last 'missingElem'
+            while (i < missingElems.length - 1) {
+                QName name = missingElems[i].getName();
+                int index = missingElems[i].getNormalizedIndex();
+                if (entry.hasNodeEntry(name, index)) {
+                    entry = entry.getNodeEntry(name, index);
+                } else {
+                    entry = entry.addNodeEntry(name, null, index);
+                }
+                i++;
             }
-            NodeState state = new NodeState(info.getQName(), uniqueID, parent, info.getNodetype(),
-                definition, Status.EXISTING, this, service.getIdFactory(), true);
-
-            // names of child property entries
-            Set propNames = new HashSet();
-            for (IdIterator it = info.getPropertyIds(); it.hasNext(); ) {
-                PropertyId pId = (PropertyId) it.nextId();
-                propNames.add(pId.getQName());
+            // create PropertyEntry for the last element if not existing yet
+            QName propName = missingElems[i].getName();
+            PropertyEntry propEntry;
+            if (!entry.hasPropertyEntry(propName)) {
+                propEntry = entry.addPropertyEntry(propName);
+            } else {
+                propEntry = entry.getPropertyEntry(propName);
             }
-
-            // Build node-references object even if the state is not refereceable yet.
-            PropertyId[] references = info.getReferences();
-            NodeReferences nodeRefs = new NodeReferencesImpl(state, references);
-
-            state.init(info.getMixins(), propNames, nodeRefs);
-
-            state.addListener(cache);
-            cache.created(state);
-
-            return state;
-        } catch (NodeTypeConflictException e) {
-            String msg = "Internal error: failed to retrieve node definition.";
-            log.debug(msg);
-            throw new ItemStateException(msg, e);
-        } catch (ConstraintViolationException e) {
-            String msg = "Internal error: failed to retrieve node definition.";
-            log.debug(msg);
-            throw new ItemStateException(msg, e);
-        } catch (NoSuchNodeTypeException e) {
-            String msg = "internal error: failed to retrieve node definition.";
-            log.debug(msg);
-            throw new ItemStateException(msg, e);
+            return createPropertyState(info, propEntry);
+        } catch (PathNotFoundException e) {
+            throw new NoSuchItemStateException(e.getMessage(), e);
+        } catch (ItemNotFoundException e) {
+            throw new NoSuchItemStateException(e.getMessage(), e);
         } catch (RepositoryException e) {
             throw new ItemStateException(e.getMessage(), e);
+        } catch (MalformedPathException e) {
+            throw new ItemStateException(e.getMessage(), e);
         }
     }
 
     /**
-     * Creates the property with information retrieved from the
-     * <code>RepositoryService</code>.
-     *
      * @inheritDoc
-     * @see ItemStateFactory#createPropertyState(PropertyId, NodeState)
+     * @see ItemStateFactory#getChildNodeInfos(NodeId)
+     * @param nodeId
      */
-    public PropertyState createPropertyState(PropertyId propertyId,
-                                             NodeState parent)
-            throws NoSuchItemStateException, ItemStateException {
+    public Iterator getChildNodeInfos(NodeId nodeId)
+        throws NoSuchItemStateException, ItemStateException {
         try {
-            PropertyInfo info = service.getPropertyInfo(sessionInfo, propertyId);
-            return createPropertyState(info, parent);
+            return service.getChildInfos(sessionInfo, nodeId);
         } catch (PathNotFoundException e) {
             throw new NoSuchItemStateException(e.getMessage(), e);
+        } catch (ItemNotFoundException e) {
+            throw new NoSuchItemStateException(e.getMessage(), e);
         } catch (RepositoryException e) {
             throw new ItemStateException(e.getMessage(), e);
         }
     }
 
-    public ChildNodeEntries getChildNodeEntries(NodeState nodeState)
-        throws NoSuchItemStateException, ItemStateException {
+    /**
+     * @inheritDoc
+     * @see ItemStateFactory#getNodeReferences(NodeState)
+     * @param nodeState
+     */
+    public NodeReferences getNodeReferences(NodeState nodeState) {
+        nodeState.checkIsWorkspaceState();
+        // shortcut
+        if (nodeState.getUniqueID() == null || !nodeState.hasPropertyName(QName.JCR_UUID)) {
+            // for sure not referenceable
+            return EmptyNodeReferences.getInstance();
+        }
+
+        // nodestate has a unique ID and is potentially mix:referenceable
+        // => try to retrieve references
         try {
-            ChildNodeEntries entries = new ChildNodeEntries(nodeState);
-            Iterator childInfos = service.getChildInfos(sessionInfo, nodeState.getNodeId());
-            while (childInfos.hasNext()) {
-                ChildInfo ci = (ChildInfo) childInfos.next();
-                entries.add(ci.getName(), ci.getUniqueID(), ci.getIndex());
-            }
-            return entries;
-        } catch (PathNotFoundException e) {
-            throw new NoSuchItemStateException(e.getMessage(), e);
+            NodeInfo info = service.getNodeInfo(sessionInfo, nodeState.getNodeId());
+            return new NodeReferencesImpl(info.getReferences());
         } catch (RepositoryException e) {
-            throw new ItemStateException(e.getMessage(), e);
+            log.debug("No references for NodeState " + nodeState);
+            return EmptyNodeReferences.getInstance();
         }
     }
 
+    //------------------------------------------------------------< private >---
     /**
-     * Creates the property with information retrieved from <code>info</code>.
+     * Creates the node with information retrieved from <code>info</code>.
      *
-     * @param info   the <code>PropertyInfo</code> to use to create the
-     *               <code>PropertyState</code>.
-     * @param parent the parent <code>NodeState</code>.
-     * @return the new <code>PropertyState</code>.
-     * @throws ItemStateException if an error occurs while retrieving the
-     *                            <code>PropertyState</code>.
+     * @param info the <code>NodeInfo</code> to use to create the <code>NodeState</code>.
+     * @param entry
+     * @return the new <code>NodeState</code>.
      */
-    private PropertyState createPropertyState(PropertyInfo info, NodeState parent)
-        throws ItemStateException {
-        try {
+    private NodeState createNodeState(NodeInfo info, NodeEntry entry) {
+        // make sure the entry has the correct ItemId
+        // this make not be the case, if the hierachy has not been completely
+        // resolved yet -> if uniqueID is present, set it on this entry or on
+        // the appropriate parent entry
+        String uniqueID = info.getId().getUniqueID();
+        Path path = info.getId().getPath();
+        if (path == null) {
+            entry.setUniqueID(uniqueID);
+        } else if (uniqueID != null) {
+            // uniqueID that applies to a parent NodeEntry -> get parentEntry
+            NodeEntry parent = getAncestor(entry, path.getLength());
+            parent.setUniqueID(uniqueID);
+        }
 
-            // retrieve property definition
-            EffectiveNodeType ent = wspManager.getNodeTypeRegistry().getEffectiveNodeType(parent.getNodeTypeNames());
-            QPropertyDefinition def = ent.getApplicablePropertyDefinition(info.getQName(), info.getType(), info.isMultiValued());
-
-            // build the PropertyState
-            PropertyState state = new PropertyState(info.getQName(), parent,
-                def, Status.EXISTING, this, service.getIdFactory(), true);
-            state.init(info.getType(), info.getValues());
-            state.addListener(cache);
-            cache.created(state);
-
-            return state;
-        } catch (NodeTypeConflictException e) {
-            String msg = "internal error: failed to build property state.";
-            log.debug(msg);
-            throw new ItemStateException(msg, e);
-        } catch (RepositoryException e) {
-            String msg = "internal error: failed to build property state.";
-            log.debug(msg);
-            throw new ItemStateException(msg, e);
+        // retrieve definition
+        NodeTypeRegistry ntReg = wspManager.getNodeTypeRegistry();
+        QNodeDefinition definition = null;
+        NodeEntry parent = entry.getParent();
+        if (parent == null) {
+            // special case for root state
+            definition = wspManager.getNodeTypeRegistry().getRootNodeDef();
+        } else if (parent.isAvailable() && parent.getStatus() != Status.INVALIDATED) {
+            // try to retrieve definition if the parent is available
+            try {
+                NodeState parentState = parent.getNodeState();
+                EffectiveNodeType ent = ntReg.getEffectiveNodeType(parentState.getNodeTypeNames());
+                definition = ent.getApplicableNodeDefinition(info.getQName(), info.getNodetype(), ntReg);
+            } catch (RepositoryException e) {
+                // should not get here
+                log.warn("Internal error", e);
+            } catch (ItemStateException e) {
+                // should not get here
+                log.warn("Internal error", e);
+            } catch (NodeTypeConflictException e) {
+                // should not get here
+               log.warn("Internal error", e);
+            }
+        }
+
+        // now build the nodestate itself
+        NodeState state = new NodeState(entry, info.getNodetype(), info.getMixins(), definition, Status.EXISTING, true, this, ntReg);
+
+        // update NodeEntry from the information present in the NodeInfo (prop entries)
+        List propNames = new ArrayList();
+        for (IdIterator it = info.getPropertyIds(); it.hasNext(); ) {
+            PropertyId pId = (PropertyId) it.nextId();
+            QName propertyName = pId.getQName();
+            propNames.add(propertyName);
         }
+        try {
+            entry.addPropertyEntries(propNames);
+        } catch (ItemExistsException e) {
+            // should not get here
+            log.warn("Internal error", e);
+        }
+
+        notifyCreated(state);
+        return state;
     }
 
     /**
+     * Creates the property with information retrieved from <code>info</code>.
      *
-     * @param cache
-     * @see ItemStateFactory#setCache(ItemStateCache)
+     * @param info   the <code>PropertyInfo</code> to use to create the
+     *               <code>PropertyState</code>.
+     * @param entry
+     * @return the new <code>PropertyState</code>.
      */
-    public void setCache(ItemStateCache cache) {
-        this.cache = cache;
+    private PropertyState createPropertyState(PropertyInfo info, PropertyEntry entry) {
+        // make sure uuid part of id is correct
+        String uniqueID = info.getId().getUniqueID();
+        if (uniqueID != null) {
+            // uniqueID always applies to a parent NodeEntry -> get parentEntry
+            NodeEntry parent = getAncestor(entry, info.getId().getPath().getLength());
+            parent.setUniqueID(uniqueID);
+        }
+
+        QPropertyDefinition definition = null;
+        // try to retrieve property definition
+        if (entry.getParent().isAvailable() && entry.getStatus() != Status.INVALIDATED) {
+            NodeState parentState = null;
+            try {
+                parentState = entry.getParent().getNodeState();
+                EffectiveNodeType ent = wspManager.getNodeTypeRegistry().getEffectiveNodeType(parentState.getNodeTypeNames());
+                definition = ent.getApplicablePropertyDefinition(info.getQName(), info.getType(), info.isMultiValued());
+            } catch (ItemStateException e) {
+                // should not get here
+                log.warn("Internal error", e);
+            } catch (RepositoryException e) {
+                // should not get here
+                log.warn("Internal error", e);
+            } catch (NodeTypeConflictException e) {
+                // should not get here
+                log.warn("Internal error", e);
+            }
+        }
+
+        // build the PropertyState
+        PropertyState state = new PropertyState(entry, info.isMultiValued(), definition, Status.EXISTING, true, this, wspManager.getNodeTypeRegistry());
+        state.init(info.getType(), info.getValues());
+
+        //state.addListener(cache);
+        //cache.created(state);
+        notifyCreated(state);
+
+        return state;
     }
 
+    private static NodeEntry getAncestor(HierarchyEntry entry, int degree) {
+        NodeEntry parent = entry.getParent();
+        degree--;
+        while (parent != null && degree > 0) {
+            parent = parent.getParent();
+            degree--;
+        }
+        if (degree != 0) {
+            throw new IllegalArgumentException();
+        }
+        return parent;
+    }
     //-----------------------------------------------------< NodeReferences >---
     /**
      * <code>NodeReferences</code> represents the references (i.e. properties of
@@ -275,21 +380,15 @@
      */
     private class NodeReferencesImpl implements NodeReferences {
 
-        private NodeState nodeState;
+        private PropertyId[] references;
 
         /**
          * Private constructor
          *
-         * @param nodeState
-         * @param referenceIds
+         * @param references
          */
-        private NodeReferencesImpl(NodeState nodeState, PropertyId[] referenceIds) {
-            this.nodeState = nodeState;
-
-            // TODO: improve. make usage of the references returned
-            // with NodeInfo that was just retrieved and implement a notification
-            // mechanism that updates this NodeReference object if references
-            // are modified.
+        private NodeReferencesImpl(PropertyId[] references) {
+            this.references = references;
         }
 
         //-------------------------------------------------< NodeReferences >---
@@ -297,42 +396,18 @@
          * @see NodeReferences#isEmpty()
          */
         public boolean isEmpty() {
-            // shortcut
-            if (nodeState.getUniqueID() == null) {
-                return true;
-            }
-            // nodestate has a unique ID and is potentially mix:referenceable
-            // => try to retrieve references
-            try {
-                NodeInfo info = service.getNodeInfo(sessionInfo, nodeState.getNodeId());
-                return info.getReferences().length > 0;
-            } catch (RepositoryException e) {
-                log.error("Internal error.",e);
-                return false;
-            }
+            return references.length <= 0;
         }
 
         /**
          * @see NodeReferences#iterator()
          */
         public Iterator iterator() {
-            // shortcut
-            if (nodeState.getUniqueID() == null) {
-                return Collections.EMPTY_SET.iterator();
-            }
-            // nodestate has a uniqueID and is potentially mix:referenceable
-            // => try to retrieve references
-            try {
-                NodeInfo info = service.getNodeInfo(sessionInfo, nodeState.getNodeId());
-                if (info.getReferences().length > 0) {
-                    Set referenceIds = new HashSet();
-                    referenceIds.addAll(Arrays.asList(info.getReferences()));
-                    return Collections.unmodifiableSet(referenceIds).iterator();
-                } else {
-                    return Collections.EMPTY_SET.iterator();
-                }
-            } catch (RepositoryException e) {
-                log.error("Internal error.", e);
+            if (references.length > 0) {
+                Set referenceIds = new HashSet();
+                referenceIds.addAll(Arrays.asList(references));
+                return Collections.unmodifiableSet(referenceIds).iterator();
+            } else {
                 return Collections.EMPTY_SET.iterator();
             }
         }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/LogUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/LogUtil.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/LogUtil.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/LogUtil.java Tue Feb 13 01:31:36 2007
@@ -62,10 +62,9 @@
      * @param nsResolver
      * @return JCR path
      */
-    public static String safeGetJCRPath(ItemState itemState, NamespaceResolver nsResolver
-    ) {
+    public static String safeGetJCRPath(ItemState itemState, NamespaceResolver nsResolver) {
         try {
-            return safeGetJCRPath(itemState.getQPath(), nsResolver);
+            return safeGetJCRPath(itemState.getHierarchyEntry().getPath(), nsResolver);
         } catch (RepositoryException e) {
             ItemId id = itemState.getId();
             log.error("failed to convert " + id + " to JCR path.");

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java?view=auto&rev=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java Tue Feb 13 01:31:36 2007
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.jcr2spi.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.jcr2spi.state.PropertyState;
+import org.apache.jackrabbit.jcr2spi.state.Status;
+import org.apache.jackrabbit.jcr2spi.state.ItemState;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.spi.QValue;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * <code>StateUtility</code>...
+ */
+public class StateUtility {
+
+    private static Logger log = LoggerFactory.getLogger(StateUtility.class);
+
+    /**
+     *
+     * @param ps
+     * @return
+     * @throws IllegalArgumentException if the name of the PropertyState is NOT
+     * {@link QName#JCR_MIXINTYPES}
+     */
+    public static QName[] getMixinNames(PropertyState ps) {
+        if (!QName.JCR_MIXINTYPES.equals(ps.getQName())) {
+            throw new IllegalArgumentException();
+        }
+        if (ps.getStatus() == Status.REMOVED) {
+            return QName.EMPTY_ARRAY;
+        } else {
+            QValue[] values = ps.getValues();
+            QName[] newMixins = new QName[values.length];
+            for (int i = 0; i < values.length; i++) {
+                try {
+                    newMixins[i] = QName.valueOf(values[i].getString());
+                } catch (RepositoryException e) {
+                    // ignore: should never occur.
+                }
+            }
+            return newMixins;
+        }
+    }
+
+
+    public static boolean isUuidOrMixin(QName propName) {
+        return QName.JCR_UUID.equals(propName) || QName.JCR_MIXINTYPES.equals(propName);
+    }
+
+    public static boolean isMovedState(NodeState state) {
+        state.checkIsSessionState();
+        if (state.isRoot()) {
+            // the root state cannot be moved
+            return false;
+        } else {
+            // a session-state is moved, if its NodeEntry is not the same as
+            // the NodeEntry of its overlayed state. If no overlayedState
+            // exists the state not moved anyway.
+            ItemState overlayed = state.getWorkspaceState();
+            if (overlayed == null) {
+                return false;
+            } else {
+                return state.getHierarchyEntry() != overlayed.getHierarchyEntry();
+                //return modState.overlayedState.getParent() != modState.getParent().overlayedState;
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java Tue Feb 13 01:31:36 2007
@@ -26,6 +26,7 @@
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.name.Path;
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
 import org.apache.jackrabbit.spi.IdIterator;
 
 /**
@@ -78,5 +79,13 @@
 
     public void resolveMergeConflict(NodeState nodeState, NodeState versionState, boolean done) throws RepositoryException {
         throw new UnsupportedRepositoryOperationException("Versioning ist not supported by this repository.");
+    }
+
+    public NodeEntry getVersionableNodeState(NodeState versionState) {
+        throw new UnsupportedOperationException();
+    }
+
+    public NodeEntry getVersionHistoryNodeState(NodeState versionableState) {
+        throw new UnsupportedOperationException();
     }
 }



Mime
View raw message