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

svn commit: r704361 [3/5] - in /jackrabbit/trunk: jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/o...

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java Tue Oct 14 00:48:22 2008
@@ -16,26 +16,26 @@
  */
 package org.apache.jackrabbit.jcr2spi.operation;
 
-import org.apache.jackrabbit.jcr2spi.util.LogUtil;
 import org.apache.jackrabbit.jcr2spi.hierarchy.HierarchyManager;
 import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
-import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.jcr2spi.util.LogUtil;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.conversion.PathResolver;
-import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import javax.jcr.RepositoryException;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.ItemExistsException;
-import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.ItemNotFoundException;
-import javax.jcr.version.VersionException;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.lock.LockException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NoSuchNodeTypeException;
-import javax.jcr.lock.LockException;
+import javax.jcr.version.VersionException;
 
 /**
  * <code>Move</code>...
@@ -54,7 +54,8 @@
 
     private final boolean sessionMove;
 
-    private Move(NodeState srcNodeState, NodeState srcParentState, NodeState destParentState, Name destName, boolean sessionMove) {
+    private Move(NodeState srcNodeState, NodeState srcParentState, NodeState destParentState, Name destName, boolean sessionMove)
+            throws RepositoryException {
 
         this.srcId = (NodeId) srcNodeState.getId();
         this.destParentId = destParentState.getNodeId();
@@ -77,6 +78,7 @@
      * @param visitor
      */
     public void accept(OperationVisitor visitor) throws LockException, ConstraintViolationException, AccessDeniedException, ItemExistsException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
@@ -87,22 +89,39 @@
      *
      * @see Operation#persisted()
      */
-    public void persisted() {
+    public void persisted() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
         if (sessionMove) {
-            throw new UnsupportedOperationException("persisted() not implemented for transient modification.");
+            srcState.getNodeEntry().complete(this);
+        } else {
+            // non-recursive invalidation
+            try {
+                srcState.getNodeEntry().move(destName, destParentState.getNodeEntry(), false);
+                // TODO: TOBEFIXED. moved state ev. got a new definition.
+            } catch (RepositoryException e) {
+                // should not occure
+                log.error("Internal error", e);
+                srcParentState.getHierarchyEntry().invalidate(false);
+                destParentState.getHierarchyEntry().invalidate(false);
+                srcState.getHierarchyEntry().invalidate(false);
+            }
         }
-        // non-recursive invalidation
-        try {
-            srcState.getNodeEntry().move(destName, destParentState.getNodeEntry(), false);
-            // TODO: TOBEFIXED. moved state ev. got a new definition.
-        } catch (RepositoryException e) {
-            // should not occure
-            log.error("Internal error", e);
-            srcParentState.getHierarchyEntry().invalidate(false);
-            destParentState.getHierarchyEntry().invalidate(false);
-            srcState.getHierarchyEntry().invalidate(false);
+    }
+
+    /**
+     * @see Operation#undo()
+     */
+    public void undo() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        if (sessionMove) {
+            status = STATUS_UNDO;
+            srcState.getHierarchyEntry().complete(this);
+        } else {
+            super.undo();
         }
     }
