You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2004/10/26 17:44:47 UTC

svn commit: rev 55615 - in incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core: . nodetype state util version virtual

Author: tripod
Date: Tue Oct 26 08:44:46 2004
New Revision: 55615

Added:
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/util/ChildrenCollectorFilter.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/DefaultItemStateProvider.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java   (contents, props changed)
Removed:
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/NodeWrapper.java
Modified:
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/InternalValue.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/ItemState.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/PropertyState.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFreeze.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersion.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentNode.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentProperty.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionIteratorImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/package.html
Log:
- adapted versioning again to spec 0.15
- added VirtualItemStateManager for reflecting virtual content


Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/InternalValue.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/InternalValue.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/InternalValue.java	Tue Oct 26 08:44:46 2004
@@ -215,6 +215,30 @@
     }
 
     /**
+     * @param values
+     * @return
+     */
+    public static InternalValue[] create(QName[] values) {
+        InternalValue[] ret = new InternalValue[values.length];
+        for (int i=0; i<values.length; i++) {
+            ret[i] = new InternalValue(values[i]);
+        }
+        return ret;
+    }
+
+    /**
+     * @param values
+     * @return
+     */
+    public static InternalValue[] create(String[] values) {
+        InternalValue[] ret = new InternalValue[values.length];
+        for (int i=0; i<values.length; i++) {
+            ret[i] = new InternalValue(values[i]);
+        }
+        return ret;
+    }
+
+    /**
      * @param value
      * @return
      */

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java	Tue Oct 26 08:44:46 2004
@@ -314,7 +314,7 @@
      *
      * @return the primary path to this <code>Item</code>
      */
-    protected Path getPrimaryPath() throws RepositoryException {
+    public Path getPrimaryPath() throws RepositoryException {
         return session.getHierarchyManager().getPath(id);
     }
 
@@ -782,7 +782,7 @@
             if (itemState.isNode() && itemState.getStatus() == ItemState.STATUS_NEW) {
                 NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId());
                 if (node.isNodeType(NodeTypeRegistry.MIX_VERSIONABLE)) {
-                    VersionHistory hist = rep.getVersionManager().createVersionHistory(node);
+                    VersionHistory hist = session.versionMgr.createVersionHistory(node);
                     node.internalSetProperty(VersionManager.PROPNAME_VERSION_HISTORY, InternalValue.create(new UUID(hist.getUUID())));
                     node.internalSetProperty(VersionManager.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(hist.getRootVersion().getUUID())));
                     node.internalSetProperty(VersionManager.PROPNAME_IS_CHECKED_OUT, InternalValue.create(true));

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java	Tue Oct 26 08:44:46 2004
@@ -18,16 +18,14 @@
 import org.apache.commons.collections.ReferenceMap;
 import org.apache.jackrabbit.core.state.*;
 import org.apache.jackrabbit.core.util.IteratorHelper;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.log4j.Logger;
 
 import javax.jcr.*;
 import javax.jcr.nodetype.NodeDef;
 import javax.jcr.nodetype.PropertyDef;
 import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
+import java.util.*;
 
 /**
  * There's one <code>ItemManager</code> instance per <code>Session</code>
@@ -156,6 +154,7 @@
     }
 
     /**
+     * Checks if the item with the given id exists
      * @param id
      * @return
      */
@@ -335,6 +334,8 @@
             }
         }
 
+        // not need to add virtual properties
+
         return new IteratorHelper(Collections.unmodifiableList(children));
     }
 
@@ -368,8 +369,17 @@
         // in order to maintain item cache consistency
         ItemLifeCycleListener[] listeners = new ItemLifeCycleListener[]{this};
 
-        // create node object
-        return new NodeImpl(this, session, id, state, def, listeners);
+
+        // check spezial nodes
+        if (state.getNodeTypeName().equals(NodeTypeRegistry.NT_VERSION)) {
+            return session.versionMgr.createVersionInstance(session, state, def, this, listeners);
+        } else if (state.getNodeTypeName().equals(NodeTypeRegistry.NT_VERSION_HISTORY)) {
+            return session.versionMgr.createVersionHistoryInstance(session, state, def, this, listeners);
+        } else {
+            // create node object
+            return new NodeImpl(this, session, id, state, def, listeners);
+        }
+
     }
 
     NodeImpl createNodeInstance(NodeState state) throws RepositoryException {

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java	Tue Oct 26 08:44:46 2004
@@ -19,6 +19,7 @@
 import org.apache.jackrabbit.core.state.*;
 import org.apache.jackrabbit.core.util.ChildrenCollector;
 import org.apache.jackrabbit.core.util.IteratorHelper;
+import org.apache.jackrabbit.core.util.ChildrenCollectorFilter;
 import org.apache.jackrabbit.core.util.uuid.UUID;
 import org.apache.jackrabbit.core.version.*;
 import org.apache.log4j.Logger;
@@ -27,7 +28,6 @@
 import javax.jcr.lock.Lock;
 import javax.jcr.lock.LockException;
 import javax.jcr.nodetype.*;
-import javax.jcr.util.TraversingItemVisitor;
 import javax.jcr.version.Version;
 import javax.jcr.version.VersionException;
 import javax.jcr.version.VersionHistory;
@@ -482,16 +482,16 @@
 
         // check for name collisions
         try {
-            ItemImpl item = itemMgr.getItem(nodePath);
+            Item item = itemMgr.getItem(nodePath);
             if (!item.isNode()) {
                 // there's already a property with that name
-                throw new ItemExistsException(item.safeGetJCRPath());
+                throw new ItemExistsException(itemMgr.safeGetJCRPath(nodePath));
             } else {
                 // there's already a node with that name
                 // check same-name sibling setting of both new and existing node
                 if (!def.allowSameNameSibs()
                         || !((NodeImpl) item).getDefinition().allowSameNameSibs()) {
-                    throw new ItemExistsException(item.safeGetJCRPath());
+                    throw new ItemExistsException(itemMgr.safeGetJCRPath(nodePath));
                 }
             }
         } catch (PathNotFoundException pnfe) {
@@ -1655,7 +1655,7 @@
             if (!entExisting.includesNodeType(NodeTypeRegistry.MIX_VERSIONABLE) &&
                     entNew.includesNodeType(NodeTypeRegistry.MIX_VERSIONABLE)) {
                 // node has become 'versionable', initialize version history
-                VersionHistory hist = rep.getVersionManager().createVersionHistory(this);
+                VersionHistory hist = session.versionMgr.createVersionHistory(this);
                 internalSetProperty(VersionManager.PROPNAME_VERSION_HISTORY, InternalValue.create(new UUID(hist.getUUID())));
                 internalSetProperty(VersionManager.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(hist.getRootVersion().getUUID())));
                 internalSetProperty(VersionManager.PROPNAME_IS_CHECKED_OUT, InternalValue.create(true));
@@ -2010,7 +2010,7 @@
             log.debug(msg);
             throw new IllegalStateException(msg);
         }
-        Version v = rep.getVersionManager().checkin(this);
+        Version v = session.versionMgr.checkin(this);
         Property prop = internalSetProperty(VersionManager.PROPNAME_IS_CHECKED_OUT, InternalValue.create(false));
         prop.save();
         prop = internalSetProperty(VersionManager.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(v.getUUID())));
@@ -2563,7 +2563,7 @@
         restoreFrozenState(version.getFrozenNode(), vsel);
 
         // 2. N�s jcr:baseVersion property will be changed to point to V.
-        internalSetProperty(VersionManager.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(version.getUUID())));
+        internalSetProperty(VersionManager.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(version.getId())));
 
         // 3. N�s jcr:isCheckedOut property is set to false.
         internalSetProperty(VersionManager.PROPNAME_IS_CHECKED_OUT, InternalValue.create(false));
@@ -2632,11 +2632,10 @@
                     internalSetProperty(props[i].getName(), prop.getValues()[0]);
                     continue;
                 } catch (RepositoryException e) {
-// ignore and try multiple below
+                    // ignore and try multiple below
                 }
             }
             internalSetProperty(props[i].getName(), prop.getValues());
-
         }
 
         // restore the frozen nodes
