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 12:37:18 UTC

svn commit: r709146 - in /jackrabbit/branches/1.5: ./ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/s...

Author: jukka
Date: Thu Oct 30 04:37:18 2008
New Revision: 709146

URL: http://svn.apache.org/viewvc?rev=709146&view=rev
Log:
1.5: Merged revisions from trunk (JCR-1775 and JCR-1841).

Modified:
    jackrabbit/branches/1.5/   (props changed)
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/VirtualNodeTypeStateProvider.java
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessControlPolicyIteratorAdapter.java   (props changed)
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/NodeStateEx.java
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateManager.java
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java
    jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java
    jackrabbit/branches/1.5/jackrabbit-ocm-nodemanagement/src/test/resources/log4j.properties   (props changed)

Propchange: jackrabbit/branches/1.5/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Oct 30 04:37:18 2008
@@ -1,2 +1,2 @@
 /jackrabbit/branches/1.3:631261
-/jackrabbit/trunk:703899-704158,704165,704167,704324,704358,704361,704864,704933,704939,705010,705033,705243,705496,705522,705579,705925,705932,705934,705937-705938,705961,706242,706273,706285-706286,706562,706606,706649,706655,706660,706697,706918,707303-707304,707307,707310,707630,708206,708598,708609,708613,708619,708634
+/jackrabbit/trunk:703899-704158,704165,704167,704324,704358,704361,704864,704933,704939,705010,705033,705243,705496,705522,705579,705925,705932,705934,705937-705938,705961,706242,706273,706285-706286,706562,706606,706649,706655,706660,706697,706918,707303-707304,707307,707310,707630,708206,708598,708609,708613,708619,708634,708840,708863,708909,708929,708943,709115,709142

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java Thu Oct 30 04:37:18 2008
@@ -37,8 +37,8 @@
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
@@ -364,7 +364,7 @@
             throws ConfigurationException {
         try {
             File file = new File(directory, WORKSPACE_XML);
-            InputSource xml = new InputSource(new FileReader(file));
+            InputSource xml = new InputSource(new FileInputStream(file));
             xml.setSystemId(file.toURI().toString());
 
             Properties variables = new Properties();

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/VirtualNodeTypeStateProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/VirtualNodeTypeStateProvider.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/VirtualNodeTypeStateProvider.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/VirtualNodeTypeStateProvider.java Thu Oct 30 04:37:18 2008
@@ -16,6 +16,14 @@
  */
 package org.apache.jackrabbit.core.nodetype.virtual;
 
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.version.OnParentVersionAction;
+
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.nodetype.NodeDef;
 import org.apache.jackrabbit.core.nodetype.NodeDefId;
@@ -23,22 +31,15 @@
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.nodetype.PropDef;
 import org.apache.jackrabbit.core.nodetype.ValueConstraint;
+import org.apache.jackrabbit.core.state.ChangeLog;
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.NoSuchItemStateException;
-import org.apache.jackrabbit.core.state.NodeReferences;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.core.virtual.AbstractVISProvider;
 import org.apache.jackrabbit.core.virtual.VirtualNodeState;
 import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.uuid.UUID;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
-
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.version.OnParentVersionAction;
-import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
+import org.apache.jackrabbit.uuid.UUID;
 
 /**
  * This Class implements a virtual item state provider that exposes the
@@ -285,7 +286,7 @@
     /**
      * @inheritDoc
      */
-    public boolean setNodeReferences(NodeReferences refs) {
+    public boolean setNodeReferences(ChangeLog references) {
         return false;
     }
 }

Propchange: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessControlPolicyIteratorAdapter.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Oct 30 04:37:18 2008
@@ -1,2 +1,2 @@
 /jackrabbit/branches/1.3/jackrabbit-core/src/main/java/org/apache/jackrabbit/commons/iterator/AccessControlPolicyIteratorAdapter.java:631261
-/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessControlPolicyIteratorAdapter.java:705938,705961,706242,706273,708634
+/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessControlPolicyIteratorAdapter.java:705938,705961,706242,706273,708634,708840,708863,708909,708929,708943,709115,709142

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java Thu Oct 30 04:37:18 2008
@@ -16,41 +16,42 @@
  */
 package org.apache.jackrabbit.core.state;
 
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.PropertyType;
+import javax.jcr.ReferentialIntegrityException;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+
 import org.apache.jackrabbit.core.ItemId;
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
 import org.apache.jackrabbit.core.RepositoryImpl;
 import org.apache.jackrabbit.core.cluster.UpdateEventChannel;
-import org.apache.jackrabbit.core.persistence.PersistenceManager;
-import org.apache.jackrabbit.core.persistence.bundle.CachingPersistenceManager;
 import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.core.nodetype.NodeDef;
 import org.apache.jackrabbit.core.nodetype.NodeDefId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.nodetype.PropDef;
-import org.apache.jackrabbit.core.nodetype.NodeDef;
 import org.apache.jackrabbit.core.observation.EventStateCollection;
 import org.apache.jackrabbit.core.observation.EventStateCollectionFactory;
+import org.apache.jackrabbit.core.persistence.PersistenceManager;
+import org.apache.jackrabbit.core.persistence.bundle.CachingPersistenceManager;
 import org.apache.jackrabbit.core.util.Dumpable;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.uuid.UUID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.PropertyType;
-import javax.jcr.ReferentialIntegrityException;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
-import java.io.PrintStream;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.HashMap;
-
 /**
  * Shared <code>ItemStateManager</code> (SISM). Caches objects returned from a
  * <code>PersistenceManager</code>. Objects returned by this item state
@@ -495,7 +496,7 @@
         /**
          * Virtual node references.
          */
-        private List[] virtualNodeReferences;
+        private ChangeLog[] virtualNodeReferences;
 
         /**
          * Events to dispatch.
@@ -533,7 +534,7 @@
         public void begin() throws ItemStateException, ReferentialIntegrityException {
             shared = new ChangeLog();
 
-            virtualNodeReferences = new List[virtualProviders.length];
+            virtualNodeReferences = new ChangeLog[virtualProviders.length];
 
             /* let listener know about change */
             if (eventChannel != null) {
@@ -552,17 +553,15 @@
 
             try {
                 if (usesReferences) {
-                    /**
-                     * Update node references based on modifications in change log
-                     * (added/modified/removed REFERENCE properties)
-                     */
-                    updateReferences(local, virtualProvider);
+                    // Update node references based on modifications in change
+                    // log (added/modified/removed REFERENCE properties)
+                    updateReferences();
                 }
 
                 // If enabled, check whether reference targets
                 // exist/were not removed
                 if (checkReferences) {
-                    checkReferentialIntegrity(local);
+                    checkReferentialIntegrity();
                 }
 
                 /**
@@ -660,12 +659,12 @@
                     NodeId id = refs.getId().getTargetId();
                     for (int i = 0; i < virtualProviders.length; i++) {
                         if (virtualProviders[i].hasItemState(id)) {
-                            List virtualRefs = virtualNodeReferences[i];
+                            ChangeLog virtualRefs = virtualNodeReferences[i];
                             if (virtualRefs == null) {
-                                virtualRefs = new LinkedList();
+                                virtualRefs = new ChangeLog();
                                 virtualNodeReferences[i] = virtualRefs;
                             }
-                            virtualRefs.add(refs);
+                            virtualRefs.modified(refs);
                             virtual = true;
                             break;
                         }
@@ -733,12 +732,9 @@
 
                 /* notify virtual providers about node references */
                 for (int i = 0; i < virtualNodeReferences.length; i++) {
-                    List virtualRefs = virtualNodeReferences[i];
+                    ChangeLog virtualRefs = virtualNodeReferences[i];
                     if (virtualRefs != null) {
-                        for (Iterator iter = virtualRefs.iterator(); iter.hasNext();) {
-                            NodeReferences refs = (NodeReferences) iter.next();
-                            virtualProviders[i].setNodeReferences(refs);
-                        }
+                        virtualProviders[i].setNodeReferences(virtualRefs);
                     }
                 }
 
@@ -837,6 +833,212 @@
         public List getEvents() {
             return events.getEvents();
         }
+
+        /**
+         * Updates the target node references collections based on the
+         * modifications in the change log (i.e. added/removed/modified
+         * <code>REFERENCE</code> properties).
+         * <p>
+         * <b>Important node:</b> For consistency reasons this method must
+         * only be called <i>once</i> per change log and the change log
+         * should not be modified anymore afterwards.
+         *
+         * @param changes change log
+         * @param virtualProvider virtual provider that may already contain a
+         *                        node references object
+         * @throws ItemStateException if an error occurs
+         */
+        private void updateReferences() throws ItemStateException {
+            // process added REFERENCE properties
+            for (Iterator i = local.addedStates(); i.hasNext(); ) {
+                addReferences((ItemState) i.next());
+            }
+
+            // process modified REFERENCE properties
+            for (Iterator i = local.modifiedStates(); i.hasNext(); ) {
+                ItemState state = (ItemState) i.next();
+                if (!state.isNode()) {
+                    // remove old references from the target
+                    removeReferences(getItemState(state.getId()));
+                    // add new references to the target
+                    addReferences(state);
+                }
+            }
+
+            // process removed REFERENCE properties
+            for (Iterator i = local.deletedStates(); i.hasNext(); ) {
+                removeReferences((ItemState) i.next());
+            }
+        }
+
+        private void addReferences(ItemState state)
+                throws NoSuchItemStateException, ItemStateException {
+            if (!state.isNode()) {
+                PropertyState property = (PropertyState) state;
+                if (property.getType() == PropertyType.REFERENCE) {
+                    InternalValue[] values = property.getValues();
+                    for (int i = 0; values != null && i < values.length; i++) {
+                        addReference(
+                                property.getPropertyId(), values[i].getUUID());
+                    }
+                }
+            }
+        }
+
+        private void addReference(PropertyId id, UUID uuid)
+                throws ItemStateException {
+            NodeReferencesId refsId = new NodeReferencesId(uuid);
+            if (virtualProvider == null
+                    || ! virtualProvider.hasNodeReferences(refsId)) {
+                // get or create the references instance
+                NodeReferences refs = local.get(refsId);
+                if (refs == null) {
+                    if (hasNodeReferences(refsId)) {
+                        refs = getNodeReferences(refsId);
+                    } else {
+                        refs = new NodeReferences(refsId);
+                    }
+                }
+                // add reference
+                refs.addReference(id);
+                // update change log
+                local.modified(refs);
+            }
+        }
+
+        private void removeReferences(ItemState state)
+                throws NoSuchItemStateException, ItemStateException {
+            if (!state.isNode()) {
+                PropertyState property = (PropertyState) state;
+                if (property.getType() == PropertyType.REFERENCE) {
+                    InternalValue[] values = property.getValues();
+                    for (int i = 0; values != null && i < values.length; i++) {
+                        removeReference(
+                                property.getPropertyId(), values[i].getUUID());
+                    }
+                }
+            }
+        }
+
+        private void removeReference(PropertyId id, UUID uuid)
+                throws ItemStateException {
+            NodeReferencesId refsId = new NodeReferencesId(uuid);
+            if (virtualProvider == null
+                    || !virtualProvider.hasNodeReferences(refsId)) {
+                // either get node references from change log or load from
+                // persistence manager
+                NodeReferences refs = local.get(refsId);
+                if (refs == null && hasNodeReferences(refsId)) {
+                    refs = getNodeReferences(refsId);
+                }
+                if (refs != null) {
+                    // remove reference
+                    refs.removeReference(id);
+                    // update change log
+                    local.modified(refs);
+                }
+            }
+        }
+
+        /**
+         * 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);
+            }
+        }
+
     }
 
     /**
@@ -1189,268 +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);
-        }
-    }
-
-    /**
-     * Updates the target node references collections based on the modifications
-     * in the change log (i.e. added/removed/modified <code>REFERENCE</code>
-     * properties).
-     * <p/>
-     * <b>Important node:</b> For consistency reasons this method must only be
-     * called <i>once</i> per change log and the change log should not be modified
-     * anymore afterwards.
-     *
-     * @param changes change log
-     * @param virtualProvider virtual provider that may already contain a
-     *                        node references object
-     * @throws ItemStateException if an error occurs
-     */
-    protected void updateReferences(ChangeLog changes,
-                                    VirtualItemStateProvider virtualProvider)
-            throws ItemStateException {
-
-        // process added REFERENCE properties
-        for (Iterator iter = changes.addedStates(); iter.hasNext();) {
-            ItemState state = (ItemState) iter.next();
-            if (!state.isNode()) {
-                PropertyState prop = (PropertyState) state;
-                if (prop.getType() == PropertyType.REFERENCE) {
-                    // this is a new REFERENCE property:
-                    // add the new 'reference'
-                    InternalValue[] vals = prop.getValues();
-                    for (int i = 0; vals != null && i < vals.length; i++) {
-                        NodeReferencesId refsId = new NodeReferencesId(
-                                vals[i].getUUID());
-                        if (virtualProvider != null
-                                && virtualProvider.hasNodeReferences(refsId)) {
-                            continue;
-                        }
-                        NodeReferences refs =
-                                getOrCreateNodeReferences(refsId, changes);
-                        // add reference
-                        refs.addReference(prop.getPropertyId());
-                        // update change log
-                        changes.modified(refs);
-                    }
-                }
-            }
-        }
-
-        // process modified REFERENCE properties
-        for (Iterator iter = changes.modifiedStates(); iter.hasNext();) {
-            ItemState state = (ItemState) iter.next();
-            if (!state.isNode()) {
-                PropertyState newProp = (PropertyState) state;
-                PropertyState oldProp =
-                        (PropertyState) getItemState(state.getId());
-                // check old type
-                if (oldProp.getType() == PropertyType.REFERENCE) {
-                    // this is a modified REFERENCE property:
-                    // remove the old 'reference' from the target
-                    InternalValue[] vals = oldProp.getValues();
-                    for (int i = 0; vals != null && i < vals.length; i++) {
-                        NodeReferencesId refsId = new NodeReferencesId(
-                                vals[i].getUUID());
-                        if (virtualProvider != null
-                                && virtualProvider.hasNodeReferences(refsId)) {
-                            continue;
-                        }
-                        // either get node references from change log or load from
-                        // persistence manager
-                        NodeReferences refs = changes.get(refsId);
-                        if (refs == null) {
-                            refs = getNodeReferences(refsId);
-                        }
-                        // remove reference
-                        refs.removeReference(oldProp.getPropertyId());
-                        // update change log
-                        changes.modified(refs);
-                    }
-                }
-                // check new type
-                if (newProp.getType() == PropertyType.REFERENCE) {
-                    // this is a modified REFERENCE property:
-                    // add the new 'reference' to the target
-                    InternalValue[] vals = newProp.getValues();
-                    for (int i = 0; vals != null && i < vals.length; i++) {
-                        NodeReferencesId refsId = new NodeReferencesId(
-                                vals[i].getUUID());
-                        if (virtualProvider != null
-                                && virtualProvider.hasNodeReferences(refsId)) {
-                            continue;
-                        }
-                        NodeReferences refs =
-                                getOrCreateNodeReferences(refsId, changes);
-                        // add reference
-                        refs.addReference(newProp.getPropertyId());
-                        // update change log
-                        changes.modified(refs);
-                    }
-                }
-            }
-        }
-
-        // process removed REFERENCE properties
-        for (Iterator iter = changes.deletedStates(); iter.hasNext();) {
-            ItemState state = (ItemState) iter.next();
-            if (!state.isNode()) {
-                PropertyState prop = (PropertyState) state;
-                if (prop.getType() == PropertyType.REFERENCE) {
-                    // this is a removed REFERENCE property:
-                    // remove the 'reference' from the target
-                    InternalValue[] vals = prop.getValues();
-                    for (int i = 0; vals != null && i < vals.length; i++) {
-                        NodeReferencesId refsId = new NodeReferencesId(
-                                vals[i].getUUID());
-                        if (virtualProvider != null
-                                && virtualProvider.hasNodeReferences(refsId)) {
-                            continue;
-                        }
-                        // either get node references from change log or
-                        // load from persistence manager
-                        NodeReferences refs = changes.get(refsId);
-                        if (refs == null) {
-                            refs = getNodeReferences(refsId);
-                        }
-                        // remove reference
-                        refs.removeReference(prop.getPropertyId());
-                        // update change log
-                        changes.modified(refs);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns a node references object using the following rules:<p/>
-     * <ul>
-     * <li>1. return a modified instance from the change log (if one exists)</li>
-     * <li>2. return an existing instance from <i>this</i> item state manager
-     * (if one exists)</li>
-     * <li>3. create and return a new instance</li>
-     * </ul>
-     *
-     * @param refsId  node references id
-     * @param changes change log
-     * @return a node references object
-     * @throws ItemStateException if an error occurs
-     */
-    private NodeReferences getOrCreateNodeReferences(NodeReferencesId refsId,
-                                                     ChangeLog changes)
-            throws ItemStateException {
-        // check change log
-        NodeReferences refs = changes.get(refsId);
-        if (refs == null) {
-            // not yet in change log:
-            // either load existing or create new
-            if (hasNodeReferences(refsId)) {
-                refs = getNodeReferences(refsId);
-            } else {
-                refs = new NodeReferences(refsId);
-            }
-        }
-        return refs;
-    }
-
-    /**
-     * 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.

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java Thu Oct 30 04:37:18 2008
@@ -30,6 +30,9 @@
 
 import javax.jcr.ReferentialIntegrityException;
 import javax.jcr.PropertyType;
+
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.IdentityHashMap;
@@ -449,6 +452,8 @@
      * @throws ItemStateException if an error occurs
      */
     private void updateVirtualReferences(ChangeLog changes) throws ItemStateException {
+        ChangeLog references = new ChangeLog();
+
         for (Iterator iter = changes.addedStates(); iter.hasNext();) {
             ItemState state = (ItemState) iter.next();
             if (!state.isNode()) {
@@ -458,7 +463,8 @@
                     for (int i = 0; vals != null && i < vals.length; i++) {
                         UUID uuid = vals[i].getUUID();
                         NodeReferencesId refsId = new NodeReferencesId(uuid);
-                        addVirtualReference(prop.getPropertyId(), refsId);
+                        addVirtualReference(
+                                references, prop.getPropertyId(), refsId);
                     }
                 }
             }
@@ -474,7 +480,8 @@
                     for (int i = 0; vals != null && i < vals.length; i++) {
                         UUID uuid = vals[i].getUUID();
                         NodeReferencesId refsId = new NodeReferencesId(uuid);
-                        removeVirtualReference(oldProp.getPropertyId(), refsId);
+                        removeVirtualReference(
+                                references, oldProp.getPropertyId(), refsId);
                     }
                 }
                 if (newProp.getType() == PropertyType.REFERENCE) {
@@ -482,7 +489,8 @@
                     for (int i = 0; vals != null && i < vals.length; i++) {
                         UUID uuid = vals[i].getUUID();
                         NodeReferencesId refsId = new NodeReferencesId(uuid);
-                        addVirtualReference(newProp.getPropertyId(), refsId);
+                        addVirtualReference(
+                                references, newProp.getPropertyId(), refsId);
                     }
                 }
             }
@@ -496,11 +504,14 @@
                     for (int i = 0; vals != null && i < vals.length; i++) {
                         UUID uuid = vals[i].getUUID();
                         NodeReferencesId refsId = new NodeReferencesId(uuid);
-                        removeVirtualReference(prop.getPropertyId(), refsId);
+                        removeVirtualReference(
+                                references, prop.getPropertyId(), refsId);
                     }
                 }
             }
         }
+
+        virtualProvider.setNodeReferences(references);
     }
 
     /**
@@ -510,17 +521,20 @@
      * @param sourceId property id
      * @param refsId node references id
      */
-    private void addVirtualReference(PropertyId sourceId,
-                                     NodeReferencesId refsId)
+    private void addVirtualReference(
+            ChangeLog references, PropertyId sourceId, NodeReferencesId refsId)
             throws NoSuchItemStateException, ItemStateException {
 
-        NodeReferences refs = virtualProvider.getNodeReferences(refsId);
+        NodeReferences refs = references.get(refsId);
+        if (refs == null) {
+            refs = virtualProvider.getNodeReferences(refsId);
+        }
         if (refs == null && virtualProvider.hasItemState(refsId.getTargetId())) {
             refs = new NodeReferences(refsId);
         }
         if (refs != null) {
             refs.addReference(sourceId);
-            virtualProvider.setNodeReferences(refs);
+            references.modified(refs);
         }
     }
 
@@ -531,17 +545,20 @@
      * @param sourceId property id
      * @param refsId node references id
      */
-    private void removeVirtualReference(PropertyId sourceId,
-                                        NodeReferencesId refsId)
+    private void removeVirtualReference(
+            ChangeLog references, PropertyId sourceId, NodeReferencesId refsId)
             throws NoSuchItemStateException, ItemStateException {
 
-        NodeReferences refs = virtualProvider.getNodeReferences(refsId);
+        NodeReferences refs = references.get(refsId);
+        if (refs == null) {
+            refs = virtualProvider.getNodeReferences(refsId);
+        }
         if (refs == null && virtualProvider.hasItemState(refsId.getTargetId())) {
             refs = new NodeReferences(refsId);
         }
         if (refs != null) {
             refs.removeReference(sourceId);
-            virtualProvider.setNodeReferences(refs);
+            references.modified(refs);
         }
     }
 }

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/NodeStateEx.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/NodeStateEx.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/NodeStateEx.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/NodeStateEx.java Thu Oct 30 04:37:18 2008
@@ -35,7 +35,6 @@
 import org.apache.jackrabbit.uuid.UUID;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateManager.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateManager.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateManager.java Thu Oct 30 04:37:18 2008
@@ -16,21 +16,22 @@
  */
 package org.apache.jackrabbit.core.version;
 
-import org.apache.jackrabbit.core.state.SharedItemStateManager;
-import org.apache.jackrabbit.core.state.ItemStateCacheFactory;
-import org.apache.jackrabbit.core.state.ItemStateException;
-import org.apache.jackrabbit.core.state.ChangeLog;
-import org.apache.jackrabbit.core.state.NodeReferences;
-import org.apache.jackrabbit.core.state.ISMLocking;
-import org.apache.jackrabbit.core.persistence.PersistenceManager;
+import java.util.Iterator;
+
+import javax.jcr.ReferentialIntegrityException;
+
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
-import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.persistence.PersistenceManager;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.ISMLocking;
+import org.apache.jackrabbit.core.state.ItemStateCacheFactory;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeReferences;
+import org.apache.jackrabbit.core.state.SharedItemStateManager;
 import org.slf4j.Logger;
-
-import javax.jcr.ReferentialIntegrityException;
-import java.util.Iterator;
+import org.slf4j.LoggerFactory;
 
 /**
  * Spezialized SharedItemStateManager that filters out NodeReferences to
@@ -63,21 +64,28 @@
      * @param references
      * @return
      */
-    public boolean setNodeReferences(NodeReferences references) {
+    public boolean setNodeReferences(ChangeLog references) {
         try {
-            // filter out version storage intern ones
-            NodeReferences refs = new NodeReferences(references.getId());
-            Iterator iter = references.getReferences().iterator();
-            while (iter.hasNext()) {
-                PropertyId id = (PropertyId) iter.next();
-                if (!hasItemState(id.getParentId())) {
-                    refs.addReference(id);
+            ChangeLog log = new ChangeLog();
+
+            Iterator iterator = references.modifiedRefs();
+            while (iterator.hasNext()) {
+                // filter out version storage intern ones
+                NodeReferences source = (NodeReferences) iterator.next();
+                NodeReferences target = new NodeReferences(source.getId());
+                Iterator iter = source.getReferences().iterator();
+                while (iter.hasNext()) {
+                    PropertyId id = (PropertyId) iter.next();
+                    if (!hasItemState(id.getParentId())) {
+                        target.addReference(id);
+                    }
                 }
+                log.modified(target);
             }
 
-            ChangeLog log = new ChangeLog();
-            log.modified(refs);
-            pMgr.store(log);
+            if (log.hasUpdates()) {
+                pMgr.store(log);
+            }
             return true;
         } catch (ItemStateException e) {
             log.error("Error while setting references: " + e.toString());

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java Thu Oct 30 04:37:18 2008
@@ -16,9 +16,12 @@
  */
 package org.apache.jackrabbit.core.version;
 
+import javax.jcr.RepositoryException;
+
 import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.jackrabbit.core.ItemId;
 import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.state.ChangeLog;
 import org.apache.jackrabbit.core.state.ItemState;
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.ItemStateListener;
@@ -30,8 +33,6 @@
 import org.apache.jackrabbit.core.virtual.VirtualPropertyState;
 import org.apache.jackrabbit.spi.Name;
 
-import javax.jcr.RepositoryException;
-
 /**
  * This Class implements a virtual item state provider.
  */
@@ -115,8 +116,8 @@
     /**
      * @inheritDoc
      */
-    public boolean setNodeReferences(NodeReferences refs) {
-        return stateMgr.setNodeReferences(refs);
+    public boolean setNodeReferences(ChangeLog references) {
+        return stateMgr.setNodeReferences(references);
     }
 
     /**

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java Thu Oct 30 04:37:18 2008
@@ -16,6 +16,16 @@
  */
 package org.apache.jackrabbit.core.version;
 
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionException;
+import javax.jcr.version.VersionHistory;
+
 import org.apache.jackrabbit.core.InternalXAResource;
 import org.apache.jackrabbit.core.ItemId;
 import org.apache.jackrabbit.core.NodeId;
@@ -42,14 +52,6 @@
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionException;
-import javax.jcr.version.VersionHistory;
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * Implementation of a {@link VersionManager} that works in an XA environment.
  * Works as a filter between a version manager client and the global version
@@ -242,13 +244,17 @@
     /**
      * {@inheritDoc}
      */
-    public boolean setNodeReferences(NodeReferences refs) {
+    public boolean setNodeReferences(ChangeLog references) {
         ChangeLog changeLog = ((XAItemStateManager) stateMgr).getChangeLog();
         if (changeLog != null) {
-            changeLog.modified(refs);
+            Iterator iterator = references.modifiedRefs();
+            while (iterator.hasNext()) {
+                changeLog.modified((NodeReferences) iterator.next());
+            }
             return true;
+        } else {
+            return false;
         }
-        return false;
     }
 
     /**

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java Thu Oct 30 04:37:18 2008
@@ -42,7 +42,6 @@
 import org.slf4j.LoggerFactory;
 
 import javax.jcr.RepositoryException;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Collection;
 

Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java?rev=709146&r1=709145&r2=709146&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java Thu Oct 30 04:37:18 2008
@@ -16,15 +16,16 @@
  */
 package org.apache.jackrabbit.core.virtual;
 
+import javax.jcr.RepositoryException;
+
 import org.apache.jackrabbit.core.ItemId;
 import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.ItemStateListener;
 import org.apache.jackrabbit.core.state.ItemStateManager;
 import org.apache.jackrabbit.core.state.NodeReferences;
-import org.apache.jackrabbit.core.state.ItemStateListener;
 import org.apache.jackrabbit.spi.Name;
 
-import javax.jcr.RepositoryException;
-
 /**
  * This Interface defines a virtual item state provider.
  */
@@ -75,13 +76,13 @@
         throws RepositoryException;
 
     /**
-     * Informs this provider that the node references to one of its states has
-     * changed.
+     * Informs this provider that the node references to some of its states
+     * have changed.
      *
-     * @param refs
+     * @param references collection of {@link NodeReferences} instances
      * @return <code>true</code> if the reference target is one of its items.
      */
-    boolean setNodeReferences(NodeReferences refs);
+    boolean setNodeReferences(ChangeLog references);
 
 
     /**

Propchange: jackrabbit/branches/1.5/jackrabbit-ocm-nodemanagement/src/test/resources/log4j.properties
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Oct 30 04:37:18 2008
@@ -1 +1,2 @@
 /jackrabbit/branches/1.3/jackrabbit-ocm-nodemanagement/src/test/log4j.properties:631261
+/jackrabbit/trunk/jackrabbit-ocm-nodemanagement/src/test/resources/log4j.properties:708840,708863,708909,708929,708943,709115,709142