+
     //----------------------------------------< Access Operation Parameters >---
     public NodeId getSourceId() {
         return srcId;
@@ -161,24 +180,28 @@
         NodeState destParentState = getNodeState(destPath.getAncestor(1), hierMgr, resolver);
         Name destName = destElement.getName();
 
-        // for session-move perform a lazy check for existing items at destination.
-        // since the hierarchy may not be complete it is possible that an conflict
-        // is only detected upon saving the 'move'.
-        NodeEntry destEntry = (NodeEntry) destParentState.getHierarchyEntry();
-        if (destEntry.hasPropertyEntry(destName) && sessionMove) {
-            throw new ItemExistsException("Move destination already exists (Property).");
-        }
-        // force childnodeentries list to be present before the move is executed
-        // on the hierarchy entry.
-        if (destEntry.hasNodeEntry(destName)) {
-            NodeEntry existing = destEntry.getNodeEntry(destName, Path.INDEX_DEFAULT);
-            if (existing != null && sessionMove) {
-                try {
-                    if (!existing.getNodeState().getDefinition().allowsSameNameSiblings()) {
-                        throw new ItemExistsException("Node existing at move destination does not allow same name siblings.");
+        if (sessionMove) {
+            NodeEntry destEntry = (NodeEntry) destParentState.getHierarchyEntry();
+            if (destEntry.hasPropertyEntry(destName)) {
+                // TODO: remove for 283
+                throw new ItemExistsException("Move destination already exists (Property).");
+            }
+
+            // force childnodeentries list to be present before the move is executed
+            // on the hierarchy entry.
+            assertChildNodeEntries(srcParentState);
+            assertChildNodeEntries(destParentState);
+
+            if (destEntry.hasNodeEntry(destName)) {
+                NodeEntry existing = destEntry.getNodeEntry(destName, Path.INDEX_DEFAULT);
+                if (existing != null && sessionMove) {
+                    try {
+                        if (!existing.getNodeState().getDefinition().allowsSameNameSiblings()) {
+                            throw new ItemExistsException("Node existing at move destination does not allow same name siblings.");
+                        }
+                    } catch (ItemNotFoundException e) {
+                        // existing apparent not valid any more -> probably no conflict
                     }
-                } catch (ItemNotFoundException e) {
-                    // existing apparent not valid any more -> probably no conflict
                 }
             }
         }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Operation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Operation.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Operation.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Operation.java Tue Oct 14 00:48:22 2008
@@ -32,6 +32,10 @@
  */
 public interface Operation {
 
+    int STATUS_PENDING = 0;
+    int STATUS_PERSISTED = 1;
+    int STATUS_UNDO = 2;
+
     /**
      * Returns the name of <code>this</code> operation.
      *
@@ -56,6 +60,22 @@
 
     /**
      * Informs this Operation that it has been successfully executed.
+     *
+     * @throws RepositoryException
+     */
+    public void persisted() throws RepositoryException;
+
+    /**
+     * Revert changes made by this operation.
+     * 
+     * @throws RepositoryException
+     */
+    public void undo() throws RepositoryException;
+
+    /**
+     * Returns the status of this operation.
+     *
+     * @return status of this operation.
      */
-    public void persisted();
+    public int getStatus();
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Remove.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Remove.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Remove.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Remove.java Tue Oct 14 00:48:22 2008
@@ -19,6 +19,8 @@
 import org.apache.jackrabbit.jcr2spi.state.ItemState;
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
 import org.apache.jackrabbit.spi.ItemId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.jcr.AccessDeniedException;
 import javax.jcr.RepositoryException;
@@ -30,11 +32,13 @@
  */
 public class Remove extends AbstractOperation {
 
+    private static Logger log = LoggerFactory.getLogger(Remove.class);
+
     private ItemId removeId;
     protected ItemState removeState;
     protected NodeState parent;
 
-    protected Remove(ItemState removeState, NodeState parent) {
+    protected Remove(ItemState removeState, NodeState parent) throws RepositoryException {
         this.removeId = removeState.getId();
         this.removeState = removeState;
         this.parent = parent;
@@ -48,20 +52,30 @@
      * @see Operation#accept(OperationVisitor)
      */
     public void accept(OperationVisitor visitor) throws AccessDeniedException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
     /**
-     * Throws UnsupportedOperationException
-     *
      * @see Operation#persisted()
      */
-    public void persisted() {
-        throw new UnsupportedOperationException("persisted() not implemented for transient modification.");
+    public void persisted() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
+        parent.getHierarchyEntry().complete(this);
+    }
+
+    /**
+     * @see Operation#undo()
+     */
+    public void undo() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        status = STATUS_UNDO;
+        parent.getHierarchyEntry().complete(this);
     }
 
     //----------------------------------------< Access Operation Parameters >---
-    public ItemId getRemoveId() {
+    public ItemId getRemoveId() throws RepositoryException {
         return removeId;
     }
 

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java Tue Oct 14 00:48:22 2008
@@ -16,22 +16,22 @@
  */
 package org.apache.jackrabbit.jcr2spi.operation;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.Path;
-import org.apache.jackrabbit.jcr2spi.state.NodeState;
 import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import javax.jcr.RepositoryException;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.ItemExistsException;
+import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.version.VersionException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.version.VersionException;
 
 /**
  * <code>RemoveLabel</code>...
@@ -63,7 +63,8 @@
      * @throws UnsupportedRepositoryOperationException
      * @throws VersionException
      */
-    public void accept(OperationVisitor visitor) throws RepositoryException, ConstraintViolationException, AccessDeniedException, ItemExistsException, NoSuchNodeTypeException, UnsupportedRepositoryOperationException, VersionException {
+    public void accept(OperationVisitor visitor) throws RepositoryException {       
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
@@ -73,7 +74,8 @@
      *
      * @see Operation#persisted()
      */
-    public void persisted() {
+    public void persisted() throws RepositoryException {
+        status = STATUS_PERSISTED;
         try {
             NodeEntry vhEntry = (NodeEntry) versionHistoryState.getHierarchyEntry();
             NodeEntry lnEntry = vhEntry.getNodeEntry(NameConstants.JCR_VERSIONLABELS, Path.INDEX_DEFAULT);
@@ -86,11 +88,11 @@
     }
 
     //----------------------------------------< Access Operation Parameters >---
-    public NodeId getVersionHistoryId() {
+    public NodeId getVersionHistoryId() throws RepositoryException {
         return versionHistoryState.getNodeEntry().getWorkspaceId();
     }
 
-    public NodeId getVersionId() {
+    public NodeId getVersionId() throws RepositoryException {
         return versionState.getNodeEntry().getWorkspaceId();
     }
 

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java Tue Oct 14 00:48:22 2008
@@ -40,12 +40,13 @@
 
     private NodeEntry versionableEntry = null;
 
-    protected RemoveVersion(ItemState removeState, NodeState parent, VersionManager mgr) {
+    protected RemoveVersion(ItemState removeState, NodeState parent, VersionManager mgr)
+            throws RepositoryException {
         super(removeState, parent);
         try {
             versionableEntry = mgr.getVersionableNodeEntry((NodeState) removeState);
         } catch (RepositoryException e) {
-            log.warn("Internal error", e);
+            log.warn("Failed to retrieve the hierarchy entry of the versionable node.", e);
         }
     }
 
@@ -54,6 +55,7 @@
      * @see Operation#accept(OperationVisitor)
      */
     public void accept(OperationVisitor visitor) throws AccessDeniedException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
@@ -64,6 +66,8 @@
      * @see Operation#persisted()
      */
     public void persisted() {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
         // invaliate the versionable node as well (version related properties)
         if (versionableEntry != null) {
             Iterator propEntries = versionableEntry.getPropertyEntries();
@@ -80,12 +84,13 @@
     }
 
     //----------------------------------------< Access Operation Parameters >---
-    public ItemId getRemoveId() {
+    public ItemId getRemoveId() throws RepositoryException {
         return removeState.getWorkspaceId();
     }
 
     //------------------------------------------------------------< Factory >---
-    public static Operation create(NodeState versionState, NodeState vhState, VersionManager mgr) {
+    public static Operation create(NodeState versionState, NodeState vhState, VersionManager mgr)
+            throws RepositoryException {
         RemoveVersion rm = new RemoveVersion(versionState, vhState, mgr);
         return rm;
     }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ReorderNodes.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ReorderNodes.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ReorderNodes.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ReorderNodes.java Tue Oct 14 00:48:22 2008
@@ -40,7 +40,8 @@
     private final NodeState insert;
     private final NodeState before;
 
-    private ReorderNodes(NodeState parentState, NodeState insert, NodeState before) {
+    private ReorderNodes(NodeState parentState, NodeState insert, NodeState before)
+            throws RepositoryException {
         this.parentState = parentState;
         this.insert = insert;
         this.before = before;
@@ -58,6 +59,7 @@
      * @param visitor
      */
     public void accept(OperationVisitor visitor) throws ConstraintViolationException, AccessDeniedException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
@@ -66,9 +68,21 @@
      *
      * @see Operation#persisted()
      */
-    public void persisted() {
-        throw new UnsupportedOperationException("persisted() not implemented for transient modification.");
+    public void persisted() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
+        insert.getHierarchyEntry().complete(this);
     }
+
+    /**
+     * @see Operation#undo()
+     */
+    public void undo() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        status = STATUS_UNDO;
+        insert.getHierarchyEntry().complete(this);
+    }
+
     //----------------------------------------< Access Operation Parameters >---
 
     public NodeId getParentId() {
@@ -99,6 +113,9 @@
 
     public static Operation create(NodeState parentState, Path.Element srcName,
                                    Path.Element beforeName) throws ItemNotFoundException, RepositoryException {
+        // make sure the parent hierarchy entry has its child entries loaded
+        assertChildNodeEntries(parentState);
+
         NodeState insert = parentState.getChildNodeState(srcName.getName(), srcName.getNormalizedIndex());
         NodeState before = (beforeName == null) ? null : parentState.getChildNodeState(beforeName.getName(), beforeName.getNormalizedIndex());
         return new ReorderNodes(parentState, insert, before);

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java Tue Oct 14 00:48:22 2008
@@ -16,18 +16,18 @@
  */
 package org.apache.jackrabbit.jcr2spi.operation;
 
-import org.apache.jackrabbit.jcr2spi.state.NodeState;
-import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
 import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
 import org.apache.jackrabbit.spi.NodeId;
 
-import javax.jcr.RepositoryException;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.ItemExistsException;
+import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.version.VersionException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.version.VersionException;
 import java.util.Iterator;
 
 /**
@@ -55,6 +55,7 @@
      * @see Operation#accept(OperationVisitor)
      */
     public void accept(OperationVisitor visitor) throws RepositoryException, ConstraintViolationException, AccessDeniedException, ItemExistsException, NoSuchNodeTypeException, UnsupportedRepositoryOperationException, VersionException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
@@ -65,6 +66,8 @@
      * @see Operation#persisted()
      */
     public void persisted() {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
         // non-recursive invalidation BUT including all properties
         Iterator propEntries = ((NodeEntry) nodeState.getHierarchyEntry()).getPropertyEntries();
         while (propEntries.hasNext()) {
@@ -74,7 +77,7 @@
         nodeState.getHierarchyEntry().invalidate(false);
     }
     //----------------------------------------< Access Operation Parameters >---
-    public NodeId getNodeId() {
+    public NodeId getNodeId() throws RepositoryException {
         return nodeState.getNodeEntry().getWorkspaceId();
     }
 

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java Tue Oct 14 00:48:22 2008
@@ -55,6 +55,7 @@
      * @see Operation#accept(OperationVisitor)
      */
     public void accept(OperationVisitor visitor) throws PathNotFoundException, ItemExistsException, VersionException, ConstraintViolationException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
@@ -66,6 +67,8 @@
      * @see Operation#persisted()
      */
     public void persisted() {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
         NodeEntry entry;
         if (nodeState == null || removeExisting) {
             // invalidate the complete tree
@@ -88,7 +91,7 @@
      *
      * @return
      */
-    public NodeId getNodeId() {
+    public NodeId getNodeId() throws RepositoryException {
         return (nodeState == null) ? null : nodeState.getNodeEntry().getWorkspaceId();
     }
 
@@ -103,7 +106,7 @@
         return relQPath;
     }
 
-    public NodeId[] getVersionIds() {
+    public NodeId[] getVersionIds() throws RepositoryException {
         NodeId[] versionIds = new NodeId[versionStates.length];
         for (int i = 0; i < versionStates.length; i++) {
             versionIds[i] = versionStates[i].getNodeEntry().getWorkspaceId();

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java Tue Oct 14 00:48:22 2008
@@ -36,7 +36,7 @@
     private final NodeState nodeState;
     private final Name[] mixinNames;
 
-    private SetMixin(NodeState nodeState, Name[] mixinNames) {
+    private SetMixin(NodeState nodeState, Name[] mixinNames) throws RepositoryException {
         this.nodeState = nodeState;
         this.nodeId = nodeState.getNodeId();
         this.mixinNames = mixinNames;
@@ -59,16 +59,26 @@
      * @see Operation#accept(OperationVisitor)
      */
     public void accept(OperationVisitor visitor) throws AccessDeniedException, NoSuchNodeTypeException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
     /**
-     * Throws UnsupportedOperationException
-     *
      * @see Operation#persisted()
      */
-    public void persisted() {
-        throw new UnsupportedOperationException("persisted() not implemented for transient modification.");
+    public void persisted() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
+        nodeState.getHierarchyEntry().complete(this);
+    }
+
+    /**
+     * @see Operation#undo()
+     */
+    public void undo() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        status = STATUS_UNDO;
+        nodeState.getHierarchyEntry().complete(this);
     }
 
     //----------------------------------------< Access Operation Parameters >---
@@ -86,7 +96,11 @@
 
     //------------------------------------------------------------< Factory >---
 
-    public static Operation create(NodeState nodeState, Name[] mixinNames) {
+    public static Operation create(NodeState nodeState, Name[] mixinNames)
+            throws RepositoryException {
+        if (nodeState == null || mixinNames == null) {
+            throw new IllegalArgumentException();
+        }
         SetMixin sm = new SetMixin(nodeState, mixinNames);
         return sm;
     }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java Tue Oct 14 00:48:22 2008
@@ -41,7 +41,8 @@
     private final QValue[] values;
     private final int valueType;
 
-    private SetPropertyValue(PropertyState propertyState, int valueType, QValue[] values) {
+    private SetPropertyValue(PropertyState propertyState, int valueType, QValue[] values)
+            throws RepositoryException {
         this.propertyState = propertyState;
 
         propertyId = (PropertyId) propertyState.getId();
@@ -58,16 +59,26 @@
      * @see Operation#accept(OperationVisitor)
      */
     public void accept(OperationVisitor visitor) throws ValueFormatException, LockException, ConstraintViolationException, AccessDeniedException, ItemExistsException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
     /**
-     * Throws UnsupportedOperationException
-     *
      * @see Operation#persisted()
      */
-    public void persisted() {
-        throw new UnsupportedOperationException("persisted() not implemented for transient modification.");
+    public void persisted() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
+        propertyState.getHierarchyEntry().complete(this);
+    }
+
+    /**
+     * @see Operation#undo()
+     */
+    public void undo() throws RepositoryException {
+        assert status == STATUS_PENDING;
+        status = STATUS_UNDO;
+        propertyState.getHierarchyEntry().complete(this);
     }
 
     //----------------------------------------< Access Operation Parameters >---
@@ -93,7 +104,7 @@
 
     //------------------------------------------------------------< Factory >---
     public static Operation create(PropertyState propState, QValue[] qValues,
-                                   int valueType) {
+                                   int valueType) throws RepositoryException {
         // compact array (purge null entries)
         List list = new ArrayList();
         for (int i = 0; i < qValues.length; i++) {

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.java Tue Oct 14 00:48:22 2008
@@ -19,13 +19,13 @@
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
 import org.apache.jackrabbit.spi.NodeId;
 
-import javax.jcr.RepositoryException;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.ItemExistsException;
+import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.version.VersionException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.version.VersionException;
 
 /**
  * <code>Update</code>...
@@ -47,6 +47,7 @@
      * @see Operation#accept(OperationVisitor)
      */
     public void accept(OperationVisitor visitor) throws RepositoryException, ConstraintViolationException, AccessDeniedException, ItemExistsException, NoSuchNodeTypeException, UnsupportedRepositoryOperationException, VersionException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
@@ -57,11 +58,13 @@
      * @see Operation#persisted()
      */
     public void persisted() {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
         nodeState.getHierarchyEntry().invalidate(true);
     }
 
     //----------------------------------------< Access Operation Parameters >---
-    public NodeId getNodeId() {
+    public NodeId getNodeId() throws RepositoryException {
         return nodeState.getNodeEntry().getWorkspaceId();
     }
 

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/WorkspaceImport.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/WorkspaceImport.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/WorkspaceImport.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/WorkspaceImport.java Tue Oct 14 00:48:22 2008
@@ -55,6 +55,7 @@
      * @see Operation#accept(OperationVisitor)
      */
     public void accept(OperationVisitor visitor) throws RepositoryException, ConstraintViolationException, AccessDeniedException, ItemExistsException, NoSuchNodeTypeException, UnsupportedRepositoryOperationException, VersionException {
+        assert status == STATUS_PENDING;
         visitor.visit(this);
     }
 
@@ -65,6 +66,8 @@
      * @see Operation#persisted()
      */
     public void persisted() {
+        assert status == STATUS_PENDING;
+        status = STATUS_PERSISTED;
         NodeEntry entry;
         if (uuidBehaviour == ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING ||
                 uuidBehaviour == ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING) {
@@ -82,7 +85,7 @@
     }
 
     //----------------------------------------< Access Operation Parameters >---
-    public NodeId getNodeId() {
+    public NodeId getNodeId() throws RepositoryException {
         return nodeState.getNodeId();
     }
 

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java Tue Oct 14 00:48:22 2008
@@ -17,22 +17,18 @@
 package org.apache.jackrabbit.jcr2spi.state;
 
 import org.apache.jackrabbit.jcr2spi.operation.Operation;
-import org.apache.jackrabbit.jcr2spi.operation.AddNode;
-import org.apache.jackrabbit.jcr2spi.operation.AddProperty;
 import org.apache.jackrabbit.jcr2spi.operation.SetMixin;
-import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
-import org.apache.jackrabbit.spi.commons.name.NameConstants;
-import org.apache.commons.collections.iterators.IteratorChain;
+import org.apache.jackrabbit.jcr2spi.hierarchy.HierarchyEntry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.InvalidItemStateException;
 import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.ConstraintViolationException;
 import java.util.Iterator;
 import java.util.Set;
-import java.util.LinkedHashSet;
-import java.util.HashSet;
-import java.util.Collection;
+import java.util.List;
+import java.util.ArrayList;
 
 /**
  * Registers changes made to states and references and consolidates
@@ -50,101 +46,129 @@
      * in this changelog.
      */
     private final ItemState target;
-    /**
-     * Added states
-     */
-    private final Set addedStates = new LinkedHashSet();
-
-    /**
-     * Modified states
-     */
-    private final Set modifiedStates = new LinkedHashSet();
-
-    /**
-     * Deleted states
-     */
-    private final Set deletedStates = new LinkedHashSet();
 
     /**
      * Set of operations
      */
-    private Set operations = new LinkedHashSet();
+    private final Set operations;
+
+    private final Set affectedStates;
 
     /**
+     * Create a new change log and populates it with operations and states
+     * that are within the scope of this change set.
      *
      * @param target
+     * @param operations
+     * @param affectedStates
+     * @throws InvalidItemStateException
+     * @throws ConstraintViolationException
      */
-    ChangeLog(ItemState target) {
+    ChangeLog(ItemState target, Set operations, Set affectedStates)
+            throws InvalidItemStateException, ConstraintViolationException {
         this.target = target;
+        this.operations = operations;
+        this.affectedStates = affectedStates;
     }
 
     //-----------------------------------------------< Inform the ChangeLog >---
     /**
-     * Add the given operation to the list of operations to be recorded within
-     * the current update cycle of this ChangeLog.
-     *
-     * @param operation
-     */
-    public void addOperation(Operation operation) {
-        operations.add(operation);
-    }
-
-    /**
-     * A state has been added
-     *
-     * @param state state that has been added
-     */
-    public void added(ItemState state) {
-        addedStates.add(state);
-    }
-
-    /**
-     * A state has been modified. If the state is not a new state
-     * (not in the collection of added ones), then add
-     * it to the modified states collection.
-     *
-     * @param state state that has been modified
-     */
-    public void modified(ItemState state) {
-        if (!addedStates.contains(state)) {
-            modifiedStates.add(state);
+     * Call this method when this change log has been sucessfully persisted.
+     * This implementation will call {@link Operation#persisted() on the
+     * individual operations followed by setting all remaining modified
+     * states to EXISTING.
+     */
+    public void persisted() throws RepositoryException {
+        List changedMixins = new ArrayList();
+        Operation[] ops = (Operation[]) operations.toArray(new Operation[operations.size()]);
+        for (int i = 0; i < ops.length; i++) {
+            ops[i].persisted();
+            if (ops[i] instanceof SetMixin) {
+                changedMixins.add(((SetMixin) ops[i]).getNodeState());
+            }
         }
-    }
-
-    /**
-     * A state has been deleted. If the state is not a new state
-     * (not in the collection of added ones), then remove
-     * it from the modified states collection and add it to the
-     * deleted states collection.
-     *
-     * @param state state that has been deleted
-     */
-    public void deleted(ItemState state) {
-        if (!addedStates.remove(state)) {
-            modifiedStates.remove(state);
-            deletedStates.add(state);
+        // process all remaining states that were not covered by the
+        // operation persistence.
+        for (Iterator it = affectedStates.iterator(); it.hasNext();) {
+            ItemState state = (ItemState) it.next();
+            HierarchyEntry he = state.getHierarchyEntry();
+
+            switch (state.getStatus()) {
+                case Status.EXISTING_MODIFIED:
+                    state.setStatus(Status.EXISTING);
+                    if (state.isNode() && changedMixins.contains(state)) {
+                        // mixin changed for a node -> force reloading upon next
+                        // access in order to be aware of modified uniqueID.
+                        he.invalidate(false);
+                    }
+                    break;
+                case Status.EXISTING_REMOVED:
+                    he.remove();
+                    break;
+                case Status.NEW:
+                    // illegal. should not get here.
+                    log.error("ChangeLog still contains NEW state: " + state.getName());
+                    state.setStatus(Status.EXISTING);
+                    break;
+                case Status.MODIFIED:
+                case Status._UNDEFINED_:
+                case Status.STALE_DESTROYED:
+                case Status.STALE_MODIFIED:
+                    // illegal.
+                    log.error("ChangeLog contains state (" + state.getName() + ") with illegal status " + Status.getName(state.getStatus()));
+                    break;
+                case Status.EXISTING:
+                    if (state.isNode() && changedMixins.contains(state)) {
+                        // mixin changed for a node -> force reloading upon next
+                        // access in order to be aware of modified uniqueID.
+                        he.invalidate(false);
+                    }
+                    // otherwise: ignore. operations already have been completed
+                    break;
+                case Status.INVALIDATED:
+                case Status.REMOVED:
+                    // ignore. operations already have been completed
+                    break;
+            }
         }
     }
 
     /**
-     * Call this method when this change log has been sucessfully persisted.
-     * This implementation will call {@link ItemState#persisted(ChangeLog)
-     * ItemState.refresh(this)} on the target item of this change log.
-     */
-    public void persisted() {
-        target.persisted(this);
-    }
-
-    /**
      * Revert the changes listed within this changelog
      */
     public void undo() throws RepositoryException {
-        // TODO: check if states are reverted in the correct order
-        Iterator[] its = new Iterator[] {addedStates(), deletedStates(), modifiedStates()};
-        IteratorChain chain = new IteratorChain(its);
-        while (chain.hasNext()) {
-            ItemState state = (ItemState) chain.next();
-            state.getHierarchyEntry().revert();
+        Operation[] ops = (Operation[]) operations.toArray(new Operation[operations.size()]);
+        for (int i = ops.length - 1; i >= 0; i--) {
+            ops[i].undo();
+        }
+
+        // process all remaining states that were not covered by the
+        // operation undo.
+        for (Iterator it = affectedStates.iterator(); it.hasNext();) {
+            ItemState state = (ItemState) it.next();
+            switch (state.getStatus()) {
+                case Status.EXISTING_MODIFIED:
+                case Status.EXISTING_REMOVED:
+                case Status.STALE_MODIFIED:
+                case Status.STALE_DESTROYED:
+                    state.getHierarchyEntry().revert();
+                    break;
+                case Status.NEW:
+                    // illegal. should not get here.
+                    log.error("ChangeLog still contains NEW state: " + state.getName());
+                    state.getHierarchyEntry().revert();
+                    break;
+                case Status.MODIFIED:
+                case Status._UNDEFINED_:
+                    // illegal.
+                    log.error("ChangeLog contains state (" + state.getName() + ") with illegal status " + Status.getName(state.getStatus()));
+                    break;
+                case Status.EXISTING:
+                case Status.REMOVED:
+                case Status.INVALIDATED:
+                    // ignore already processed
+                    break;
+            }
         }
     }
     //----------------------< Retrieve information present in the ChangeLog >---
@@ -156,264 +180,33 @@
     }
 
     /**
-     * @return <code>true</code> if this changelog is empty.
+     * @return true if no <code>operations</code> are present.
      */
     public boolean isEmpty() {
         return operations.isEmpty();
     }
 
     /**
-     * @return an iterator over all operations.
+     * @return set of operations.
      */
-    public Iterator getOperations() {
-        return operations.iterator();
+    public Set getOperations() {
+        return operations;
     }
 
     /**
-     * Return an iterator over all added states.
-     *
-     * @return iterator over all added states.
-     */
-    public Iterator addedStates() {
-        return addedStates.iterator();
-    }
-
-    /**
-     * Return an iterator over all modified states.
-     *
-     * @return iterator over all modified states.
+     * @return set of the affected states.
      */
-    public Iterator modifiedStates() {
-        return modifiedStates.iterator();
-    }
-
-    /**
-     * Return an iterator over all deleted states.
-     *
-     * @return iterator over all deleted states.
-     */
-    public Iterator deletedStates() {
-        return deletedStates.iterator();
-    }
-
-    /**
-     * Returns true, if this change log contains the given <code>ItemState</code>
-     * in the set of transiently removed states.
-     *
-     * @param state
-     * @return
-     */
-    public boolean containsDeletedState(ItemState state) {
-        return deletedStates.contains(state);
-    }
-
-    /**
-     * Removes the subset of this changelog represented by the given
-     * <code>ChangeLog</code> from this changelog.
-     *
-     * @param subChangeLog remove all entries (states, operations) present in
-     * the given changelog from this changelog.
-     */
-    public void removeAll(ChangeLog subChangeLog) {
-        addedStates.removeAll(subChangeLog.addedStates);
-        modifiedStates.removeAll(subChangeLog.modifiedStates);
-        deletedStates.removeAll(subChangeLog.deletedStates);
-
-        operations.removeAll(subChangeLog.operations);
-    }
-
-    /**
-     * Adjust this ChangeLog according to the status change with the given
-     * ItemState:
-     * Remove all entries and operation related to the given ItemState, that
-     * are not used any more (respecting the status change).
-     *
-     * @param state
-     */
-    public void statusChanged(ItemState state, int previousStatus) {
-        switch (state.getStatus()) {
-            case (Status.EXISTING):
-                switch (previousStatus) {
-                    case Status.EXISTING_MODIFIED:
-                        // was modified and is now refreshed
-                        modifiedStates.remove(state);
-                        break;
-                    case Status.EXISTING_REMOVED:
-                        // was removed and is now refreshed
-                        deletedStates.remove(state);
-                        break;
-                    case Status.STALE_MODIFIED:
-                        // was modified and state and is now refreshed
-                        modifiedStates.remove(state);
-                        break;
-                    case Status.NEW:
-                        // was new and has been saved now
-                        addedStates.remove(state);
-                        break;
-                }
-                // TODO: check if correct: changelog gets cleared any way -> no need to remove operations
-                break;
-            case Status.EXISTING_MODIFIED:
-                modified(state);
-                break;
-            case (Status.EXISTING_REMOVED):
-                deleted(state);
-                // removeAffectedOperations(state);
-                break;
-            case (Status.REMOVED):
-                switch (previousStatus) {
-                    case Status.EXISTING_REMOVED:
-                        // was removed and is now saved
-                        deletedStates.remove(state);
-                        removeAffectedOperations(state);
-                        break;
-                    case Status.NEW:
-                        newStateRemoved(state);
-                        break;
-                }
-                break;
-        }
-    }
-
-    private void newStateRemoved(ItemState state) {
-        NodeEntry parentEntry = state.getHierarchyEntry().getParent();
-        if (!parentEntry.isAvailable() || Status.isTerminal(parentEntry.getStatus())) {
-            return; // TODO: check if correct
-        }
-        // was new and now removed again
-        addedStates.remove(state);
-
-        // remove any operations performed on the removed state
-        removeAffectedOperations(state);
-
-        /* remove the add-operation as well:
-           since the affected state of an 'ADD' operation is the parent instead
-           of the added-state, the set of operations need to be searched for the
-           parent state && the proper operation type.
-           SET_MIXIN is considered as a special case of adding a property
-         */
-        NodeState parent;
-        try {
-            parent = parentEntry.getNodeState();
-        } catch (RepositoryException e) {
-            // should never occur
-            log.error("Internal error:", e);
-            return;
-        }
-        for (Iterator it = operations.iterator(); it.hasNext();) {
-            Operation op = (Operation) it.next();
-            if (op instanceof AddNode) {
-                AddNode operation = (AddNode) op;
-                if (operation.getParentState() == parent
-                        && operation.getNodeName().equals(state.getName())) {
-                    // TODO: this will not work for name name siblings!
-                    it.remove();
-                    break;
-                }
-            } else if (op instanceof AddProperty) {
-                AddProperty operation = (AddProperty) op;
-                if (operation.getParentState() == parent
-                        && operation.getPropertyName().equals(state.getName())) {
-                    it.remove();
-                    break;
-                }
-            } else if (op instanceof SetMixin &&
-                    NameConstants.JCR_MIXINTYPES.equals(state.getName()) &&
-                    ((SetMixin)op).getNodeState() == parent) {
-                it.remove();
-                break;
-            }
-        }
-    }
-
-    private void removeAffectedOperations(ItemState state) {
-        for (Iterator it = operations.iterator(); it.hasNext();) {
-            Operation op = (Operation) it.next();
-            if (op.getAffectedItemStates().contains(state)) {
-                it.remove();
-            }
-        }
-    }
-
-    /**
-     * Make sure that this ChangeLog is totally 'self-contained'
-     * and independant; items within the scope of this update operation
-     * must not have 'external' dependencies;
-     * (e.g. moving a node requires that the target node including both
-     * old and new parents are saved)
-     */
-    public void checkIsSelfContained() throws ConstraintViolationException {
-        Set affectedStates = new HashSet();
-        affectedStates.addAll(modifiedStates);
-        affectedStates.addAll(deletedStates);
-        affectedStates.addAll(addedStates);
-
-        // check if the affected states listed by the operations are all
-        // listed in the modified,deleted or added states collected by this
-        // changelog.
-        Iterator it = getOperations();
-        while (it.hasNext()) {
-            Operation op = (Operation) it.next();
-            Collection opStates = op.getAffectedItemStates();
-            if (!affectedStates.containsAll(opStates)) {
-                // need to save the parent as well
-                String msg = "ChangeLog is not self contained.";
-                throw new ConstraintViolationException(msg);
-            }
-        }
-    }
-
-    /**
-     * Populates this <code>ChangeLog</code> with operations that are within the
-     * scope of this change set.
-     *
-     * @param operations an Iterator of <code>Operation</code>s which are the
-     *                   candidates to be included in this <code>ChangeLog</code>.
-     */
-    public void collectOperations(Iterator operations) {
-        Set affectedStates = new HashSet();
-        affectedStates.addAll(addedStates);
-        affectedStates.addAll(deletedStates);
-        affectedStates.addAll(modifiedStates);
-        while (operations.hasNext()) {
-            Operation op = (Operation) operations.next();
-            Iterator states = op.getAffectedItemStates().iterator();
-            while (states.hasNext()) {
-                ItemState state = (ItemState) states.next();
-                if (affectedStates.contains(state)) {
-                    addOperation(op);
-                    break;
-                }
-            }
-        }
+    public Set getAffectedStates() {
+        return affectedStates;
     }
 
     /**
      * Reset this change log, removing all members inside the
      * maps we built.
      */
-    public void reset() {
-        addedStates.clear();
-        modifiedStates.clear();
-        deletedStates.clear();
+    void reset() {
+        affectedStates.clear();
         // also clear all operations
         operations.clear();
     }
-
-    //-------------------------------------------------------------< Object >---
-    /**
-     * Returns a string representation of this change log for diagnostic
-     * purposes.
-     *
-     * @return a string representation of this change log
-     */
-    public String toString() {
-        StringBuffer buf = new StringBuffer();
-        buf.append("{");
-        buf.append("#addedStates=").append(addedStates.size());
-        buf.append(", #modifiedStates=").append(modifiedStates.size());
-        buf.append(", #deletedStates=").append(deletedStates.size());
-        buf.append("}");
-        return buf.toString();
-    }
 }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java Tue Oct 14 00:48:22 2008
@@ -16,25 +16,22 @@
  */
 package org.apache.jackrabbit.jcr2spi.state;
 
-import org.apache.jackrabbit.util.WeakIdentityCollection;
-import org.apache.jackrabbit.spi.ItemId;
-import org.apache.jackrabbit.spi.NodeId;
-import org.apache.jackrabbit.spi.PropertyId;
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.jcr2spi.hierarchy.HierarchyEntry;
 import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
-import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
 import org.apache.jackrabbit.jcr2spi.nodetype.ItemDefinitionProvider;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.util.WeakIdentityCollection;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.RepositoryException;
-import javax.jcr.ItemNotFoundException;
 import javax.jcr.InvalidItemStateException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.RepositoryException;
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.Collections;
+import java.util.Iterator;
 
 /**
  * <code>ItemState</code> represents the state of an <code>Item</code>.
@@ -108,10 +105,6 @@
         this.hierarchyEntry = entry;
         this.isf = isf;
         this.definitionProvider = definitionProvider;
-
-        if (!entry.isAvailable()) {
-            entry.setItemState(this);
-        }
     }
 
     /**
@@ -144,17 +137,13 @@
     }
 
     /**
-     * Returns <code>true</code> if this item state is valid, that is its status
-     * is one of:
-     * <ul>
-     * <li>{@link Status#EXISTING}</li>
-     * <li>{@link Status#EXISTING_MODIFIED}</li>
-     * <li>{@link Status#NEW}</li>
-     * </ul>
+     * Returns <code>true</code> if this item state is valid and can be accessed.
      * @return
+     * @see Status#isValid(int)
+     * @see Status#isStale(int)
      */
     public boolean isValid() {
-        return Status.isValid(getStatus());
+        return Status.isValid(getStatus()) || Status.isStale(getStatus());
     }
 
     /**
@@ -183,7 +172,7 @@
      *
      * @return the identifier of this item state..
      */
-    public abstract ItemId getId();
+    public abstract ItemId getId() throws RepositoryException;
 
     /**
      * Utility method:
@@ -192,7 +181,7 @@
      *
      * @return the identifier of this item state..
      */
-    public abstract ItemId getWorkspaceId();
+    public abstract ItemId getWorkspaceId() throws RepositoryException;
 
     /**
      * Utility method:
@@ -239,7 +228,7 @@
             return;
         }
 
-        if (Status.isTerminal(oldStatus)) {
+        if (oldStatus == Status.REMOVED) {
             throw new IllegalStateException("State is already in terminal status " + Status.getName(oldStatus));
         }
         if (Status.isValidStatusChange(oldStatus, newStatus)) {
@@ -319,55 +308,6 @@
     }
 
     /**
-     * Used on the target state of a save call AFTER the changelog has been
-     * successfully submitted to the SPI..
-     *
-     * @param changeLog
-     * @throws IllegalStateException if this state is a 'workspace' state.
-     */
-    abstract void persisted(ChangeLog changeLog) throws IllegalStateException;
-
-    /**
-     * 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
-     */
-    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;
-        }
-
-        boolean modified = merge(tmp, keepChanges);
-        if (status == Status.NEW || status == Status.INVALIDATED) {
-            setStatus(Status.EXISTING);
-        } else if (modified) {
-            // start notification by marking this state modified.
-            setStatus(Status.MODIFIED);
-        }
-    }
-
-    /**
      * Marks this item state as modified.
      */
     void markModified() throws InvalidItemStateException {

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java Tue Oct 14 00:48:22 2008
@@ -16,31 +16,25 @@
  */
 package org.apache.jackrabbit.jcr2spi.state;
 
-import org.apache.commons.collections.iterators.IteratorChain;
 import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
 import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
-import org.apache.jackrabbit.jcr2spi.util.StateUtility;
 import org.apache.jackrabbit.jcr2spi.nodetype.ItemDefinitionProvider;
+import org.apache.jackrabbit.jcr2spi.util.StateUtility;
+import org.apache.jackrabbit.spi.ItemId;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.NodeId;
-import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.NodeInfo;
 import org.apache.jackrabbit.spi.PropertyId;
 import org.apache.jackrabbit.spi.QNodeDefinition;
-import org.apache.jackrabbit.spi.NodeInfo;
 import org.apache.jackrabbit.spi.QValue;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
-import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import javax.jcr.RepositoryException;
 import javax.jcr.ItemNotFoundException;
-import java.util.ArrayList;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import javax.jcr.RepositoryException;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * <code>NodeState</code> represents the state of a <code>Node</code>.
@@ -113,7 +107,7 @@
      * {@inheritDoc}
      * @see ItemState#getId()
      */
-    public ItemId getId() {
+    public ItemId getId() throws RepositoryException {
         return getNodeId();
     }
 
@@ -121,7 +115,7 @@
      * {@inheritDoc}
      * @see ItemState#getWorkspaceId()
      */
-    public ItemId getWorkspaceId() {
+    public ItemId getWorkspaceId() throws RepositoryException {
         return getNodeEntry().getWorkspaceId();
     }
 
@@ -177,125 +171,6 @@
         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 (NameConstants.JCR_MIXINTYPES.equals(modState.getName())) {
-                    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.entrySet().iterator(); it.hasNext();) {
-            Map.Entry entry = (Map.Entry) it.next();
-            NodeState parent = (NodeState) entry.getKey();
-            List l = (List) entry.getValue();
-            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.
@@ -309,7 +184,7 @@
      *
      * @return the id of this node state.
      */
-    public NodeId getNodeId() {
+    public NodeId getNodeId() throws RepositoryException {
         return getNodeEntry().getId();
     }
 
@@ -349,7 +224,6 @@
     }
 
     /**
-     * TODO improve
      * Used by NodeEntryImpl and NodeState only
      *
      * @param mixinTypeNames
@@ -573,51 +447,10 @@
              before. The effective NT must be evaluated as if it had been
              evaluated upon creating the workspace state.
              */
-            def = definitionProvider.getQNodeDefinition(getParent().getNodeTypeNames(), getName(), getNodeTypeName(), getNodeEntry().getWorkspaceId());
+            NodeState parent = getParent();
+            NodeId wspId = (NodeId) getWorkspaceId();
+            def = definitionProvider.getQNodeDefinition(getParent().getNodeTypeNames(), getName(), getNodeTypeName(), wspId);
         }
         return def;
     }
-    /**
-     *
-     * @param childState
-     * @param modParents
-     */
-    private static void modifiedParent(NodeState parent, ItemState childState, Map modParents) {
-        List l;
-        if (modParents.containsKey(parent)) {
-            l = (List) modParents.get(parent);
-        } else {
-            l = new ArrayList(2);
-            modParents.put(parent, l);
-        }
-        if (childState != null && !childState.isNode() && StateUtility.isUuidOrMixin(childState.getName())) {
-            l.add(childState);
-        }
-    }
-
-    /**
-     *
-     * @param parent
-     * @param props
-     */
-    private static void adjustNodeState(NodeState parent, PropertyState[] props) {
-        for (int i = 0; i < props.length; i++) {
-            PropertyState propState = props[i];
-            if (NameConstants.JCR_UUID.equals(propState.getName())) {
-                if (propState.getStatus() == Status.REMOVED) {
-                    parent.getNodeEntry().setUniqueID(null);
-                } else {
-                    // retrieve uuid from persistent layer
-                    propState.reload(false);
-                }
-            } else if (NameConstants.JCR_MIXINTYPES.equals(propState.getName())) {
-                Name[] mixins = StateUtility.getMixinNames(propState);
-                parent.setMixinTypeNames(mixins);
-            } // else: ignore.
-        }
-
-        // set parent status to 'existing'
-        parent.setStatus(Status.EXISTING);
-        parent.reload(false);
-    }
 }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java Tue Oct 14 00:48:22 2008
@@ -30,7 +30,6 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.ValueFormatException;
 import javax.jcr.nodetype.ConstraintViolationException;
-import java.util.Iterator;
 
 /**
  * <code>PropertyState</code> represents the state of a <code>Property</code>.
@@ -50,14 +49,15 @@
     private final boolean multiValued;
 
     /**
-     *
+     * Value(s) and type of an existing property that has been transiently
+     * modified.
      */
-    private TransientData transientData;
+    private PropertyData transientData;
 
     /**
-     *
+     * Original value(s) and type of an existing or a new property.
      */
-    private PropertyInfo pInfo;
+    private PropertyData data;
 
     /**
      * Create a NEW PropertyState
@@ -69,12 +69,13 @@
      */
     protected PropertyState(PropertyEntry entry, ItemStateFactory isf,
                             QPropertyDefinition definition,
-                            ItemDefinitionProvider definitionProvider) {
+                            ItemDefinitionProvider definitionProvider,
+                            QValue[] values, int propertyType)
+            throws ConstraintViolationException, RepositoryException {
         super(Status.NEW, entry, isf, definitionProvider);
         this.multiValued = definition.isMultiple();
         this.definition = definition;
-        this.transientData = null; // TODO: maybe type/values should be passed to constructor
-        this.pInfo = null;
+        setValues(values, propertyType);
     }
 
     /**
@@ -90,8 +91,8 @@
                             ItemDefinitionProvider definitionProvider) {
         super(entry, isf, definitionProvider);
         this.multiValued = pInfo.isMultiValued();
+        this.data = new PropertyData(pInfo);
         this.transientData = null;
-        this.pInfo = pInfo;
     }
 
     //----------------------------------------------------------< ItemState >---
@@ -109,7 +110,7 @@
      * {@inheritDoc}
      * @see ItemState#getId()
      */
-    public ItemId getId() {
+    public ItemId getId() throws RepositoryException {
         return ((PropertyEntry) getHierarchyEntry()).getId();
     }
 
@@ -117,15 +118,15 @@
      * {@inheritDoc}
      * @see ItemState#getWorkspaceId()
      */
-    public ItemId getWorkspaceId() {
+    public ItemId getWorkspaceId() throws RepositoryException {
         return ((PropertyEntry) getHierarchyEntry()).getWorkspaceId();
     }
 
     /**
-     * If <code>keepChanges</code> is true, this method does nothing and returns
-     * false. Otherwise type and values of the other property state are compared
-     * to this state. If they differ, they will be copied to this state and
-     * this method returns true.
+     * If <code>keepChanges</code> is true, this method only compares the existing
+     * values with the values from 'another' and returns true, if the underlying
+     * persistent state is different to the stored persistent values. Otherwise
+     * the transient changes will be discarded.
      *
      * @see ItemState#merge(ItemState, boolean)
      */
@@ -136,14 +137,21 @@
         if (another.isNode()) {
             throw new IllegalArgumentException("Attempt to merge property state with node state.");
         }
-        boolean modified = diff(this, (PropertyState) another);
-        this.pInfo = ((PropertyState) another).pInfo;
-        if (!keepChanges && transientData != null) {
-            modified = true;
+        // calculate if the persistent values of this state differ from the
+        // other state.
+        boolean diff = diff(data, ((PropertyState) another).data);
+        // reset the pInfo to point to the pInfo of another state.
+        this.data = ((PropertyState) another).data;
+        // if transient changes should be preserved OR if there are not
+        // transient changes, simply return diff to indicate if this state
+        // was internally changed.
+        if (keepChanges || transientData == null) {
+            return diff;
+        } else {
             transientData.discardValues();
             transientData = null;
+            return true;
         }
-        return modified;
     }
 
     /**
@@ -163,26 +171,6 @@
         }
     }
 
-
-    /**
-     * {@inheritDoc}
-     * @see ItemState#persisted(ChangeLog)
-     */
-    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).
@@ -194,7 +182,7 @@
      * type if the latter is {@link PropertyType#UNDEFINED}.
      */
     public int getType() {
-        return (transientData == null) ? pInfo.getType() : transientData.type;
+        return (transientData == null) ? data.type : transientData.type;
     }
 
     /**
@@ -236,8 +224,8 @@
      * @return the value(s) of this property.
      */
     public QValue[] getValues() {
-        // if transientData are null the pInfo MUST be present (ev. add check)
-        return (transientData == null) ? pInfo.getValues() : transientData.values;
+        // if transientData are null the data MUST be present (ev. add check)
+        return (transientData == null) ? data.values : transientData.values;
     }
 
     /**
@@ -264,12 +252,20 @@
      * @param values the new values
      */
     void setValues(QValue[] values, int type) throws RepositoryException {
-        if (transientData == null) {
-            transientData = new TransientData(type, values);
+        if (getStatus() == Status.NEW) {
+            if (data == null) {
+                data = new PropertyData(type, values);
+            } else {
+                data.setValues(type, values);
+            }
         } else {
-            transientData.setValues(type, values);
+            if (transientData == null) {
+                transientData = new PropertyData(type, values);
+            } else {
+                transientData.setValues(type, values);
+            }
+            markModified();
         }
-        markModified();
     }
 
     //------------------------------------------------------------< private >---
@@ -317,14 +313,14 @@
      * @return if the 2 <code>PropertyState</code>s are different in terms of
      * type and/or values.
      */
-    private static boolean diff(PropertyState p1, PropertyState p2) {
+    private static boolean diff(PropertyData p1, PropertyData p2) {
         // compare type
-        if (p1.getType() != p2.getType()) {
+        if (p1.type != p2.type) {
             return true;
         }
 
-        QValue[] vs1 = p1.getValues();
-        QValue[] vs2 = p2.getValues();
+        QValue[] vs1 = p1.values;
+        QValue[] vs2 = p2.values;
         if (vs1.length != vs2.length) {
             return true;
         } else {
@@ -341,18 +337,23 @@
 
     //--------------------------------------------------------< inner class >---
     /**
-     * Inner class storing transient property values an their type.
+     * Inner class storing property values an their type.
      */
-    private class TransientData {
+    private class PropertyData {
 
         private int type;
         private QValue[] values;
 
-        private TransientData(int type, QValue[] values) throws RepositoryException {
+        private PropertyData(PropertyInfo pInfo) {
+            this.type = pInfo.getType();
+            this.values = pInfo.getValues();
+        }
+
+        private PropertyData(int type, QValue[] values) throws ConstraintViolationException, RepositoryException {
             setValues(type, values);
         }
 
-        private void setValues(int type, QValue[] values) throws RepositoryException {
+        private void setValues(int type, QValue[] values) throws ConstraintViolationException, RepositoryException {
             // make sure the arguements are consistent and do not violate the
             // given property definition.
             validate(values, type, getDefinition());