@@ -2658,7 +2657,7 @@
                     // do nothing
                 } else {
                     // get desired version from version selector
-                    VersionHistory history = ((InternalFrozenVersionHistory) child).getVersionHistory(session);
+                    VersionHistory history = (VersionHistory) session.getNodeByUUID(((InternalFrozenVersionHistory) child).getVersionHistoryId());
                     InternalVersion v = ((VersionImpl) vsel.select(history)).getInternalVersion();
                     NodeImpl node = addNode(child.getName(), v.getFrozenNode());
                     node.internalRestore(v, vsel);
@@ -2673,7 +2672,7 @@
     public VersionHistory getVersionHistory()
             throws UnsupportedRepositoryOperationException, RepositoryException {
         checkVersionable();
-        return rep.getVersionManager().getVersionHistory(this);
+        return session.versionMgr.getVersionHistory(this);
     }
 
     /**
@@ -2682,7 +2681,7 @@
     public Version getBaseVersion()
             throws UnsupportedRepositoryOperationException, RepositoryException {
         checkVersionable();
-        return rep.getVersionManager().getBaseVersion(this);
+        return session.versionMgr.getBaseVersion(this);
     }
 
     /**
@@ -2772,151 +2771,5 @@
     public boolean isLocked() throws RepositoryException {
         // @todo implement locking support
         return false;
-    }
-}
-
-/**
- * <code>ChildrenCollectorFilter</code> is a utility class
- * which can be used to 'collect' child items of a
- * node whose names match a certain pattern. It implements the
- * <code>ItemVisitor</code> interface.
- */
-class ChildrenCollectorFilter extends TraversingItemVisitor.Default {
-    static final char WILDCARD_CHAR = '*';
-    static final String OR = "|";
-
-    private final Collection children;
-    private final boolean collectNodes;
-    private final boolean collectProperties;
-    private final String namePattern;
-
-    /**
-     * Constructs a <code>ChildrenCollectorFilter</code>
-     *
-     * @param namePattern       the pattern which should be applied to the names
-     *                          of the children
-     * @param children          where the matching children should be added
-     * @param collectNodes      true, if child nodes should be collected; otherwise false
-     * @param collectProperties true, if child properties should be collected; otherwise false
-     * @param maxLevel          umber of hierarchy levels to traverse
-     *                          (e.g. 1 for direct children only, 2 for children and their children, and so on)
-     */
-    ChildrenCollectorFilter(String namePattern, Collection children, boolean collectNodes, boolean collectProperties, int maxLevel) {
-        super(false, maxLevel);
-        this.namePattern = namePattern;
-        this.children = children;
-        this.collectNodes = collectNodes;
-        this.collectProperties = collectProperties;
-    }
-
-    /**
-     * @see TraversingItemVisitor#entering(Node, int)
-     */
-    protected void entering(Node node, int level)
-            throws RepositoryException {
-        if (level > 0 && collectNodes) {
-            if (matches(node.getName(), namePattern)) {
-                children.add(node);
-            }
-        }
-    }
-
-    /**
-     * @see TraversingItemVisitor#entering(Property, int)
-     */
-    protected void entering(Property property, int level)
-            throws RepositoryException {
-        if (level > 0 && collectProperties) {
-            if (matches(property.getName(), namePattern)) {
-                children.add(property);
-            }
-        }
-    }
-
-    /**
-     * Applies the name pattern against the specified name.
-     * <p/>
-     * The pattern may be a full name or a partial name with one or more
-     * wildcard characters ("*"), or a disjunction (using the "|" character
-     * to represent logical <i>OR</i>) of these. For example,
-     * <p/>
-     * <code>"jcr:*|foo:bar"</code>
-     * <p/>
-     * would match
-     * <p/>
-     * <code>"foo:bar"</code>, but also <code>"jcr:whatever"</code>.
-     *
-     * @param name the name to test the pattern with
-     * @return true if the specified name matches the pattern
-     */
-    static boolean matches(String name, String pattern) {
-        // split pattern
-        StringTokenizer st = new StringTokenizer(pattern, OR, false);
-        while (st.hasMoreTokens()) {
-            if (internalMatches(name, st.nextToken(), 0, 0)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Internal helper used to recursively match the pattern
-     *
-     * @param s       The string to be tested
-     * @param pattern The pattern
-     * @param sOff    offset within <code>s</code>
-     * @param pOff    offset within <code>pattern</code>.
-     * @return true if <code>s</code> matched pattern, else false.
-     */
-    private static boolean internalMatches(String s, String pattern, int sOff, int pOff) {
-        int pLen = pattern.length();
-        int sLen = s.length();
-
-        for (; ;) {
-            if (pOff >= pLen) {
-                if (sOff >= sLen) {
-                    return true;
-                } else if (s.charAt(sOff) == '[') {
-                    // check for subscript notation (e.g. "whatever[1]")
-
-                    // the entire pattern matched up to the subscript:
-                    // -> ignore the subscript
-                    return true;
-                } else {
-                    return false;
-                }
-            }
-            if (sOff >= sLen && pattern.charAt(pOff) != WILDCARD_CHAR) {
-                return false;
-            }
-
-            // check for a '*' as the next pattern char;
-            // this is handled by a recursive call for
-            // each postfix of the name.
-            if (pattern.charAt(pOff) == WILDCARD_CHAR) {
-                if (++pOff >= pLen) {
-                    return true;
-                }
-
-                for (; ;) {
-                    if (internalMatches(s, pattern, sOff, pOff)) {
-                        return true;
-                    }
-                    if (sOff >= sLen) {
-                        return false;
-                    }
-                    sOff++;
-                }
-            }
-
-            if (pOff < pLen && sOff < sLen) {
-                if (pattern.charAt(pOff) != s.charAt(sOff)) {
-                    return false;
-                }
-            }
-            pOff++;
-            sOff++;
-        }
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java	Tue Oct 26 08:44:46 2004
@@ -27,7 +27,7 @@
 import org.apache.jackrabbit.core.state.tx.TransactionManager;
 import org.apache.jackrabbit.core.state.tx.XASessionImpl;
 import org.apache.jackrabbit.core.util.uuid.UUID;
-import org.apache.jackrabbit.core.version.VersionManager;
+import org.apache.jackrabbit.core.version.PersistentVersionManager;
 import org.apache.log4j.Logger;
 
 import javax.jcr.*;
@@ -79,7 +79,7 @@
 
     private final NamespaceRegistryImpl nsReg;
     private final NodeTypeRegistry ntReg;
-    private final VersionManager vMgr;
+    private final PersistentVersionManager vMgr;
     private final TransactionManager txMgr;
 
     // configuration of the repository
@@ -295,7 +295,7 @@
             log.error(msg, npde);
             throw new RepositoryException(msg, npde);
         }
-        vMgr = new VersionManager(verSession);
+        vMgr = new PersistentVersionManager(verSession);
 
         // load repository properties
         repProps = new Properties();
@@ -375,7 +375,7 @@
         return ntReg;
     }
 
-    VersionManager getVersionManager() {
+    PersistentVersionManager getPersistentVersionManager() {
         // check state
         if (disposed) {
             throw new IllegalStateException("repository instance has been shut down");

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java	Tue Oct 26 08:44:46 2004
@@ -22,6 +22,7 @@
 import org.apache.jackrabbit.core.state.PersistentItemStateProvider;
 import org.apache.jackrabbit.core.state.SessionItemStateManager;
 import org.apache.jackrabbit.core.xml.ImportHandler;
+import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.log4j.Logger;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.InputSource;
@@ -105,6 +106,11 @@
     protected final TransientNamespaceMappings nsMappings;
 
     /**
+     * The version manager for this session
+     */
+    protected final VersionManager versionMgr;
+
+    /**
      * Protected constructor.
      *
      * @param rep
@@ -145,6 +151,16 @@
         hierMgr = itemStateMgr.getHierarchyMgr();
         itemMgr = createItemManager(itemStateMgr, hierMgr);
         accessMgr = createAccessManager(credentials, hierMgr);
+        versionMgr = rep.getPersistentVersionManager()==null?null:rep.getPersistentVersionManager().getVersionManager();
+
+        // add virtual item managers only for normal sessions
+        if (!(this instanceof SystemSession)) {
+            try {
+                itemStateMgr.addVirtualItemStateProvider(versionMgr.getVirtualItemStateProvider(itemStateMgr));
+            } catch (Exception e) {
+                log.error("Unable to add vmgr: " + e.toString(), e);
+            }
+        }
     }
 
     /**
@@ -169,6 +185,16 @@
         itemStateMgr = new SessionItemStateManager(rep.getRootNodeUUID(), wsp.getPersistentStateManager(), getNamespaceResolver());
         hierMgr = itemStateMgr.getHierarchyMgr();
         itemMgr = createItemManager(itemStateMgr, hierMgr);
+        versionMgr = rep.getPersistentVersionManager()==null?null:rep.getPersistentVersionManager().getVersionManager();
+
+        // add virtual item managers only for normal sessions
+        if (!(this instanceof SystemSession)) {
+            try {
+                itemStateMgr.addVirtualItemStateProvider(versionMgr.getVirtualItemStateProvider(itemStateMgr));
+            } catch (Exception e) {
+                log.error("Unable to add vmgr: " + e.toString(), e);
+            }
+        }
     }
 
     /**

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml	Tue Oct 26 08:44:46 2004
@@ -139,7 +139,7 @@
         <supertypes>
             <supertype>nt:base</supertype>
         </supertypes>
-        <propertyDef name="jcr:name" type="Name" autoCreate="false" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
+        <propertyDef name="jcr:name" type="Name" autoCreate="false" mandatory="false" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
         <propertyDef name="jcr:type" type="String" autoCreate="false" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
         <propertyDef name="jcr:valueConstraints" type="String" autoCreate="false" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="false" multiple="true"/>
         <propertyDef name="jcr:defaultValues" type="undefined" autoCreate="false" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="false" multiple="true"/>
@@ -154,7 +154,7 @@
         <supertypes>
             <supertype>nt:base</supertype>
         </supertypes>
-        <propertyDef name="jcr:name" type="Name" autoCreate="false" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
+        <propertyDef name="jcr:name" type="Name" autoCreate="false" mandatory="false" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
         <propertyDef name="jcr:requiredPrimaryTypes" type="String" autoCreate="true" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="false" multiple="true">
             <defaultValues>
                 <defaultValue>nt:base</defaultValue>
@@ -199,28 +199,16 @@
             </valueConstraints>
         </propertyDef>
     </nodeType>
-    <nodeType name="nt:frozen" mixin="false" orderableChildNodes="false">
-        <supertypes>
-            <supertype>nt:base</supertype>
-        </supertypes>
-        <propertyDef name="jcr:frozenPrimaryType" type="Name" autoCreate="false" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="false"/>
-        <propertyDef name="jcr:frozenMixinTypes" type="Name" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
-        <propertyDef name="jcr:frozenUUID" type="String" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="false"/>
-        <propertyDef name="*" type="undefined" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
-        <propertyDef name="*" type="undefined" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="false"/>
-        <childNodeDef name="*" defaultPrimaryType="nt:frozen" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" sameNameSibs="true">
-            <requiredPrimaryTypes>
-                <requiredPrimaryType>nt:base</requiredPrimaryType>
-            </requiredPrimaryTypes>
-        </childNodeDef>
-    </nodeType>
     <nodeType name="nt:version" mixin="false" orderableChildNodes="false">
         <supertypes>
-            <supertype>nt:frozen</supertype>
+            <supertype>nt:base</supertype>
             <supertype>mix:referenceable</supertype>
         </supertypes>
         <propertyDef name="jcr:versionLabels" type="String" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
         <propertyDef name="jcr:created" type="Date" autoCreate="true" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="false"/>
+        <propertyDef name="jcr:frozenPrimaryType" type="Name" autoCreate="false" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="false"/>
+        <propertyDef name="jcr:frozenMixinTypes" type="Name" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
+        <propertyDef name="jcr:frozenUUID" type="String" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="false"/>
         <propertyDef name="jcr:predecessors" type="Reference" autoCreate="true" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true">
             <valueConstraints>
                 <valueConstraint>nt:version</valueConstraint>
@@ -231,6 +219,11 @@
                 <valueConstraint>nt:version</valueConstraint>
             </valueConstraints>
         </propertyDef>
+        <childNodeDef name="jcr:frozen" defaultPrimaryType="nt:base" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" sameNameSibs="false">
+            <requiredPrimaryTypes>
+                <requiredPrimaryType>nt:base</requiredPrimaryType>
+            </requiredPrimaryTypes>
+        </childNodeDef>
     </nodeType>
     <nodeType name="nt:query" mixin="false" orderableChildNodes="false">
         <supertypes>

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/ItemState.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/ItemState.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/ItemState.java	Tue Oct 26 08:44:46 2004
@@ -65,6 +65,10 @@
      * 'existing', i.e. persistent state that has been destroyed by somebody else
      */
     public static final int STATUS_STALE_DESTROYED = 6;
+    /**
+     * 'virtual' status, i.e. persistent state is virtual
+     */
+    public static final int STATUS_EXISTING_VIRTUAL = 7;
 
     protected int status = STATUS_UNDEFINED;
 
@@ -100,6 +104,10 @@
             case STATUS_NEW:
                 status = initialStatus;
                 break;
+            case STATUS_EXISTING_VIRTUAL:
+                // todo: should be keep this state?
+                status = STATUS_EXISTING;
+                break;
             default:
                 String msg = "illegal status: " + initialStatus;
                 log.error(msg);
@@ -125,6 +133,10 @@
             case STATUS_EXISTING_MODIFIED:
             case STATUS_EXISTING_REMOVED:
                 status = initialStatus;
+                break;
+            case STATUS_EXISTING_VIRTUAL:
+                // todo: should be keep this state?
+                status = STATUS_EXISTING;
                 break;
             default:
                 String msg = "illegal status: " + initialStatus;

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java	Tue Oct 26 08:44:46 2004
@@ -59,7 +59,7 @@
      * @param overlayedState the backing node state being overlayed
      * @param initialStatus  the initial status of the node state object
      */
-    NodeState(NodeState overlayedState, int initialStatus) {
+    protected NodeState(NodeState overlayedState, int initialStatus) {
         super(overlayedState, initialStatus);
 
         copy(overlayedState);
@@ -73,7 +73,7 @@
      * @param parentUUID    the UUID of the parent node
      * @param initialStatus the initial status of the node state object
      */
-    NodeState(String uuid, QName nodeTypeName, String parentUUID, int initialStatus) {
+    protected NodeState(String uuid, QName nodeTypeName, String parentUUID, int initialStatus) {
         super(parentUUID, new NodeId(uuid), initialStatus);
         if (parentUUID != null) {
             parentUUIDs.add(parentUUID);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/PropertyState.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/PropertyState.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/PropertyState.java	Tue Oct 26 08:44:46 2004
@@ -58,7 +58,7 @@
      * @param parentUUID    the uuid of the parent node
      * @param initialStatus the initial status of the property state object
      */
-    PropertyState(QName name, String parentUUID, int initialStatus) {
+    protected PropertyState(QName name, String parentUUID, int initialStatus) {
         super(parentUUID, new PropertyId(parentUUID, name), initialStatus);
         this.name = name;
         type = PropertyType.UNDEFINED;

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java	Tue Oct 26 08:44:46 2004
@@ -16,6 +16,7 @@
 package org.apache.jackrabbit.core.state;
 
 import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
 import org.apache.log4j.Logger;
 
 import javax.jcr.RepositoryException;
@@ -30,6 +31,7 @@
     private static Logger log = Logger.getLogger(SessionItemStateManager.class);
 
     private final PersistentItemStateProvider persistentStateMgr;
+    private VirtualItemStateProvider[] virtualProviders = new VirtualItemStateProvider[0];
     private final TransientItemStateManager transientStateMgr;
     private final HierarchyManager hierMgr;
 
@@ -48,6 +50,17 @@
         hierMgr = new HierarchyManagerImpl(rootNodeUUID, this, nsResolver);
     }
 
+    /**
+     * Adds a new virtual item state provider
+     * @param prov
+     */
+    public synchronized void addVirtualItemStateProvider(VirtualItemStateProvider prov) {
+        VirtualItemStateProvider[] provs = new VirtualItemStateProvider[virtualProviders.length+1];
+        System.arraycopy(virtualProviders, 0, provs, 0, virtualProviders.length);
+        provs[virtualProviders.length] = prov;
+        virtualProviders = provs;
+    }
+
     private synchronized void collectDescendantItemStates(ItemId id, List descendents) {
         // XXX very inefficient implementation, especially if # of transient states
         // is relatively small compared to the total # of persistent states
@@ -172,6 +185,13 @@
      */
     public ItemState getItemState(ItemId id)
             throws NoSuchItemStateException, ItemStateException {
+        // check if there is a virtual state for the specified item
+        for (int i=0; i<virtualProviders.length; i++) {
+            if (virtualProviders[i].hasItemState(id)) {
+                return virtualProviders[i].getItemState(id);
+            }
+        }
+
         // first check if the specified item has been transiently removed
         if (transientStateMgr.hasItemStateInAttic(id)) {
             /**
@@ -183,25 +203,42 @@
              */
             return transientStateMgr.getItemState(id);
         }
-        try {
-            // check if there's transient state for the specified item
+
+        // check if there's transient state for the specified item
+        if (transientStateMgr.hasItemState(id)) {
             return transientStateMgr.getItemState(id);
-        } catch (NoSuchItemStateException nsise) {
-            // check if there's persistent state for the specified item
+        }
+
+        // check if there's persistent state for the specified item
+        if (persistentStateMgr.hasItemState(id)) {
             return persistentStateMgr.getItemState(id);
         }
+
+        throw new NoSuchItemStateException(id.toString());
     }
 
     /**
      * @see ItemStateProvider#hasItemState(ItemId)
      */
     public boolean hasItemState(ItemId id) {
-        try {
-            getItemState(id);
-            return true;
-        } catch (ItemStateException ise) {
-            return false;
+        return transientStateMgr.hasItemStateInAttic(id)
+                || transientStateMgr.hasItemState(id)
+                || persistentStateMgr.hasItemState(id)
+                || hasVirtualItemState(id);
+    }
+
+    /**
+     * Checks if there is a virtual item state
+     * @param id
+     * @return
+     */
+    private boolean hasVirtualItemState(ItemId id) {
+        for (int i=0; i<virtualProviders.length; i++) {
+            if (virtualProviders[i].hasItemState(id)) {
+                return true;
+            }
         }
+        return false;
     }
 
     /**
@@ -216,12 +253,7 @@
      * @see ItemStateProvider#hasItemStateInAttic(ItemId)
      */
     public boolean hasItemStateInAttic(ItemId id) {
-        try {
-            getItemStateInAttic(id);
-            return true;
-        } catch (ItemStateException ise) {
-            return false;
-        }
+        return transientStateMgr.hasItemStateInAttic(id);
     }
 
     //< more methods for listing and retrieving transient ItemState instances >

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/util/ChildrenCollectorFilter.java
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/util/ChildrenCollectorFilter.java	Tue Oct 26 08:44:46 2004
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.util;
+
+import javax.jcr.util.TraversingItemVisitor;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Property;
+import java.util.Collection;
+import java.util.StringTokenizer;
+
+/**
+ * <code>ChildrenCollectorFilter</code> is a utility class
+ * which can be used to 'collect' child items of a
+ * node whose names match a certain pattern. It implements the
+ * <code>ItemVisitor</code> interface.
+ */
+public class ChildrenCollectorFilter extends TraversingItemVisitor.Default {
+    static final char WILDCARD_CHAR = '*';
+    static final String OR = "|";
+
+    private final Collection children;
+    private final boolean collectNodes;
+    private final boolean collectProperties;
+    private final String namePattern;
+
+    /**
+     * Constructs a <code>ChildrenCollectorFilter</code>
+     *
+     * @param namePattern       the pattern which should be applied to the names
+     *                          of the children
+     * @param children          where the matching children should be added
+     * @param collectNodes      true, if child nodes should be collected; otherwise false
+     * @param collectProperties true, if child properties should be collected; otherwise false
+     * @param maxLevel          umber of hierarchy levels to traverse
+     *                          (e.g. 1 for direct children only, 2 for children and their children, and so on)
+     */
+    public ChildrenCollectorFilter(String namePattern, Collection children, boolean collectNodes, boolean collectProperties, int maxLevel) {
+        super(false, maxLevel);
+        this.namePattern = namePattern;
+        this.children = children;
+        this.collectNodes = collectNodes;
+        this.collectProperties = collectProperties;
+    }
+
+    /**
+     * @see TraversingItemVisitor#entering(javax.jcr.Node, int)
+     */
+    protected void entering(Node node, int level)
+            throws RepositoryException {
+        if (level > 0 && collectNodes) {
+            if (matches(node.getName(), namePattern)) {
+                children.add(node);
+            }
+        }
+    }
+
+    /**
+     * @see TraversingItemVisitor#entering(javax.jcr.Property, int)
+     */
+    protected void entering(Property property, int level)
+            throws RepositoryException {
+        if (level > 0 && collectProperties) {
+            if (matches(property.getName(), namePattern)) {
+                children.add(property);
+            }
+        }
+    }
+
+    /**
+     * Applies the name pattern against the specified name.
+     * <p/>
+     * The pattern may be a full name or a partial name with one or more
+     * wildcard characters ("*"), or a disjunction (using the "|" character
+     * to represent logical <i>OR</i>) of these. For example,
+     * <p/>
+     * <code>"jcr:*|foo:bar"</code>
+     * <p/>
+     * would match
+     * <p/>
+     * <code>"foo:bar"</code>, but also <code>"jcr:whatever"</code>.
+     *
+     * @param name the name to test the pattern with
+     * @return true if the specified name matches the pattern
+     */
+    static boolean matches(String name, String pattern) {
+        // split pattern
+        StringTokenizer st = new StringTokenizer(pattern, OR, false);
+        while (st.hasMoreTokens()) {
+            if (internalMatches(name, st.nextToken(), 0, 0)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Internal helper used to recursively match the pattern
+     *
+     * @param s       The string to be tested
+     * @param pattern The pattern
+     * @param sOff    offset within <code>s</code>
+     * @param pOff    offset within <code>pattern</code>.
+     * @return true if <code>s</code> matched pattern, else false.
+     */
+    private static boolean internalMatches(String s, String pattern, int sOff, int pOff) {
+        int pLen = pattern.length();
+        int sLen = s.length();
+
+        for (; ;) {
+            if (pOff >= pLen) {
+                if (sOff >= sLen) {
+                    return true;
+                } else if (s.charAt(sOff) == '[') {
+                    // check for subscript notation (e.g. "whatever[1]")
+
+                    // the entire pattern matched up to the subscript:
+                    // -> ignore the subscript
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+            if (sOff >= sLen && pattern.charAt(pOff) != WILDCARD_CHAR) {
+                return false;
+            }
+
+            // check for a '*' as the next pattern char;
+            // this is handled by a recursive call for
+            // each postfix of the name.
+            if (pattern.charAt(pOff) == WILDCARD_CHAR) {
+                if (++pOff >= pLen) {
+                    return true;
+                }
+
+                for (; ;) {
+                    if (internalMatches(s, pattern, sOff, pOff)) {
+                        return true;
+                    }
+                    if (sOff >= sLen) {
+                        return false;
+                    }
+                    sOff++;
+                }
+            }
+
+            if (pOff < pLen && sOff < sLen) {
+                if (pattern.charAt(pOff) != s.charAt(sOff)) {
+                    return false;
+                }
+            }
+            pOff++;
+            sOff++;
+        }
+    }
+}

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFreeze.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFreeze.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFreeze.java	Tue Oct 26 08:44:46 2004
@@ -23,10 +23,33 @@
  */
 public abstract class InternalFreeze {
 
+    /** the parent 'freeze' */
+    private final InternalFreeze parent;
+
+    /**
+     * Creates a new 'Freeze'
+     * @param parent
+     */
+    protected InternalFreeze(InternalFreeze parent) {
+        this.parent = parent;
+    }
+
     /**
      * Returns the name of the frozen node
      *
      * @return
      */
     public abstract QName getName();
+
+    /**
+     * returns the version manager
+     * @return
+     */
+    public PersistentVersionManager getVersionManager() {
+        return parent==null ? null : parent.getVersionManager();
+    }
+
+    public InternalFreeze getParent() {
+        return parent;
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java	Tue Oct 26 08:44:46 2004
@@ -18,7 +18,6 @@
 import org.apache.jackrabbit.core.*;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
-import org.apache.jackrabbit.core.util.uuid.UUID;
 
 import javax.jcr.NodeIterator;
 import javax.jcr.PropertyIterator;
@@ -73,7 +72,8 @@
      * @param node
      * @throws RepositoryException
      */
-    protected InternalFrozenNode(PersistentNode node) throws RepositoryException {
+    protected InternalFrozenNode(InternalFreeze parent, PersistentNode node) throws RepositoryException {
+        super(parent);
         this.node = node;
 
         // init the frozen properties
@@ -120,9 +120,9 @@
         frozenChildNodes = new InternalFreeze[childNodes.length];
         for (int i = 0; i < childNodes.length; i++) {
             if (childNodes[i].hasProperty(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE)) {
-                frozenChildNodes[i] = new InternalFrozenNode(childNodes[i]);
+                frozenChildNodes[i] = new InternalFrozenNode(this, childNodes[i]);
             } else if (childNodes[i].hasProperty(VersionManager.PROPNAME_VERSION_HISTORY)) {
-                frozenChildNodes[i] = new InternalFrozenVersionHistory(childNodes[i]);
+                frozenChildNodes[i] = new InternalFrozenVersionHistory(this, childNodes[i]);
             } else {
                 // unkown ?
             }
@@ -206,7 +206,7 @@
      * @return
      * @throws RepositoryException
      */
-    protected static InternalFrozenNode checkin(PersistentNode parent, QName name, NodeImpl src)
+    protected static PersistentNode checkin(PersistentNode parent, QName name, NodeImpl src, boolean initOnly)
             throws RepositoryException {
 
         // create new node
@@ -229,61 +229,63 @@
             node.setPropertyValues(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES, PropertyType.NAME, ivalues);
         }
 
-        // add the properties
-        PropertyIterator piter = src.getProperties();
-        while (piter.hasNext()) {
-            PropertyImpl prop = (PropertyImpl) piter.nextProperty();
-// ignore some properties that not have a OPV=Ignore yet
-            if (prop.getQName().equals(VersionManager.PROPNAME_VERSION_HISTORY)) {
-                continue;
-            }
-            if (prop.getQName().equals(VersionManager.PROPNAME_PREDECESSORS)) {
-                continue;
-            }
-            switch (prop.getDefinition().getOnParentVersion()) {
-                case OnParentVersionAction.ABORT:
-                    parent.reload();
-                    throw new RepositoryException("Checkin aborted due to OPV in " + prop.safeGetJCRPath());
-                case OnParentVersionAction.COMPUTE:
-                case OnParentVersionAction.IGNORE:
-                case OnParentVersionAction.INITIALIZE:
-                    break;
-                case OnParentVersionAction.VERSION:
-                case OnParentVersionAction.COPY:
-                    node.copyFrom(prop);
-                    break;
+        if (!initOnly) {
+            // add the properties
+            PropertyIterator piter = src.getProperties();
+            while (piter.hasNext()) {
+                PropertyImpl prop = (PropertyImpl) piter.nextProperty();
+    // ignore some properties that not have a OPV=Ignore yet
+                if (prop.getQName().equals(VersionManager.PROPNAME_VERSION_HISTORY)) {
+                    continue;
+                }
+                if (prop.getQName().equals(VersionManager.PROPNAME_PREDECESSORS)) {
+                    continue;
+                }
+                switch (prop.getDefinition().getOnParentVersion()) {
+                    case OnParentVersionAction.ABORT:
+                        parent.reload();
+                        throw new RepositoryException("Checkin aborted due to OPV in " + prop.safeGetJCRPath());
+                    case OnParentVersionAction.COMPUTE:
+                    case OnParentVersionAction.IGNORE:
+                    case OnParentVersionAction.INITIALIZE:
+                        break;
+                    case OnParentVersionAction.VERSION:
+                    case OnParentVersionAction.COPY:
+                        node.copyFrom(prop);
+                        break;
+                }
             }
-        }
 
-        // add the frozen children and vistories
-        NodeIterator niter = src.getNodes();
-        while (niter.hasNext()) {
-            NodeImpl child = (NodeImpl) niter.nextNode();
-            switch (child.getDefinition().getOnParentVersion()) {
-                case OnParentVersionAction.ABORT:
-                    throw new RepositoryException("Checkin aborted due to OPV in " + child.safeGetJCRPath());
-                case OnParentVersionAction.COMPUTE:
-                case OnParentVersionAction.IGNORE:
-                case OnParentVersionAction.INITIALIZE:
-                    break;
-                case OnParentVersionAction.VERSION:
-                    if (child.isNodeType(NodeTypeRegistry.MIX_VERSIONABLE)) {
-// create frozen versionable child
-                        PersistentNode newChild = node.addNode(child.getQName(), NodeTypeRegistry.NT_UNSTRUCTURED);
-                        newChild.setPropertyValue(VersionManager.PROPNAME_VERSION_HISTORY,
-                                InternalValue.create(new UUID(child.getVersionHistory().getUUID())));
-                        newChild.setPropertyValue(VersionManager.PROPNAME_BASE_VERSION,
-                                InternalValue.create(new UUID(child.getBaseVersion().getUUID())));
-                    }
-                    // else ignore
-                    break;
-                case OnParentVersionAction.COPY:
-                    checkin(node, child.getQName(), child);
-                    break;
+            // add the frozen children and vistories
+            NodeIterator niter = src.getNodes();
+            while (niter.hasNext()) {
+                NodeImpl child = (NodeImpl) niter.nextNode();
+                switch (child.getDefinition().getOnParentVersion()) {
+                    case OnParentVersionAction.ABORT:
+                        throw new RepositoryException("Checkin aborted due to OPV in " + child.safeGetJCRPath());
+                    case OnParentVersionAction.COMPUTE:
+                    case OnParentVersionAction.IGNORE:
+                    case OnParentVersionAction.INITIALIZE:
+                        break;
+                    case OnParentVersionAction.VERSION:
+                        if (child.isNodeType(NodeTypeRegistry.MIX_VERSIONABLE)) {
+                            // create frozen versionable child
+                            PersistentNode newChild = node.addNode(child.getQName(), NodeTypeRegistry.NT_UNSTRUCTURED);
+                            newChild.setPropertyValue(VersionManager.PROPNAME_VERSION_HISTORY,
+                                    InternalValue.create(child.getVersionHistory().getUUID()));
+                            newChild.setPropertyValue(VersionManager.PROPNAME_BASE_VERSION,
+                                    InternalValue.create(child.getBaseVersion().getUUID()));
+                        }
+                        // else ignore
+                        break;
+                    case OnParentVersionAction.COPY:
+                        checkin(node, child.getQName(), child, false);
+                        break;
+                }
             }
         }
         parent.store();
-        return new InternalFrozenNode(node);
+        return node;
     }
 
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java	Tue Oct 26 08:44:46 2004
@@ -16,11 +16,8 @@
 package org.apache.jackrabbit.core.version;
 
 import org.apache.jackrabbit.core.QName;
-import org.apache.jackrabbit.core.util.uuid.UUID;
 
 import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.version.VersionHistory;
 
 /**
  * This Class represents a frozen versionable child node, that was created
@@ -38,7 +35,8 @@
      *
      * @param node
      */
-    protected InternalFrozenVersionHistory(PersistentNode node) {
+    protected InternalFrozenVersionHistory(InternalFreeze parent, PersistentNode node) {
+        super(parent);
         this.node = node;
     }
 
@@ -54,16 +52,31 @@
     /**
      * Returns the version history that was versioned with this node.
      *
-     * @param session
      * @return
      * @throws RepositoryException
      */
-    public VersionHistory getVersionHistory(Session session)
+    public String getVersionHistoryId()
             throws RepositoryException {
-        String historyId = ((UUID) node.getPropertyValue(VersionManager.PROPNAME_VERSION_HISTORY).internalValue()).toString();
-        PersistentNode hNode = node.getNodeByUUID(historyId);
-        return new VersionHistoryImpl(session, new InternalVersionHistory(hNode));
+        return (String) node.getPropertyValue(VersionManager.PROPNAME_VERSION_HISTORY).internalValue();
     }
 
+    /**
+     * Returns the version history that was versioned with this node.
+     *
+     * @return
+     * @throws RepositoryException
+     */
+    public InternalVersionHistory getVersionHistory()
+            throws RepositoryException {
+        return getVersionManager().getVersionHistory(getVersionHistoryId());
+    }
+
+    public String getBaseVersionId() throws RepositoryException {
+        return (String) node.getPropertyValue(VersionManager.PROPNAME_BASE_VERSION).internalValue();
+    }
 
+    public InternalVersion getBaseVesion()
+            throws RepositoryException {
+        return getVersionManager().getVersion(getVersionHistoryId(), getBaseVersionId());
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersion.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersion.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersion.java	Tue Oct 26 08:44:46 2004
@@ -30,7 +30,7 @@
 /**
  * This Class implements the Version representation of the node.
  */
-public final class InternalVersion {
+public final class InternalVersion extends InternalFreeze {
 
     /**
      * the list/cache of predecessors (values == InternalVersion)
@@ -68,6 +68,16 @@
     private InternalFrozenNode frozen;
 
     /**
+     * the id of this version
+     */
+    private String versionId;
+
+    /**
+     * specifies if this is the root version
+     */
+    private final boolean isRoot;
+
+    /**
      * Creates a new internal version with the given version history and
      * persistance node
      *
@@ -76,11 +86,19 @@
      * @throws RepositoryException
      */
     InternalVersion(InternalVersionHistory vh, PersistentNode node) throws RepositoryException {
+        super(null);
         this.versionHistory = vh;
         this.node = node;
+
+        // check name
+        isRoot = node.getName().equals(VersionManager.NODENAME_ROOTVERSION);
+
+        // get id
+        versionId = (String) node.getPropertyValue(PersistentVersionManager.PROPNAME_VERSION_ID).internalValue();
+
         // get frozen node
-        PersistentNode pNode = node.getNode(VersionManager.NODENAME_FROZEN, 1);
-        frozen = pNode == null ? null : new InternalFrozenNode(pNode);
+        PersistentNode pNode = node.getNode(PersistentVersionManager.NODENAME_FROZEN, 1);
+        frozen = pNode == null ? null : new InternalFrozenNode(this, pNode);
 
         // init internal values
         InternalValue[] values = node.getPropertyValues(VersionManager.PROPNAME_CREATED);
@@ -94,8 +112,8 @@
      *
      * @return
      */
-    public String getUUID() {
-        return node.getUUID();
+    public String getId() {
+        return versionId;
     }
 
     /**
@@ -108,6 +126,14 @@
     }
 
     /**
+     * returns the version manager
+     * @return
+     */
+    public PersistentVersionManager getVersionManager() {
+        return versionHistory.getVersionManager();
+    }
+
+    /**
      * Returns the frozen node
      *
      * @return
@@ -169,9 +195,9 @@
     private void storePredecessors() throws RepositoryException {
         InternalValue[] values = new InternalValue[predecessors.size()];
         for (int i = 0; i < values.length; i++) {
-            values[i] = InternalValue.create(new UUID(((InternalVersion) predecessors.get(i)).getUUID()));
+            values[i] = InternalValue.create(new UUID(((InternalVersion) predecessors.get(i)).getId()));
         }
-        node.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.REFERENCE, values);
+        node.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.STRING, values);
     }
 
     /**
@@ -289,4 +315,12 @@
         return labelCache == null ? new String[0] : (String[]) labelCache.toArray(new String[labelCache.size()]);
     }
 
+    /**
+     * checks if this is the root version.
+     * @return <code>true</code> if this version is the root version;
+     *         <code>false</code> otherwise.
+     */
+    public boolean isRootVersion() {
+        return isRoot;
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java	Tue Oct 26 08:44:46 2004
@@ -16,7 +16,6 @@
 package org.apache.jackrabbit.core.version;
 
 import org.apache.jackrabbit.core.InternalValue;
-import org.apache.jackrabbit.core.ItemImpl;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.QName;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
@@ -57,7 +56,7 @@
 
     /**
      * the hashmap of all versions
-     * key = UUID (String)
+     * key = versionId (String)
      * value = version
      */
     private HashMap versionCache = new HashMap();
@@ -73,9 +72,20 @@
     private PersistentNode labelNode;
 
     /**
+     * the id of this history
+     */
+    private String historyId;
+
+    /**
+     * the version manager
+     */
+    private final PersistentVersionManager vMgr;
+
+    /**
      * Creates a new VersionHistory object for the given node state.
      */
-    InternalVersionHistory(PersistentNode node) throws RepositoryException {
+    InternalVersionHistory(PersistentVersionManager vMgr, PersistentNode node) throws RepositoryException {
+        this.vMgr = vMgr;
         this.node = node;
         init();
     }
@@ -89,17 +99,20 @@
         versionCache.clear();
         labelCache.clear();
 
+        // get id
+        historyId = (String) node.getPropertyValue(PersistentVersionManager.PROPNAME_HISTORY_ID).internalValue();
+
         // get entries
         PersistentNode[] children = node.getChildNodes();
         for (int i = 0; i < children.length; i++) {
             PersistentNode child = children[i];
-            if (child.getName().equals(VersionManager.NODENAME_VERSION_LABELS)) {
+            if (child.getName().equals(PersistentVersionManager.NODENAME_VERSION_LABELS)) {
                 labelNode = child;
                 continue;
             }
             InternalVersion v = new InternalVersion(this, child);
-            versionCache.put(child.getUUID(), v);
-            if (child.getName().equals(VersionManager.NODENAME_ROOTVERSION)) {
+            versionCache.put(v.getId(), v);
+            if (v.isRootVersion()) {
                 rootVersion = v;
             }
         }
@@ -115,8 +128,8 @@
         PersistentNode labels[] = labelNode.getChildNodes();
         for (int i = 0; i < labels.length; i++) {
             PersistentNode lNode = labels[i];
-            String name = (String) lNode.getPropertyValue(VersionManager.PROPNAME_NAME).internalValue();
-            String ref = ((UUID) lNode.getPropertyValue(VersionManager.PROPNAME_VERSION).internalValue()).toString();
+            String name = (String) lNode.getPropertyValue(PersistentVersionManager.PROPNAME_NAME).internalValue();
+            String ref = (String) lNode.getPropertyValue(PersistentVersionManager.PROPNAME_VERSION).internalValue();
             InternalVersion v = getVersion(ref);
             labelCache.put(name, v);
             v.internalAddLabel(name);
@@ -124,12 +137,20 @@
     }
 
     /**
-     * Returns the uuid of this version history
+     * returns the version manager
+     * @return
+     */
+    public PersistentVersionManager getVersionManager() {
+        return vMgr;
+    }
+
+    /**
+     * Returns the id of this version history
      *
      * @return
      */
-    public String getUUID() {
-        return node.getUUID();
+    public String getId() {
+        return historyId;
     }
 
     /**
@@ -222,7 +243,7 @@
         v.internalDetach();
 
         // and remove from history
-        versionCache.remove(v.getUUID());
+        versionCache.remove(v.getId());
         store();
 
     }
@@ -234,14 +255,15 @@
      * @param label
      * @throws RepositoryException
      */
-    public void addVersionLabel(InternalVersion version, String label, boolean move) throws RepositoryException {
+    public void addVersionLabel(InternalVersion version, String label, boolean move)
+            throws VersionException, RepositoryException {
         InternalVersion prev = (InternalVersion) labelCache.get(label);
         if (version.equals(prev)) {
             // ignore
             return;
         } else if (prev != null && !move) {
             // already defined elsewhere, throw
-            throw new RepositoryException("Version label " + label + " already defined for version " + prev);
+            throw new VersionException("Version label " + label + " already defined for version " + prev.getName());
         } else if (prev != null) {
             // if already defined, but move, remove old label first
             removeVersionLabel(label);
@@ -250,10 +272,12 @@
         version.internalAddLabel(label);
         QName name = new QName("", Text.md5(label));
         PersistentNode lNode = labelNode.addNode(name, NodeTypeRegistry.NT_UNSTRUCTURED);
-        lNode.setPropertyValue(VersionManager.PROPNAME_NAME, InternalValue.create(label));
-        lNode.setPropertyValue(VersionManager.PROPNAME_VERSION, InternalValue.create(new UUID(version.getUUID())));
-        lNode.store();
+        lNode.setPropertyValue(PersistentVersionManager.PROPNAME_NAME, InternalValue.create(label));
+        lNode.setPropertyValue(PersistentVersionManager.PROPNAME_VERSION, InternalValue.create(version.getId()));
+        labelNode.store();
 
+        // inform manager
+        vMgr.onVersionModified(version);
     }
 
     /**
@@ -271,6 +295,9 @@
         QName name = new QName("", Text.md5(label));
         labelNode.removeNode(name);
         labelNode.store();
+
+        // inform manager
+        vMgr.onVersionModified(v);
     }
 
     /**
@@ -289,25 +316,24 @@
         Value[] preds = src.getProperty(VersionManager.PROPNAME_PREDECESSORS).getValues();
         InternalValue[] predecessors = new InternalValue[preds.length];
         for (int i = 0; i < preds.length; i++) {
-            String uuid = preds[i].getString();
+            String predId = preds[i].getString();
             // check if version exist
-            if (!versionCache.containsKey(uuid)) {
+            if (!versionCache.containsKey(predId)) {
                 throw new RepositoryException("invalid predecessor in source node");
             }
-            predecessors[i] = InternalValue.create(new UUID(uuid));
+            predecessors[i] = InternalValue.create(predId);
         }
 
         PersistentNode vNode = node.addNode(name, NodeTypeRegistry.NT_UNSTRUCTURED);
-        vNode.setPropertyValue(ItemImpl.PROPNAME_UUID, InternalValue.create(vNode.getUUID()));
-        vNode.setMixinNodeTypes(new QName[]{NodeTypeRegistry.MIX_REFERENCEABLE});
+        String versionId = UUID.randomUUID().toString();
+        vNode.setPropertyValue(PersistentVersionManager.PROPNAME_VERSION_ID, InternalValue.create(versionId));
 
         // initialize 'created' and 'predecessors'
         vNode.setPropertyValue(VersionManager.PROPNAME_CREATED, InternalValue.create(Calendar.getInstance()));
-        vNode.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.REFERENCE, predecessors);
-
+        vNode.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.STRING, predecessors);
 
         // checkin source node
-        InternalFrozenNode.checkin(vNode, VersionManager.NODENAME_FROZEN, src);
+        InternalFrozenNode.checkin(vNode, PersistentVersionManager.NODENAME_FROZEN, src, false);
 
         // and store
         store();
@@ -317,7 +343,7 @@
         version.resolvePredecessors();
 
         // update cache
-        versionCache.put(version.getUUID(), version);
+        versionCache.put(version.getId(), version);
 
         return version;
     }
@@ -343,6 +369,14 @@
     }
 
     /**
+     * Returns an iterator over all versions (not ordered yet)
+     * @return
+     */
+    protected Iterator getVersions() {
+        return versionCache.values().iterator();
+    }
+
+    /**
      * Creates a new <code>InternalVersionHistory</code> below the given parent
      * node and with the given name.
      *
@@ -351,28 +385,30 @@
      * @return
      * @throws RepositoryException
      */
-    protected static InternalVersionHistory create(PersistentNode parent, QName name)
+    protected static InternalVersionHistory create(PersistentVersionManager vMgr, PersistentNode parent, String historyId, QName name, NodeImpl src)
             throws RepositoryException {
 
         // create history node
         PersistentNode pNode = parent.addNode(name, NodeTypeRegistry.NT_UNSTRUCTURED);
-        pNode.setPropertyValue(ItemImpl.PROPNAME_UUID, InternalValue.create(pNode.getUUID()));
-        pNode.setMixinNodeTypes(new QName[]{NodeTypeRegistry.MIX_REFERENCEABLE});
+        pNode.setPropertyValue(PersistentVersionManager.PROPNAME_HISTORY_ID, InternalValue.create(historyId));
 
         // create label node
-        pNode.addNode(VersionManager.NODENAME_VERSION_LABELS, NodeTypeRegistry.NT_UNSTRUCTURED);
+        pNode.addNode(PersistentVersionManager.NODENAME_VERSION_LABELS, NodeTypeRegistry.NT_UNSTRUCTURED);
 
         // create root version
+        String versionId = UUID.randomUUID().toString();
         PersistentNode vNode = pNode.addNode(VersionManager.NODENAME_ROOTVERSION, NodeTypeRegistry.NT_UNSTRUCTURED);
-        vNode.setPropertyValue(ItemImpl.PROPNAME_UUID, InternalValue.create(vNode.getUUID()));
-        vNode.setMixinNodeTypes(new QName[]{NodeTypeRegistry.MIX_REFERENCEABLE});
+        vNode.setPropertyValue(PersistentVersionManager.PROPNAME_VERSION_ID, InternalValue.create(versionId));
 
         // initialize 'created' and 'predecessors'
         vNode.setPropertyValue(VersionManager.PROPNAME_CREATED, InternalValue.create(Calendar.getInstance()));
         vNode.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.REFERENCE, new InternalValue[0]);
 
+        // add also an empty frozen node to the root version
+        InternalFrozenNode.checkin(vNode, PersistentVersionManager.NODENAME_FROZEN, src, true);
+
         parent.store();
-        return new InternalVersionHistory(pNode);
+        return new InternalVersionHistory(vMgr, pNode);
     }
 }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentNode.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentNode.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentNode.java	Tue Oct 26 08:44:46 2004
@@ -111,7 +111,8 @@
             for (int i = 0; i < list.size(); i++) {
                 NodeState.PropertyEntry entry = (NodeState.PropertyEntry) list.get(i);
                 PropertyId propId = new PropertyId(nodeState.getUUID(), entry.getName());
-                props[i] = new PersistentProperty((PropertyState) stateMgr.getItemState(propId));
+                PropertyState pState = (PropertyState) stateMgr.getItemState(propId);
+                props[i] = new PersistentProperty(pState, ntMgr.getPropDef(pState.getDefinitionId()).isMultiple());
             }
             return props;
         } catch (ItemStateException e) {
@@ -171,7 +172,7 @@
      */
     protected void setPropertyValue(QName name, InternalValue value)
             throws RepositoryException {
-        setPropertyValues(name, value.getType(), new InternalValue[]{value});
+        setPropertyValues(name, value.getType(), new InternalValue[]{value}, false);
     }
 
     /**
@@ -184,7 +185,20 @@
      */
     protected void setPropertyValues(QName name, int type, InternalValue[] values)
             throws RepositoryException {
-        PersistentPropertyState prop = getOrCreatePropertyState(name, type, true);
+        setPropertyValues(name, type, values, true);
+    }
+
+    /**
+     * Sets the property values
+     *
+     * @param name
+     * @param type
+     * @param values
+     * @throws RepositoryException
+     */
+    protected void setPropertyValues(QName name, int type, InternalValue[] values, boolean multiple)
+            throws RepositoryException {
+        PersistentPropertyState prop = getOrCreatePropertyState(name, type, multiple);
         prop.setValues(values);
     }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentProperty.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentProperty.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentProperty.java	Tue Oct 26 08:44:46 2004
@@ -28,15 +28,21 @@
     /**
      * the underlaying persistent state
      */
-    private PropertyState state;
+    private final PropertyState state;
+
+    /**
+     * flag if this is a multivalued propertery
+     */
+    private final boolean isMultiple;
 
     /**
      * Creates a new persistent property
      *
      * @param state
      */
-    public PersistentProperty(PropertyState state) {
+    public PersistentProperty(PropertyState state, boolean isMultiple) {
         this.state = state;
+        this.isMultiple = isMultiple;
     }
 
     /**
@@ -66,4 +72,11 @@
         return state.getType();
     }
 
+    /**
+     * returns <code>true</code> if this is a multivalue propererty
+     * @return
+     */
+    public boolean isMultiple() {
+        return isMultiple;
+    }
 }

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java	Tue Oct 26 08:44:46 2004
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.version;
+
+import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.util.uuid.UUID;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.PersistentNodeState;
+import org.apache.jackrabbit.core.state.PersistentItemStateProvider;
+import org.apache.log4j.Logger;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * This Class provides general versioning functions.
+ */
+public class PersistentVersionManager {
+
+    /**
+     * the logger
+     */
+    private static Logger log = Logger.getLogger(PersistentVersionManager.class);
+
+    /**
+     * root path for version storage
+     */
+    public static final QName VERSION_HISTORY_ROOT_NAME = new QName(NamespaceRegistryImpl.NS_JCR_URI, "persistentVersionStorage");
+    /**
+     * name of the 'jcr:historyId' property
+     */
+    public static final QName PROPNAME_HISTORY_ID = new QName(NamespaceRegistryImpl.NS_JCR_URI, "historyId");
+    /**
+     * name of the 'jcr:versionId' property
+     */
+    public static final QName PROPNAME_VERSION_ID = new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionId");
+    /**
+     * name of the 'jcr:versionLabels' node
+     */
+    public static final QName NODENAME_VERSION_LABELS = new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionLabels");
+    /**
+     * name of the 'jcr:frozen' property
+     */
+    public static final QName NODENAME_FROZEN = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozen");
+    /**
+     * name of the 'jcr:name' property
+     */
+    public static final QName PROPNAME_NAME = new QName(NamespaceRegistryImpl.NS_JCR_URI, "name");
+    /**
+     * name of the 'jcr:version' property
+     */
+    public static final QName PROPNAME_VERSION = new QName(NamespaceRegistryImpl.NS_JCR_URI, "version");
+
+
+    /**
+     * the root node of the version histories
+     */
+    private final PersistentNode historyRoot;
+
+    /**
+     * the system root id
+     */
+    private final String systemRootId;
+
+    /**
+     * the state manager for the version storage
+     */
+    private PersistentItemStateProvider stateMgr;
+
+    /**
+     * the nodetype manager for the version storage
+     */
+    private NodeTypeManagerImpl ntMgr;
+
+    /**
+     * The representation version manager
+     */
+    private VersionManager versionManager;
+
+    /**
+     * the version histories
+     */
+    private HashMap histories = new HashMap();
+
+    /**
+     * Creates a new PersistentVersionManager.
+     *
+     * @param session
+     * @throws RepositoryException
+     */
+    public PersistentVersionManager(SessionImpl session) throws RepositoryException {
+        this.stateMgr = ((WorkspaceImpl) session.getWorkspace()).getPersistentStateManager();
+        this.ntMgr = session.getNodeTypeManager();
+
+        // check for versionhistory root
+        NodeImpl systemRoot = ((RepositoryImpl) session.getRepository()).getSystemRootNode(session);
+        systemRootId = systemRoot.internalGetUUID();
+        if (!systemRoot.hasNode(VERSION_HISTORY_ROOT_NAME)) {
+            // if not exist, create
+            systemRoot.addNode(VERSION_HISTORY_ROOT_NAME, NodeTypeRegistry.NT_UNSTRUCTURED);
+            systemRoot.save();
+        }
+
+        try {
+            PersistentNodeState nodeState = (PersistentNodeState) stateMgr.getItemState(new NodeId(systemRoot.getNode(VERSION_HISTORY_ROOT_NAME).internalGetUUID()));
+            historyRoot = new PersistentNode(stateMgr, ntMgr, nodeState);
+        } catch (ItemStateException e) {
+            throw new RepositoryException("Unable to initialize PersistentVersionManager: " + e.toString());
+        }
+    }
+
+    /**
+     * Creates a new Version History..
+     *
+     * @param node the node for which the version history is to be initialized
+     * @return the newly created version history.
+     * @throws RepositoryException
+     */
+    public synchronized InternalVersionHistory createVersionHistory(NodeImpl node)
+            throws RepositoryException {
+
+        // create deep path
+        String uuid = UUID.randomUUID().toString();
+        QName historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid);
+        if (historyRoot.hasNode(historyNodeName)) {
+            historyRoot.removeNode(historyNodeName);
+        }
+        historyRoot.store();
+
+        // create new history node in the persistent state
+        InternalVersionHistory hist = InternalVersionHistory.create(this, historyRoot, uuid, historyNodeName, node);
+        histories.put(hist.getId(), hist);
+        return hist;
+    }
+
+    /**
+     * returns the internal version history for the id
+     *
+     * @param histId the id of the history
+     * @return
+     * @throws RepositoryException
+     */
+    public synchronized InternalVersionHistory getVersionHistory(String histId)
+            throws RepositoryException {
+
+        InternalVersionHistory hist = (InternalVersionHistory) histories.get(histId);
+        if (hist==null) {
+            // we cannot used the uuid, since the persistent state do not share the same ids
+            QName historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, histId);
+            PersistentNode hNode = historyRoot.getNode(historyNodeName, 1);
+            hist = new InternalVersionHistory(this, hNode);
+            histories.put(histId, hist);
+        }
+        return hist;
+    }
+
+    /**
+     * returns an iterator over all existing version histories
+     * @return
+     * @throws RepositoryException
+     */
+    public synchronized Iterator getVersionHistories() throws RepositoryException {
+        PersistentNode[] ph = historyRoot.getChildNodes();
+        ArrayList list = new ArrayList(ph.length);
+        for (int i=0; i<ph.length; i++) {
+            list.add(getVersionHistory(ph[i].getName().getLocalName()));
+        }
+        return list.iterator();
+    }
+
+    /**
+     * returns the internal version for the id
+     *
+     * @param versionId
+     * @return
+     * @throws RepositoryException
+     */
+    public synchronized InternalVersion getVersion(String histId, String versionId)
+            throws RepositoryException {
+        InternalVersionHistory history = getVersionHistory(histId);
+        return history.getVersion(versionId);
+    }
+
+    /**
+     * is informed by the versions if they were modified
+     * @param version
+     */
+    protected void onVersionModified(InternalVersion version)  throws RepositoryException {
+        // check if version manager already generated item states
+        if (versionManager!=null) {
+            versionManager.onVersionModified(version);
+        }
+    }
+
+    /**
+     * Checks in a node
+     *
+     * @param node
+     * @return
+     * @throws RepositoryException
+     * @see Node#checkin()
+     */
+    public synchronized InternalVersion checkin(NodeImpl node) throws RepositoryException {
+        // assuming node is versionable and checkout (check in nodeimpl)
+        // To create a new version of a versionable node N, the client calls N.checkin.
+        // This causes the following series of events:
+        String histUUID = node.getProperty(VersionManager.PROPNAME_VERSION_HISTORY).getString();
+        InternalVersionHistory history = getVersionHistory(histUUID);
+
+        // 0. resolve the predecessors
+        Value[] values = node.getProperty(VersionManager.PROPNAME_PREDECESSORS).getValues();
+        InternalVersion[] preds = new InternalVersion[values.length];
+        for (int i = 0; i < values.length; i++) {
+            preds[i] = history.getVersion(values[i].getString());
+        }
+
+        // 0.1 search a predecessor, suitable for generating the new name
+        String versionName = null;
+        int maxDots = Integer.MAX_VALUE;
+        for (int i = 0; i < preds.length; i++) {
+            // take the first pred. without a successor
+            if (preds[i].getSuccessors().length == 0) {
+                versionName = preds[i].getName().getLocalName(); //assuming no namespaces in version names
+                // need to count the dots
+                int pos = -1;
+                int numDots = 0;
+                while (versionName.indexOf('.', pos + 1) >= 0) {
+                    pos = versionName.indexOf('.', pos + 1);
+                    numDots++;
+                }
+                if (numDots < maxDots) {
+                    maxDots = numDots;
+                    versionName = pos < 0 ? "1.0" : versionName.substring(0, pos + 1) + (Integer.parseInt(versionName.substring(pos + 1)) + 1);
+                }
+                break;
+            }
+        }
+        // if no empty found, generate new name
+        if (versionName == null) {
+            versionName = preds[0].getName().getLocalName();
+            do {
+                versionName += ".1";
+            } while (history.hasVersion(new QName("", versionName)));
+        }
+
+        return history.checkin(new QName("", versionName), node);
+    }
+
+    /**
+     * returns the version manager
+     * @return
+     */
+    public synchronized VersionManager getVersionManager() {
+        if (versionManager==null) {
+            versionManager = new VersionManager(this, systemRootId);
+        }
+        return versionManager;
+    }
+
+    /**
+     * returns the node type manager of the version storage
+     * @return
+     */
+    public NodeTypeManagerImpl getNodeTypeManager(){
+        return ntMgr;
+    }
+}

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryImpl.java	Tue Oct 26 08:44:46 2004
@@ -16,11 +16,12 @@
 package org.apache.jackrabbit.core.version;
 
 import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.state.NodeState;
 
 import javax.jcr.Item;
 import javax.jcr.RepositoryException;
-import javax.jcr.Session;
 import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.nodetype.NodeDef;
 import javax.jcr.version.Version;
 import javax.jcr.version.VersionHistory;
 import javax.jcr.version.VersionIterator;
@@ -29,7 +30,7 @@
 /**
  * This Class implements a version history that extends a node.
  */
-public class VersionHistoryImpl extends NodeWrapper implements VersionHistory {
+public class VersionHistoryImpl extends NodeImpl implements VersionHistory {
 
     /**
      * the internal version history
@@ -37,16 +38,21 @@
     private final InternalVersionHistory history;
 
     /**
-     * creates a new version history implementation for the given session and
-     * internal version history
-     *
+     * creates a new version history node.
+     * @param itemMgr
      * @param session
+     * @param id
+     * @param state
+     * @param definition
+     * @param listeners
      * @param history
      * @throws RepositoryException
      */
-    protected VersionHistoryImpl(Session session, InternalVersionHistory history)
-            throws RepositoryException {
-        super((NodeImpl) session.getNodeByUUID(history.getUUID()));
+    protected VersionHistoryImpl(ItemManager itemMgr, SessionImpl session, NodeId id,
+                              NodeState state, NodeDef definition,
+                              ItemLifeCycleListener[] listeners,
+                              InternalVersionHistory history) throws RepositoryException {
+        super(itemMgr, session, id, state, definition, listeners);
         this.history = history;
     }
 
@@ -54,14 +60,14 @@
      * @see VersionHistory#getRootVersion()
      */
     public Version getRootVersion() throws RepositoryException {
-        return new VersionImpl(unwrap().getSession(), history.getRootVersion());
+        return (Version) session.getNodeByUUID(history.getRootVersion().getId());
     }
 
     /**
      * @see VersionHistory#getAllVersions()
      */
     public VersionIterator getAllVersions() throws RepositoryException {
-        return new VersionIteratorImpl(unwrap().getSession(), history.getRootVersion());
+        return new VersionIteratorImpl(session, history.getRootVersion());
     }
 
     /**
@@ -69,9 +75,9 @@
      */
     public Version getVersion(String versionName) throws RepositoryException {
         try {
-            QName name = QName.fromJCRName(versionName, ((SessionImpl) unwrap().getSession()).getNamespaceResolver());
+            QName name = QName.fromJCRName(versionName, session.getNamespaceResolver());
             InternalVersion v = history.getVersion(name);
-            return v == null ? null : new VersionImpl(unwrap().getSession(), v);
+            return v == null ? null : (Version) session.getNodeByUUID(v.getId());
         } catch (IllegalNameException e) {
             throw new RepositoryException(e);
         } catch (UnknownPrefixException e) {
@@ -84,40 +90,48 @@
      */
     public Version getVersionByLabel(String label) throws RepositoryException {
         InternalVersion v = history.getVersionByLabel(label);
-        return v == null ? null : new VersionImpl(unwrap().getSession(), v);
+        return v == null ? null : (Version) session.getNodeByUUID(v.getId());
     }
 
     /**
      * @see VersionHistory#addVersionLabel(String, String)
      */
-    public void addVersionLabel(String versionName, String label) throws VersionException, RepositoryException {
-        InternalVersion v;
+    public void addVersionLabel(String version, String label) throws VersionException, RepositoryException {
+        addVersionLabel(version, label, false);
+    }
+
+    /**
+     * @see VersionHistory#addVersionLabel(String, String, boolean)
+     */
+    public void addVersionLabel(String version, String label, boolean move)
+            throws VersionException, RepositoryException {
         try {
-            QName name = QName.fromJCRName(versionName, ((SessionImpl) unwrap().getSession()).getNamespaceResolver());
-            v = history.getVersion(name);
+            QName name = QName.fromJCRName(version, session.getNamespaceResolver());
+            InternalVersion v = history.getVersion(name);
+            if (v==null) {
+                throw new VersionException("Version " + version + " does not exist in this version history.");
+            }
+            history.addVersionLabel(v, label, move);
         } catch (IllegalNameException e) {
             throw new RepositoryException(e);
         } catch (UnknownPrefixException e) {
             throw new RepositoryException(e);
         }
-        if (v == null) {
-            throw new VersionException("specified version does not exist");
-        }
-        history.addVersionLabel(v, label, false);
     }
 
     /**
      * @see VersionHistory#removeVersionLabel(String)
      */
-    public void removeVersionLabel(String label) throws VersionException, RepositoryException {
+    public void removeVersionLabel(String label) throws RepositoryException {
         history.removeVersionLabel(label);
     }
 
+
     /**
      * @see javax.jcr.Node#getUUID()
      */
     public String getUUID() throws UnsupportedRepositoryOperationException, RepositoryException {
-        return history.getUUID();
+        return history.getId();
     }
 
     /**
@@ -126,7 +140,7 @@
     public boolean isSame(Item otherItem) {
         if (otherItem instanceof VersionHistoryImpl) {
             // since all version histories live in the same workspace, we can compare the uuids
-            return ((VersionHistoryImpl) otherItem).history.getUUID().equals(history.getUUID());
+            return ((VersionHistoryImpl) otherItem).history.getId().equals(history.getId());
         } else {
             return false;
         }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionImpl.java	Tue Oct 26 08:44:46 2004
@@ -15,19 +15,20 @@
  */
 package org.apache.jackrabbit.core.version;
 
-import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.state.NodeState;
 
 import javax.jcr.Item;
 import javax.jcr.RepositoryException;
-import javax.jcr.Session;
 import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.nodetype.NodeDef;
 import javax.jcr.version.Version;
 import java.util.Calendar;
 
 /**
  * This Class implements a Version that extends the node interface
  */
-public class VersionImpl extends NodeWrapper implements Version {
+public class VersionImpl extends NodeImpl implements Version {
 
     /**
      * the internal version
@@ -35,15 +36,21 @@
     protected final InternalVersion version;
 
     /**
-     * Creates a new version implementation
-     *
+     * creates a new version node
+     * @param itemMgr
      * @param session
+     * @param id
+     * @param state
+     * @param definition
+     * @param listeners
      * @param version
      * @throws RepositoryException
      */
-    protected VersionImpl(Session session, InternalVersion version)
+    protected VersionImpl(ItemManager itemMgr, SessionImpl session, NodeId id,
+                       NodeState state, NodeDef definition,
+                       ItemLifeCycleListener[] listeners, InternalVersion version)
             throws RepositoryException {
-        super((NodeImpl) session.getNodeByUUID(version.getUUID()));
+        super(itemMgr, session, id, state, definition, listeners);
         this.version = version;
     }
 
@@ -76,7 +83,7 @@
         InternalVersion[] suc = version.getSuccessors();
         Version[] ret = new Version[suc.length];
         for (int i = 0; i < suc.length; i++) {
-            ret[i] = new VersionImpl(unwrap().getSession(), suc[i]);
+            ret[i] = (Version) session.getNodeByUUID(suc[i].getId());
         }
         return ret;
     }
@@ -89,7 +96,7 @@
         InternalVersion[] pred = version.getPredecessors();
         Version[] ret = new Version[pred.length];
         for (int i = 0; i < pred.length; i++) {
-            ret[i] = new VersionImpl(unwrap().getSession(), pred[i]);
+            ret[i] = (Version) session.getNodeByUUID(pred[i].getId());
         }
         return ret;
     }
@@ -98,7 +105,7 @@
      * @see javax.jcr.Node#getUUID()
      */
     public String getUUID() throws UnsupportedRepositoryOperationException, RepositoryException {
-        return version.getUUID();
+        return version.getId();
     }
 
     /**
@@ -126,9 +133,10 @@
     public boolean isSame(Item otherItem) {
         if (otherItem instanceof VersionImpl) {
             // since all versions live in the same workspace, we can compare the uuids
-            return ((VersionImpl) otherItem).version.getUUID().equals(version.getUUID());
+            return ((VersionImpl) otherItem).version.getId().equals(version.getId());
         } else {
             return false;
         }
     }
+
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionIteratorImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionIteratorImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionIteratorImpl.java	Tue Oct 26 08:44:46 2004
@@ -75,7 +75,7 @@
         push(ret.getSuccessors());
 
         try {
-            return new VersionImpl(session, ret);
+            return (Version) session.getNodeByUUID(ret.getId());
         } catch (RepositoryException e) {
             throw new NoSuchElementException("Unable to provide element: " + e.toString());
         }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java	Tue Oct 26 08:44:46 2004
@@ -16,177 +16,152 @@
 package org.apache.jackrabbit.core.version;
 
 import org.apache.jackrabbit.core.*;
-import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.state.*;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.util.uuid.UUID;
+import org.apache.jackrabbit.core.virtual.*;
 import org.apache.jackrabbit.core.state.ItemStateException;
-import org.apache.jackrabbit.core.state.PersistentItemStateProvider;
-import org.apache.jackrabbit.core.state.PersistentNodeState;
 import org.apache.log4j.Logger;
 
-import javax.jcr.Node;
 import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.version.Version;
+import javax.jcr.PropertyType;
+import javax.jcr.nodetype.NodeDef;
 import javax.jcr.version.VersionHistory;
+import javax.jcr.version.Version;
+import java.util.Iterator;
 
 /**
- * This Class provides general versioning functions.
+ * This Class implements the session tied version manager. It is also repsonsible
+ * for mapping the internal versions to the presentation layer using virtual
+ * nodes and items.
+ *
+ * @author tripod
+ * @version $Revision:$, $Date:$
  */
 public class VersionManager {
 
+    /**
+     * the default logger
+     */
     private static Logger log = Logger.getLogger(VersionManager.class);
 
     /**
      * root path for version storage
      */
     public static final QName VERSION_HISTORY_ROOT_NAME = new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionStorage");
-
     /**
      * name of the 'jcr:frozenUUID' property
      */
     public static final QName PROPNAME_FROZEN_UUID = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozenUUID");
-
     /**
      * name of the 'jcr:frozenPrimaryType' property
      */
     public static final QName PROPNAME_FROZEN_PRIMARY_TYPE = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozenPrimaryType");
-
     /**
      * name of the 'jcr:frozenMixinTypes' property
      */
     public static final QName PROPNAME_FROZEN_MIXIN_TYPES = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozenMixinTypes");
-
-    /**
-     * name of the 'jcr:versionLabels' node
-     */
-    public static final QName NODENAME_VERSION_LABELS = new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionLabels");
-
-    /**
-     * name of the 'jcr:frozen' property
-     */
-    public static final QName NODENAME_FROZEN = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozen");
-
     /**
      * name of the 'jcr:predecessors' property
      */
     public static final QName PROPNAME_PREDECESSORS = new QName(NamespaceRegistryImpl.NS_JCR_URI, "predecessors");
-
     /**
-     * name of the 'jcr:successors' property
+     * name of the 'jcr:versionLabels' property
      */
-    public static final QName PROPNAME_SUCCESSORS = new QName(NamespaceRegistryImpl.NS_JCR_URI, "successors");
-
-    /**
-     * name of the 'jcr:name' property
-     */
-    public static final QName PROPNAME_NAME = new QName(NamespaceRegistryImpl.NS_JCR_URI, "name");
-
+    public static final QName PROPNAME_VERSION_LABELS= new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionLabels");
     /**
-     * name of the 'jcr:version' property
+     * name of the 'jcr:successors' property
      */
-    public static final QName PROPNAME_VERSION = new QName(NamespaceRegistryImpl.NS_JCR_URI, "version");
-
+    public static final QName PROPNAME_SUCCESSORS = new QName(NamespaceRegistryImpl.NS_JCR_URI, "successors");
     /**
      * name of the 'jcr:isCheckedOut' property
      */
     public static final QName PROPNAME_IS_CHECKED_OUT = new QName(NamespaceRegistryImpl.NS_JCR_URI, "isCheckedOut");
-
     /**
      * name of the 'jcr:versionHistory' property
      */
     public static final QName PROPNAME_VERSION_HISTORY = new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionHistory");
-
     /**
      * name of the 'jcr:baseVersion' property
      */
     public static final QName PROPNAME_BASE_VERSION = new QName(NamespaceRegistryImpl.NS_JCR_URI, "baseVersion");
-
     /**
      * name of the 'jcr:created' property
      */
     public static final QName PROPNAME_CREATED = new QName(NamespaceRegistryImpl.NS_JCR_URI, "created");
-
     /**
      * the name of the 'jcr:rootVersion' node
      */
     public static final QName NODENAME_ROOTVERSION = new QName(NamespaceRegistryImpl.NS_JCR_URI, "rootVersion");
 
     /**
-     * the root node of the version histories
+     * The version manager of the internal versions
      */
-    private final PersistentNode historyRoot;
+    private final PersistentVersionManager vMgr;
 
     /**
-     * the state manager for the version storage
+     * the uuid of the system root node
      */
-    private PersistentItemStateProvider stateMgr;
+    private final String rootId;
 
     /**
-     * the nodetype manager for the version storage
+     * The virtual item manager that exposes the versions to the content
      */
-    private NodeTypeManagerImpl ntMgr;
+    private DefaultItemStateProvider virtProvider;
 
     /**
-     * Creates a new VersionManager.
-     *
-     * @param session
-     * @throws RepositoryException
+     * The virtual history root
      */
-    public VersionManager(SessionImpl session) throws RepositoryException {
-        this.stateMgr = ((WorkspaceImpl) session.getWorkspace()).getPersistentStateManager();
-        this.ntMgr = session.getNodeTypeManager();
-
-        // check for versionhistory root
-        NodeImpl systemRoot = ((RepositoryImpl) session.getRepository()).getSystemRootNode(session);
-        if (!systemRoot.hasNode(VERSION_HISTORY_ROOT_NAME)) {
-            // if not exist, create
-            systemRoot.addNode(VERSION_HISTORY_ROOT_NAME, NodeTypeRegistry.NT_UNSTRUCTURED);
-            systemRoot.save();
-        }
+    private VirtualNodeState historyRoot;
 
-        try {
-            PersistentNodeState nodeState = (PersistentNodeState) stateMgr.getItemState(new NodeId(systemRoot.getNode(VERSION_HISTORY_ROOT_NAME).internalGetUUID()));
-            historyRoot = new PersistentNode(stateMgr, ntMgr, nodeState);
-        } catch (ItemStateException e) {
-            throw new RepositoryException("Unable to initialize VersionManager: " + e.toString());
+
+    /**
+     * @param vMgr
+     */
+    protected VersionManager(PersistentVersionManager vMgr, String rootId) {
+        this.vMgr = vMgr;
+        this.rootId = rootId;
+    }
+
+    /**
+     * returns the virtual item state provider that exposes the internal versions
+     * as items.
+     * @param base
+     * @return
+     */
+    public VirtualItemStateProvider getVirtualItemStateProvider(ItemStateProvider base) {
+        if (virtProvider==null) {
+            try {
+                NodeState rootState = (NodeState) base.getItemState(new NodeId(rootId));
+                virtProvider = new DefaultItemStateProvider(vMgr.getNodeTypeManager(), rootState);
+                historyRoot = virtProvider.addNode(virtProvider.getRootState(), VERSION_HISTORY_ROOT_NAME, null, NodeTypeRegistry.NT_UNSTRUCTURED, null);
+                Iterator iter = vMgr.getVersionHistories();
+                while (iter.hasNext()) {
+                    InternalVersionHistory vh = (InternalVersionHistory) iter.next();
+                    mapVersionHistory(vh);
+                }
+            } catch (Exception e) {
+                // todo: better error handling
+                log.error("Error while initializing virtual items.", e);
+                throw new IllegalStateException(e.toString());
+            }
         }
+        return virtProvider;
     }
 
     /**
-     * Creates a new Version History..
+     * Creates a new version history. This action is needed either when creating
+     * a new 'mix:versionable' node or when adding the 'mix:versionalbe' mixin
+     * to a node.
      *
-     * @param node the node for which the version history is to be initialized
-     * @return the newly created version history.
+     * @param node
+     * @return
      * @throws RepositoryException
      */
-    public VersionHistory createVersionHistory(NodeImpl node)
-            throws RepositoryException {
-
-        // create deep path
-        String uuid = node.getUUID();
-        PersistentNode parent = historyRoot;
-        QName historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid.substring(0, 2));
-        if (!parent.hasNode(historyNodeName)) {
-            parent = parent.addNode(historyNodeName, NodeTypeRegistry.NT_UNSTRUCTURED);
-        } else {
-            parent = parent.getNode(historyNodeName, 1);
-        }
-        historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid.substring(2, 4));
-        if (!parent.hasNode(historyNodeName)) {
-            parent = parent.addNode(historyNodeName, NodeTypeRegistry.NT_UNSTRUCTURED);
-        } else {
-            parent = parent.getNode(historyNodeName, 1);
-        }
-
-        historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid.substring(4));
-        if (parent.hasNode(historyNodeName)) {
-            parent.removeNode(historyNodeName);
-        }
-        historyRoot.store();
-
-        // create new history node in the persistent state
-        InternalVersionHistory history = InternalVersionHistory.create(parent, historyNodeName);
-        return new VersionHistoryImpl(node.getSession(), history);
+    public VersionHistory createVersionHistory(NodeImpl node) throws RepositoryException {
+        InternalVersionHistory history = vMgr.createVersionHistory(node);
+        mapVersionHistory(history);
+        return (VersionHistory) node.getSession().getNodeByUUID(history.getId());
     }
 
     /**
@@ -197,9 +172,10 @@
      * @throws RepositoryException
      */
     public Version getBaseVersion(NodeImpl node) throws RepositoryException {
-        InternalVersionHistory history = getInternalVersionHistory(node);
+        String histUUID = node.getProperty(VersionManager.PROPNAME_VERSION_HISTORY).getString();
+        InternalVersionHistory history = vMgr.getVersionHistory(histUUID);
         InternalVersion version = history.getVersion(node.getProperty(PROPNAME_BASE_VERSION).getString());
-        return version == null ? null : new VersionImpl(node.getSession(), version);
+        return version == null ? null : (Version) node.getSession().getNodeByUUID(version.getId());
     }
 
     /**
@@ -212,81 +188,230 @@
      */
     public VersionHistory getVersionHistory(NodeImpl node)
             throws RepositoryException {
-        InternalVersionHistory history = getInternalVersionHistory(node);
-        return new VersionHistoryImpl(node.getSession(), history);
+        String histUUID = node.getProperty(VersionManager.PROPNAME_VERSION_HISTORY).getString();
+        InternalVersionHistory history = vMgr.getVersionHistory(histUUID);
+        return (VersionHistory) node.getSession().getNodeByUUID(history.getId());
     }
 
+
     /**
-     * returns the internal version history for the given node
-     *
-     * @param node
+     * Creates a new VersionHistoryImpl instance. this is usually called by
+     * the {@link ItemManager}.
+     * @param session
+     * @param state
+     * @param def
+     * @param itemMgr
+     * @param listeners
      * @return
      * @throws RepositoryException
      */
-    private InternalVersionHistory getInternalVersionHistory(NodeImpl node)
+    public VersionHistoryImpl createVersionHistoryInstance(SessionImpl session,
+                                                           NodeState state, NodeDef def,
+                                                           ItemManager itemMgr,
+                                                           ItemLifeCycleListener[] listeners)
             throws RepositoryException {
-        String histUUID = node.getProperty(PROPNAME_VERSION_HISTORY).getString();
-        try {
-            PersistentNodeState state = (PersistentNodeState) stateMgr.getItemState(new NodeId(histUUID));
-            PersistentNode hNode = new PersistentNode(stateMgr, ntMgr, state);
-            return new InternalVersionHistory(hNode);
-        } catch (ItemStateException e) {
-            throw new RepositoryException(e);
+        if (!state.getNodeTypeName().equals(NodeTypeRegistry.NT_VERSION_HISTORY)) {
+            throw new RepositoryException("node not nt:versionhistory");
         }
+        NodeId nodeId = (NodeId) state.getId();
+        InternalVersionHistory history = vMgr.getVersionHistory(nodeId.getUUID());
+        return new VersionHistoryImpl(itemMgr, session, nodeId, state, def, listeners, history);
     }
 
     /**
-     * Checks in a node
-     *
+     * Creates a new VersionImpl instance. this is usually called by
+     * the {@link ItemManager}.
+     * @param session
+     * @param state
+     * @param def
+     * @param itemMgr
+     * @param listeners
+     * @return
+     * @throws RepositoryException
+     */
+    public VersionImpl createVersionInstance(SessionImpl session,
+                                             NodeState state, NodeDef def,
+                                             ItemManager itemMgr,
+                                             ItemLifeCycleListener[] listeners)
+            throws RepositoryException {
+        if (!state.getNodeTypeName().equals(NodeTypeRegistry.NT_VERSION)) {
+            throw new RepositoryException("node not nt:version");
+        }
+        NodeId nodeId = (NodeId) state.getId();
+        String historyId = state.getParentUUID();
+        InternalVersionHistory history = vMgr.getVersionHistory(historyId);
+        InternalVersion version = history.getVersion(nodeId.getUUID());
+        return new VersionImpl(itemMgr, session, nodeId, state, def, listeners, version);
+    }
+
+    /**
+     * invokes the checkin() on the persistent version manager and remaps the
+     * newly created version objects.
      * @param node
      * @return
      * @throws RepositoryException
-     * @see Node#checkin()
      */
     public Version checkin(NodeImpl node) throws RepositoryException {
-        // assuming node is versionable and checkout (check in nodeimpl)
-        // To create a new version of a versionable node N, the client calls N.checkin.
-        // This causes the following series of events:
-        InternalVersionHistory history = getInternalVersionHistory(node);
-
-        // 0. resolve the predecessors
-        Value[] values = node.getProperty(PROPNAME_PREDECESSORS).getValues();
-        InternalVersion[] preds = new InternalVersion[values.length];
-        for (int i = 0; i < values.length; i++) {
-            preds[i] = history.getVersion(values[i].getString());
+        try {
+            InternalVersion version = vMgr.checkin(node);
+            VirtualNodeState vhNode = (VirtualNodeState) virtProvider.getItemState(new NodeId(version.getVersionHistory().getId()));
+            mapVersion(vhNode, version);
+            // invalidate predecessors 'sucessors' properties
+            InternalVersion[] pred = version.getPredecessors();
+            for (int i=0; i<pred.length; i++) {
+                onVersionModified(pred[i]);
+            }
+            return (Version) node.getSession().getNodeByUUID(version.getId());
+        } catch (NoSuchItemStateException e) {
+            throw new RepositoryException(e);
         }
+    }
 
-        // 0.1 search a predecessor, suitable for generating the new name
-        String versionName = null;
-        int maxDots = Integer.MAX_VALUE;
-        for (int i = 0; i < preds.length; i++) {
-            // take the first pred. without a successor
-            if (preds[i].getSuccessors().length == 0) {
-                versionName = preds[i].getName().getLocalName(); //assuming no namespaces in version names
-                // need to count the dots
-                int pos = -1;
-                int numDots = 0;
-                while (versionName.indexOf('.', pos + 1) >= 0) {
-                    pos = versionName.indexOf('.', pos + 1);
-                    numDots++;
-                }
-                if (numDots < maxDots) {
-                    maxDots = numDots;
-                    versionName = pos < 0 ? "1.0" : versionName.substring(0, pos + 1) + (Integer.parseInt(versionName.substring(pos + 1)) + 1);
-                }
-                break;
+    /**
+     * Called when a internal version has changed its internal structure, and
+     * some of the properties has to be remapped to the content.
+     * @param v
+     * @throws RepositoryException
+     */
+    protected void onVersionModified(InternalVersion v) throws RepositoryException {
+        try {
+            VirtualNodeState ns = (VirtualNodeState) virtProvider.getItemState(new NodeId(v.getId()));
+            mapDynamicProperties(ns, v);
+        } catch (NoSuchItemStateException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     * Maps the version history and it's versions to the content representation.
+     * @param vh
+     * @throws RepositoryException
+     */
+    private void mapVersionHistory(InternalVersionHistory vh)
+            throws RepositoryException {
+        try {
+            String uuid = vh.getId();
+            VirtualNodeState parent = historyRoot;
+            QName historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid.substring(0, 2));
+            if (!parent.hasChildNodeEntry(historyNodeName)) {
+                parent = virtProvider.addNode(parent, historyNodeName, null, NodeTypeRegistry.NT_UNSTRUCTURED, null);
+            } else {
+                parent = virtProvider.getNode(parent, historyNodeName, 1);
+            }
+            historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid.substring(2, 4));
+            if (!parent.hasChildNodeEntry(historyNodeName)) {
+                parent = virtProvider.addNode(parent, historyNodeName, null, NodeTypeRegistry.NT_UNSTRUCTURED, null);
+            } else {
+                parent = virtProvider.getNode(parent, historyNodeName, 1);
+            }
+
+            historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid.substring(4));
+            VirtualNodeState vhNode = virtProvider.addNode(parent, historyNodeName, vh.getId(), NodeTypeRegistry.NT_VERSION_HISTORY, null);
+
+            // add the versions
+            Iterator iter = vh.getVersions();
+            while (iter.hasNext()) {
+                InternalVersion v = (InternalVersion) iter.next();
+                mapVersion(vhNode, v);
+            }
+
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     * Maps the internal version to its respective content representation
+     * @param vhNode
+     * @param version
+     * @throws RepositoryException
+     */
+    private void mapVersion(VirtualNodeState vhNode, InternalVersion version)
+            throws RepositoryException {
+        try {
+            VirtualNodeState vNode = virtProvider.addNode(vhNode, version.getName(), version.getId(), NodeTypeRegistry.NT_VERSION, null);
+
+            // initialize the version
+            virtProvider.setPropertyValue(vNode, VersionManager.PROPNAME_CREATED, InternalValue.create(version.getCreated()));
+
+            // initialize the primary properties
+            InternalFrozenNode fNode = version.getFrozenNode();
+            virtProvider.setPropertyValue(vNode, VersionManager.PROPNAME_FROZEN_UUID, InternalValue.create(fNode.getFrozenUUID()));
+            virtProvider.setPropertyValue(vNode, VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE, InternalValue.create(fNode.getFrozenPrimaryType()));
+            virtProvider.setPropertyValues(vNode, VersionManager.PROPNAME_FROZEN_MIXIN_TYPES, PropertyType.NAME, InternalValue.create(fNode.getFrozenMixinTypes()));
+
+            // map dynamic ones
+            mapDynamicProperties(vNode, version);
+
+            if (!version.isRootVersion()) {
+                // don't map for root verion
+                mapFrozenNode(vNode, PersistentVersionManager.NODENAME_FROZEN, fNode);
             }
+
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
         }
-        // if no empty found, generate new name
-        if (versionName == null) {
-            versionName = preds[0].getName().getLocalName();
-            do {
-                versionName += ".1";
-            } while (history.hasVersion(new QName("", versionName)));
+    }
+
+    /**
+     * Maps those properties of the internal version to the content that might
+     * change over time. such as labels and successors.
+     * @param vNode
+     * @param version
+     * @throws RepositoryException
+     */
+    private void mapDynamicProperties(VirtualNodeState vNode, InternalVersion version) throws RepositoryException {
+        // add version labels
+        virtProvider.setPropertyValues(vNode, VersionManager.PROPNAME_VERSION_LABELS, PropertyType.STRING, InternalValue.create(version.internalGetLabels()));
+
+        // add predecessors
+        InternalVersion[] preds = version.getPredecessors();
+        InternalValue[] predV = new InternalValue[preds.length];
+        for (int i=0; i<preds.length; i++) {
+            predV[i] = InternalValue.create(new UUID(preds[i].getId()));
         }
+        virtProvider.setPropertyValues(vNode, VersionManager.PROPNAME_PREDECESSORS, PropertyType.REFERENCE, predV);
 
-        InternalVersion v = history.checkin(new QName("", versionName), node);
-        return new VersionImpl(node.getSession(), v);
+        // add successors
+        InternalVersion[] succ= version.getSuccessors();
+        InternalValue[] succV = new InternalValue[succ.length];
+        for (int i=0; i<succ.length; i++) {
+            succV[i] = InternalValue.create(new UUID(succ[i].getId()));
+        }
+        virtProvider.setPropertyValues(vNode, VersionManager.PROPNAME_SUCCESSORS, PropertyType.REFERENCE, succV);
     }
 
+    /**
+     * Maps the frozen content of an internal version to the content
+     * representation.
+     * @param parent
+     * @param name
+     * @param fNode
+     * @throws RepositoryException
+     */
+    private void mapFrozenNode(VirtualNodeState parent, QName name, InternalFrozenNode fNode) throws RepositoryException {
+        try {
+            VirtualNodeState node = virtProvider.addNode(parent, name, null, fNode.getFrozenPrimaryType(), fNode.getFrozenMixinTypes());
+
+            // initialize the content
+            PersistentProperty[] props = fNode.getFrozenProperties();
+            for (int i=0; i<props.length; i++) {
+                virtProvider.setPropertyValues(node, props[i].getName(), props[i].getType(), props[i].getValues(), props[i].isMultiple());
+            }
+            InternalFreeze[] freezes = fNode.getFrozenChildNodes();
+            for (int i=0; i<freezes.length; i++) {
+                if (freezes[i] instanceof InternalFrozenVersionHistory) {
+                    InternalFrozenVersionHistory vh = (InternalFrozenVersionHistory) freezes[i];
+                    VirtualNodeState fChild = virtProvider.addNode(node.getId(), vh.getName(), null, NodeTypeRegistry.NT_FROZEN_VERSIONABLE_CHILD);
+                    virtProvider.setPropertyValue(fChild, VersionManager.PROPNAME_VERSION_HISTORY, InternalValue.create(UUID.fromString(vh.getVersionHistoryId())));
+                } else { // instance of InternalFrozenNode
+                    InternalFrozenNode fn = (InternalFrozenNode) freezes[i];
+                    mapFrozenNode(node, fn.getName(), fn);
+                }
+            }
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
+
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/package.html
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/package.html	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/package.html	Tue Oct 26 08:44:46 2004
@@ -1,14 +1,25 @@
 <body>
-The version storage is currently implement using the normal storage of the
-repository. For performance and scalability reasons, it will be probably
-stored externally later.<br>
-A lot of the versioning functionality is handled in the NodeImpl or VersionImpl
-itself, since it operates on internal properties and node of that nodes. This
-also might move to another class, eg. the VersionManager later.<br>
+The versioning framework in jackrabbit consists of 3 layers. A persistence layer,
+an application layer and an presentation layer.<p>
+The persistence layer uses a 'normal' workspace as storage. The storage can later
+be exchanged by a more scaleable one. The application layer operates on the
+persistent one and provides the internal view of the version storage. It is
+manifested through the <code>InternalVersion</code> and
+<code>InternalVersionHistory</code> objects. The
+<code>PersistentVersionManager</code> is responsible for those 2 layers.<p>
+The internal versions are also mapped to the content and exposed through the
+API (i.e. the <code>Version</code> extends <code>Node</code> and can be inspected
+with normal Node methods). Furthermore the version store is also exposed below
+<code>/jcr:system/jcr:versionStorage</code>. The exact structure of it is not
+defined yet, so applications should not relay on it and rather use
+<code>Node.getVersionHistory()</code> to access a particular version history or
+use the search mechanisms to find the respective versions.<p>
+The presentation layer is managed by the <code>VersionManager</code>. it is
+responsible for mapping the version storage to the content.
 <p>
 Open issues:
 <ul>
 <li>consider multi-threading behaviour
 </ul>
 
-</body>
\ No newline at end of file
+</body>

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/DefaultItemStateProvider.java
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/DefaultItemStateProvider.java	Tue Oct 26 08:44:46 2004
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.virtual;
+
+import org.apache.jackrabbit.core.state.*;
+import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.nodetype.*;
+import org.apache.jackrabbit.core.util.uuid.UUID;
+import org.apache.log4j.Logger;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Arrays;
+
+/**
+ * This Class implements a virtual item state provider.
+ *
+ * @author tripod
+ * @version $Revision:$, $Date:$
+ */
+public class DefaultItemStateProvider implements VirtualItemStateProvider {
+
+    /**
+     * the default logger
+     */
+    private static Logger log = Logger.getLogger(DefaultItemStateProvider.class);
+
+    /**
+     * the nodetype manager that is used by this provider
+     */
+    private final NodeTypeManagerImpl ntMgr;
+
+    /**
+     * the virtual root state of this provider (does not have to be /)
+     */
+    private final VirtualNodeState rootState;
+
+    /**
+     * the items of this provider
+     */
+    private final HashMap items = new HashMap();
+
+    /**
+     * Creates a new item state provider.
+     * @param ntMgr the nodetype manager
+     * @param overlayedRoot the node state that is overlayed
+     */
+    public DefaultItemStateProvider(NodeTypeManagerImpl ntMgr, NodeState overlayedRoot) {
+        this.ntMgr = ntMgr;
+        rootState = new VirtualNodeState(overlayedRoot);
+        items.put(rootState.getId(), rootState);
+    }
+
+    /**
+     * Returns the nodestate of the relative root of this provider
+     * @return
+     */
+    public VirtualNodeState getRootState() {
+        return rootState;
+    }
+
+    /**
+     * @see ItemStateProvider#getItemState(org.apache.jackrabbit.core.ItemId)
+     */
+    public ItemState getItemState(ItemId id) throws NoSuchItemStateException {
+        ItemState state = (ItemState) items.get(id);
+        if (state==null) {
+            throw new NoSuchItemStateException(id.toString());
+        }
+        return state;
+    }
+
+    /**
+     * @see ItemStateProvider#hasItemState(org.apache.jackrabbit.core.ItemId)
+     */
+    public boolean hasItemState(ItemId id) {
+        return items.containsKey(id);
+    }
+
+    /**
+     * virtual item state provider do not have attics.
+     * @throws NoSuchItemStateException always
+     */
+    public ItemState getItemStateInAttic(ItemId id) throws NoSuchItemStateException {
+        // never has states in attic
+        throw new NoSuchItemStateException(id.toString());
+    }
+
+    /**
+     * virtual item state provider do not have attics.
+     * @return <code>false</code>
+     */
+    public boolean hasItemStateInAttic(ItemId id) {
+        // never has states in attic
+        return false;
+    }
+
+    /**
+     * Adds a node state
+     * @param parentId
+     * @param name
+     * @param id
+     * @param nodeType
+     * @return
+     * @throws ItemStateException
+     * @throws RepositoryException
+     */
+    public VirtualNodeState addNode(ItemId parentId, QName name, String id, QName nodeType)
+            throws ItemStateException, RepositoryException {
+        if (!(parentId instanceof NodeId)) {
+            throw new ItemStateException("Parent must be a node");
+        }
+        VirtualNodeState parent = (VirtualNodeState) getItemState(parentId);
+        return addNode(parent, name, id, nodeType, null);
+    }
+
+    /**
+     * Adds a node state
+     * @param parent
+     * @param name
+     * @param id
+     * @param nodeTypeName
+     * @param mixins
+     * @return
+     * @throws ItemStateException
+     * @throws RepositoryException
+     */
+    public VirtualNodeState addNode(VirtualNodeState parent, QName name, String id, QName nodeTypeName, QName[] mixins)
+            throws ItemStateException, RepositoryException {
+        NodeTypeImpl nodeType = nodeTypeName==null ? null : ntMgr.getNodeType(nodeTypeName);
+        NodeDefImpl def;
+        try {
+            def = getApplicableChildNodeDef(parent, name, nodeType == null ? null : nodeType.getQName());
+        } catch (RepositoryException re) {
+            String msg = "no definition found in parent node's node type for new node";
+            throw new ConstraintViolationException(msg, re);
+        }
+        if (nodeType == null) {
+            // use default node type
+            nodeType = (NodeTypeImpl) def.getDefaultPrimaryType();
+        }
+
+        // default properties
+        VirtualNodeState ns = createChildNode(parent, name, def, nodeType, id);
+        setPropertyValue(ns, ItemImpl.PROPNAME_PRIMARYTYPE, InternalValue.create(nodeType.getQName()));
+        if (mixins!=null) {
+            ns.setMixinTypeNames(new HashSet(Arrays.asList(mixins)));
+        }
+        if (getEffectiveNodeType(ns).includesNodeType(NodeTypeRegistry.MIX_REFERENCEABLE)) {
+            setPropertyValue(ns, ItemImpl.PROPNAME_UUID, InternalValue.create(ns.getUUID()));
+        }
+        items.put(ns.getId(), ns);
+        return ns;
+    }
+
+    /**
+     * returns the child node of the given parent
+     * @param parent
+     * @param name
+     * @param index
+     * @return
+     * @throws NoSuchItemStateException
+     */
+    public VirtualNodeState getNode(VirtualNodeState parent, QName name, int index) throws NoSuchItemStateException {
+        NodeState.ChildNodeEntry entry = parent.getChildNodeEntry(name, index);
+        if (entry==null) {
+            throw new NoSuchItemStateException(name.toString());
+        }
+        return (VirtualNodeState) getItemState(new NodeId(entry.getUUID()));
+    }
+
+    /**
+     * Sets the property value
+     *
+     * @param name
+     * @param value
+     * @throws RepositoryException
+     */
+    public void setPropertyValue(VirtualNodeState parentState, QName name, InternalValue value)
+            throws RepositoryException {
+        setPropertyValues(parentState, name, value.getType(), new InternalValue[]{value}, false);
+    }
+
+    /**
+     * Sets the property values
+     *
+     * @param name
+     * @param type
+     * @param values
+     * @throws RepositoryException
+     */
+    public void setPropertyValues(VirtualNodeState parentState, QName name, int type, InternalValue[] values)
+            throws RepositoryException {
+        setPropertyValues(parentState, name, type, values, true);
+    }
+
+    /**
+     * Sets the property values
+     *
+     * @param name
+     * @param type
+     * @param values
+     * @throws RepositoryException
+     */
+    public void setPropertyValues(VirtualNodeState parentState, QName name, int type, InternalValue[] values, boolean multiple)
+            throws RepositoryException {
+        VirtualPropertyState prop = getOrCreatePropertyState(parentState, name, type, multiple);
+        prop.setValues(values);
+    }
+
+    /**
+     * creates a new child node
+     *
+     * @param name
+     * @param def
+     * @param nodeType
+     * @param uuid
+     * @return
+     */
+    private VirtualNodeState createChildNode(VirtualNodeState parentState,
+                                             QName name, NodeDefImpl def,
+                                             NodeTypeImpl nodeType, String uuid) {
+
+        String parentUUID = parentState.getUUID();
+        // create a new node state
+        VirtualNodeState state = null;
+        if (uuid == null) {
+            uuid = UUID.randomUUID().toString();
+        }
+        state = new VirtualNodeState(uuid, nodeType.getQName(), parentUUID);
+        state.setDefinitionId(new NodeDefId(def.unwrap()));
+
+        // add new child node entry
+        parentState.addChildNodeEntry(name, state.getUUID());
+
+        return state;
+    }
+
+    /**
+     * Retrieves or creates a new property state as child property of this node
+     *
+     * @param name
+     * @param type
+     * @param multiValued
+     * @return
+     * @throws RepositoryException
+     */
+    private VirtualPropertyState getOrCreatePropertyState(VirtualNodeState parentState, QName name, int type, boolean multiValued)
+            throws RepositoryException {
+
+        PropertyId propId = new PropertyId(parentState.getUUID(), name);
+        if (hasItemState(propId)) {
+            try {
+                return (VirtualPropertyState) getItemState(propId);
+            } catch (ItemStateException e) {
+                throw new RepositoryException("Unable to create property: " + e.toString());
+            }
+        } else {
+            try {
+                PropertyDefImpl def = getApplicablePropertyDef(parentState, name, type, multiValued);
+                VirtualPropertyState propState = createPropertyState(parentState.getUUID(), name);
+                propState.setType(type);
+                propState.setDefinitionId(new PropDefId(def.unwrap()));
+                parentState.addPropertyEntry(name);
+                return propState;
+            } catch (ItemStateException e) {
+                throw new RepositoryException("Unable to store property: " + e.toString());
+            }
+        }
+    }
+
+    /**
+     * Creates a property state
+     * @param parentUUID
+     * @param propName
+     * @return
+     * @throws ItemStateException
+     */
+    private VirtualPropertyState createPropertyState(String parentUUID, QName propName) throws ItemStateException {
+        PropertyId id = new PropertyId(parentUUID, propName);
+        // check cache
+        if (hasItemState(id)) {
+            String msg = "there's already a property state instance with id " + id;
+            log.error(msg);
+            throw new ItemStateException(msg);
+        }
+
+        VirtualPropertyState propState = new VirtualPropertyState(propName, parentUUID);
+        items.put(id, propState);
+        return propState;
+
+    }
+    /**
+     * retrieves the property definition for the given contraints
+     *
+     * @param propertyName
+     * @param type
+     * @param multiValued
+     * @return
+     * @throws javax.jcr.RepositoryException
+     */
+    protected PropertyDefImpl getApplicablePropertyDef(VirtualNodeState parentState, QName propertyName,
+                                                       int type, boolean multiValued)
+            throws RepositoryException {
+        PropDef pd = getEffectiveNodeType(parentState).getApplicablePropertyDef(propertyName, type, multiValued);
+        return ntMgr.getPropDef(new PropDefId(pd));
+    }
+
+    /**
+     * Retrieves the node definition for the given contraints.
+     *
+     * @param nodeName
+     * @param nodeTypeName
+     * @return
+     * @throws RepositoryException
+     */
+    protected NodeDefImpl getApplicableChildNodeDef(VirtualNodeState parentState, QName nodeName, QName nodeTypeName)
+            throws RepositoryException {
+        ChildNodeDef cnd = getEffectiveNodeType(parentState).getApplicableChildNodeDef(nodeName, nodeTypeName);
+        return ntMgr.getNodeDef(new NodeDefId(cnd));
+    }
+
+    /**
+     * Returns the effective (i.e. merged and resolved) node type representation
+     * of this node's primary and mixin node types.
+     *
+     * @return the effective node type
+     * @throws RepositoryException
+     */
+    protected EffectiveNodeType getEffectiveNodeType(VirtualNodeState nodeState) throws RepositoryException {
+        // build effective node type of mixins & primary type
+        NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+        // existing mixin's
+        HashSet set = new HashSet(nodeState.getMixinTypeNames());
+        // primary type
+        set.add(nodeState.getNodeTypeName());
+        try {
+            return ntReg.buildEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
+        } catch (NodeTypeConflictException ntce) {
+            String msg = "internal error: failed to build effective node type for node " + nodeState.getUUID();
+            throw new RepositoryException(msg, ntce);
+        }
+    }
+
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java	Tue Oct 26 08:44:46 2004
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.virtual;
+
+import org.apache.jackrabbit.core.state.ItemStateProvider;
+/**
+ * This Interface defines a virtual item state provide.
+ *
+ * @author tripod
+ * @version $Revision:$, $Date:$
+ */
+public interface VirtualItemStateProvider extends ItemStateProvider {
+
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java	Tue Oct 26 08:44:46 2004
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.virtual;
+
+import org.apache.jackrabbit.core.state.*;
+import org.apache.jackrabbit.core.QName;
+
+/**
+ * This Class implements a virtual node state
+ *
+ * @author tripod
+ * @version $Revision:$, $Date:$
+ */
+public class VirtualNodeState extends NodeState {
+
+    /**
+     *
+     * @param uuid
+     * @param nodeTypeName
+     * @param parentUUID
+     */
+    protected VirtualNodeState(String uuid, QName nodeTypeName, String parentUUID) {
+        super(uuid, nodeTypeName, parentUUID, ItemState.STATUS_EXISTING_VIRTUAL);
+    }
+
+    /**
+     *
+     * @param overlayedState
+     */
+    protected VirtualNodeState(NodeState overlayedState) {
+        super(overlayedState, ItemState.STATUS_EXISTING_VIRTUAL);
+    }
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java	Tue Oct 26 08:44:46 2004
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.virtual;
+
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.QName;
+
+/**
+ * This Class implements a virtual property state
+ *
+ * @author tripod
+ * @version $Revision:$, $Date:$
+ */
+public class VirtualPropertyState extends PropertyState {
+
+    /**
+     *
+     * @param name
+     * @param parentUUID
+     */
+    public VirtualPropertyState(QName name, String parentUUID) {
+        super(name, parentUUID, ItemState.STATUS_EXISTING);
+    }
+
+}