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

svn commit: r709115 - /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java

Author: jukka
Date: Thu Oct 30 01:31:00 2008
New Revision: 709115

URL: http://svn.apache.org/viewvc?rev=709115&view=rev
Log:
JCR-1775: Transaction-safe versioning

Improved referential integrity checks

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java?rev=709115&r1=709114&r2=709115&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java Thu Oct 30 01:31:00 2008
@@ -561,7 +561,7 @@
                 // If enabled, check whether reference targets
                 // exist/were not removed
                 if (checkReferences) {
-                    checkReferentialIntegrity(local);
+                    checkReferentialIntegrity();
                 }
 
                 /**
@@ -940,6 +940,105 @@
             }
         }
 
+        /**
+         * Verifies that
+         * <ul>
+         * <li>no referenceable nodes are deleted if they are still being referenced</li>
+         * <li>targets of modified node references exist</li>
+         * </ul>
+         *
+         * @throws ReferentialIntegrityException if a new or modified REFERENCE
+         *                                       property refers to a non-existent
+         *                                       target or if a removed node is still
+         *                                       being referenced
+         * @throws ItemStateException            if another error occurs
+         */
+        private void checkReferentialIntegrity()
+                throws ReferentialIntegrityException, ItemStateException {
+
+            // check whether removed referenceable nodes are still being referenced
+            for (Iterator iter = local.deletedStates(); iter.hasNext();) {
+                ItemState state = (ItemState) iter.next();
+                if (state.isNode()) {
+                    NodeState node = (NodeState) state;
+                    if (isReferenceable(node)) {
+                        NodeReferencesId refsId = new NodeReferencesId(node.getNodeId());
+                        // either get node references from change log or
+                        // load from persistence manager
+                        NodeReferences refs = local.get(refsId);
+                        if (refs == null) {
+                            if (!hasNodeReferences(refsId)) {
+                                continue;
+                            }
+                            refs = getNodeReferences(refsId);
+                        }
+                        // in some versioning operations (such as restore) a node
+                        // may actually be deleted and then again added with the
+                        // same UUID, i.e. the node is still referenceable.
+                        if (refs.hasReferences() && !local.has(node.getNodeId())) {
+                            String msg = node.getNodeId()
+                                    + ": the node cannot be removed because it is still being referenced.";
+                            log.debug(msg);
+                            throw new ReferentialIntegrityException(msg);
+                        }
+                    }
+                }
+            }
+
+            // check whether targets of modified node references exist
+            for (Iterator iter = local.modifiedRefs(); iter.hasNext();) {
+                NodeReferences refs = (NodeReferences) iter.next();
+                NodeId id = refs.getTargetId();
+                // no need to check existence of target if there are no references
+                if (refs.hasReferences()) {
+                    // please note:
+                    // virtual providers are indirectly checked via 'hasItemState()'
+                    if (!local.has(id) && !hasItemState(id)) {
+                        String msg = "Target node " + id
+                                + " of REFERENCE property does not exist";
+                        log.debug(msg);
+                        throw new ReferentialIntegrityException(msg);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Determines whether the specified node is <i>referenceable</i>, i.e.
+         * whether the mixin type <code>mix:referenceable</code> is either
+         * directly assigned or indirectly inherited.
+         *
+         * @param state node state to check
+         * @return true if the specified node is <i>referenceable</i>, false otherwise.
+         * @throws ItemStateException if an error occurs
+         */
+        private boolean isReferenceable(NodeState state) throws ItemStateException {
+            // shortcut: check some well known built-in types first
+            Name primary = state.getNodeTypeName();
+            Set mixins = state.getMixinTypeNames();
+            if (mixins.contains(NameConstants.MIX_REFERENCEABLE)
+                    || mixins.contains(NameConstants.MIX_VERSIONABLE)
+                    || primary.equals(NameConstants.NT_RESOURCE)) {
+                return true;
+            }
+
+            // build effective node type
+            try {
+                EffectiveNodeType type = ntReg.getEffectiveNodeType(primary, mixins);
+                return type.includesNodeType(NameConstants.MIX_REFERENCEABLE);
+            } catch (NodeTypeConflictException ntce) {
+                String msg = "internal error: failed to build effective node type for node "
+                        + state.getNodeId();
+                log.debug(msg);
+                throw new ItemStateException(msg, ntce);
+            } catch (NoSuchNodeTypeException nsnte) {
+                String msg = "internal error: failed to build effective node type for node "
+                        + state.getNodeId();
+                log.debug(msg);
+                throw new ItemStateException(msg, nsnte);
+            }
+        }
+
     }
 
     /**
@@ -1292,106 +1391,6 @@
     }
 
     /**
-     * Determines whether the specified node is <i>referenceable</i>, i.e.
-     * whether the mixin type <code>mix:referenceable</code> is either
-     * directly assigned or indirectly inherited.
-     *
-     * @param state node state to check
-     * @return true if the specified node is <i>referenceable</i>, false otherwise.
-     * @throws ItemStateException if an error occurs
-     */
-    private boolean isReferenceable(NodeState state) throws ItemStateException {
-        // shortcut: check some well known built-in types first
-        Name primary = state.getNodeTypeName();
-        Set mixins = state.getMixinTypeNames();
-        if (mixins.contains(NameConstants.MIX_REFERENCEABLE)
-                || mixins.contains(NameConstants.MIX_VERSIONABLE)
-                || primary.equals(NameConstants.NT_RESOURCE)) {
-            return true;
-        }
-
-        // build effective node type
-        try {
-            EffectiveNodeType type = ntReg.getEffectiveNodeType(primary, mixins);
-            return type.includesNodeType(NameConstants.MIX_REFERENCEABLE);
-        } catch (NodeTypeConflictException ntce) {
-            String msg = "internal error: failed to build effective node type for node "
-                    + state.getNodeId();
-            log.debug(msg);
-            throw new ItemStateException(msg, ntce);
-        } catch (NoSuchNodeTypeException nsnte) {
-            String msg = "internal error: failed to build effective node type for node "
-                    + state.getNodeId();
-            log.debug(msg);
-            throw new ItemStateException(msg, nsnte);
-        }
-    }
-
-    /**
-     * Verifies that
-     * <ul>
-     * <li>no referenceable nodes are deleted if they are still being referenced</li>
-     * <li>targets of modified node references exist</li>
-     * </ul>
-     *
-     * @param changes change log
-     * @throws ReferentialIntegrityException if a new or modified REFERENCE
-     *                                       property refers to a non-existent
-     *                                       target or if a removed node is still
-     *                                       being referenced
-     * @throws ItemStateException            if another error occurs
-     */
-    protected void checkReferentialIntegrity(ChangeLog changes)
-            throws ReferentialIntegrityException, ItemStateException {
-
-        // check whether removed referenceable nodes are still being referenced
-        for (Iterator iter = changes.deletedStates(); iter.hasNext();) {
-            ItemState state = (ItemState) iter.next();
-            if (state.isNode()) {
-                NodeState node = (NodeState) state;
-                if (isReferenceable(node)) {
-                    NodeReferencesId refsId = new NodeReferencesId(node.getNodeId());
-                    // either get node references from change log or
-                    // load from persistence manager
-                    NodeReferences refs = changes.get(refsId);
-                    if (refs == null) {
-                        if (!hasNodeReferences(refsId)) {
-                            continue;
-                        }
-                        refs = getNodeReferences(refsId);
-                    }
-                    // in some versioning operations (such as restore) a node
-                    // may actually be deleted and then again added with the
-                    // same UUID, i.e. the node is still referenceable.
-                    if (refs.hasReferences() && !changes.has(node.getNodeId())) {
-                        String msg = node.getNodeId()
-                                + ": the node cannot be removed because it is still being referenced.";
-                        log.debug(msg);
-                        throw new ReferentialIntegrityException(msg);
-                    }
-                }
-            }
-        }
-
-        // check whether targets of modified node references exist
-        for (Iterator iter = changes.modifiedRefs(); iter.hasNext();) {
-            NodeReferences refs = (NodeReferences) iter.next();
-            NodeId id = refs.getTargetId();
-            // no need to check existence of target if there are no references
-            if (refs.hasReferences()) {
-                // please note:
-                // virtual providers are indirectly checked via 'hasItemState()'
-                if (!changes.has(id) && !hasItemState(id)) {
-                    String msg = "Target node " + id
-                            + " of REFERENCE property does not exist";
-                    log.debug(msg);
-                    throw new ReferentialIntegrityException(msg);
-                }
-            }
-        }
-    }
-
-    /**
      * Acquires the read lock on this item state manager.
      *
      * @param id the id of the item for which to acquire a read lock.