You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2009/12/04 18:25:03 UTC

svn commit: r887279 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: ItemImpl.java SessionImpl.java state/SessionItemStateManager.java

Author: stefan
Date: Fri Dec  4 17:24:44 2009
New Revision: 887279

URL: http://svn.apache.org/viewvc?rev=887279&view=rev
Log:
JCR-2425: Session.save() and Session.refresh(boolean) rely on accessibility of the root node

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java?rev=887279&r1=887278&r2=887279&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java Fri Dec  4 17:24:44 2009
@@ -979,7 +979,7 @@
              */
             Collection<ItemState> removed = getRemovedStates();
 
-            // All affected item states. They keys are used to look up whether
+            // All affected item states. The keys are used to look up whether
             // an item is affected, and the values are iterated through below
             Map<ItemId, ItemState> affected =
                 new HashMap<ItemId, ItemState>(dirty.size() + removed.size());

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=887279&r1=887278&r2=887279&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java Fri Dec  4 17:24:44 2009
@@ -914,7 +914,13 @@
         // check sanity of this session
         sanityCheck();
 
-        getItemManager().getRootNode().save();
+        // /JCR-2425: check whether session is allowed to read root node
+        if (hasPermission("/", ACTION_READ)) {
+            getItemManager().getRootNode().save();
+        } else {
+            NodeId id = getItemStateManager().getIdOfRootTransientNodeState();
+            getItemManager().getItem(id).save();
+        }
     }
 
     /**
@@ -936,11 +942,12 @@
         }
 
         if (!keepChanges) {
-            // optimization
             itemStateMgr.disposeAllTransientItemStates();
-            return;
+        } else {
+            /** todo FIXME should reset Item#status field to STATUS_NORMAL
+             * of all non-transient instances; maybe also
+             * have to reset stale ItemState instances */
         }
-        getItemManager().getRootNode().refresh(keepChanges);
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java?rev=887279&r1=887278&r2=887279&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java Fri Dec  4 17:24:44 2009
@@ -22,12 +22,12 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.LinkedList;
 
 import javax.jcr.InvalidItemStateException;
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.ReferentialIntegrityException;
 import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
 
 import org.apache.commons.collections.iterators.IteratorChain;
 import org.apache.jackrabbit.core.CachingHierarchyManager;
@@ -38,10 +38,12 @@
 import org.apache.jackrabbit.core.id.PropertyId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
-import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
 import org.apache.jackrabbit.core.util.Dumpable;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.PathFactory;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -391,7 +393,7 @@
      * Returns an iterator over those transient item state instances that are
      * direct or indirect descendants of the item state with the given
      * <code>parentId</code>. The transient item state instance with the given
-     * <code>parentId</code> itself (if there is such)                                                                            not be included.
+     * <code>parentId</code> itself (if there is such) will not be included.
      * <p/>
      * The instances are returned in depth-first tree traversal order.
      *
@@ -417,9 +419,7 @@
         List[] la = new List[10];
         try {
             HierarchyManager atticAware = getAtticAwareHierarchyMgr();
-            Iterator iter = transientStore.values().iterator();
-            while (iter.hasNext()) {
-                ItemState state = (ItemState) iter.next();
+            for (ItemState state : transientStore.values()) {
                 // determine relative depth: > 0 means it's a descendant
                 int depth;
                 try {
@@ -562,6 +562,104 @@
     }
 
     /**
+     * Returns the id of the root of the minimal subtree including all
+     * transient states.
+     *
+     * @return id of nearest common ancestor of all transient states or null
+     *         if there's no transient state.
+     * @throws RepositoryException if an error occurs
+     */
+    public NodeId getIdOfRootTransientNodeState() throws RepositoryException {
+        if (transientStore.isEmpty()) {
+            return null;
+        }
+
+        // short cut
+        if (transientStore.contains(hierMgr.getRootNodeId())) {
+            return hierMgr.getRootNodeId();
+        }
+
+        // the nearest common ancestor of all transient states
+        // must be either
+        // a) a node state with STATUS_EXISTING_MODIFIED, or
+        // b) the parent node of a property state with STATUS_EXISTING_MODIFIED 
+
+        // collect all candidates based on above criteria
+        Collection<NodeId> candidateIds = new LinkedList<NodeId>();
+        try {
+            HierarchyManager hierMgr = getHierarchyMgr();
+            for (ItemState state : transientStore.values()) {
+                if (state.getStatus() == ItemState.STATUS_EXISTING_MODIFIED) {
+                    NodeId nodeId;
+                    if (state.isNode()) {
+                        nodeId = (NodeId) state.getId();
+                    } else {
+                        nodeId = state.getParentId();
+                    }
+                    // remove any descendant candidates
+                    boolean skip = false;
+                    for (NodeId id : candidateIds) {
+                        if (nodeId.equals(id) || hierMgr.isAncestor(id, nodeId)) {
+                            // already a candidate or a descendant thereof
+                            // => skip
+                            skip = true;
+                            break;
+                        }
+                        if (hierMgr.isAncestor(nodeId, id)) {
+                            // candidate is a descendant => remove
+                            candidateIds.remove(id);
+                        }
+                    }
+                    if (!skip) {
+                        // add to candidates
+                        candidateIds.add(nodeId);
+                    }
+                }
+            }
+
+            if (candidateIds.size() == 1) {
+                return candidateIds.iterator().next();
+            }
+
+            // pick (any) candidate with shortest path to start with
+            NodeId candidateId = null;
+            for (NodeId id : candidateIds) {
+                if (candidateId == null) {
+                    candidateId = id;
+                } else {
+                    if (hierMgr.getDepth(id) < hierMgr.getDepth(candidateId)) {
+                        candidateId = id;
+                    }
+                }
+            }
+
+            // starting with this candidate closest to root, find first parent
+            // which is an ancestor of all candidates
+            NodeState state = (NodeState) getItemState(candidateId);
+            NodeId parentId = state.getParentId();
+            boolean continueWithParent = false;
+            while (parentId != null) {
+                for (NodeId id : candidateIds) {
+                    if (hierMgr.getRelativeDepth(parentId, id) == -1) {
+                        continueWithParent = true;
+                        break;
+                    }
+                }
+                if (continueWithParent) {
+                    state = (NodeState) getItemState(candidateId);
+                    parentId = state.getParentId();
+                    continueWithParent = false;
+                } else {
+                    break;
+                }
+            }
+            return parentId;
+        } catch (ItemStateException e) {
+            throw new RepositoryException("failed to determine common root of transient changes", e);
+        }
+    }
+
+    /**
      * Return a flag indicating whether the specified item is in the transient
      * item state manager's attic space.
      *