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/12/20 11:29:47 UTC

svn commit: r122838 - in incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core: . nodetype version version/persistence virtual

Author: tripod
Date: Mon Dec 20 02:29:45 2004
New Revision: 122838

URL: http://svn.apache.org/viewcvs?view=rev&rev=122838
Log:
- improved versioning
Added:
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionItem.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFreezeImpl.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFrozenNodeImpl.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFrozenVHImpl.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionHistoryImpl.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionImpl.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionItemImpl.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/NativePVM.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/PersistentNode.java   (contents, props changed)
Removed:
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentNode.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentProperty.java
Modified:
   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/version/HistoryRootNodeState.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/PersistentVersionManager.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryNodeState.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionNodeState.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java	Mon Dec 20 02:29:45 2004
@@ -20,6 +20,10 @@
 import org.apache.jackrabbit.core.nodetype.PropDefId;
 import org.apache.jackrabbit.core.nodetype.NodeDefId;
 import org.apache.jackrabbit.core.state.*;
+import org.apache.jackrabbit.core.version.InternalVersionHistory;
+import org.apache.jackrabbit.core.version.VersionHistoryImpl;
+import org.apache.jackrabbit.core.version.InternalVersion;
+import org.apache.jackrabbit.core.version.VersionImpl;
 import org.apache.log4j.Logger;
 
 import javax.jcr.*;
@@ -586,9 +590,13 @@
 
         // check special nodes
         if (state.getNodeTypeName().equals(NodeTypeRegistry.NT_VERSION)) {
-            return session.versionMgr.createVersionInstance(session, state, def, this, listeners);
+            InternalVersion version = session.versionMgr.getVersion(state.getUUID());
+            return new VersionImpl(this, session, id, state, def, listeners, version);
+
         } else if (state.getNodeTypeName().equals(NodeTypeRegistry.NT_VERSION_HISTORY)) {
-            return session.versionMgr.createVersionHistoryInstance(session, state, def, this, listeners);
+            InternalVersionHistory history = session.versionMgr.getVersionHistory(state.getUUID());
+            return new VersionHistoryImpl(this, session, id, state, def, listeners, history);
+
         } else {
             // create node object
             return new NodeImpl(this, session, id, state, def, listeners);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java	Mon Dec 20 02:29:45 2004
@@ -2795,10 +2795,10 @@
         }
 
         // copy frozen properties
-        PersistentProperty[] props = freeze.getFrozenProperties();
+        PropertyState[] props = freeze.getFrozenProperties();
         HashSet propNames = new HashSet();
         for (int i = 0; i < props.length; i++) {
-            PersistentProperty prop = props[i];
+            PropertyState prop = props[i];
             propNames.add(prop.getName());
             if (prop.getValues().length == 1) {
                 try {

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java	Mon Dec 20 02:29:45 2004
@@ -31,6 +31,9 @@
 import org.apache.jackrabbit.core.state.tx.XASessionImpl;
 import org.apache.jackrabbit.core.util.uuid.UUID;
 import org.apache.jackrabbit.core.version.PersistentVersionManager;
+import org.apache.jackrabbit.core.version.VersionManager;
+import org.apache.jackrabbit.core.version.VersionManagerImpl;
+import org.apache.jackrabbit.core.version.persistence.NativePVM;
 import org.apache.log4j.Logger;
 
 import javax.jcr.*;
@@ -83,7 +86,8 @@
 
     private final NamespaceRegistryImpl nsReg;
     private final NodeTypeRegistry ntReg;
-    private final PersistentVersionManager vMgr;
+    private final PersistentVersionManager pvMgr;
+    private final VersionManager vMgr;
     private final TransactionManager txMgr;
 
     // configuration of the repository
@@ -282,7 +286,8 @@
         // init version manager
         // todo: as soon as dynamic workspaces are available, base on system ws
         SessionImpl verSession = getSystemSession(repConfig.getDefaultWorkspaceName());
-        vMgr = new PersistentVersionManager(verSession);
+        pvMgr = new NativePVM(verSession);
+        vMgr = new VersionManagerImpl(pvMgr);
 
         // load repository properties
         repProps = new Properties();
@@ -362,7 +367,7 @@
         return ntReg;
     }
 
-    PersistentVersionManager getPersistentVersionManager() {
+    VersionManager getVersionManager() {
         // 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
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java	Mon Dec 20 02:29:45 2004
@@ -22,6 +22,7 @@
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PersistentItemStateProvider;
 import org.apache.jackrabbit.core.state.SessionItemStateManager;
+import org.apache.jackrabbit.core.version.VersionManagerImpl;
 import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.jackrabbit.core.xml.ImportHandler;
 import org.apache.log4j.Logger;
@@ -158,7 +159,7 @@
         hierMgr = itemStateMgr.getHierarchyMgr();
         itemMgr = createItemManager(itemStateMgr, hierMgr);
         accessMgr = createAccessManager(credentials, hierMgr);
-        versionMgr = rep.getPersistentVersionManager() == null ? null : rep.getPersistentVersionManager().getVersionManager(wsp);
+        versionMgr = rep.getVersionManager();
 
         // add virtual item managers only for normal sessions
         if (!(this instanceof SystemSession)) {
@@ -190,7 +191,7 @@
         itemStateMgr = new SessionItemStateManager(rep.getRootNodeUUID(), wsp.getPersistentStateManager(), getNamespaceResolver());
         hierMgr = itemStateMgr.getHierarchyMgr();
         itemMgr = createItemManager(itemStateMgr, hierMgr);
-        versionMgr = rep.getPersistentVersionManager() == null ? null : rep.getPersistentVersionManager().getVersionManager(wsp);
+        versionMgr = rep.getVersionManager();
 
         // add virtual item managers only for normal sessions
         if (!(this instanceof SystemSession)) {

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml&r2=122838
==============================================================================
--- 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	Mon Dec 20 02:29:45 2004
@@ -104,7 +104,7 @@
         </supertypes>
         <propertyDef name="jcr:encoding" type="String" autoCreate="false" mandatory="false" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
         <propertyDef name="jcr:mimeType" type="String" autoCreate="false" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
-        <propertyDef name="jcr:data" type="Binary" autoCreate="false" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="true" multiple="false"/>
+        <propertyDef name="jcr:data" type="Binary" autoCreate="false" mandatory="false" onParentVersion="COPY" protected="false" primaryItem="true" multiple="false"/>
         <propertyDef name="jcr:lastModified" type="Date" autoCreate="true" mandatory="true" onParentVersion="COMPUTE" protected="false" primaryItem="false" multiple="false"/>
     </nodeType>
     <nodeType name="nt:folder" mixin="false" orderableChildNodes="false">
@@ -295,6 +295,22 @@
                 <requiredPrimaryType>nt:base</requiredPrimaryType>
             </requiredPrimaryTypes>
         </childNodeDef>
+    </nodeType>
+    <!-- internal nodetypes for persistent version manager -->
+    <nodeType name="rep:versionHistory" mixin="false" orderableChildNodes="false">
+        <supertypes>
+            <supertype>nt:unstructured</supertype>
+        </supertypes>
+    </nodeType>
+    <nodeType name="rep:version" mixin="false" orderableChildNodes="false">
+        <supertypes>
+            <supertype>nt:unstructured</supertype>
+        </supertypes>
+    </nodeType>
+    <nodeType name="rep:frozen" mixin="false" orderableChildNodes="true">
+        <supertypes>
+            <supertype>nt:unstructured</supertype>
+        </supertypes>
     </nodeType>
 
 </nodeTypes>

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/HistoryRootNodeState.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/HistoryRootNodeState.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/HistoryRootNodeState.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/HistoryRootNodeState.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/HistoryRootNodeState.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/HistoryRootNodeState.java	Mon Dec 20 02:29:45 2004
@@ -17,41 +17,73 @@
 
 import org.apache.jackrabbit.core.NamespaceRegistryImpl;
 import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.version.VersionManager;
+import org.apache.jackrabbit.core.version.InternalVersionHistory;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.virtual.VirtualNodeState;
 
 import javax.jcr.RepositoryException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
+import java.util.Iterator;
 
 /**
- * This Class implements...
+ * The history root node state represents the root node of all version histories.
+ * the version histories are dynamically exposed. since there could be very many,
+ * it does not return all the child nodes by the {@link #getChildNodeEntries()}}
+ * method. this implies, that the version storage is not browsable, but the
+ * nodes are nevertheless correctly exposed (this behaviour can be changed, by
+ * modifying the compile-time constant {@link #LIST_ALL_HISTORIES}.
  */
 public class HistoryRootNodeState extends VirtualNodeState {
 
-    private VersionManager vm;
-
-    public HistoryRootNodeState(VersionItemStateProvider vm, String uuid, String parentUUID) {
-        super(vm, uuid, NodeTypeRegistry.NT_UNSTRUCTURED, parentUUID);
-        this.vm = vm.getVersionManager();
-
-        setDefinitionId(vm.getNodeDefId(VersionManager.NODENAME_HISTORY_ROOT));
-    }
-
+    /**
+     * flag for listing all histories
+     */
+    private static final boolean LIST_ALL_HISTORIES = true;
+
+    /**
+     * the version manager
+     */
+    private final VersionManager vm;
+
+    /**
+     * creates a new history root state
+     * @param stateMgr
+     * @param parentUUID
+     * @param uuid
+     * @throws RepositoryException
+     */
+    protected HistoryRootNodeState(VersionItemStateProvider stateMgr,
+                                   VersionManager vm,
+                                String parentUUID,
+                                String uuid) throws RepositoryException {
+        super(stateMgr, parentUUID, uuid, NodeTypeRegistry.NT_UNSTRUCTURED, new QName[0]);
+        this.vm = vm;
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#hasChildNodeEntry(org.apache.jackrabbit.core.QName)
+     */
     public synchronized boolean hasChildNodeEntry(QName name) {
-        return vm.hasVersionHistory(name);
+        return vm.hasVersionHistory(name.getLocalName());
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#hasChildNodeEntry(org.apache.jackrabbit.core.QName, int)
+     */
     public synchronized boolean hasChildNodeEntry(QName name, int index) {
-        return index <= 1 ? vm.hasVersionHistory(name) : false;
+        return index <= 1 ? vm.hasVersionHistory(name.getLocalName()) : false;
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#getChildNodeEntry(org.apache.jackrabbit.core.QName, int)
+     */
     public synchronized ChildNodeEntry getChildNodeEntry(QName nodeName, int index) {
         try {
             if (index <= 1) {
-                InternalVersionHistory hist = vm.getVersionHistory(nodeName);
+                InternalVersionHistory hist = vm.getVersionHistory(nodeName.getLocalName());
                 return new ChildNodeEntry(nodeName, hist.getId(), 1);
             }
         } catch (RepositoryException e) {
@@ -60,22 +92,30 @@
         return null;
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#getChildNodeEntries()
+     */
     public synchronized List getChildNodeEntries() {
-        try {
-            ArrayList list = new ArrayList(vm.getNumVersionHistories());
-            Iterator iter = vm.getVersionHistories();
-            while (iter.hasNext()) {
-                InternalVersionHistory vh = (InternalVersionHistory) iter.next();
-                QName name = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, vh.getId());
-                list.add(new ChildNodeEntry(name, vh.getId(), 1));
+        if (LIST_ALL_HISTORIES) {
+            try {
+                ArrayList list = new ArrayList(vm.getNumVersionHistories());
+                Iterator iter = vm.getVersionHistoryIds();
+                while (iter.hasNext()) {
+                    String id = (String) iter.next();
+                    QName name = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, id);
+                    list.add(new ChildNodeEntry(name, id, 1));
+                }
+                return list;
+            } catch (RepositoryException e) {
+                // ignore
             }
-            return list;
-        } catch (RepositoryException e) {
-            // ignore
         }
         return Collections.EMPTY_LIST;
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#getChildNodeEntries(String)
+     */
     public synchronized List getChildNodeEntries(String uuid) {
         // todo: do nicer
         try {
@@ -91,6 +131,9 @@
         return Collections.EMPTY_LIST;
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#getChildNodeEntries(org.apache.jackrabbit.core.QName)
+     */
     public synchronized List getChildNodeEntries(QName nodeName) {
         // todo: do nicer
         try {
@@ -105,6 +148,4 @@
         }
         return Collections.EMPTY_LIST;
     }
-
-
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFreeze.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFreeze.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFreeze.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFreeze.java&r2=122838
==============================================================================
--- 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	Mon Dec 20 02:29:45 2004
@@ -18,42 +18,15 @@
 import org.apache.jackrabbit.core.QName;
 
 /**
- * Abstract class that represents either a frozen child or a frozen versionable
- * node.
+ * the base interface for nodes that were versioned and turned either into
+ * InternalFrozenNode or InteralFrozenVersionHistory.
  */
-public abstract class InternalFreeze {
+public interface InternalFreeze extends InternalVersionItem {
 
     /**
-     * the parent 'freeze'
+     * returns the name of the node.
+     * @return the name of the node.
      */
-    private final InternalFreeze parent;
+    public QName getName();
 
-    /**
-     * 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
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java&r2=122838
==============================================================================
--- 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	Mon Dec 20 02:29:45 2004
@@ -16,321 +16,51 @@
 package org.apache.jackrabbit.core.version;
 
 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;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.version.OnParentVersionAction;
-import java.util.ArrayList;
-import java.util.List;
+import org.apache.jackrabbit.core.state.PropertyState;
+import javax.jcr.version.VersionException;
 
 /**
- * The InternalFrozenNode class presents the frozen node that was generated
+ * The InternalFrozenNode interface represents the frozen node that was generated
  * during a {@link javax.jcr.Node#checkin()}. It holds the set of frozen
  * properties, the frozen child nodes and the frozen version history
  * references of the original node.
  */
-public class InternalFrozenNode extends InternalFreeze {
-
-    private static final boolean FREEZEMODE_CLONE = true;
-
-    /**
-     * the underlaying persistance node
-     */
-    private PersistentNode node;
-
-    /**
-     * the list of frozen child nodes
-     */
-    private InternalFreeze[] frozenChildNodes;
-
-    /**
-     * the list of frozen properties
-     */
-    private PersistentProperty[] frozenProperties;
-
-    /**
-     * the frozen uuid of the original node
-     */
-    private String frozenUUID = null;
-
-    /**
-     * the frozen primary type of the orginal node
-     */
-    private QName frozenPrimaryType = null;
-
-    /**
-     * the frozen list of mixin types of the original node
-     */
-    private QName[] frozenMixinTypes = null;
-
-    /**
-     * uuid of this node
-     */
-    private String uuid;
-
-    /**
-     * Creates a new frozen node based on the given persistance node.
-     *
-     * @param node
-     * @throws RepositoryException
-     */
-    protected InternalFrozenNode(InternalFreeze parent, PersistentNode node) throws RepositoryException {
-        super(parent);
-        this.node = node;
-
-        // init the frozen properties
-        PersistentProperty[] props = node.getProperties();
-        List propList = new ArrayList();
-
-        for (int i = 0; i < props.length; i++) {
-            PersistentProperty prop = props[i];
-            if (FREEZEMODE_CLONE) {
-                if (prop.getName().equals(ItemImpl.PROPNAME_PRIMARYTYPE)) {
-                    frozenPrimaryType = (QName) node.getPropertyValue(prop.getName()).internalValue();
-                } else if (prop.getName().equals(ItemImpl.PROPNAME_UUID)) {
-                    frozenUUID = node.getPropertyValue(prop.getName()).toString();
-                } else if (prop.getName().equals(ItemImpl.PROPNAME_MIXINTYPES)) {
-                    InternalValue[] values = node.getPropertyValues(prop.getName());
-                    if (values == null) {
-                        frozenMixinTypes = new QName[0];
-                    } else {
-                        frozenMixinTypes = new QName[values.length];
-                        for (int j = 0; j < values.length; j++) {
-                            frozenMixinTypes[j] = (QName) values[j].internalValue();
-                        }
-                    }
-                } else {
-                    propList.add(prop);
-                }
-
-            } else {
-                if (prop.getName().equals(VersionManager.PROPNAME_FROZEN_UUID)) {
-                    // special property
-                    frozenUUID = node.getPropertyValue(VersionManager.PROPNAME_FROZEN_UUID).internalValue().toString();
-                } else if (prop.getName().equals(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE)) {
-                    // special property
-                    frozenPrimaryType = (QName) node.getPropertyValue(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE).internalValue();
-                } else if (prop.getName().equals(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES)) {
-                    // special property
-                    InternalValue[] values = node.getPropertyValues(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES);
-                    if (values == null) {
-                        frozenMixinTypes = new QName[0];
-                    } else {
-                        frozenMixinTypes = new QName[values.length];
-                        for (int j = 0; j < values.length; j++) {
-                            frozenMixinTypes[j] = (QName) values[j].internalValue();
-                        }
-                    }
-                } else if (prop.getName().equals(ItemImpl.PROPNAME_PRIMARYTYPE)) {
-                    // ignore
-                } else if (prop.getName().equals(ItemImpl.PROPNAME_UUID)) {
-                    // ignore
-                } else {
-                    propList.add(prop);
-                }
-            }
-        }
-        frozenProperties = (PersistentProperty[]) propList.toArray(new PersistentProperty[propList.size()]);
-
-        // do some checks
-        if (frozenMixinTypes == null) {
-            frozenMixinTypes = new QName[0];
-        }
-        if (frozenPrimaryType == null) {
-            throw new RepositoryException("Illegal frozen node. Must have 'frozenPrimaryType'");
-        }
-        // init the frozen child nodes
-        PersistentNode[] childNodes = node.getChildNodes();
-        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(this, childNodes[i]);
-            } else if (childNodes[i].hasProperty(VersionManager.PROPNAME_VERSION_HISTORY)) {
-                frozenChildNodes[i] = new InternalFrozenVersionHistory(this, childNodes[i]);
-            } else {
-                // unkown ?
-            }
-        }
-
-    }
-
-    public String getInternalUUID() {
-        return node.getUUID();
-    }
-
-    /**
-     * Returns the name of this frozen node
-     *
-     * @return
-     */
-    public QName getName() {
-        return node.getName();
-    }
-
-    /**
-     * Returns the UUID of this frozen node
-     *
-     * @return
-     */
-    public String getUUID() {
-        return node.getUUID();
-    }
+public interface InternalFrozenNode extends InternalFreeze {
 
     /**
      * Returns the list of frozen child nodes
      *
-     * @return
+     * @return an array of internal freezes
+     * @throws VersionException if the freezes cannot be retrieved
      */
-    public InternalFreeze[] getFrozenChildNodes() {
-        return frozenChildNodes;
-    }
+    public InternalFreeze[] getFrozenChildNodes() throws VersionException;
 
     /**
-     * Returns the list of frozen properties
+     * Returns the list of frozen properties.
      *
-     * @return
+     * @return an array of property states
      */
-    public PersistentProperty[] getFrozenProperties() {
-        return frozenProperties;
-    }
+    public PropertyState[] getFrozenProperties();
 
     /**
-     * Returns the frozen UUID
+     * Returns the frozen UUID.
      *
-     * @return
+     * @return the frozen uuid.
      */
-    public String getFrozenUUID() {
-        return frozenUUID;
-    }
+    public String getFrozenUUID();
 
     /**
-     * Returns the frozen primary type
+     * Returns the name of frozen primary type.
      *
-     * @return
+     * @return the name of the frozen primary type.
      */
-    public QName getFrozenPrimaryType() {
-        return frozenPrimaryType;
-    }
+    public QName getFrozenPrimaryType();
 
     /**
-     * Returns the list of the frozen mixin types
+     * Returns the list of names of the frozen mixin types.
      *
-     * @return
+     * @return the list of names of the frozen mixin types.
      */
-    public QName[] getFrozenMixinTypes() {
-        return frozenMixinTypes;
-    }
-
-    /**
-     * Checks-in a <code>src</code> node. It creates a new child node of
-     * <code>parent</code> with the given <code>name</code> and adds the
-     * source nodes properties according to their OPV value to the
-     * list of frozen properties. It creates frozen child nodes for each child
-     * node of <code>src</code> according to its OPV value.
-     *
-     * @param parent
-     * @param name
-     * @param src
-     * @return
-     * @throws RepositoryException
-     */
-    protected static PersistentNode checkin(PersistentNode parent, QName name, NodeImpl src, boolean initOnly, boolean forceCopy)
-            throws RepositoryException {
-
-        PersistentNode node;
-        if (FREEZEMODE_CLONE) {
-            // identiycopy
-            // create new node
-            NodeType[] mixins = src.getMixinNodeTypes();
-            QName[] mixinNames = new QName[mixins.length];
-            for (int i = 0; i < mixins.length; i++) {
-                mixinNames[i] = ((NodeTypeImpl) mixins[i]).getQName();
-            }
-            node = parent.addNode(name, ((NodeTypeImpl) src.getPrimaryNodeType()).getQName());
-            node.setMixinNodeTypes(mixinNames);
-
-        } else {
-            // emulated
-            // create new node
-            node = parent.addNode(name, NodeTypeRegistry.NT_UNSTRUCTURED);
-
-            // initialize the internal properties
-            if (src.isNodeType(NodeTypeRegistry.MIX_REFERENCEABLE)) {
-                node.setPropertyValue(VersionManager.PROPNAME_FROZEN_UUID, InternalValue.create(src.getUUID()));
-            }
-
-            node.setPropertyValue(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE,
-                    InternalValue.create(((NodeTypeImpl) src.getPrimaryNodeType()).getQName()));
-
-            if (src.hasProperty(NodeImpl.PROPNAME_MIXINTYPES)) {
-                NodeType[] mixins = src.getMixinNodeTypes();
-                InternalValue[] ivalues = new InternalValue[mixins.length];
-                for (int i = 0; i < mixins.length; i++) {
-                    ivalues[i] = InternalValue.create(((NodeTypeImpl) mixins[i]).getQName());
-                }
-                node.setPropertyValues(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES, PropertyType.NAME, ivalues);
-            }
-        }
-
-        if (!initOnly) {
-            // add the properties
-            PropertyIterator piter = src.getProperties();
-            while (piter.hasNext()) {
-                PropertyImpl prop = (PropertyImpl) piter.nextProperty();
-                int opv = forceCopy ? OnParentVersionAction.COPY : prop.getDefinition().getOnParentVersion();
-                switch (opv) {
-                    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();
-                int opv = forceCopy ? OnParentVersionAction.COPY : child.getDefinition().getOnParentVersion();
-                switch (opv) {
-                    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_FROZEN_VERSIONABLE_CHILD);
-                            newChild.setPropertyValue(VersionManager.PROPNAME_VERSION_HISTORY,
-                                    InternalValue.create(UUID.fromString(child.getVersionHistory().getUUID())));
-                            newChild.setPropertyValue(VersionManager.PROPNAME_BASE_VERSION,
-                                    InternalValue.create(UUID.fromString(child.getBaseVersion().getUUID())));
-                            break;
-                        }
-                        // else copy
-                    case OnParentVersionAction.COPY:
-                        checkin(node, child.getQName(), child, false, true);
-                        break;
-                }
-            }
-        }
-        parent.store();
-        return node;
-    }
+    public QName[] getFrozenMixinTypes();
 
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenVersionHistory.java&r2=122838
==============================================================================
--- 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	Mon Dec 20 02:29:45 2004
@@ -15,68 +15,46 @@
  */
 package org.apache.jackrabbit.core.version;
 
-import org.apache.jackrabbit.core.QName;
-
-import javax.jcr.RepositoryException;
+import javax.jcr.version.VersionException;
 
 /**
- * This Class represents a frozen versionable child node, that was created
+ * This interface defines a frozen versionable child node, that was created
  * during a {@link javax.jcr.Node#checkin()} with a OPV==Version node.
  */
-public class InternalFrozenVersionHistory extends InternalFreeze {
-
-    /**
-     * the underlaying persistence node
-     */
-    private PersistentNode node;
+public interface InternalFrozenVersionHistory extends InternalFreeze {
 
     /**
-     * Creates a new frozen version history.
+     * Returns the id of the version history that was assigned to the node at
+     * the time it was versioned.
      *
-     * @param node
+     * @return the id of the version history
      */
-    protected InternalFrozenVersionHistory(InternalFreeze parent, PersistentNode node) {
-        super(parent);
-        this.node = node;
-    }
+    public String getVersionHistoryId();
 
     /**
-     * Returns the name of this frozen version history
+     * Returns the version history that was assigned to the node at
+     * the time it was versioned.
      *
-     * @return
+     * @return the internal version history.
+     * @throws VersionException if the history cannot be retrieved.
      */
-    public QName getName() {
-        return node.getName();
-    }
+    public InternalVersionHistory getVersionHistory()
+            throws VersionException;
 
     /**
-     * Returns the version history that was versioned with this node.
+     * Returns the id of the base version that was assigned to the node at
+     * the time it was versioned.
      *
-     * @return
-     * @throws RepositoryException
+     * @return the id of the base version
      */
-    public String getVersionHistoryId()
-            throws RepositoryException {
-        return (String) node.getPropertyValue(VersionManager.PROPNAME_VERSION_HISTORY).internalValue();
-    }
+    public String getBaseVersionId();
 
     /**
-     * Returns the version history that was versioned with this node.
+     * Returns the base version that was assigned to the node at
+     * the time it was versioned.
      *
-     * @return
-     * @throws RepositoryException
+     * @return the inernal base version
+     * @throws VersionException if the version could not be retrieved
      */
-    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());
-    }
+    public InternalVersion getBaseVesion() throws VersionException;
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersion.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersion.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersion.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersion.java&r2=122838
==============================================================================
--- 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	Mon Dec 20 02:29:45 2004
@@ -15,229 +15,47 @@
  */
 package org.apache.jackrabbit.core.version;
 
-import org.apache.jackrabbit.core.InternalValue;
 import org.apache.jackrabbit.core.QName;
-import org.apache.jackrabbit.core.util.uuid.UUID;
-
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
 import javax.jcr.version.Version;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Calendar;
-import java.util.HashSet;
 
 /**
- * This Class implements the Version representation of the node.
+ * This interface defines the internal version.
  */
-public final class InternalVersion extends InternalFreeze {
-
-    /**
-     * the list/cache of predecessors (values == InternalVersion)
-     */
-    private ArrayList predecessors = new ArrayList();
-
-    /**
-     * the list of successors (values == InternalVersion)
-     */
-    private ArrayList successors = new ArrayList();
-
-    /**
-     * the internal version history that this version is contained in
-     */
-    private InternalVersionHistory versionHistory;
-
-    /**
-     * the underlaying persistance node of this history
-     */
-    private PersistentNode node;
-
-    /**
-     * the date when this version was created
-     */
-    private Calendar created;
-
-    /**
-     * the set of version labes of this history (values == String)
-     */
-    private HashSet labelCache = null;
-
-    /**
-     * 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
-     *
-     * @param vh
-     * @param node
-     */
-    InternalVersion(InternalVersionHistory vh, PersistentNode node) {
-        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();
-
-        // init internal values
-        InternalValue[] values = node.getPropertyValues(VersionManager.PROPNAME_CREATED);
-        if (values != null) {
-            created = (Calendar) values[0].internalValue();
-        }
-    }
-
-    /**
-     * Returns the uuid of this version
-     *
-     * @return
-     */
-    public String getId() {
-        return versionId;
-    }
-
-    /**
-     * Returns the name of this version
-     *
-     * @return
-     */
-    public QName getName() {
-        return node.getName();
-    }
+public interface InternalVersion extends InternalVersionItem {
 
     /**
-     * returns the version manager
+     * Returns the name of this version.
      *
-     * @return
+     * @return the name of this version.
      */
-    public PersistentVersionManager getVersionManager() {
-        return versionHistory.getVersionManager();
-    }
+    public QName getName();
 
     /**
-     * Returns the frozen node
+     * Returns the frozen node of this version or <code>null</code> if this is
+     * the root version.
      *
-     * @return
+     * @return the frozen node.
      */
-    public InternalFrozenNode getFrozenNode() {
-        // get frozen node
-        try {
-            PersistentNode pNode = node.getNode(PersistentVersionManager.NODENAME_FROZEN, 1);
-            return pNode == null ? null : new InternalFrozenNode(this, pNode);
-        } catch (RepositoryException e) {
-            // ignore
-        }
-        return null;
-    }
-
-    /**
-     * adds a successor version to the internal cache
-     *
-     * @param successor
-     */
-    private void addSuccessor(InternalVersion successor) {
-        successors.add(successor);
-    }
-
-    /**
-     * resolves the predecessors property and indirectly adds it self to their
-     * successor list.
-     */
-    void resolvePredecessors() {
-        InternalValue[] values = node.getPropertyValues(VersionManager.PROPNAME_PREDECESSORS);
-        if (values != null) {
-            for (int i = 0; i < values.length; i++) {
-                InternalVersion v = versionHistory.getVersion(values[i].internalValue().toString());
-                predecessors.add(v);
-                v.addSuccessor(this);
-            }
-        }
-    }
+    public InternalFrozenNode getFrozenNode();
 
     /**
+     * Aequivalent to {@link javax.jcr.version.Version#getCreated()}
      * @see Version#getCreated()
      */
-    public Calendar getCreated() {
-        return created;
-    }
+    public Calendar getCreated();
 
     /**
+     * Aequivalent to {@link javax.jcr.version.Version#getSuccessors()}}
      * @see Version#getSuccessors()
      */
-    public InternalVersion[] getSuccessors() {
-        return (InternalVersion[]) successors.toArray(new InternalVersion[successors.size()]);
-    }
+    public InternalVersion[] getSuccessors();
 
     /**
-     * @see Version#getSuccessors()
+     * Aequivalent to {@link javax.jcr.version.Version#getPredecessors()}}
+     * @see javax.jcr.version.Version#getPredecessors()
      */
-    public InternalVersion[] getPredecessors() {
-        return (InternalVersion[]) predecessors.toArray(new InternalVersion[predecessors.size()]);
-    }
-
-    /**
-     * stores the internal predecessor cache to the persistance node
-     *
-     * @throws RepositoryException
-     */
-    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)).getId()));
-        }
-        node.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.STRING, values);
-    }
-
-    /**
-     * Detaches itself from the version graph.
-     *
-     * @throws RepositoryException
-     */
-    void internalDetach() throws RepositoryException {
-        // detach this from all successors
-        InternalVersion[] succ = (InternalVersion[]) getSuccessors();
-        for (int i = 0; i < succ.length; i++) {
-            succ[i].internalDetachPredecessor(this);
-        }
-
-        // clear properties
-        successors.clear();
-        predecessors.clear();
-        labelCache = null;
-        storePredecessors();
-    }
-
-    /**
-     * Removes the predecessor V of this predecessor list and adds all of Vs
-     * predecessors to it.
-     * <p/>
-     * please note, that this operation might corrupt the version graph
-     *
-     * @param v the successor to detach
-     */
-    private void internalDetachPredecessor(InternalVersion v) throws RepositoryException {
-        // remove 'v' from predecessor list
-        for (int i = 0; i < predecessors.size(); i++) {
-            if (predecessors.get(i).equals(v)) {
-                predecessors.remove(i);
-                break;
-            }
-        }
-        // attach v's successors
-        predecessors.clear();
-        predecessors.addAll(Arrays.asList(v.getPredecessors()));
-        storePredecessors();
-    }
+    public InternalVersion[] getPredecessors();
 
     /**
      * Checks if this version is more recent than the given version <code>v</code>.
@@ -248,78 +66,34 @@
      * @return <code>true</code> if the version is more recent;
      *         <code>false</code> otherwise.
      */
-    public boolean isMoreRecent(InternalVersion v) {
-        for (int i = 0; i < predecessors.size(); i++) {
-            InternalVersion pred = (InternalVersion) predecessors.get(i);
-            if (pred.equals(this) || pred.isMoreRecent(v)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * returns the internal version history of this version
-     *
-     * @return
-     */
-    protected InternalVersionHistory getVersionHistory() {
-        return versionHistory;
-    }
-
-    /**
-     * adds a label to the label cache. does not affect storage
-     *
-     * @param label
-     * @return
-     */
-    protected boolean internalAddLabel(String label) {
-        if (labelCache == null) {
-            labelCache = new HashSet();
-        }
-        return labelCache.add(label);
-    }
+    public boolean isMoreRecent(InternalVersion v);
 
     /**
-     * removes a label from the label cache. does not affect storage
+     * returns the internal version history in wich this version lifes in.
      *
-     * @param label
-     * @return
+     * @return the version history for this version.
      */
-    protected boolean internalRemoveLabel(String label) {
-        if (labelCache == null) {
-            return false;
-        } else {
-            return labelCache.remove(label);
-        }
-    }
+    public InternalVersionHistory getVersionHistory();
 
     /**
-     * checks, if a label is in the label cache
+     * checks if this is the root version.
      *
-     * @param label
-     * @return
+     * @return <code>true</code> if this version is the root version;
+     *         <code>false</code> otherwise.
      */
-    protected boolean internalHasLabel(String label) {
-        return labelCache == null ? false : labelCache.contains(label);
-    }
+    public boolean isRootVersion();
 
     /**
-     * returns the array of the cached labels
-     *
-     * @return
+     * Checks, if this version has the given label assosiated
+     * @param label the label to check.
+     * @return <code>true</code> if the label is assigned to this version;
+     *         <code>false</code> otherwise.
      */
-    protected String[] internalGetLabels() {
-        return labelCache == null ? new String[0] : (String[]) labelCache.toArray(new String[labelCache.size()]);
-    }
+    public boolean hasLabel(String label);
 
     /**
-     * checks if this is the root version.
-     *
-     * @return <code>true</code> if this version is the root version;
-     *         <code>false</code> otherwise.
+     * returns the labels that are assigned to this version
+     * @return a string array of labels.
      */
-    public boolean isRootVersion() {
-        return isRoot;
-    }
+    public String[] getLabels();
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java&r2=122838
==============================================================================
--- 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	Mon Dec 20 02:29:45 2004
@@ -15,209 +15,63 @@
  */
 package org.apache.jackrabbit.core.version;
 
-import org.apache.jackrabbit.core.InternalValue;
-import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.QName;
-import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
-import org.apache.jackrabbit.core.util.Text;
-import org.apache.jackrabbit.core.util.uuid.UUID;
-import org.apache.log4j.Logger;
-
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
+
 import javax.jcr.version.VersionException;
 import javax.jcr.version.VersionHistory;
-import java.util.Calendar;
-import java.util.HashMap;
 import java.util.Iterator;
 
 /**
- * This Class implements a version history.
+ * This interface defines the internal version history.
  */
-public class InternalVersionHistory {
+public interface InternalVersionHistory extends InternalVersionItem {
 
     /**
-     * default logger
-     */
-    private static Logger log = Logger.getLogger(InternalVersionHistory.class);
-
-    /**
-     * the cache of the version labels
-     * key = version label (String)
-     * value = version
-     */
-    private HashMap labelCache = new HashMap();
-
-    /**
-     * the root version of this history
-     */
-    private InternalVersion rootVersion;
-
-    /**
-     * the hashmap of all versions
-     * key = versionId (String)
-     * value = version
-     */
-    private HashMap versionCache = new HashMap();
-
-    /**
-     * The nodes state of this version history
-     */
-    private PersistentNode node;
-
-    /**
-     * the node that holds the label nodes
-     */
-    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.
+     * Aequivalalent to {@link VersionHistory#getRootVersion()}.
+     * @see VersionHistory#getRootVersion()
      */
-    InternalVersionHistory(PersistentVersionManager vMgr, PersistentNode node) throws RepositoryException {
-        this.vMgr = vMgr;
-        this.node = node;
-        init();
-    }
+    public InternalVersion getRootVersion();
 
     /**
-     * Initialies the history and loads all internal caches
-     *
-     * @throws RepositoryException
+     * Aequivalent to {@link VersionHistory#getVersion(java.lang.String)}.
+     * @see VersionHistory#getVersion(java.lang.String)
      */
-    private void init() throws RepositoryException {
-        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(PersistentVersionManager.NODENAME_VERSION_LABELS)) {
-                labelNode = child;
-                continue;
-            }
-            InternalVersion v = new InternalVersion(this, child);
-            versionCache.put(v.getId(), v);
-            if (v.isRootVersion()) {
-                rootVersion = v;
-            }
-        }
-
-        // resolve successors and predecessors
-        Iterator iter = versionCache.values().iterator();
-        while (iter.hasNext()) {
-            InternalVersion v = (InternalVersion) iter.next();
-            v.resolvePredecessors();
-        }
-
-        // init label cache
-        PersistentNode labels[] = labelNode.getChildNodes();
-        for (int i = 0; i < labels.length; i++) {
-            PersistentNode lNode = labels[i];
-            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);
-        }
-    }
+    public InternalVersion getVersion(QName versionName) throws VersionException;
 
     /**
-     * returns the version manager
+     * Checks if the version with the given name exists in this version history.
      *
-     * @return
+     * @param versionName the name of the version
+     * @return <code>true</code> if the version exists;
+     *         <code>false</code> otherwise.
      */
-    public PersistentVersionManager getVersionManager() {
-        return vMgr;
-    }
+    public boolean hasVersion(QName versionName);
 
     /**
-     * Returns the id of this version history
+     * Checks if the version for the given uuid exists in this history.
      *
-     * @return
-     */
-    public String getId() {
-        return historyId;
-    }
-
-    /**
-     * @see VersionHistory#getRootVersion()
+     * @param uuid the uuid of the version
+     * @return <code>true</code> if the version exists;
+     *         <code>false</code> otherwise.
      */
-    public InternalVersion getRootVersion() throws RepositoryException {
-        return rootVersion;
-    }
-
-    /**
-     * @see VersionHistory#getVersion(java.lang.String)
-     */
-    public InternalVersion getVersion(QName versionName) throws RepositoryException {
-        // maybe add cache by name?
-        Iterator iter = versionCache.values().iterator();
-        while (iter.hasNext()) {
-            InternalVersion v = (InternalVersion) iter.next();
-            if (v.getName().equals(versionName)) {
-                return v;
-            }
-        }
-        throw new VersionException("Version " + versionName + " does not exist.");
-    }
-
-    /**
-     * @see VersionHistory#hasVersion(String)
-     */
-    public boolean hasVersion(QName versionName) {
-        // maybe add cache?
-        Iterator iter = versionCache.values().iterator();
-        while (iter.hasNext()) {
-            InternalVersion v = (InternalVersion) iter.next();
-            if (v.getName().equals(versionName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Checks if the version for the given uuid exists
-     *
-     * @param uuid
-     * @return
-     */
-    public boolean hasVersion(String uuid) {
-        return versionCache.containsKey(uuid);
-    }
+    public boolean hasVersion(String uuid);
 
     /**
      * Returns the version with the given uuid or <code>null</code> if the
      * respective version does not exist.
      *
-     * @param uuid
-     * @return
+     * @param uuid the uuid of the version
+     * @return the internal version ot <code>null</code>
      */
-    public InternalVersion getVersion(String uuid) {
-        return (InternalVersion) versionCache.get(uuid);
-    }
+    public InternalVersion getVersion(String uuid);
 
     /**
+     * Aequivalent to {@link VersionHistory#getVersionByLabel(java.lang.String)}
+     * but returns <code>null</code> if the version does not exists.
+     *
      * @see VersionHistory#getVersionByLabel(java.lang.String)
      */
-    public InternalVersion getVersionByLabel(String label) throws RepositoryException {
-        return (InternalVersion) labelCache.get(label);
-    }
+    public InternalVersion getVersionByLabel(String label);
 
     /**
      * Removes the indicated version from this VersionHistory. If the specified
@@ -228,209 +82,50 @@
      * predecessors of the removed version and vice versa. then, the entire
      * version node and all its subnodes are removed.
      *
-     * @param versionName
-     * @throws RepositoryException
-     */
-    public void removeVersion(QName versionName) throws RepositoryException {
-        InternalVersion v = (InternalVersion) getVersion(versionName);
-        if (v.equals(rootVersion)) {
-            String msg = "Removal of " + versionName + " not allowed.";
-            log.error(msg);
-            throw new VersionException(msg);
-        }
-
-        // remove from persistance state
-        node.removeNode(versionName);
-
-        // unregister from labels
-        String[] labels = v.internalGetLabels();
-        for (int i = 0; i < labels.length; i++) {
-            v.internalRemoveLabel(labels[i]);
-            QName name = new QName("", Text.md5(labels[i]));
-            labelNode.removeNode(name);
-        }
-
-        // detach from the version graph
-        v.internalDetach();
-
-        // and remove from history
-        versionCache.remove(v.getId());
-        store();
-
-    }
-
-    /**
-     * Adds a label to a version
-     *
-     * @param version
-     * @param label
-     * @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 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);
-        }
-        labelCache.put(label, version);
-        version.internalAddLabel(label);
-        QName name = new QName("", Text.md5(label));
-        PersistentNode lNode = labelNode.addNode(name, NodeTypeRegistry.NT_UNSTRUCTURED);
-        lNode.setPropertyValue(PersistentVersionManager.PROPNAME_NAME, InternalValue.create(label));
-        lNode.setPropertyValue(PersistentVersionManager.PROPNAME_VERSION, InternalValue.create(version.getId()));
-        labelNode.store();
-
-        // inform manager
-        vMgr.onVersionModified(version);
-    }
-
-    /**
-     * Removes the label from the respective version
-     *
-     * @param label
-     * @throws RepositoryException if the label does not exist
+     * @param versionName the name of the version to be removed
+     * @throws VersionException if an error occurrs.
      */
-    public void removeVersionLabel(String label) throws RepositoryException {
-        InternalVersion v = (InternalVersion) labelCache.remove(label);
-        if (v == null) {
-            throw new RepositoryException("Version label " + label + " is not in version history.");
-        }
-        v.internalRemoveLabel(label);
-        QName name = new QName("", Text.md5(label));
-        labelNode.removeNode(name);
-        labelNode.store();
-
-        // inform manager
-        vMgr.onVersionModified(v);
-    }
+    public void removeVersion(QName versionName) throws VersionException;
 
     /**
-     * Checks in a node. It creates a new version with the given name and freezes
-     * the state of the given node.
+     * Adds a label to a version. If the given label is already assigned to
+     * another version in this version history, a VersionException is thrown,
+     * unless <code>move</code> is set to <code>true</code>. in this case, the
+     * label is removed from the previously assigned version and added to the
+     * specified one.
      *
-     * @param name
-     * @param src
-     * @return
-     * @throws RepositoryException
+     * @param name the name of the version
+     * @param label the label to assgign
+     * @param move flag what to do by collisions
+     * @return the version that was previously assigned by this label or <code>null</code>.
+     * @throws VersionException
      */
-    protected InternalVersion checkin(QName name, NodeImpl src)
-            throws RepositoryException {
-
-        // copy predecessors from src node
-        Value[] preds = src.getProperty(VersionManager.PROPNAME_PREDECESSORS).getValues();
-        InternalValue[] predecessors = new InternalValue[preds.length];
-        for (int i = 0; i < preds.length; i++) {
-            String predId = preds[i].getString();
-            // check if version exist
-            if (!versionCache.containsKey(predId)) {
-                throw new RepositoryException("invalid predecessor in source node");
-            }
-            predecessors[i] = InternalValue.create(predId);
-        }
-
-        PersistentNode vNode = node.addNode(name, NodeTypeRegistry.NT_UNSTRUCTURED);
-        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.STRING, predecessors);
-
-        // checkin source node
-        InternalFrozenNode.checkin(vNode, PersistentVersionManager.NODENAME_FROZEN, src, false, false);
-
-        // and store
-        store();
-
-        // update version graph
-        InternalVersion version = new InternalVersion(this, vNode);
-        version.resolvePredecessors();
-
-        // update cache
-        versionCache.put(version.getId(), version);
-
-        return version;
-    }
-
+    public InternalVersion addVersionLabel(QName name, String label, boolean move)
+            throws VersionException;
 
     /**
-     * Stores the changes made to this version history
+     * Removes the label from the respective version.
      *
-     * @throws RepositoryException
+     * @param label the label to be removed
+     * @return the version that had the label assigned
+     * @throws VersionException if the label does not exist
      */
-    protected void store() throws RepositoryException {
-        node.store();
-    }
+    public InternalVersion removeVersionLabel(String label) throws VersionException;
 
     /**
-     * discards the changes made to this version history
+     * Returns an iterator over all versions (not ordered yet), including the
+     * root version.
      *
-     * @throws RepositoryException
+     * @return an iterator over {@link InternalVersion} objects.
      */
-    protected void reload() throws RepositoryException {
-        node.reload();
-        init();
-    }
+    public Iterator getVersions();
 
     /**
-     * Returns an iterator over all versions (not ordered yet)
+     * Returns the number of versions in this version history.
      *
-     * @return
+     * @return the number of versions, including the root version.
      */
-    protected Iterator getVersions() {
-        return versionCache.values().iterator();
-    }
+    public int getNumVersions();
 
-    /**
-     * Returns the number of versions
-     *
-     * @return
-     */
-    protected int getNumVersions() {
-        return versionCache.size();
-    }
 
-    /**
-     * Creates a new <code>InternalVersionHistory</code> below the given parent
-     * node and with the given name.
-     *
-     * @param parent
-     * @param name
-     * @return
-     * @throws RepositoryException
-     */
-    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(PersistentVersionManager.PROPNAME_HISTORY_ID, InternalValue.create(historyId));
-
-        // create label node
-        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(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, false);
-
-        parent.store();
-        return new InternalVersionHistory(vMgr, pNode);
-    }
 }
-
-

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionItem.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionItem.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionItem.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+/**
+ * This interface defines the base for all internal versioning items. Internal
+ * versioning items are decoupled from their external form as exposed to the
+ * repository or in form of the node extensions {@link javax.jcr.version.Version}
+ * or {@link javax.jcr.version.VersionHistory}.
+ */
+public interface InternalVersionItem {
+
+    /**
+     * Returns the external id of this item
+     * @return
+     */
+    public String getId();
+
+    /**
+     * returns the parent version item or null
+     * @return
+     */
+    public InternalVersionItem getParent();
+}

Deleted: /incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentNode.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentNode.java?view=auto&rev=122837
==============================================================================

Deleted: /incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentProperty.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentProperty.java?view=auto&rev=122837
==============================================================================

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java	Mon Dec 20 02:29:45 2004
@@ -15,150 +15,18 @@
  */
 package org.apache.jackrabbit.core.version;
 
-import org.apache.commons.collections.ReferenceMap;
 import org.apache.jackrabbit.core.*;
-import org.apache.jackrabbit.core.nodetype.NodeDefId;
-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.PersistentItemStateProvider;
-import org.apache.jackrabbit.core.state.PersistentNodeState;
-import org.apache.jackrabbit.core.util.uuid.UUID;
-import org.apache.log4j.Logger;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.Workspace;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
+import java.util.*;
 
 /**
- * This Class provides implements the persistent part of the versionin. the
- * current implementation uses the 'normal' repository content as storage.
+ * This interface defines the access to the persistence layer of the
+ * versioning. The way how the versions are stored may totaly differ from
+ * the way they are exposed to the client.
  */
-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 id of the persisten root node
-     */
-    private static final NodeId PERSISTENT_ROOT_ID = new NodeId("faceface-ab3b-48a9-b31b-e7d0a9c1c3b1");
-
-    /**
-     * the persistent root node of the version histories
-     */
-    private final PersistentNode historyRoot;
-
-    /**
-     * the state manager for the version storage
-     */
-    private PersistentItemStateProvider stateMgr;
-
-    /**
-     * the nodetype manager for the version storage
-     */
-    private NodeTypeManagerImpl ntMgr;
-
-    /**
-     * The representation version managers (per workspace)
-     */
-    private HashMap versionManagers = new HashMap();
-
-    /**
-     * the version histories. key=uuid, value=version history
-     */
-    private Map histories = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
-
-    /**
-     * Creates a new PersistentVersionManager.
-     *
-     * @param session
-     * @throws RepositoryException
-     */
-    public PersistentVersionManager(SessionImpl session) throws RepositoryException {
-        this.stateMgr = ((WorkspaceImpl) session.getWorkspace()).getPersistentStateManager();
-        this.ntMgr = session.getNodeTypeManager();
-
-        try {
-            NodeImpl systemRoot = ((RepositoryImpl) session.getRepository()).getSystemRootNode(session);
-            // enable this to make the persistence storage visible
-            if (true) {
-                // check for versionhistory root
-                if (!systemRoot.hasNode(VERSION_HISTORY_ROOT_NAME)) {
-                    // if not exist, create
-                    systemRoot.addNode(VERSION_HISTORY_ROOT_NAME, NodeTypeRegistry.NT_UNSTRUCTURED);
-                    systemRoot.save();
-                }
-                PersistentNodeState nodeState = (PersistentNodeState) stateMgr.getItemState(new NodeId(systemRoot.getNode(VERSION_HISTORY_ROOT_NAME).internalGetUUID()));
-                historyRoot = new PersistentNode(stateMgr, ntMgr, nodeState);
-            } else {
-                if (!stateMgr.hasItemState(PERSISTENT_ROOT_ID)) {
-                    PersistentNodeState nodeState = stateMgr.createNodeState(PERSISTENT_ROOT_ID.getUUID(), NodeTypeRegistry.NT_UNSTRUCTURED, null);
-                    nodeState.setDefinitionId(new NodeDefId(ntMgr.getRootNodeDefinition().unwrap()));
-                    nodeState.store();
-                    historyRoot = new PersistentNode(stateMgr, ntMgr, nodeState);
-                } else {
-                    PersistentNodeState nodeState = (PersistentNodeState) stateMgr.getItemState(PERSISTENT_ROOT_ID);
-                    historyRoot = new PersistentNode(stateMgr, ntMgr, nodeState);
-                }
-            }
-        } catch (ItemStateException e) {
-            throw new RepositoryException("Unable to initialize PersistentVersionManager: " + e.toString());
-        }
-    }
-
-    /**
-     * returns the version manager
-     *
-     * @return
-     */
-    public synchronized VersionManager getVersionManager(Workspace wsp) {
-        VersionManager vm = (VersionManager) versionManagers.get(wsp.getName());
-        if (vm == null) {
-            vm = new VersionManager(this);
-            versionManagers.put(wsp.getName(), vm);
-        }
-        return vm;
-    }
-
+public interface PersistentVersionManager {
 
     /**
      * Creates a new Version History.
@@ -167,25 +35,8 @@
      * @return the newly created version history.
      * @throws RepositoryException
      */
-    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);
-
-        // notify version managers
-        onVersionHistoryModified(hist);
-        return hist;
-    }
+    public InternalVersionHistory createVersionHistory(NodeImpl node)
+            throws RepositoryException;
 
     /**
      * returns the internal version history for the id
@@ -194,21 +45,8 @@
      * @return
      * @throws RepositoryException
      */
-    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);
-            if (hNode != null) {
-                hist = new InternalVersionHistory(this, hNode);
-                histories.put(histId, hist);
-            }
-        }
-        return hist;
-    }
+    public InternalVersionHistory getVersionHistory(String histId)
+            throws RepositoryException;
 
     /**
      * Checks if the versionhistory for the given id exists
@@ -216,28 +54,15 @@
      * @param histId
      * @return
      */
-    synchronized boolean hasVersionHistory(String histId) {
-        if (histories.containsKey(histId)) {
-            return true;
-        } else {
-            return historyRoot.hasNode(new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, histId));
-        }
-    }
+    public boolean hasVersionHistory(String histId);
 
     /**
-     * returns an iterator over all existing version histories
+     * returns an iterator over the external ids of the version histories
      *
      * @return
      * @throws RepositoryException
      */
-    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();
-    }
+    public Iterator getVersionHistoryIds() throws RepositoryException;
 
     /**
      * returns the number of version histories
@@ -245,9 +70,7 @@
      * @return
      * @throws RepositoryException
      */
-    synchronized int getNumVersionHistories() throws RepositoryException {
-        return historyRoot.getChildNodes().length;
-    }
+    public int getNumVersionHistories() throws RepositoryException;
 
     /**
      * returns the internal version for the id
@@ -256,11 +79,8 @@
      * @return
      * @throws RepositoryException
      */
-    synchronized InternalVersion getVersion(String histId, String versionId)
-            throws RepositoryException {
-        InternalVersionHistory history = getVersionHistory(histId);
-        return history.getVersion(versionId);
-    }
+    public InternalVersion getVersion(String histId, String versionId)
+            throws RepositoryException;
 
     /**
      * returns the version with the given id
@@ -269,20 +89,8 @@
      * @return
      * @throws RepositoryException
      */
-    synchronized InternalVersion getVersion(String versionId)
-            throws RepositoryException {
-
-        // todo: implement better
-        PersistentNode[] ph = historyRoot.getChildNodes();
-        for (int i = 0; i < ph.length; i++) {
-            InternalVersionHistory vh = getVersionHistory(ph[i].getName().getLocalName());
-            InternalVersion v = vh.getVersion(versionId);
-            if (v != null) {
-                return v;
-            }
-        }
-        return null;
-    }
+    public InternalVersion getVersion(String versionId)
+            throws RepositoryException;
 
     /**
      * Checks if the version with the given id exists
@@ -290,47 +98,32 @@
      * @param versionId
      * @return
      */
-    synchronized boolean hasVersion(String versionId) {
-        // todo: implement better
-        try {
-            PersistentNode[] ph = historyRoot.getChildNodes();
-            for (int i = 0; i < ph.length; i++) {
-                InternalVersionHistory vh = getVersionHistory(ph[i].getName().getLocalName());
-                if (vh.hasVersion(versionId)) {
-                    return true;
-                }
-            }
-        } catch (RepositoryException e) {
-            // ignore
-        }
-        return false;
-    }
+    public boolean hasVersion(String versionId);
 
     /**
-     * is informed by the versions if they were modified
-     *
-     * @param version
+     * checks, if the item with the given external id exists
+     * @param externalId
+     * @return
      */
-    void onVersionModified(InternalVersion version) throws RepositoryException {
-        // check if version manager already generated item states
-        Iterator iter = versionManagers.values().iterator();
-        while (iter.hasNext()) {
-            ((VersionManager) iter.next()).onVersionModified(version);
-        }
-    }
+    public boolean hasItem(String externalId);
 
     /**
-     * is informed by the versions if they were modified
-     *
-     * @param vh
+     * returns the item referred by the external id
+     * @param externalId
+     * @return
+     * @throws RepositoryException
      */
-    void onVersionHistoryModified(InternalVersionHistory vh) throws RepositoryException {
-        // check if version manager already generated item states
-        Iterator iter = versionManagers.values().iterator();
-        while (iter.hasNext()) {
-            ((VersionManager) iter.next()).onVersionHistoryModified(vh);
-        }
-    }
+    public InternalVersionItem getItemByExternal(String externalId)
+            throws RepositoryException;
+
+    /**
+     * returns the item referred by the internal id
+     * @param internalId
+     * @return
+     * @throws RepositoryException
+     */
+    public InternalVersionItem getItemByInternal(String internalId)
+            throws RepositoryException;
 
     /**
      * Checks in a node
@@ -340,50 +133,6 @@
      * @throws RepositoryException
      * @see Node#checkin()
      */
-    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);
-    }
+    public InternalVersion checkin(NodeImpl node) throws RepositoryException;
 
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryImpl.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryImpl.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryImpl.java&r2=122838
==============================================================================
--- 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	Mon Dec 20 02:29:45 2004
@@ -49,7 +49,7 @@
      * @param history
      * @throws RepositoryException
      */
-    protected VersionHistoryImpl(ItemManager itemMgr, SessionImpl session, NodeId id,
+    public VersionHistoryImpl(ItemManager itemMgr, SessionImpl session, NodeId id,
                                  NodeState state, NodeDef definition,
                                  ItemLifeCycleListener[] listeners,
                                  InternalVersionHistory history) throws RepositoryException {
@@ -108,11 +108,7 @@
             throws VersionException, RepositoryException {
         try {
             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);
+            history.addVersionLabel(name, label, move);
         } catch (IllegalNameException e) {
             throw new RepositoryException(e);
         } catch (UnknownPrefixException e) {

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryNodeState.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryNodeState.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryNodeState.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryNodeState.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryNodeState.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionHistoryNodeState.java	Mon Dec 20 02:29:45 2004
@@ -16,6 +16,8 @@
 package org.apache.jackrabbit.core.version;
 
 import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.version.InternalVersionHistory;
+import org.apache.jackrabbit.core.version.InternalVersion;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.virtual.VirtualNodeState;
 
@@ -25,30 +27,48 @@
 import java.util.List;
 
 /**
- * This Class implements...
+ * This Class implements the virtual node state for a version history.
  */
 public class VersionHistoryNodeState extends VirtualNodeState {
 
+    /**
+     * the rerpesenting version history
+     */
     private final InternalVersionHistory vh;
 
-    public VersionHistoryNodeState(VersionItemStateProvider vm, InternalVersionHistory vh, String parentUUID) {
-        super(vm, vh.getId(), NodeTypeRegistry.NT_VERSION_HISTORY, parentUUID);
+    /**
+     * Creates a new versiom history node state
+     * @param vm
+     * @param vh
+     * @param parentUUID
+     * @throws RepositoryException
+     */
+    protected VersionHistoryNodeState(VersionItemStateProvider vm,
+                                   InternalVersionHistory vh,
+                                   String parentUUID)
+            throws RepositoryException {
+        super(vm, parentUUID, vh.getId(), NodeTypeRegistry.NT_VERSION_HISTORY, new QName[0]);
         this.vh = vh;
-
-        setDefinitionId(vm.getNodeDefId(NodeTypeRegistry.NT_VERSION_HISTORY));
-        // we do not initialize the childnode entry array, but rather
-        // generate it every time.
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#hasChildNodeEntry(org.apache.jackrabbit.core.QName)
+     */
     public synchronized boolean hasChildNodeEntry(QName name) {
         return vh.hasVersion(name);
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#hasChildNodeEntry(org.apache.jackrabbit.core.QName, int)
+     */
     public synchronized boolean hasChildNodeEntry(QName name, int index) {
         // no same name siblings
         return index <= 1 ? vh.hasVersion(name) : false;
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#getChildNodeEntry(org.apache.jackrabbit.core.QName, int)
+     */
     public synchronized ChildNodeEntry getChildNodeEntry(QName nodeName, int index) {
         try {
             if (index <= 1) {
@@ -61,6 +81,9 @@
         return null;
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#getChildNodeEntries()
+     */
     public synchronized List getChildNodeEntries() {
         Iterator iter = vh.getVersions();
         ArrayList list = new ArrayList(vh.getNumVersions());
@@ -71,6 +94,9 @@
         return list;
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#getChildNodeEntries(String)
+     */
     public synchronized List getChildNodeEntries(String uuid) {
         ArrayList list = new ArrayList(1);
         InternalVersion v = vh.getVersion(uuid);
@@ -78,6 +104,9 @@
         return list;
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.state.NodeState#getChildNodeEntries(org.apache.jackrabbit.core.QName)
+     */
     public synchronized List getChildNodeEntries(QName nodeName) {
         ArrayList list = new ArrayList(1);
         try {
@@ -88,5 +117,4 @@
         }
         return list;
     }
-
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionImpl.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionImpl.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionImpl.java&r2=122838
==============================================================================
--- 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	Mon Dec 20 02:29:45 2004
@@ -47,7 +47,7 @@
      * @param version
      * @throws RepositoryException
      */
-    protected VersionImpl(ItemManager itemMgr, SessionImpl session, NodeId id,
+    public VersionImpl(ItemManager itemMgr, SessionImpl session, NodeId id,
                           NodeState state, NodeDef definition,
                           ItemLifeCycleListener[] listeners, InternalVersion version)
             throws RepositoryException {
@@ -66,14 +66,14 @@
      * @see Version#getVersionLabels()
      */
     public String[] getVersionLabels() throws RepositoryException {
-        return version.internalGetLabels();
+        return version.getLabels();
     }
 
     /**
      * @see Version#hasVersionLabel
      */
     public boolean hasVersionLabel(String label) {
-        return version.internalHasLabel(label);
+        return version.hasLabel(label);
     }
 
     /**

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java	Mon Dec 20 02:29:45 2004
@@ -15,58 +15,97 @@
  */
 package org.apache.jackrabbit.core.version;
 
-import org.apache.jackrabbit.core.ItemId;
-import org.apache.jackrabbit.core.NodeId;
-import org.apache.jackrabbit.core.PropertyId;
-import org.apache.jackrabbit.core.QName;
-import org.apache.jackrabbit.core.nodetype.NodeDefId;
-import org.apache.jackrabbit.core.nodetype.PropDefId;
+import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.version.*;
+import org.apache.jackrabbit.core.util.uuid.UUID;
+import org.apache.jackrabbit.core.nodetype.*;
 import org.apache.jackrabbit.core.state.*;
-import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
-import org.apache.jackrabbit.core.virtual.VirtualNodeState;
+import org.apache.jackrabbit.core.virtual.*;
 import org.apache.log4j.Logger;
 import org.apache.commons.collections.ReferenceMap;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.PropertyType;
+import javax.jcr.nodetype.ConstraintViolationException;
 import java.util.Map;
+import java.util.HashSet;
 
 /**
- * This Class implements...
+ * This Class implements a virtual item state provider, in order to expose the
+ * versions to the version storage.
  */
 public class VersionItemStateProvider implements VirtualItemStateProvider {
-
     /**
      * the default logger
      */
     private static Logger log = Logger.getLogger(VersionItemStateProvider.class);
-
+    /**
+     * the root node
+     */
     private final HistoryRootNodeState root;
-
+    /**
+     * the version manager
+     */
     private final VersionManager vMgr;
-
+    /**
+     * the node type manager
+     */
+    private final NodeTypeManagerImpl ntMgr;
     /**
      * the version histories. key=ItemId, value=ItemState
      */
     private Map items = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
+    /**
+     * node def id for a unstructured node state
+     */
+    private NodeDefId NDEF_UNSTRUCTURED;
+    /**
+     * node def id for a version node state
+     */
+    private NodeDefId NDEF_VERSION;
+    /**
+     * node def id ofr a version history node state
+     */
+    private NodeDefId NDEF_VERSION_HISTORY;
 
-
-    public VersionItemStateProvider(VersionManager vMgr, String rootId, String parentId) {
+    /**
+     * creates a new version item state provide
+     * @param vMgr
+     * @param rootId
+     * @param parentId
+     * @throws RepositoryException
+     */
+    public VersionItemStateProvider(VersionManager vMgr, NodeTypeManagerImpl ntMgr, String rootId, String parentId)  throws RepositoryException {
         this.vMgr = vMgr;
-        this.root = new HistoryRootNodeState(this, rootId, parentId);
-    }
+        this.ntMgr = ntMgr;
+        NDEF_UNSTRUCTURED = new NodeDefId(getNodeTypeManager().getNodeType(NodeTypeRegistry.NT_UNSTRUCTURED).getApplicableChildNodeDef(VersionManager.NODENAME_ROOTVERSION, NodeTypeRegistry.NT_UNSTRUCTURED).unwrap());
+        NDEF_VERSION = new NodeDefId(getNodeTypeManager().getNodeType(NodeTypeRegistry.NT_VERSION_HISTORY).getApplicableChildNodeDef(VersionManager.NODENAME_ROOTVERSION, NodeTypeRegistry.NT_VERSION).unwrap());
+        NDEF_VERSION_HISTORY = new NodeDefId(getNodeTypeManager().getNodeType(NodeTypeRegistry.NT_UNSTRUCTURED).getApplicableChildNodeDef(VersionManager.NODENAME_ROOTVERSION, NodeTypeRegistry.NT_VERSION_HISTORY).unwrap());
 
-    public VersionManager getVersionManager() {
-        return vMgr;
+        this.root = new HistoryRootNodeState(this, vMgr, parentId, rootId);
+        this.root.setDefinitionId(NDEF_UNSTRUCTURED);
     }
 
-    public boolean isVirtualRoot(ItemId id) {
-        return id.equals(root.getId());
-    }
+    //--------------------------------------------------< ItemStateProvider >---
 
-    public NodeId getVirtualRootId() {
-        return (NodeId) root.getId();
+    /**
+     * @see ItemStateProvider#hasItemState(org.apache.jackrabbit.core.ItemId)
+     */
+    public boolean hasItemState(ItemId id) {
+
+        // check cache
+        if (items.containsKey(id)) {
+            return true;
+        } else if (id instanceof NodeId) {
+            return hasNodeState((NodeId) id);
+        } else {
+            return hasPropertyState((PropertyId) id);
+        }
     }
 
+    /**
+     * @see ItemStateProvider#getItemState(org.apache.jackrabbit.core.ItemId)
+     */
     public ItemState getItemState(ItemId id)
             throws NoSuchItemStateException, ItemStateException {
 
@@ -79,28 +118,61 @@
             }
             // add state to cache
             items.put(id, state);
+            log.info("item added to cache. size=" + items.size());
         }
         return state;
     }
 
+    /**
+     * 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;
+    }
+
+    //-------------------------------------------< VirtualItemStateProvider >---
+
+    /**
+     * @see VirtualItemStateProvider#isVirtualRoot(org.apache.jackrabbit.core.ItemId)
+     */
+    public boolean isVirtualRoot(ItemId id) {
+        return id.equals(root.getId());
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.virtual.VirtualItemStateProvider#getVirtualRootId()
+     */
+    public NodeId getVirtualRootId() {
+        return (NodeId) root.getId();
+    }
+
+    /**
+     * @see VirtualItemStateProvider#hasNodeState(NodeId)
+     */
     public boolean hasNodeState(NodeId id) {
         if (id.equals(root.getId())) {
             return true;
         }
-
-        // check version history
-        if (vMgr.hasVersionHistory(id.getUUID())) {
-            return true;
-        }
-        // check verion
-        if (vMgr.hasVersion(id.getUUID())) {
-            return true;
-        }
-
-        return false;
+        return vMgr.hasItem(id.getUUID());
     }
 
-    public NodeState getNodeState(NodeId id)
+    /**
+     * @see VirtualItemStateProvider#getNodeState(org.apache.jackrabbit.core.NodeId)
+     */
+    public VirtualNodeState getNodeState(NodeId id)
             throws NoSuchItemStateException, ItemStateException {
 
         // check if root
@@ -108,33 +180,80 @@
             return root;
         }
 
-        // check version history
         try {
-            InternalVersionHistory vh = vMgr.getVersionHistory(id.getUUID());
-            if (vh != null) {
-                return new VersionHistoryNodeState(this, vh, root.getUUID());
+            InternalVersionItem vi = vMgr.getItem(id.getUUID());
+            if (vi instanceof InternalVersionHistory) {
+                VersionHistoryNodeState ns = new VersionHistoryNodeState(this, (InternalVersionHistory) vi, root.getUUID());
+                ns.setDefinitionId(NDEF_VERSION_HISTORY);
+                return ns;
+
+            } else if (vi instanceof InternalVersion) {
+                InternalVersion v = (InternalVersion) vi;
+                VersionNodeState ns = new VersionNodeState(this, v, vi.getParent().getId());
+                ns.setDefinitionId(NDEF_VERSION);
+                ns.setPropertyValue(VersionManager.PROPNAME_CREATED, InternalValue.create(v.getCreated()));
+                ns.setPropertyValue(VersionManager.PROPNAME_FROZEN_UUID, InternalValue.create(v.getFrozenNode().getFrozenUUID()));
+                ns.setPropertyValue(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE, InternalValue.create(v.getFrozenNode().getFrozenPrimaryType()));
+                ns.setPropertyValues(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES, PropertyType.NAME, InternalValue.create(v.getFrozenNode().getFrozenMixinTypes()));
+                ns.setPropertyValues(VersionManager.PROPNAME_VERSION_LABELS, PropertyType.STRING, InternalValue.create(v.getLabels()));
+                ns.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.REFERENCE, new InternalValue[0]);
+                ns.setPropertyValues(VersionManager.PROPNAME_SUCCESSORS, PropertyType.REFERENCE, new InternalValue[0]);
+                return ns;
+
+            } else if (vi instanceof InternalFrozenNode) {
+                InternalFrozenNode fn = (InternalFrozenNode) vi;
+                VirtualNodeState parent = getNodeState(new NodeId(fn.getParent().getId()));
+                VirtualNodeState state = createNodeState(
+                                parent,
+                                VersionManager.NODENAME_FROZEN,
+                                id.getUUID(),
+                                fn.getFrozenPrimaryType());
+                mapFrozenNode(state, fn);
+                return state;
+
+            } else if (vi instanceof InternalFrozenVersionHistory) {
+                InternalFrozenVersionHistory fn = (InternalFrozenVersionHistory) vi;
+                VirtualNodeState parent = getNodeState(new NodeId(fn.getParent().getId()));
+                VirtualNodeState state = createNodeState(
+                                parent,
+                                VersionManager.NODENAME_FROZEN,
+                                id.getUUID(),
+                                NodeTypeRegistry.NT_FROZEN_VERSIONABLE_CHILD);
+                mapFrozenNode(state, fn);
+                return state;
             }
         } catch (RepositoryException e) {
-            log.error("Unable to check for version history:" + e.toString());
+            log.error("Unable to check for item:" + e.toString());
             throw new ItemStateException(e);
         }
 
-        // check version
+        // not found, throw
+        throw new NoSuchItemStateException(id.toString());
+    }
+
+    /**
+     * @see VirtualItemStateProvider#hasPropertyState(org.apache.jackrabbit.core.PropertyId)
+     */
+    public boolean hasPropertyState(PropertyId id) {
+
         try {
-            InternalVersion v = vMgr.getVersion(id.getUUID());
-            if (v != null) {
-                return new VersionNodeState(this, v);
+            // get parent state
+            NodeState parent = getNodeState(new NodeId(id.getParentUUID()));
+
+            // handle some default prop states
+            if (parent instanceof VirtualNodeState) {
+                return ((VirtualNodeState) parent).hasPropertyEntry(id.getName());
             }
-        } catch (RepositoryException e) {
-            log.error("Unable to check for version:" + e.toString());
-            throw new ItemStateException(e);
+        } catch (ItemStateException e) {
+            // ignore
         }
-
-        // not found, throw
-        throw new NoSuchItemStateException(id.toString());
+        return false;
     }
 
-    public PropertyState getPropertyState(PropertyId id)
+    /**
+     * @see VirtualItemStateProvider#getPropertyState(org.apache.jackrabbit.core.PropertyId)
+     */
+    public VirtualPropertyState getPropertyState(PropertyId id)
             throws NoSuchItemStateException, ItemStateException {
 
         // get parent state
@@ -142,65 +261,177 @@
 
         // handle some default prop states
         if (parent instanceof VirtualNodeState) {
-            return ((VirtualNodeState) parent).getPropertyState(id.getName());
+            return ((VirtualNodeState) parent).getProperty(id.getName());
         }
         throw new NoSuchItemStateException(id.toString());
     }
 
-    public boolean hasPropertyState(PropertyId id) {
+    /**
+     * @see VirtualItemStateProvider#createPropertyState(org.apache.jackrabbit.core.virtual.VirtualNodeState, org.apache.jackrabbit.core.QName, int, boolean)
+     */
+    public VirtualPropertyState createPropertyState(VirtualNodeState parent,
+                                                    QName name, int type,
+                                                    boolean multiValued)
+            throws RepositoryException {
+        PropertyDefImpl def = getApplicablePropertyDef(parent, name, type, multiValued);
+        VirtualPropertyState prop = new VirtualPropertyState(name, parent.getUUID());
+        prop.setType(type);
+        prop.setMultiValued(multiValued);
+        prop.setDefinitionId(new PropDefId(def.unwrap()));
+        items.put(prop.getId(), prop);
+        return prop;
+    }
 
-        try {
-            // get parent state
-            NodeState parent = getNodeState(new NodeId(id.getParentUUID()));
+    /**
+     * @see VirtualItemStateProvider#createNodeState(org.apache.jackrabbit.core.virtual.VirtualNodeState, org.apache.jackrabbit.core.QName, String, org.apache.jackrabbit.core.QName)
+     */
+    public VirtualNodeState createNodeState(VirtualNodeState parent, QName name,
+                                            String uuid, QName nodeTypeName)
+            throws RepositoryException {
 
-            // handle some default prop states
-            if (parent instanceof VirtualNodeState) {
-                return ((VirtualNodeState) parent).getPropertyState(id.getName()) != null;
+        NodeTypeImpl nodeType = getNodeTypeManager().getNodeType(nodeTypeName);
+        NodeDefImpl def;
+        try {
+            def = getApplicableChildNodeDef(parent, name, nodeType == null ? null : nodeType.getQName());
+        } catch (RepositoryException re) {
+            // hack, use nt:unstructured as parent
+            try {
+                NodeTypeRegistry ntReg = getNodeTypeManager().getNodeTypeRegistry();
+                EffectiveNodeType ent = ntReg.buildEffectiveNodeType(new QName[]{NodeTypeRegistry.NT_UNSTRUCTURED});
+                ChildNodeDef cnd = ent.getApplicableChildNodeDef(name, nodeTypeName);
+                def = getNodeTypeManager().getNodeDef(new NodeDefId(cnd));
+            } catch (NodeTypeConflictException e) {
+                String msg = "no definition found in parent node's node type for new node";
+                throw new ConstraintViolationException(msg, re);
             }
-        } catch (ItemStateException e) {
-            // ignore
         }
-        return false;
+        if (nodeType == null) {
+            // use default node type
+            nodeType = (NodeTypeImpl) def.getDefaultPrimaryType();
+        }
+
+        // create a new node state
+        VirtualNodeState state = null;
+        if (uuid == null) {
+            uuid = UUID.randomUUID().toString();	// version 4 uuid
+        }
+        state = new VirtualNodeState(this, parent.getUUID(), uuid, nodeTypeName, new QName[0]);
+        state.setDefinitionId(new NodeDefId(def.unwrap()));
+
+        items.put(state.getId(), state);
+        return state;
     }
 
-    public boolean hasItemState(ItemId id) {
+    //-----------------------------------------------------< internal stuff >---
 
-        // check cache
-        if (items.containsKey(id)) {
-            return true;
-        } else if (id instanceof NodeId) {
-            return hasNodeState((NodeId) id);
-        } else {
-            return hasPropertyState((PropertyId) id);
-        }
+    /**
+     * returns the node type manager
+     * @return
+     */
+    private NodeTypeManagerImpl getNodeTypeManager() {
+        return ntMgr;
     }
 
-    public NodeDefId getNodeDefId(QName nodename) {
-        return vMgr.getNodeDefId(nodename);
+    /**
+     * mapps a frozen node
+     * @param state
+     * @param node
+     * @return
+     * @throws RepositoryException
+     */
+    private VirtualNodeState mapFrozenNode(VirtualNodeState state,
+                                           InternalFrozenNode node)
+            throws RepositoryException {
+
+        // map native stuff
+        state.setMixinNodeTypes(node.getFrozenMixinTypes());
+        if (node.getFrozenUUID()!=null) {
+            state.setPropertyValue(ItemImpl.PROPNAME_UUID, InternalValue.create(node.getFrozenUUID()));
+        }
+
+        // map properties
+        PropertyState[] props = node.getFrozenProperties();
+        for (int i=0; i<props.length; i++) {
+            if (props[i].isMultiValued()) {
+                state.setPropertyValues(props[i].getName(), props[i].getType(), props[i].getValues());
+            } else {
+                state.setPropertyValue(props[i].getName(), props[i].getValues()[0]);
+            }
+        }
+        // map child nodes
+        InternalFreeze[] nodes = node.getFrozenChildNodes();
+        for (int i=0; i<nodes.length; i++) {
+            state.addChildNodeEntry(nodes[i].getName(), nodes[i].getId());
+        }
+        return state;
     }
 
-    public PropDefId getPropDefId(QName propname) {
-        return vMgr.getPropDefId(propname);
+    /**
+     * maps a frozen node
+     * @param state
+     * @param node
+     * @return
+     * @throws RepositoryException
+     */
+    private VirtualNodeState mapFrozenNode(VirtualNodeState state,
+                                           InternalFrozenVersionHistory node)
+            throws RepositoryException {
+
+        // map properties
+        state.setPropertyValue(VersionManager.PROPNAME_BASE_VERSION, InternalValue.create(node.getBaseVersionId()));
+        state.setPropertyValue(VersionManager.PROPNAME_VERSION_HISTORY, InternalValue.create(node.getVersionHistoryId()));
+        return state;
     }
 
     /**
-     * virtual item state provider do not have attics.
+     * retrieves the property definition for the given contraints
      *
-     * @throws NoSuchItemStateException always
+     * @param propertyName
+     * @param type
+     * @param multiValued
+     * @return
+     * @throws RepositoryException
      */
-    public ItemState getItemStateInAttic(ItemId id) throws NoSuchItemStateException {
-        // never has states in attic
-        throw new NoSuchItemStateException(id.toString());
+    protected PropertyDefImpl getApplicablePropertyDef(NodeState parent, QName propertyName,
+                                                       int type, boolean multiValued)
+            throws RepositoryException {
+        PropDef pd = getEffectiveNodeType(parent).getApplicablePropertyDef(propertyName, type, multiValued);
+        return getNodeTypeManager().getPropDef(new PropDefId(pd));
     }
 
     /**
-     * virtual item state provider do not have attics.
+     * Retrieves the node definition for the given contraints.
      *
-     * @return <code>false</code>
+     * @param nodeName
+     * @param nodeTypeName
+     * @return
+     * @throws RepositoryException
      */
-    public boolean hasItemStateInAttic(ItemId id) {
-        // never has states in attic
-        return false;
+    protected NodeDefImpl getApplicableChildNodeDef(NodeState parent, QName nodeName, QName nodeTypeName)
+            throws RepositoryException {
+        ChildNodeDef cnd = getEffectiveNodeType(parent).getApplicableChildNodeDef(nodeName, nodeTypeName);
+        return getNodeTypeManager().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(NodeState parent) throws RepositoryException {
+        // build effective node type of mixins & primary type
+        NodeTypeRegistry ntReg = getNodeTypeManager().getNodeTypeRegistry();
+        // existing mixin's
+        HashSet set = new HashSet(parent.getMixinTypeNames());
+        // primary type
+        set.add(parent.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 " + parent.getUUID();
+            throw new RepositoryException(msg, ntce);
+        }
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java&r2=122838
==============================================================================
--- 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	Mon Dec 20 02:29:45 2004
@@ -16,41 +16,28 @@
 package org.apache.jackrabbit.core.version;
 
 import org.apache.jackrabbit.core.*;
-import org.apache.jackrabbit.core.nodetype.NodeDefId;
-import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
-import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
-import org.apache.jackrabbit.core.nodetype.PropDefId;
 import org.apache.jackrabbit.core.state.ItemStateProvider;
-import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
-import org.apache.log4j.Logger;
 
-import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
-import javax.jcr.nodetype.NodeDef;
 import javax.jcr.version.Version;
 import javax.jcr.version.VersionHistory;
-import java.util.HashMap;
 import java.util.Iterator;
 
 /**
- * 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.
+ * This interface defines the version manager. It gives access to the underlaying
+ * persistence layer of the versioning.
  */
-public class VersionManager {
-
-    /**
-     * the default logger
-     */
-    private static Logger log = Logger.getLogger(VersionManager.class);
-
+public interface VersionManager {
     /**
      * root path for version storage
      */
     public static final QName NODENAME_HISTORY_ROOT = new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionStorage");
     /**
+     * the name of the frozen node
+     */
+    public static final QName NODENAME_FROZEN = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozen");
+    /**
      * name of the 'jcr:frozenUUID' property
      */
     public static final QName PROPNAME_FROZEN_UUID = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozenUUID");
@@ -96,81 +83,14 @@
     public static final QName NODENAME_ROOTVERSION = new QName(NamespaceRegistryImpl.NS_JCR_URI, "rootVersion");
 
     /**
-     * The version manager of the internal versions
-     */
-    private final PersistentVersionManager vMgr;
-
-    /**
-     * The virtual item manager that exposes the versions to the content
-     */
-    private VersionItemStateProvider virtProvider;
-
-    /**
-     * the definition id manager helper class
-     */
-    private DefinitionIdMgr idMgr;
-
-
-    /**
-     * @param vMgr
-     */
-    protected VersionManager(PersistentVersionManager vMgr) {
-        this.vMgr = vMgr;
-    }
-
-    /**
      * returns the virtual item state provider that exposes the internal versions
      * as items.
      *
      * @param base
      * @return
      */
-    public synchronized VirtualItemStateProvider getVirtualItemStateProvider(SessionImpl session, ItemStateProvider base) {
-        if (virtProvider == null) {
-            try {
-                // init the definition id mgr
-                idMgr = new DefinitionIdMgr(session.getNodeTypeManager());
-
-                session.getNodeTypeManager().getNodeType(NodeTypeRegistry.NT_BASE).getApplicablePropertyDef(ItemImpl.PROPNAME_PRIMARYTYPE, PropertyType.NAME, false).unwrap();
-                // check, if workspace of session has history root
-                NodeImpl systemRoot = ((RepositoryImpl) session.getRepository()).getSystemRootNode(session);
-                if (!systemRoot.hasNode(VersionManager.NODENAME_HISTORY_ROOT)) {
-                    // if not exist, create
-                    systemRoot.addNode(VersionManager.NODENAME_HISTORY_ROOT, NodeTypeRegistry.NT_UNSTRUCTURED);
-                }
-                systemRoot.save();
-                String rootId = systemRoot.getNode(VersionManager.NODENAME_HISTORY_ROOT).internalGetUUID();
-
-                NodeState virtRootState = (NodeState) base.getItemState(new NodeId(rootId));
-                virtProvider = new VersionItemStateProvider(this, rootId, virtRootState.getParentUUID());
-            } catch (Exception e) {
-                // todo: better error handling
-                log.error("Error while initializing virtual items.", e);
-                throw new IllegalStateException(e.toString());
-            }
-        }
-        return virtProvider;
-    }
-
-    /**
-     * returns the node definition id for the given name
-     *
-     * @param name
-     * @return
-     */
-    public NodeDefId getNodeDefId(QName name) {
-        return idMgr.getNodeDefId(name);
-    }
-
-    /**
-     * returns the property definition id for the given name
-     *
-     * @param name
-     * @return
-     */
-    public PropDefId getPropDefId(QName name) {
-        return idMgr.getPropDefId(name);
-    }
+    public VirtualItemStateProvider getVirtualItemStateProvider(SessionImpl session,
+                                                                ItemStateProvider base);
 
     /**
      * Creates a new version history. This action is needed either when creating
@@ -181,10 +101,8 @@
      * @return
      * @throws RepositoryException
      */
-    public VersionHistory createVersionHistory(NodeImpl node) throws RepositoryException {
-        InternalVersionHistory history = vMgr.createVersionHistory(node);
-        return (VersionHistory) node.getSession().getNodeByUUID(history.getId());
-    }
+    public VersionHistory createVersionHistory(NodeImpl node) throws RepositoryException;
+
 
     /**
      * Returns the base version of the given node. assuming mix:versionable
@@ -193,12 +111,7 @@
      * @return
      * @throws RepositoryException
      */
-    public Version getBaseVersion(NodeImpl node) throws RepositoryException {
-        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 : (Version) node.getSession().getNodeByUUID(version.getId());
-    }
+    public Version getBaseVersion(NodeImpl node) throws RepositoryException;
 
     /**
      * Returns the version history for the given node. assuming mix:versionable
@@ -209,38 +122,19 @@
      * @throws RepositoryException
      */
     public VersionHistory getVersionHistory(NodeImpl node)
-            throws RepositoryException {
-        String histUUID = node.getProperty(VersionManager.PROPNAME_VERSION_HISTORY).getString();
-        InternalVersionHistory history = vMgr.getVersionHistory(histUUID);
-        return (VersionHistory) node.getSession().getNodeByUUID(history.getId());
-    }
-
-    //-----------------------------------------------------< internal stuff >---
+            throws RepositoryException;
 
     /**
-     * Checks, if the version history with the given name exists
-     *
-     * @param name
-     * @return
-     */
-    boolean hasVersionHistory(QName name) {
-        // name is uuid of version history
-        String id = name.getLocalName();
-        return vMgr.hasVersionHistory(id);
-    }
-
-    /**
-     * Returns the vesion history impl for the given name
+     * invokes the checkin() on the persistent version manager and remaps the
+     * newly created version objects.
      *
-     * @param name
+     * @param node
      * @return
      * @throws RepositoryException
      */
-    InternalVersionHistory getVersionHistory(QName name) throws RepositoryException {
-        // name is uuid of version history
-        String id = name.getLocalName();
-        return vMgr.getVersionHistory(id);
-    }
+    public Version checkin(NodeImpl node) throws RepositoryException;
+
+    //-----------------------------------------------------< internal stuff >---
 
     /**
      * Checks if the version history with the given id exists
@@ -248,9 +142,7 @@
      * @param id
      * @return
      */
-    boolean hasVersionHistory(String id) {
-        return vMgr.hasVersionHistory(id);
-    }
+    public boolean hasVersionHistory(String id);
 
     /**
      * Returns the version history with the given id
@@ -259,9 +151,7 @@
      * @return
      * @throws RepositoryException
      */
-    InternalVersionHistory getVersionHistory(String id) throws RepositoryException {
-        return vMgr.getVersionHistory(id);
-    }
+    public InternalVersionHistory getVersionHistory(String id) throws RepositoryException;
 
     /**
      * Returns the number of version histories
@@ -269,19 +159,15 @@
      * @return
      * @throws RepositoryException
      */
-    int getNumVersionHistories() throws RepositoryException {
-        return vMgr.getNumVersionHistories();
-    }
+    public int getNumVersionHistories() throws RepositoryException;
 
     /**
-     * Returns an iterator over all {@link InternalVersionHistory}s.
+     * Returns an iterator over all ids of {@link InternalVersionHistory}s.
      *
      * @return
      * @throws RepositoryException
      */
-    Iterator getVersionHistories() throws RepositoryException {
-        return vMgr.getVersionHistories();
-    }
+    public Iterator getVersionHistoryIds() throws RepositoryException;
 
     /**
      * Checks if the version with the given id exists
@@ -289,9 +175,7 @@
      * @param id
      * @return
      */
-    boolean hasVersion(String id) {
-        return vMgr.hasVersion(id);
-    }
+    boolean hasVersion(String id);
 
     /**
      * Returns the version with the given id
@@ -300,151 +184,21 @@
      * @return
      * @throws RepositoryException
      */
-    InternalVersion getVersion(String id) throws RepositoryException {
-        return vMgr.getVersion(id);
-    }
+    InternalVersion getVersion(String id) throws RepositoryException;
 
     /**
-     * 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
-     */
-    public VersionHistoryImpl createVersionHistoryInstance(SessionImpl session,
-                                                           NodeState state, NodeDef def,
-                                                           ItemManager itemMgr,
-                                                           ItemLifeCycleListener[] listeners)
-            throws RepositoryException {
-        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);
-    }
-
-    /**
-     * Creates a new VersionImpl instance. this is usually called by
-     * the {@link ItemManager}.
-     *
-     * @param session
-     * @param state
-     * @param def
-     * @param itemMgr
-     * @param listeners
+     * checks, if the node with the given id exists
+     * @param id
      * @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);
-    }
+    public boolean hasItem(String id);
 
     /**
-     * invokes the checkin() on the persistent version manager and remaps the
-     * newly created version objects.
-     *
-     * @param node
+     * Returns the version item with the given id
+     * @param id
      * @return
      * @throws RepositoryException
      */
-    public synchronized Version checkin(NodeImpl node) throws RepositoryException {
-        InternalVersion version = vMgr.checkin(node);
-
-        vMgr.onVersionHistoryModified(version.getVersionHistory());
-
-        // 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());
-    }
-
-    /**
-     * 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 synchronized void onVersionModified(InternalVersion v)
-            throws RepositoryException {
-    }
+    public InternalVersionItem getItem(String id) throws RepositoryException;
 
-    /**
-     * Called when a internal version history has changed its internal structure,
-     * and the structure has to be remapped to the content.
-     *
-     * @param vh
-     * @throws RepositoryException
-     */
-    protected synchronized void onVersionHistoryModified(InternalVersionHistory vh)
-            throws RepositoryException {
-    }
-
-    /**
-     * Helper class that generates and hold generic definition ids
-     */
-    private static class DefinitionIdMgr {
-
-        private final HashMap ids = new HashMap();
-
-        private final NodeTypeManagerImpl ntMgr;
-
-        public DefinitionIdMgr(NodeTypeManagerImpl ntMgr)
-                throws NoSuchNodeTypeException, RepositoryException {
-            this.ntMgr = ntMgr;
-            add(VersionManager.NODENAME_ROOTVERSION, NodeTypeRegistry.NT_VERSION, NodeTypeRegistry.NT_VERSION_HISTORY);
-            add(VersionManager.NODENAME_HISTORY_ROOT, NodeTypeRegistry.NT_UNSTRUCTURED, NodeTypeRegistry.NT_UNSTRUCTURED);
-            add(NodeTypeRegistry.NT_VERSION_HISTORY, NodeTypeRegistry.NT_VERSION_HISTORY, NodeTypeRegistry.NT_UNSTRUCTURED);
-            add(ItemImpl.PROPNAME_PRIMARYTYPE, NodeTypeRegistry.NT_BASE, PropertyType.NAME, false);
-            add(ItemImpl.PROPNAME_MIXINTYPES, NodeTypeRegistry.NT_BASE, PropertyType.NAME, true);
-            add(ItemImpl.PROPNAME_UUID, NodeTypeRegistry.MIX_REFERENCEABLE, PropertyType.STRING, false);
-            add(VersionManager.PROPNAME_CREATED, NodeTypeRegistry.NT_VERSION, PropertyType.DATE, false);
-            add(VersionManager.PROPNAME_FROZEN_UUID, NodeTypeRegistry.NT_VERSION, PropertyType.STRING, false);
-            add(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE, NodeTypeRegistry.NT_VERSION, PropertyType.NAME, false);
-            add(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES, NodeTypeRegistry.NT_VERSION, PropertyType.NAME, true);
-            add(VersionManager.PROPNAME_VERSION_LABELS, NodeTypeRegistry.NT_VERSION, PropertyType.STRING, true);
-            add(VersionManager.PROPNAME_PREDECESSORS, NodeTypeRegistry.NT_VERSION, PropertyType.REFERENCE, true);
-            add(VersionManager.PROPNAME_SUCCESSORS, NodeTypeRegistry.NT_VERSION, PropertyType.REFERENCE, true);
-        }
-
-        private void add(QName nodeName, QName nt, QName parentNt)
-                throws NoSuchNodeTypeException, RepositoryException {
-            NodeDefId id = new NodeDefId(ntMgr.getNodeType(parentNt).getApplicableChildNodeDef(nodeName, nt).unwrap());
-            ids.put(nodeName, id);
-        }
-
-        private void add(QName propName, QName nt, int type, boolean multivalued)
-                throws NoSuchNodeTypeException, RepositoryException {
-            PropDefId id = new PropDefId(ntMgr.getNodeType(nt).getApplicablePropertyDef(propName, type, multivalued).unwrap());
-            ids.put(propName, id);
-        }
-
-        public NodeDefId getNodeDefId(QName name) {
-            return (NodeDefId) ids.get(name);
-        }
-
-        public PropDefId getPropDefId(QName name) {
-            return (PropDefId) ids.get(name);
-        }
-    }
 }

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,245 @@
+/*
+ * 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.log4j.Logger;
+import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.state.ItemStateProvider;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.Version;
+import java.util.Iterator;
+
+/**
+ * This Class implements a VersionManager. It more or less acts as proxy
+ * between the virtual item state manager that exposes the version to the
+ * version storage ({@link VersionItemStateProvider}) and the persistent
+ * version manager.
+ */
+public class VersionManagerImpl implements VersionManager {
+
+    /**
+     * the default logger
+     */
+    private static Logger log = Logger.getLogger(VersionManager.class);
+    /**
+     * The version manager of the internal versions
+     */
+    private final PersistentVersionManager vMgr;
+    /**
+     * The virtual item manager that exposes the versions to the content
+     */
+    private VersionItemStateProvider virtProvider;
+    /**
+     * the node type manager
+     */
+    private NodeTypeManagerImpl ntMgr;
+
+
+    /**
+     * Creates a bew vesuion manager
+     * @param vMgr
+     */
+    public VersionManagerImpl(PersistentVersionManager vMgr) {
+        this.vMgr = vMgr;
+    }
+
+    /**
+     * returns the virtual item state provider that exposes the internal versions
+     * as items.
+     *
+     * @param base
+     * @return
+     */
+    public synchronized VirtualItemStateProvider getVirtualItemStateProvider(SessionImpl session, ItemStateProvider base) {
+        if (virtProvider == null) {
+            try {
+                // init the definition id mgr
+                ntMgr = session.getNodeTypeManager();
+                ntMgr.getNodeType(NodeTypeRegistry.NT_BASE).getApplicablePropertyDef(ItemImpl.PROPNAME_PRIMARYTYPE, PropertyType.NAME, false).unwrap();
+                // check, if workspace of session has history root
+                NodeImpl systemRoot = ((RepositoryImpl) session.getRepository()).getSystemRootNode(session);
+                if (!systemRoot.hasNode(VersionManager.NODENAME_HISTORY_ROOT)) {
+                    // if not exist, create
+                    systemRoot.addNode(VersionManager.NODENAME_HISTORY_ROOT, NodeTypeRegistry.NT_UNSTRUCTURED);
+                }
+                systemRoot.save();
+                String rootId = systemRoot.getNode(VersionManager.NODENAME_HISTORY_ROOT).internalGetUUID();
+
+                NodeState virtRootState = (NodeState) base.getItemState(new NodeId(rootId));
+                virtProvider = new VersionItemStateProvider(this, ntMgr, rootId, virtRootState.getParentUUID());
+            } catch (Exception e) {
+                // todo: better error handling
+                log.error("Error while initializing virtual items.", e);
+                throw new IllegalStateException(e.toString());
+            }
+        }
+        return virtProvider;
+    }
+
+    /**
+     * returns the node type manager
+     * @return
+     */
+    NodeTypeManagerImpl getNodeTypeManager() {
+        return ntMgr;
+    }
+
+    /**
+     * 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
+     * @return
+     * @throws javax.jcr.RepositoryException
+     */
+    public VersionHistory createVersionHistory(NodeImpl node) throws RepositoryException {
+        InternalVersionHistory history = vMgr.createVersionHistory(node);
+        return (VersionHistory) node.getSession().getNodeByUUID(history.getId());
+    }
+
+    /**
+     * Returns the base version of the given node. assuming mix:versionable
+     *
+     * @param node
+     * @return
+     * @throws RepositoryException
+     */
+    public Version getBaseVersion(NodeImpl node) throws RepositoryException {
+        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 : (Version) node.getSession().getNodeByUUID(version.getId());
+    }
+
+    /**
+     * Returns the version history for the given node. assuming mix:versionable
+     * and version history set in property
+     *
+     * @param node
+     * @return
+     * @throws RepositoryException
+     */
+    public VersionHistory getVersionHistory(NodeImpl node)
+            throws RepositoryException {
+        String histUUID = node.getProperty(VersionManager.PROPNAME_VERSION_HISTORY).getString();
+        InternalVersionHistory history = vMgr.getVersionHistory(histUUID);
+        return (VersionHistory) node.getSession().getNodeByUUID(history.getId());
+    }
+
+    /**
+     * Checks if the version history with the given id exists
+     *
+     * @param id
+     * @return
+     */
+    public boolean hasVersionHistory(String id) {
+        return vMgr.hasVersionHistory(id);
+    }
+
+    /**
+     * Returns the version history with the given id
+     *
+     * @param id
+     * @return
+     * @throws RepositoryException
+     */
+    public InternalVersionHistory getVersionHistory(String id) throws RepositoryException {
+        return vMgr.getVersionHistory(id);
+    }
+
+    /**
+     * Returns the number of version histories
+     *
+     * @return
+     * @throws RepositoryException
+     */
+    public int getNumVersionHistories() throws RepositoryException {
+        return vMgr.getNumVersionHistories();
+    }
+
+    /**
+     * Returns an iterator over all ids of {@link InternalVersionHistory}s.
+     *
+     * @return
+     * @throws RepositoryException
+     */
+    public Iterator getVersionHistoryIds() throws RepositoryException {
+        return vMgr.getVersionHistoryIds();
+    }
+
+    /**
+     * Checks if the version with the given id exists
+     *
+     * @param id
+     * @return
+     */
+    public boolean hasVersion(String id) {
+        return vMgr.hasVersion(id);
+    }
+
+    /**
+     * Returns the version with the given id
+     *
+     * @param id
+     * @return
+     * @throws RepositoryException
+     */
+    public InternalVersion getVersion(String id) throws RepositoryException {
+        return vMgr.getVersion(id);
+    }
+
+    /**
+     * checks, if the node with the given id exists
+     * @param id
+     * @return
+     */
+    public boolean hasItem(String id) {
+        return vMgr.hasItem(id);
+    }
+
+    /**
+     * Returns the version item with the given id
+     * @param id
+     * @return
+     * @throws RepositoryException
+     */
+    public InternalVersionItem getItem(String id) throws RepositoryException {
+        return vMgr.getItemByExternal(id);
+    }
+
+    /**
+     * invokes the checkin() on the persistent version manager and remaps the
+     * newly created version objects.
+     *
+     * @param node
+     * @return
+     * @throws RepositoryException
+     */
+    public synchronized Version checkin(NodeImpl node) throws RepositoryException {
+        InternalVersion version = vMgr.checkin(node);
+        return (Version) node.getSession().getNodeByUUID(version.getId());
+    }
+
+
+}

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionNodeState.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionNodeState.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionNodeState.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionNodeState.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionNodeState.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionNodeState.java	Mon Dec 20 02:29:45 2004
@@ -17,98 +17,73 @@
 
 import org.apache.jackrabbit.core.InternalValue;
 import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.version.VersionItemStateProvider;
+import org.apache.jackrabbit.core.version.InternalVersion;
+import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.state.NoSuchItemStateException;
 import org.apache.jackrabbit.core.util.uuid.UUID;
 import org.apache.jackrabbit.core.virtual.VirtualNodeState;
 import org.apache.jackrabbit.core.virtual.VirtualPropertyState;
 
-import javax.jcr.PropertyType;
-import java.util.Calendar;
+import javax.jcr.RepositoryException;
 
 /**
- * This Class implements...
+ * This Class implements a virtual node state that represents a version.
+ * since some properties like 'jcr:versionLabels', 'jcr:predecessors' etc. can
+ * change over time, we treat them specially.
  */
 public class VersionNodeState extends VirtualNodeState {
 
+    /**
+     * the internal version
+     */
     private final InternalVersion v;
 
-    public VersionNodeState(VersionItemStateProvider vm, InternalVersion v) {
-        super(vm, v.getId(), NodeTypeRegistry.NT_VERSION, v.getVersionHistory().getId());
+    /**
+     * Creates a new version node state
+     * @param vm
+     * @param v
+     * @param parentUUID
+     * @throws RepositoryException
+     */
+    protected VersionNodeState(VersionItemStateProvider vm, InternalVersion v,
+                            String parentUUID)
+            throws RepositoryException {
+        super(vm, parentUUID, v.getId(), NodeTypeRegistry.NT_VERSION, new QName[0]);
         this.v = v;
 
-        // we map the property entries, since they do not change
-        addPropertyEntry(VersionManager.PROPNAME_CREATED);
-        addPropertyEntry(VersionManager.PROPNAME_FROZEN_UUID);
-        addPropertyEntry(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE);
-        addPropertyEntry(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES);
-        addPropertyEntry(VersionManager.PROPNAME_VERSION_LABELS);
-        addPropertyEntry(VersionManager.PROPNAME_PREDECESSORS);
-        addPropertyEntry(VersionManager.PROPNAME_SUCCESSORS);
-
-        // and the frozen node if not root version
+        // add the frozen node id if not root version
         if (!v.isRootVersion()) {
-            addChildNodeEntry(v.getFrozenNode().getName(), v.getFrozenNode().getInternalUUID());
+            addChildNodeEntry(VersionManager.NODENAME_FROZEN, v.getFrozenNode().getId());
         }
-
-        setDefinitionId(vm.getNodeDefId(VersionManager.NODENAME_ROOTVERSION));
     }
 
-    public VirtualPropertyState getPropertyState(QName name) throws NoSuchItemStateException {
-        if (name.equals(VersionManager.PROPNAME_CREATED)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(VersionManager.PROPNAME_CREATED));
-            state.setType(PropertyType.DATE);
-            state.setValues(InternalValue.create(new Calendar[]{v.getCreated()}));
-            return state;
-        } else if (name.equals(VersionManager.PROPNAME_FROZEN_UUID)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(VersionManager.PROPNAME_FROZEN_UUID));
-            state.setType(PropertyType.STRING);
-            state.setValues(InternalValue.create(new String[]{v.getFrozenNode().getUUID()}));
-            return state;
-        } else if (name.equals(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE));
-            state.setType(PropertyType.NAME);
-            state.setValues(InternalValue.create(new QName[]{v.getFrozenNode().getFrozenPrimaryType()}));
-            return state;
-        } else if (name.equals(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES));
-            state.setType(PropertyType.NAME);
-            state.setValues(InternalValue.create(v.getFrozenNode().getFrozenMixinTypes()));
-            return state;
-        } else if (name.equals(VersionManager.PROPNAME_VERSION_LABELS)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(VersionManager.PROPNAME_VERSION_LABELS));
-            state.setType(PropertyType.STRING);
-            state.setValues(InternalValue.create(v.internalGetLabels()));
-            return state;
-        } else if (name.equals(VersionManager.PROPNAME_PREDECESSORS)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(VersionManager.PROPNAME_PREDECESSORS));
-            state.setType(PropertyType.STRING);
-            InternalVersion[] preds = v.getPredecessors();
-            InternalValue[] predV = new InternalValue[preds.length];
-            for (int i = 0; i < preds.length; i++) {
-                predV[i] = InternalValue.create(new UUID(preds[i].getId()));
-            }
-            state.setValues(predV);
-            return state;
-        } else if (name.equals(VersionManager.PROPNAME_SUCCESSORS)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(VersionManager.PROPNAME_SUCCESSORS));
-            state.setType(PropertyType.STRING);
-            InternalVersion[] succs = v.getSuccessors();
-            InternalValue[] succV = new InternalValue[succs.length];
-            for (int i = 0; i < succs.length; i++) {
-                succV[i] = InternalValue.create(new UUID(succs[i].getId()));
+    /**
+     * @see VirtualNodeState#getProperty(org.apache.jackrabbit.core.QName)
+     */
+    public VirtualPropertyState getProperty(QName name)
+            throws NoSuchItemStateException {
+        VirtualPropertyState state = super.getProperty(name);
+        if (state!=null) {
+            if (name.equals(VersionManager.PROPNAME_VERSION_LABELS)) {
+                state.setValues(InternalValue.create(v.getLabels()));
+            } else if (name.equals(VersionManager.PROPNAME_PREDECESSORS)) {
+                InternalVersion[] preds = v.getPredecessors();
+                InternalValue[] predV = new InternalValue[preds.length];
+                for (int i = 0; i < preds.length; i++) {
+                    predV[i] = InternalValue.create(new UUID(preds[i].getId()));
+                }
+                state.setValues(predV);
+            } else if (name.equals(VersionManager.PROPNAME_SUCCESSORS)) {
+                InternalVersion[] succs = v.getSuccessors();
+                InternalValue[] succV = new InternalValue[succs.length];
+                for (int i = 0; i < succs.length; i++) {
+                    succV[i] = InternalValue.create(new UUID(succs[i].getId()));
+                }
+                state.setValues(succV);
             }
-            state.setValues(succV);
-            return state;
-        } else {
-            return super.getPropertyState(name);
         }
+        return state;
     }
 }

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFreezeImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFreezeImpl.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFreezeImpl.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,38 @@
+/*
+ * 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.persistence;
+
+import org.apache.jackrabbit.core.version.InternalFreeze;
+import org.apache.jackrabbit.core.version.InternalVersionItem;
+import org.apache.jackrabbit.core.version.PersistentVersionManager;
+
+/**
+ * 
+ */
+abstract class InternalFreezeImpl extends InternalVersionItemImpl implements InternalFreeze {
+
+    private final InternalVersionItem parent;
+
+    protected InternalFreezeImpl(PersistentVersionManager vMgr, InternalVersionItem parent) {
+        super(vMgr);
+        this.parent = parent;
+    }
+
+    public InternalVersionItem getParent() {
+        return parent;
+    }
+
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFrozenNodeImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFrozenNodeImpl.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFrozenNodeImpl.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,310 @@
+/*
+ * 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.persistence;
+
+import org.apache.jackrabbit.core.version.*;
+import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.util.uuid.UUID;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.PropertyType;
+import javax.jcr.PropertyIterator;
+import javax.jcr.NodeIterator;
+import javax.jcr.version.OnParentVersionAction;
+import javax.jcr.version.VersionException;
+import javax.jcr.nodetype.NodeType;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ *
+ */
+class InternalFrozenNodeImpl extends InternalFreezeImpl implements InternalFrozenNode {
+
+    /**
+     * the underlaying persistance node
+     */
+    private PersistentNode node;
+
+    /**
+     * the list of frozen properties
+     */
+    private PropertyState[] frozenProperties;
+
+    /**
+     * the frozen uuid of the original node
+     */
+    private String frozenUUID = null;
+
+    /**
+     * the frozen primary type of the orginal node
+     */
+    private QName frozenPrimaryType = null;
+
+    /**
+     * the frozen list of mixin types of the original node
+     */
+    private QName[] frozenMixinTypes = null;
+
+    /**
+     * the external id of this node
+     */
+    private final String id;
+
+    /**
+     * Creates a new frozen node based on the given persistance node.
+     *
+     * @param node
+     * @throws javax.jcr.RepositoryException
+     */
+    protected InternalFrozenNodeImpl(PersistentVersionManager vMgr,
+                                 PersistentNode node,
+                                 String id,
+                                 InternalVersionItem parent) throws RepositoryException {
+        super(vMgr, parent);
+        this.node = node;
+        this.id = id;
+
+        // init the frozen properties
+        PropertyState[] props = node.getProperties();
+        List propList = new ArrayList();
+
+        for (int i = 0; i < props.length; i++) {
+            PropertyState prop = props[i];
+            if (prop.getName().equals(VersionManager.PROPNAME_FROZEN_UUID)) {
+                // special property
+                frozenUUID = node.getPropertyValue(VersionManager.PROPNAME_FROZEN_UUID).internalValue().toString();
+            } else if (prop.getName().equals(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE)) {
+                // special property
+                frozenPrimaryType = (QName) node.getPropertyValue(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE).internalValue();
+            } else if (prop.getName().equals(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES)) {
+                // special property
+                InternalValue[] values = node.getPropertyValues(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES);
+                if (values == null) {
+                    frozenMixinTypes = new QName[0];
+                } else {
+                    frozenMixinTypes = new QName[values.length];
+                    for (int j = 0; j < values.length; j++) {
+                        frozenMixinTypes[j] = (QName) values[j].internalValue();
+                    }
+                }
+            } else if (prop.getName().equals(ItemImpl.PROPNAME_PRIMARYTYPE)) {
+                // ignore
+            } else if (prop.getName().equals(ItemImpl.PROPNAME_UUID)) {
+                // ignore
+            } else {
+                propList.add(prop);
+            }
+        }
+        frozenProperties = (PropertyState[]) propList.toArray(new PropertyState[propList.size()]);
+
+        // do some checks
+        if (frozenMixinTypes == null) {
+            frozenMixinTypes = new QName[0];
+        }
+        if (frozenPrimaryType == null) {
+            throw new RepositoryException("Illegal frozen node. Must have 'frozenPrimaryType'");
+        }
+        // init the frozen child nodes
+        /*
+        PersistentNode[] childNodes = node.getChildNodes();
+        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(this, childNodes[i]);
+        } else if (childNodes[i].hasProperty(VersionManager.PROPNAME_VERSION_HISTORY)) {
+        frozenChildNodes[i] = new InternalFrozenVersionHistory(this, childNodes[i]);
+        } else {
+        // unkown ?
+        }
+        }
+        */
+
+    }
+
+    /**
+     * Returns the name of this frozen node
+     *
+     * @return
+     */
+    public QName getName() {
+        return node.getName();
+    }
+
+
+    protected String getPersistentId() {
+        return node.getUUID();
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.version.InternalFrozenNode#getFrozenChildNodes()
+     */
+    public InternalFreeze[] getFrozenChildNodes() throws VersionException {
+        try {
+            // maybe add iterator?
+            List entries = node.getState().getChildNodeEntries();
+            InternalFreeze[] freezes = new InternalFreeze[entries.size()];
+            Iterator iter = entries.iterator();
+            int i=0;
+            while (iter.hasNext()) {
+                NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
+                freezes[i++] = (InternalFreeze) getVersionManager().getItemByInternal(entry.getUUID());
+            }
+            return freezes;
+        } catch (RepositoryException e) {
+            throw new VersionException("Unable to retrieve frozen child nodes", e);
+        }
+    }
+
+    /**
+     * Returns the list of frozen properties
+     *
+     * @return
+     */
+    public PropertyState[] getFrozenProperties() {
+        return frozenProperties;
+    }
+
+    /**
+     * Returns the frozen UUID
+     *
+     * @return
+     */
+    public String getFrozenUUID() {
+        return frozenUUID;
+    }
+
+    /**
+     * Returns the frozen primary type
+     *
+     * @return
+     */
+    public QName getFrozenPrimaryType() {
+        return frozenPrimaryType;
+    }
+
+    /**
+     * Returns the list of the frozen mixin types
+     *
+     * @return
+     */
+    public QName[] getFrozenMixinTypes() {
+        return frozenMixinTypes;
+    }
+
+    /**
+     * Checks-in a <code>src</code> node. It creates a new child node of
+     * <code>parent</code> with the given <code>name</code> and adds the
+     * source nodes properties according to their OPV value to the
+     * list of frozen properties. It creates frozen child nodes for each child
+     * node of <code>src</code> according to its OPV value.
+     *
+     * @param parent
+     * @param name
+     * @param src
+     * @return
+     * @throws RepositoryException
+     */
+    protected static PersistentNode checkin(PersistentNode parent, QName name, NodeImpl src, boolean initOnly, boolean forceCopy)
+            throws RepositoryException {
+
+        PersistentNode node;
+
+        // create new node
+        node = parent.addNode(name, NativePVM.NT_REP_FROZEN);
+
+        // initialize the internal properties
+        if (src.isNodeType(NodeTypeRegistry.MIX_REFERENCEABLE)) {
+            node.setPropertyValue(VersionManager.PROPNAME_FROZEN_UUID, InternalValue.create(src.getUUID()));
+        }
+
+        node.setPropertyValue(VersionManager.PROPNAME_FROZEN_PRIMARY_TYPE,
+                InternalValue.create(((NodeTypeImpl) src.getPrimaryNodeType()).getQName()));
+
+        if (src.hasProperty(NodeImpl.PROPNAME_MIXINTYPES)) {
+            NodeType[] mixins = src.getMixinNodeTypes();
+            InternalValue[] ivalues = new InternalValue[mixins.length];
+            for (int i = 0; i < mixins.length; i++) {
+                ivalues[i] = InternalValue.create(((NodeTypeImpl) mixins[i]).getQName());
+            }
+            node.setPropertyValues(VersionManager.PROPNAME_FROZEN_MIXIN_TYPES, PropertyType.NAME, ivalues);
+        }
+
+        if (!initOnly) {
+            // add the properties
+            PropertyIterator piter = src.getProperties();
+            while (piter.hasNext()) {
+                PropertyImpl prop = (PropertyImpl) piter.nextProperty();
+                int opv = forceCopy ? OnParentVersionAction.COPY : prop.getDefinition().getOnParentVersion();
+                switch (opv) {
+                    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();
+                int opv = forceCopy ? OnParentVersionAction.COPY : child.getDefinition().getOnParentVersion();
+                switch (opv) {
+                    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_FROZEN_VERSIONABLE_CHILD);
+                            newChild.setPropertyValue(VersionManager.PROPNAME_VERSION_HISTORY,
+                                    InternalValue.create(UUID.fromString(child.getVersionHistory().getUUID())));
+                            newChild.setPropertyValue(VersionManager.PROPNAME_BASE_VERSION,
+                                    InternalValue.create(UUID.fromString(child.getBaseVersion().getUUID())));
+                            break;
+                        }
+                        // else copy
+                    case OnParentVersionAction.COPY:
+                        checkin(node, child.getQName(), child, false, true);
+                        break;
+                }
+            }
+        }
+        parent.store();
+        return node;
+    }
+
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFrozenVHImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFrozenVHImpl.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalFrozenVHImpl.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,101 @@
+/*
+ * 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.persistence;
+
+import org.apache.jackrabbit.core.version.*;
+import org.apache.jackrabbit.core.QName;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.version.VersionException;
+
+/**
+ *
+ */
+class InternalFrozenVHImpl extends InternalFreezeImpl implements InternalFrozenVersionHistory {
+
+    /**
+     * the underlaying persistence node
+     */
+    private PersistentNode node;
+
+    private final String id;
+
+    /**
+     * Creates a new frozen version history.
+     *
+     * @param node
+     */
+    protected InternalFrozenVHImpl(PersistentVersionManager vMgr, PersistentNode node, String id, InternalVersionItem parent) {
+        super(vMgr, parent);
+        this.node = node;
+        this.id = id;
+    }
+
+    /**
+     * Returns the name of this frozen version history
+     *
+     * @return
+     */
+    public QName getName() {
+        return node.getName();
+    }
+
+    protected String getPersistentId() {
+        return node.getUUID();
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.version.InternalFrozenVersionHistory#getVersionHistoryId()
+     */
+    public String getVersionHistoryId() {
+        return (String) node.getPropertyValue(VersionManager.PROPNAME_VERSION_HISTORY).internalValue();
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.version.InternalFrozenVersionHistory#getVersionHistory()
+     */
+    public InternalVersionHistory getVersionHistory()
+            throws VersionException {
+        try {
+            return getVersionManager().getVersionHistory(getVersionHistoryId());
+        } catch (RepositoryException e) {
+            throw new VersionException(e);
+        }
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.version.InternalFrozenVersionHistory#getBaseVersionId()
+     */
+    public String getBaseVersionId() {
+        return (String) node.getPropertyValue(VersionManager.PROPNAME_BASE_VERSION).internalValue();
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.version.InternalFrozenVersionHistory#getBaseVesion()
+     */
+    public InternalVersion getBaseVesion()
+            throws VersionException {
+        try {
+            return getVersionManager().getVersion(getVersionHistoryId(), getBaseVersionId());
+        } catch (RepositoryException e) {
+            throw new VersionException(e);
+        }
+    }
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionHistoryImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionHistoryImpl.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionHistoryImpl.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,451 @@
+/*
+ * 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.persistence;
+
+import org.apache.jackrabbit.core.version.*;
+import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.InternalValue;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.NamespaceRegistryImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.util.Text;
+import org.apache.jackrabbit.core.util.uuid.UUID;
+import org.apache.log4j.Logger;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.PropertyType;
+import javax.jcr.version.VersionException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Calendar;
+
+/**
+ *
+ */
+class InternalVersionHistoryImpl extends InternalVersionItemImpl implements InternalVersionHistory {
+    /**
+     * default logger
+     */
+    private static Logger log = Logger.getLogger(InternalVersionHistory.class);
+
+    /**
+     * the cache of the version labels
+     * key = version label (String)
+     * value = version
+     */
+    private HashMap labelCache = new HashMap();
+
+    /**
+     * the root version of this history
+     */
+    private InternalVersion rootVersion;
+
+    /**
+     * the hashmap of all versions
+     * key = versionId (String)
+     * value = version
+     */
+    private HashMap versionCache = new HashMap();
+
+    /**
+     * The nodes state of this version history
+     */
+    private PersistentNode node;
+
+    /**
+     * the node that holds the label nodes
+     */
+    private PersistentNode labelNode;
+
+    /**
+     * the id of this history
+     */
+    private String historyId;
+
+    /**
+     * Creates a new VersionHistory object for the given node state.
+     */
+    InternalVersionHistoryImpl(PersistentVersionManager vMgr, PersistentNode node) throws RepositoryException {
+        super(vMgr);
+        this.node = node;
+        init();
+    }
+
+    /**
+     * Initialies the history and loads all internal caches
+     *
+     * @throws RepositoryException
+     */
+    private void init() throws RepositoryException {
+        versionCache.clear();
+        labelCache.clear();
+
+        // get id
+        historyId = (String) node.getPropertyValue(NativePVM.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(NativePVM.NODENAME_VERSION_LABELS)) {
+                labelNode = child;
+                continue;
+            }
+            InternalVersionImpl v = new InternalVersionImpl(getVersionManager(), this, child);
+            versionCache.put(v.getId(), v);
+            if (v.isRootVersion()) {
+                rootVersion = v;
+            }
+        }
+
+        // resolve successors and predecessors
+        Iterator iter = versionCache.values().iterator();
+        while (iter.hasNext()) {
+            InternalVersionImpl v = (InternalVersionImpl) iter.next();
+            v.resolvePredecessors();
+        }
+
+        // init label cache
+        PersistentNode labels[] = labelNode.getChildNodes();
+        for (int i = 0; i < labels.length; i++) {
+            PersistentNode lNode = labels[i];
+            String name = (String) lNode.getPropertyValue(NativePVM.PROPNAME_NAME).internalValue();
+            String ref = (String) lNode.getPropertyValue(NativePVM.PROPNAME_VERSION).internalValue();
+            InternalVersionImpl v = (InternalVersionImpl) getVersion(ref);
+            labelCache.put(name, v);
+            v.internalAddLabel(name);
+        }
+    }
+
+    /**
+     * Returns the id of this version history
+     *
+     * @return
+     */
+    public String getId() {
+        return historyId;
+    }
+
+    protected String getPersistentId() {
+        return node.getUUID();
+    }
+
+    public InternalVersionItem getParent() {
+        return null;
+    }
+
+    /**
+     * @see javax.jcr.version.VersionHistory#getRootVersion()
+     */
+    public InternalVersion getRootVersion() {
+        return rootVersion;
+    }
+
+    /**
+     * @see javax.jcr.version.VersionHistory#getVersion(java.lang.String)
+     */
+    public InternalVersion getVersion(QName versionName) throws VersionException {
+        // maybe add cache by name?
+        Iterator iter = versionCache.values().iterator();
+        while (iter.hasNext()) {
+            InternalVersion v = (InternalVersion) iter.next();
+            if (v.getName().equals(versionName)) {
+                return v;
+            }
+        }
+        throw new VersionException("Version " + versionName + " does not exist.");
+    }
+
+    /**
+     *
+     * @param versionName
+     * @return
+     */
+    public boolean hasVersion(QName versionName) {
+        // maybe add cache?
+        Iterator iter = versionCache.values().iterator();
+        while (iter.hasNext()) {
+            InternalVersion v = (InternalVersion) iter.next();
+            if (v.getName().equals(versionName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks if the version for the given uuid exists
+     *
+     * @param uuid
+     * @return
+     */
+    public boolean hasVersion(String uuid) {
+        return versionCache.containsKey(uuid);
+    }
+
+    /**
+     * Returns the version with the given uuid or <code>null</code> if the
+     * respective version does not exist.
+     *
+     * @param uuid
+     * @return
+     */
+    public InternalVersion getVersion(String uuid) {
+        return (InternalVersion) versionCache.get(uuid);
+    }
+
+    /**
+     * @see javax.jcr.version.VersionHistory#getVersionByLabel(java.lang.String)
+     */
+    public InternalVersion getVersionByLabel(String label) {
+        return (InternalVersion) labelCache.get(label);
+    }
+
+    /**
+     * Removes the indicated version from this VersionHistory. If the specified
+     * vesion does not exist, if it specifies the root version or if it is
+     * referenced by any node e.g. as base version, a VersionException is thrown.
+     * <p/>
+     * all successors of the removed version become successors of the
+     * predecessors of the removed version and vice versa. then, the entire
+     * version node and all its subnodes are removed.
+     *
+     * @param versionName
+     * @throws VersionException
+     */
+    public void removeVersion(QName versionName) throws VersionException {
+        InternalVersionImpl v = (InternalVersionImpl) getVersion(versionName);
+        if (v.equals(rootVersion)) {
+            String msg = "Removal of " + versionName + " not allowed.";
+            log.error(msg);
+            throw new VersionException(msg);
+        }
+
+        try {
+            // remove from persistance state
+            node.removeNode(versionName);
+
+            // unregister from labels
+            String[] labels = v.internalGetLabels();
+            for (int i = 0; i < labels.length; i++) {
+                v.internalRemoveLabel(labels[i]);
+                QName name = new QName("", Text.md5(labels[i]));
+                labelNode.removeNode(name);
+            }
+
+            // detach from the version graph
+            v.internalDetach();
+
+            // and remove from history
+            versionCache.remove(v.getId());
+            store();
+        } catch (RepositoryException e) {
+            throw new VersionException("error while storing modifications", e);
+        }
+    }
+
+    /**
+     * @see InternalVersionHistory#addVersionLabel(org.apache.jackrabbit.core.QName, String, boolean)
+     */
+    public InternalVersion addVersionLabel(QName versionName, String label, boolean move)
+            throws VersionException {
+
+        InternalVersion version = getVersion(versionName);
+        if (version == null) {
+            throw new VersionException("Version " + versionName + " does not exist in this version history.");
+        }
+
+        InternalVersionImpl prev = (InternalVersionImpl) labelCache.get(label);
+        if (version.equals(prev)) {
+            // ignore
+            return version;
+        } else if (prev != null && !move) {
+            // already defined elsewhere, throw
+            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);
+        }
+        labelCache.put(label, version);
+        ((InternalVersionImpl) version).internalAddLabel(label);
+        QName name = new QName("", Text.md5(label));
+        try {
+            PersistentNode lNode = labelNode.addNode(name, NodeTypeRegistry.NT_UNSTRUCTURED);
+            lNode.setPropertyValue(NativePVM.PROPNAME_NAME, InternalValue.create(label));
+            lNode.setPropertyValue(NativePVM.PROPNAME_VERSION, InternalValue.create(version.getId()));
+            labelNode.store();
+        } catch (RepositoryException e) {
+            throw new VersionException("Error while storing modifications", e);
+        }
+        return prev;
+    }
+
+    /**
+     * @see InternalVersionHistory#removeVersionLabel(String)
+     */
+    public InternalVersion removeVersionLabel(String label) throws VersionException {
+        InternalVersionImpl v = (InternalVersionImpl) labelCache.remove(label);
+        if (v == null) {
+            throw new VersionException("Version label " + label + " is not in version history.");
+        }
+        v.internalRemoveLabel(label);
+        QName name = new QName("", Text.md5(label));
+
+        try {
+            labelNode.removeNode(name);
+            labelNode.store();
+        } catch (RepositoryException e) {
+            throw new VersionException("Unable to store modifications", e);
+        }
+
+        return v;
+    }
+
+    /**
+     * Checks in a node. It creates a new version with the given name and freezes
+     * the state of the given node.
+     *
+     * @param name
+     * @param src
+     * @return
+     * @throws RepositoryException
+     */
+    protected InternalVersionImpl checkin(QName name, NodeImpl src)
+            throws RepositoryException {
+
+        // copy predecessors from src node
+        Value[] preds = src.getProperty(VersionManager.PROPNAME_PREDECESSORS).getValues();
+        InternalValue[] predecessors = new InternalValue[preds.length];
+        for (int i = 0; i < preds.length; i++) {
+            String predId = preds[i].getString();
+            // check if version exist
+            if (!versionCache.containsKey(predId)) {
+                throw new RepositoryException("invalid predecessor in source node");
+            }
+            predecessors[i] = InternalValue.create(predId);
+        }
+
+        String versionId = UUID.randomUUID().toString();
+        QName nodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, versionId);
+        PersistentNode vNode = node.addNode(nodeName, NativePVM.NT_REP_VERSION);
+        vNode.setPropertyValue(NativePVM.PROPNAME_VERSION_ID, InternalValue.create(versionId));
+        vNode.setPropertyValue(NativePVM.PROPNAME_VERSION_NAME, InternalValue.create(name));
+
+        // initialize 'created' and 'predecessors'
+        vNode.setPropertyValue(VersionManager.PROPNAME_CREATED, InternalValue.create(Calendar.getInstance()));
+        vNode.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.STRING, predecessors);
+
+        // checkin source node
+        InternalFrozenNodeImpl.checkin(vNode, VersionManager.NODENAME_FROZEN, src, false, false);
+
+        // and store
+        store();
+
+        // update version graph
+        InternalVersionImpl version = new InternalVersionImpl(getVersionManager(), this, vNode);
+        version.resolvePredecessors();
+
+        // update cache
+        versionCache.put(version.getId(), version);
+
+        return version;
+    }
+
+
+    /**
+     * Stores the changes made to this version history
+     *
+     * @throws RepositoryException
+     */
+    protected void store() throws RepositoryException {
+        node.store();
+    }
+
+    /**
+     * discards the changes made to this version history
+     *
+     * @throws RepositoryException
+     */
+    protected void reload() throws RepositoryException {
+        node.reload();
+        init();
+    }
+
+    /**
+     * Returns an iterator over all versions (not ordered yet)
+     *
+     * @return
+     */
+    public Iterator getVersions() {
+        return versionCache.values().iterator();
+    }
+
+    /**
+     * Returns the number of versions
+     *
+     * @return
+     */
+    public int getNumVersions() {
+        return versionCache.size();
+    }
+
+    protected String getUUID() {
+        return node.getUUID();
+    }
+
+    protected PersistentNode getNode() {
+        return node;
+    }
+
+    /**
+     * Creates a new <code>InternalVersionHistory</code> below the given parent
+     * node and with the given name.
+     *
+     * @param parent
+     * @param name
+     * @return
+     * @throws RepositoryException
+     */
+    protected static InternalVersionHistoryImpl create(PersistentVersionManager vMgr, PersistentNode parent, String historyId, QName name, NodeImpl src)
+            throws RepositoryException {
+
+        // create history node
+        PersistentNode pNode = parent.addNode(name, NativePVM.NT_REP_VERSION_HISTORY);
+        pNode.setPropertyValue(NativePVM.PROPNAME_HISTORY_ID, InternalValue.create(historyId));
+
+        // create label node
+        pNode.addNode(NativePVM.NODENAME_VERSION_LABELS, NodeTypeRegistry.NT_UNSTRUCTURED);
+
+        // create root version
+        String versionId = UUID.randomUUID().toString();
+        QName nodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, versionId);
+
+        PersistentNode vNode = pNode.addNode(nodeName, NativePVM.NT_REP_VERSION);
+        vNode.setPropertyValue(NativePVM.PROPNAME_VERSION_ID, InternalValue.create(versionId));
+        vNode.setPropertyValue(NativePVM.PROPNAME_VERSION_NAME, InternalValue.create(VersionManager.NODENAME_ROOTVERSION));
+
+        // 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
+        InternalFrozenNodeImpl.checkin(vNode, VersionManager.NODENAME_FROZEN, src, true, false);
+
+        parent.store();
+        return new InternalVersionHistoryImpl(vMgr, pNode);
+    }
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionImpl.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionImpl.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,347 @@
+/*
+ * 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.persistence;
+
+import org.apache.jackrabbit.core.version.*;
+import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.InternalValue;
+import org.apache.jackrabbit.core.util.uuid.UUID;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.PropertyType;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashSet;
+import java.util.Arrays;
+
+/**
+ *
+ */
+class InternalVersionImpl extends InternalVersionItemImpl implements InternalVersion {
+
+    /**
+     * the list/cache of predecessors (values == InternalVersion)
+     */
+    private ArrayList predecessors = new ArrayList();
+
+    /**
+     * the list of successors (values == InternalVersion)
+     */
+    private ArrayList successors = new ArrayList();
+
+    /**
+     * the underlaying persistance node of this version
+     */
+    private PersistentNode node;
+
+    /**
+     * the date when this version was created
+     */
+    private Calendar created;
+
+    /**
+     * the set of version labes of this history (values == String)
+     */
+    private HashSet labelCache = null;
+
+    /**
+     * the id of this version
+     */
+    private String versionId;
+
+    /**
+     * specifies if this is the root version
+     */
+    private final boolean isRoot;
+
+    /**
+     * the version name
+     */
+    private final QName name;
+
+    /**
+     * the version history
+     */
+    private final InternalVersionHistory versionHistory;
+
+    /**
+     * Creates a new internal version with the given version history and
+     * persistance node
+     *
+     * @param node
+     */
+    InternalVersionImpl(PersistentVersionManager vMgr, InternalVersionHistory vh, PersistentNode node) {
+        super(vMgr);
+        this.versionHistory = vh;
+        this.node = node;
+
+        // get id
+        versionId = (String) node.getPropertyValue(NativePVM.PROPNAME_VERSION_ID).internalValue();
+
+        // init internal values
+        InternalValue[] values = node.getPropertyValues(VersionManager.PROPNAME_CREATED);
+        if (values != null) {
+            created = (Calendar) values[0].internalValue();
+        }
+        values = node.getPropertyValues(NativePVM.PROPNAME_VERSION_NAME);
+        if (values != null) {
+            name = (QName) values[0].internalValue();
+        } else {
+            name = null; // ????
+        }
+        isRoot = name.equals(VersionManager.NODENAME_ROOTVERSION);
+    }
+
+    public String getId() {
+        return versionId;
+    }
+
+    protected String getPersistentId() {
+        return node.getUUID();
+    }
+
+    public InternalVersionItem getParent() {
+        return versionHistory;
+    }
+
+    /**
+     * Returns the name of this version
+     *
+     * @return
+     */
+    public QName getName() {
+        return name;
+    }
+
+    protected PersistentNode getNode() {
+        return node;
+    }
+
+    /**
+     * Returns the frozen node
+     *
+     * @return
+     */
+    public InternalFrozenNode getFrozenNode() {
+        // get frozen node
+        try {
+            // assuming only child
+            PersistentNode[] nodes = node.getChildNodes();
+            return nodes.length==0 ? null : (InternalFrozenNode) getVersionManager().getItemByInternal(nodes[0].getUUID());
+        } catch (RepositoryException e) {
+            // ignore
+        }
+        return null;
+    }
+
+    /**
+     * adds a successor version to the internal cache
+     *
+     * @param successor
+     */
+    private void addSuccessor(InternalVersion successor) {
+        successors.add(successor);
+    }
+
+    /**
+     * resolves the predecessors property and indirectly adds it self to their
+     * successor list.
+     */
+    void resolvePredecessors() {
+        InternalValue[] values = node.getPropertyValues(VersionManager.PROPNAME_PREDECESSORS);
+        if (values != null) {
+            for (int i = 0; i < values.length; i++) {
+                InternalVersionImpl v = (InternalVersionImpl) versionHistory.getVersion(values[i].internalValue().toString());
+                predecessors.add(v);
+                v.addSuccessor(this);
+            }
+        }
+    }
+
+    /**
+     * @see javax.jcr.version.Version#getCreated()
+     */
+    public Calendar getCreated() {
+        return created;
+    }
+
+    /**
+     * @see javax.jcr.version.Version#getSuccessors()
+     */
+    public InternalVersion[] getSuccessors() {
+        return (InternalVersion[]) successors.toArray(new InternalVersion[successors.size()]);
+    }
+
+    /**
+     * @see javax.jcr.version.Version#getSuccessors()
+     */
+    public InternalVersion[] getPredecessors() {
+        return (InternalVersion[]) predecessors.toArray(new InternalVersion[predecessors.size()]);
+    }
+
+    /**
+     * stores the internal predecessor cache to the persistance node
+     *
+     * @throws RepositoryException
+     */
+    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)).getId()));
+        }
+        node.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.STRING, values);
+    }
+
+    /**
+     * Detaches itself from the version graph.
+     *
+     * @throws RepositoryException
+     */
+    void internalDetach() throws RepositoryException {
+        // detach this from all successors
+        InternalVersionImpl[] succ = (InternalVersionImpl[]) getSuccessors();
+        for (int i = 0; i < succ.length; i++) {
+            succ[i].internalDetachPredecessor(this);
+        }
+
+        // clear properties
+        successors.clear();
+        predecessors.clear();
+        labelCache = null;
+        storePredecessors();
+    }
+
+    /**
+     * Removes the predecessor V of this predecessor list and adds all of Vs
+     * predecessors to it.
+     * <p/>
+     * please note, that this operation might corrupt the version graph
+     *
+     * @param v the successor to detach
+     */
+    private void internalDetachPredecessor(InternalVersion v) throws RepositoryException {
+        // remove 'v' from predecessor list
+        for (int i = 0; i < predecessors.size(); i++) {
+            if (predecessors.get(i).equals(v)) {
+                predecessors.remove(i);
+                break;
+            }
+        }
+        // attach v's successors
+        predecessors.clear();
+        predecessors.addAll(Arrays.asList(v.getPredecessors()));
+        storePredecessors();
+    }
+
+    /**
+     * Checks if this version is more recent than the given version <code>v</code>.
+     * A version is more recent if and only if it is a successor (or a successor
+     * of a successor, etc., to any degree of separation) of the compared one.
+     *
+     * @param v the version to check
+     * @return <code>true</code> if the version is more recent;
+     *         <code>false</code> otherwise.
+     */
+    public boolean isMoreRecent(InternalVersion v) {
+        for (int i = 0; i < predecessors.size(); i++) {
+            InternalVersion pred = (InternalVersion) predecessors.get(i);
+            if (pred.equals(this) || pred.isMoreRecent(v)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * returns the internal version history of this version
+     *
+     * @return
+     */
+    public InternalVersionHistory getVersionHistory() {
+        return versionHistory;
+    }
+
+    /**
+     * adds a label to the label cache. does not affect storage
+     *
+     * @param label
+     * @return
+     */
+    protected boolean internalAddLabel(String label) {
+        if (labelCache == null) {
+            labelCache = new HashSet();
+        }
+        return labelCache.add(label);
+    }
+
+    /**
+     * removes a label from the label cache. does not affect storage
+     *
+     * @param label
+     * @return
+     */
+    protected boolean internalRemoveLabel(String label) {
+        if (labelCache == null) {
+            return false;
+        } else {
+            return labelCache.remove(label);
+        }
+    }
+
+    /**
+     * checks, if a label is in the label cache
+     *
+     * @param label
+     * @return
+     */
+    protected boolean internalHasLabel(String label) {
+        return labelCache == null ? false : labelCache.contains(label);
+    }
+
+    /**
+     * @see InternalVersion#hasLabel(String)
+     */
+    public boolean hasLabel(String label) {
+        return internalHasLabel(label);
+    }
+
+    /**
+     * returns the array of the cached labels
+     *
+     * @return
+     */
+    protected String[] internalGetLabels() {
+        return labelCache == null ? new String[0] : (String[]) labelCache.toArray(new String[labelCache.size()]);
+    }
+
+    /**
+     * @see InternalVersionImpl#getLabels()
+     */
+    public String[] getLabels() {
+        return internalGetLabels();
+    }
+
+    /**
+     * 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;
+    }
+
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionItemImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionItemImpl.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/InternalVersionItemImpl.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,66 @@
+/*
+ * 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.persistence;
+
+import org.apache.jackrabbit.core.version.PersistentVersionManager;
+import org.apache.jackrabbit.core.version.InternalVersionItem;
+
+/**
+ *
+ */
+abstract class InternalVersionItemImpl {
+
+    /**
+     * the version manager
+     */
+    private final PersistentVersionManager vMgr;
+
+    /**
+     * Creates a new Internal version item impl
+     * @param vMgr
+     */
+    protected InternalVersionItemImpl(PersistentVersionManager vMgr) {
+        this.vMgr = vMgr;
+    }
+
+    /**
+     * Returns the persistent version manager for this item
+     * @return
+     */
+    protected PersistentVersionManager getVersionManager() {
+        return vMgr;
+    }
+
+    /**
+     * Returns the internal persistent id of this item
+     * @return
+     */
+    protected abstract String getPersistentId();
+
+    /**
+     * Returns the external id of this item
+     * @return
+     */
+    public abstract String getId();
+
+
+    /**
+     * returns the parent version item or null
+     * @return
+     */
+    public abstract InternalVersionItem getParent();
+
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/NativePVM.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/NativePVM.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/NativePVM.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,557 @@
+/*
+ * 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.persistence;
+
+import org.apache.log4j.Logger;
+import 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.nodetype.NodeDefId;
+import org.apache.jackrabbit.core.state.PersistentItemStateProvider;
+import org.apache.jackrabbit.core.state.PersistentNodeState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.commons.collections.ReferenceMap;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ * This Class implements the persistent part of the versioning. the
+ * current implementation uses the 'normal' repository content as storage.
+ * <p>
+ * although the nodes need to be mapped again virtually in the real content,
+ * the persistent nodes use a different structure as exposed later.
+ * each versioning element (version history, version, freezes) is stored in a
+ * persistent node state, where the name is the original UUID. eg. the name of
+ * a persistentnodestate that represents a version, is the UUID of that version.
+ * the hierarchy is somewhat similar, thus histories contain versions, contain
+ * frozen nodes, etc.
+ * <p>
+ * on startup, the entire structure is traversed, in order to get a mapping
+ * from real to persistent uuids.
+ */
+public class NativePVM implements 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:versionName' property
+     */
+    public static final QName PROPNAME_VERSION_NAME = new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionName");
+    /**
+     * name of the 'jcr:versionLabels' node
+     */
+    public static final QName NODENAME_VERSION_LABELS = new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionLabels");
+    /**
+     * 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 id of the persisten root node
+     */
+    private static final NodeId PERSISTENT_ROOT_ID = new NodeId("faceface-ab3b-48a9-b31b-e7d0a9c1c3b1");
+
+    /**
+     * The nodetype name of a persistent version
+     */
+    protected static final QName NT_REP_VERSION = new QName(NamespaceRegistryImpl.NS_REP_URI, "version");
+
+    /**
+     * The nodetype name of a presistent version history
+     */
+    protected static final QName NT_REP_VERSION_HISTORY = new QName(NamespaceRegistryImpl.NS_REP_URI, "versionHistory");
+
+    /**
+     * the nodetype name of a persistent frozen node
+     */
+    protected static final QName NT_REP_FROZEN = new QName(NamespaceRegistryImpl.NS_REP_URI, "frozen");
+
+    /**
+     * the persistent root node of the version histories
+     */
+    private final PersistentNode historyRoot;
+
+    /**
+     * the state manager for the version storage
+     */
+    private PersistentItemStateProvider stateMgr;
+
+    /**
+     * the nodetype manager for the version storage
+     */
+    private NodeTypeManagerImpl ntMgr;
+
+    /**
+     * mapping from virtual uuids to persistent ids of the persistent nodes
+     * key=externalId, value=PersistentId
+     */
+    private HashMap idsByExternal = new HashMap();
+
+    /**
+     * mapping from virtual uuids to persistent ids of the persistent nodes
+     * key=internalId, value=PersistentId
+     */
+    private HashMap idsByInternal= new HashMap();
+
+    /**
+     * list of histories for fast retrieval
+     */
+    private LinkedList histories = new LinkedList();
+
+    /**
+     * the version histories. key=uuid, value=version history
+     */
+    private Map items = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
+
+    /**
+     * Creates a new PersistentVersionManager.
+     *
+     * @param session
+     * @throws javax.jcr.RepositoryException
+     */
+    public NativePVM(SessionImpl session) throws RepositoryException {
+        this.stateMgr = ((WorkspaceImpl) session.getWorkspace()).getPersistentStateManager();
+        this.ntMgr = session.getNodeTypeManager();
+
+        try {
+            NodeImpl systemRoot = ((RepositoryImpl) session.getRepository()).getSystemRootNode(session);
+            // enable this to make the persistence storage visible
+            if (true) {
+                // check for versionhistory root
+                if (!systemRoot.hasNode(VERSION_HISTORY_ROOT_NAME)) {
+                    // if not exist, create
+                    systemRoot.addNode(VERSION_HISTORY_ROOT_NAME, NodeTypeRegistry.NT_UNSTRUCTURED);
+                    systemRoot.save();
+                }
+                PersistentNodeState nodeState = (PersistentNodeState) stateMgr.getItemState(new NodeId(systemRoot.getNode(VERSION_HISTORY_ROOT_NAME).internalGetUUID()));
+                historyRoot = new PersistentNode(stateMgr, ntMgr, nodeState);
+            } else {
+                if (!stateMgr.hasItemState(PERSISTENT_ROOT_ID)) {
+                    PersistentNodeState nodeState = stateMgr.createNodeState(PERSISTENT_ROOT_ID.getUUID(), NodeTypeRegistry.NT_UNSTRUCTURED, null);
+                    nodeState.setDefinitionId(new NodeDefId(ntMgr.getRootNodeDefinition().unwrap()));
+                    nodeState.store();
+                    historyRoot = new PersistentNode(stateMgr, ntMgr, nodeState);
+                } else {
+                    PersistentNodeState nodeState = (PersistentNodeState) stateMgr.getItemState(PERSISTENT_ROOT_ID);
+                    historyRoot = new PersistentNode(stateMgr, ntMgr, nodeState);
+                }
+            }
+            initVirtualIds(historyRoot.getState());
+            log.info("loaded " + idsByExternal.size() + " virtual ids.");
+        } catch (ItemStateException e) {
+            throw new RepositoryException("Unable to initialize PersistentVersionManager: " + e.toString());
+        }
+    }
+
+    /**
+     * initializes the internal item ids
+     * @param parent
+     * @throws RepositoryException
+     * @throws ItemStateException
+     */
+    private void initVirtualIds(NodeState parent)
+            throws RepositoryException, ItemStateException {
+
+        Iterator iter = parent.getChildNodeEntries().iterator();
+        while (iter.hasNext()) {
+            NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
+            String realUUID = entry.getName().getLocalName();
+            initVirtualIds(realUUID, (NodeState) stateMgr.getItemState(new NodeId(entry.getUUID())));
+        }
+    }
+
+    /**
+     * initializes the internal item ids
+     * @param realUUID
+     * @param state
+     * @throws ItemStateException
+     * @throws RepositoryException
+     */
+    private void initVirtualIds(String realUUID, NodeState state)
+            throws ItemStateException, RepositoryException {
+        PersistentId id = new PersistentId(realUUID, state);
+        if (id.type != PersistentId.TYPE_UNDEFINED) {
+            idsByExternal.put(id.externalId, id);
+            idsByInternal.put(id.internalId, id);
+            if (id.type == PersistentId.TYPE_HISTORY) {
+                histories.add(id.externalId);
+            }
+        }
+        initVirtualIds(state);
+    }
+
+    /**
+     * returns the persistentid for a given external uuid
+     * @param uuid
+     * @return
+     */
+    private PersistentId getIdByExternal(String uuid) {
+        return (PersistentId) idsByExternal.get(uuid);
+    }
+
+    /**
+     * returns the persustentid for a given internal uuid
+     * @param uuid
+     * @return
+     */
+    private PersistentId getIdByInternal(String uuid) {
+        return (PersistentId) idsByInternal.get(uuid);
+    }
+
+    /**
+     * returns the persustentid for a give internal uuid and item type
+     * @param uuid
+     * @param type
+     * @return
+     */
+    private PersistentId getIdByExternal(String uuid, int type) {
+        PersistentId id = (PersistentId) idsByExternal.get(uuid);
+        return id != null && id.type == type ? id : null;
+    }
+
+    /**
+     * 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();
+        PersistentNode root = historyRoot;
+        for (int i=0; i<3; i++) {
+            QName name = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid.substring(i*2, i*2+2));
+            if (!root.hasNode(name)) {
+                root.addNode(name, NodeTypeRegistry.NT_UNSTRUCTURED);
+                root.store();
+            }
+            root = root.getNode(name, 1);
+        }
+        QName historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid);
+
+        // create new history node in the persistent state
+        InternalVersionHistoryImpl hist = InternalVersionHistoryImpl.create(this, root, uuid, historyNodeName, node);
+        try {
+            initVirtualIds(hist.getId(), hist.getNode().getState());
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
+
+        log.info("Created new version history " + uuid + ". NumHistories=" + histories.size());
+        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 {
+
+        PersistentId pid = getIdByExternal(histId, PersistentId.TYPE_HISTORY);
+        return pid==null ? null : (InternalVersionHistory) getItem(pid);
+    }
+
+    /**
+     * Checks if the versionhistory for the given id exists
+     *
+     * @param histId
+     * @return
+     */
+    public synchronized boolean hasVersionHistory(String histId) {
+        return getIdByExternal(histId, PersistentId.TYPE_HISTORY) != null;
+    }
+
+    /**
+     * returns an iterator over the external ids of the version histories
+     *
+     * @return
+     * @throws RepositoryException
+     */
+    public synchronized Iterator getVersionHistoryIds() throws RepositoryException {
+        return histories.iterator();
+    }
+
+    /**
+     * returns the number of version histories
+     *
+     * @return
+     * @throws RepositoryException
+     */
+    public synchronized int getNumVersionHistories() throws RepositoryException {
+        return histories.size();
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * returns the version with the given id
+     *
+     * @param versionId
+     * @return
+     * @throws RepositoryException
+     */
+    public synchronized InternalVersion getVersion(String versionId)
+            throws RepositoryException {
+
+        PersistentId pid = getIdByExternal(versionId, PersistentId.TYPE_VERSION);
+        return pid==null ? null : (InternalVersion) getItem(pid);
+    }
+
+    /**
+     * Checks if the version with the given id exists
+     *
+     * @param versionId
+     * @return
+     */
+    public synchronized boolean hasVersion(String versionId) {
+        return getIdByExternal(versionId, PersistentId.TYPE_VERSION) != null;
+    }
+
+    /**
+     * checks, if the item with the given external id exists
+     * @param externalId
+     * @return
+     */
+    public synchronized boolean hasItem(String externalId) {
+        return getIdByExternal(externalId) != null;
+    }
+
+    /**
+     * returns the item referred by the external id
+     * @param externalId
+     * @return
+     * @throws RepositoryException
+     */
+    public synchronized InternalVersionItem getItemByExternal(String externalId)
+            throws RepositoryException {
+        PersistentId pid = getIdByExternal(externalId);
+        return pid==null ? null : getItem(pid);
+    }
+
+    /**
+     * returns the item referred by the internal id
+     * @param internalId
+     * @return
+     * @throws RepositoryException
+     */
+    public synchronized InternalVersionItem getItemByInternal(String internalId)
+            throws RepositoryException {
+        PersistentId pid = getIdByInternal(internalId);
+        return pid==null ? null : getItem(pid);
+    }
+
+    /**
+     * returns the item with the given persistent id
+     * @param pid
+     * @return
+     * @throws RepositoryException
+     */
+    synchronized private InternalVersionItem getItem(PersistentId pid)
+            throws RepositoryException {
+
+        InternalVersionItem item =(InternalVersionItem) items.get(pid);
+        if (item==null) {
+            PersistentNode pNode = historyRoot.getNodeByUUID(pid.internalId);
+            if (pNode!=null) {
+                InternalVersionItem parent = getItemByInternal(pNode.getParentUUID());
+                if (pid.type == PersistentId.TYPE_FROZEN) {
+                    item = new InternalFrozenNodeImpl(this, pNode, pid.externalId, parent);
+                } else if (pid.type == PersistentId.TYPE_FROZEN_HISTORY) {
+                    item = new InternalFrozenVHImpl(this, pNode, pid.externalId, parent);
+                } else if (pid.type == PersistentId.TYPE_VERSION) {
+                    item = new InternalVersionImpl(this, (InternalVersionHistory) parent, pNode);
+                } else if (pid.type == PersistentId.TYPE_HISTORY) {
+                    item = new InternalVersionHistoryImpl(this, pNode);
+                } else {
+                    //return null;
+                }
+            }
+            if (item!=null) {
+                items.put(pid, item);
+            }
+        }
+        return item;
+    }
+
+    /**
+     * Checks in a node
+     *
+     * @param node
+     * @return
+     * @throws RepositoryException
+     * @see javax.jcr.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();
+        InternalVersionHistoryImpl history = (InternalVersionHistoryImpl) 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)));
+        }
+
+        InternalVersionImpl v = history.checkin(new QName("", versionName), node);
+        try {
+            initVirtualIds(v.getId(), v.getNode().getState());
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
+        return v;
+    }
+
+    /**
+     * Helper class for persistent items
+     */
+    public static final class PersistentId {
+
+        private static final int TYPE_UNDEFINED = 0;
+        private static final int TYPE_HISTORY = 1;
+        private static final int TYPE_VERSION = 2;
+        private static final int TYPE_FROZEN = 3;
+        private static final int TYPE_FROZEN_HISTORY = 3;
+
+        /** the type of the persistent node */
+        private final int type;
+
+        /** the persistent uuid of the node */
+        private final String externalId;
+
+        /** the persistent uuid of the node */
+        private final String internalId;
+
+        public PersistentId(int type, String external, String internal) {
+            this.type = type;
+            this.internalId = internal;
+            this.externalId = external;
+        }
+
+        public PersistentId(String external, NodeState state) {
+            this.internalId = state.getUUID();
+            if (state.getNodeTypeName().equals(NT_REP_VERSION)) {
+                this.externalId = external;
+                type = TYPE_VERSION;
+            } else if (state.getNodeTypeName().equals(NT_REP_VERSION_HISTORY)) {
+                this.externalId = external;
+                type = TYPE_HISTORY;
+            } else if (state.getNodeTypeName().equals(NT_REP_FROZEN)) {
+                // ignore given externalid, and generate new one
+                this.externalId = UUID.randomUUID().toString();
+                type = TYPE_FROZEN;
+            } else if (state.getNodeTypeName().equals(NodeTypeRegistry.NT_FROZEN_VERSIONABLE_CHILD)) {
+                // ignore given externalid, and generate new one
+                this.externalId = UUID.randomUUID().toString();
+                type = TYPE_FROZEN_HISTORY;
+            } else {
+                // ignore given externalid, and generate new one
+                this.externalId = UUID.randomUUID().toString();
+                type = TYPE_UNDEFINED;
+            }
+        }
+
+        public boolean isVersion() {
+            return type == TYPE_VERSION;
+        }
+
+        public boolean isHistory() {
+            return type == TYPE_HISTORY;
+        }
+
+        public boolean isFrozen() {
+            return type == TYPE_FROZEN;
+        }
+    }
+
+}

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/PersistentNode.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/PersistentNode.java?view=auto&rev=122838
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/persistence/PersistentNode.java	Mon Dec 20 02:29:45 2004
@@ -0,0 +1,607 @@
+/*
+ * 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.persistence;
+
+import org.apache.jackrabbit.core.*;
+import org.apache.jackrabbit.core.nodetype.*;
+import org.apache.jackrabbit.core.state.*;
+import org.apache.jackrabbit.core.util.uuid.UUID;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDef;
+import javax.jcr.nodetype.PropertyDef;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * This Class provides some basic node operations directly on the persistent
+ * state.
+ */
+class PersistentNode {
+
+    /**
+     * the underlaying persistent state
+     */
+    private PersistentNodeState nodeState;
+
+    /**
+     * the state manager
+     */
+    private final PersistentItemStateProvider stateMgr;
+
+    /**
+     * the node type manager
+     */
+    private final NodeTypeManagerImpl ntMgr;
+
+    /**
+     * the cached name
+     */
+    private QName name = null;
+
+    /**
+     * Creates a new persistent node
+     *
+     * @param statemgr
+     * @param ntMgr
+     * @param nodeState
+     */
+    protected PersistentNode(PersistentItemStateProvider statemgr,
+                             NodeTypeManagerImpl ntMgr,
+                             PersistentNodeState nodeState) {
+        this.nodeState = nodeState;
+        this.stateMgr = statemgr;
+        this.ntMgr = ntMgr;
+    }
+
+
+    /**
+     * returns the name of this node
+     *
+     * @return
+     */
+    protected QName getName() {
+        if (name == null) {
+            try {
+                String parentId = nodeState.getParentUUID();
+                NodeState parent = (NodeState) stateMgr.getItemState(new NodeId(parentId));
+                name = ((NodeState.ChildNodeEntry) parent.getChildNodeEntries(nodeState.getUUID()).get(0)).getName();
+            } catch (ItemStateException e) {
+                // should never occurr
+                throw new IllegalStateException(e.toString());
+            }
+        }
+        return name;
+    }
+
+    /**
+     * Returns the uuid of this node
+     *
+     * @return
+     */
+    protected String getUUID() {
+        return nodeState.getUUID();
+    }
+
+    protected String getParentUUID() {
+        return nodeState.getParentUUID();
+    }
+
+    protected PersistentNodeState getState() {
+        return nodeState;
+    }
+
+    /**
+     * Returns the properties of this node
+     *
+     * @return
+     */
+    protected PropertyState[] getProperties() {
+        try {
+            List list = nodeState.getPropertyEntries();
+            PropertyState[] props = new PropertyState[list.size()];
+            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] = (PropertyState) stateMgr.getItemState(propId);
+            }
+            return props;
+        } catch (ItemStateException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Checks if the given property exists
+     *
+     * @param name
+     * @return
+     */
+    protected boolean hasProperty(QName name) {
+        PropertyId propId = new PropertyId(nodeState.getUUID(), name);
+        return stateMgr.hasItemState(propId);
+    }
+
+    /**
+     * Returns the values of the given property of <code>null</code>
+     *
+     * @param name
+     * @return
+     */
+    protected InternalValue[] getPropertyValues(QName name) {
+        PropertyId propId = new PropertyId(nodeState.getUUID(), name);
+        try {
+            PropertyState ps = (PropertyState) stateMgr.getItemState(propId);
+            return ps.getValues();
+        } catch (ItemStateException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value of the given property or <code>null</code>
+     *
+     * @param name
+     * @return
+     */
+    protected InternalValue getPropertyValue(QName name) {
+        PropertyId propId = new PropertyId(nodeState.getUUID(), name);
+        try {
+            PropertyState ps = (PropertyState) stateMgr.getItemState(propId);
+            return ps.getValues()[0];
+        } catch (ItemStateException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Sets the property value
+     *
+     * @param name
+     * @param value
+     * @throws RepositoryException
+     */
+    protected void setPropertyValue(QName name, InternalValue value)
+            throws RepositoryException {
+        setPropertyValues(name, value.getType(), new InternalValue[]{value}, false);
+    }
+
+    /**
+     * Sets the property values
+     *
+     * @param name
+     * @param type
+     * @param values
+     * @throws RepositoryException
+     */
+    protected void setPropertyValues(QName name, int type, InternalValue[] values)
+            throws RepositoryException {
+        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);
+    }
+
+    /**
+     * Retrieves or creates a new property state as child property of this node
+     *
+     * @param name
+     * @param type
+     * @param multiValued
+     * @return
+     * @throws RepositoryException
+     */
+    private PersistentPropertyState getOrCreatePropertyState(QName name, int type, boolean multiValued)
+            throws RepositoryException {
+
+        PropertyId propId = new PropertyId(nodeState.getUUID(), name);
+        if (stateMgr.hasItemState(propId)) {
+            try {
+                PersistentPropertyState propState = (PersistentPropertyState) stateMgr.getItemState(propId);
+                // someone calling this method will always alter the property state, so set status to modified
+                propState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
+                return propState;
+            } catch (ItemStateException e) {
+                throw new RepositoryException("Unable to create property: " + e.toString());
+            }
+        } else {
+            try {
+                PropertyDefImpl def = getApplicablePropertyDef(name, type, multiValued);
+                PersistentPropertyState propState = stateMgr.createPropertyState(nodeState.getUUID(), name);
+                propState.setType(type);
+                propState.setMultiValued(multiValued);
+                propState.setDefinitionId(new PropDefId(def.unwrap()));
+
+                // need to store nodestate
+                nodeState.addPropertyEntry(name);
+                nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
+                return propState;
+            } catch (ItemStateException e) {
+                throw new RepositoryException("Unable to store property: " + e.toString());
+            }
+        }
+    }
+
+    /**
+     * retrieves the property definition for the given contraints
+     *
+     * @param propertyName
+     * @param type
+     * @param multiValued
+     * @return
+     * @throws RepositoryException
+     */
+    protected PropertyDefImpl getApplicablePropertyDef(QName propertyName,
+                                                       int type, boolean multiValued)
+            throws RepositoryException {
+        PropDef pd = getEffectiveNodeType().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(QName nodeName, QName nodeTypeName)
+            throws RepositoryException {
+        ChildNodeDef cnd = getEffectiveNodeType().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() 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);
+        }
+    }
+
+    /**
+     * checks if the given child node exists.
+     *
+     * @param name
+     * @return
+     */
+    protected boolean hasNode(QName name) {
+        return nodeState.hasChildNodeEntry(name);
+    }
+
+    /**
+     * removes the (first) child node with the given name.
+     *
+     * @param name
+     * @return
+     * @throws RepositoryException
+     */
+    protected boolean removeNode(QName name) throws RepositoryException {
+        return removeNode(name, 1);
+    }
+
+    /**
+     * removes the child node with the given name and 1-based index
+     *
+     * @param name
+     * @param index
+     * @return
+     * @throws RepositoryException
+     */
+    protected boolean removeNode(QName name, int index) throws RepositoryException {
+        if (nodeState.removeChildNodeEntry(name, index)) {
+            nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * retrieves the child node with the given name and 1-base index or
+     * <code>null</code> if the node does not exist.
+     *
+     * @param name
+     * @param index
+     * @return
+     * @throws RepositoryException
+     */
+    protected PersistentNode getNode(QName name, int index) throws RepositoryException {
+        NodeState.ChildNodeEntry entry = nodeState.getChildNodeEntry(name, index);
+        if (entry == null) {
+            return null;
+        }
+        try {
+            PersistentNodeState state = (PersistentNodeState) stateMgr.getItemState(new NodeId(entry.getUUID()));
+            return new PersistentNode(stateMgr, ntMgr, state);
+        } catch (ItemStateException e) {
+            throw new RepositoryException("Unable to getNode: " + e.toString());
+        }
+    }
+
+    /**
+     * returns the node with the given uuid.
+     *
+     * @param uuid
+     * @return
+     * @throws RepositoryException
+     */
+    protected PersistentNode getNodeByUUID(String uuid) throws RepositoryException {
+        try {
+            PersistentNodeState state = (PersistentNodeState) stateMgr.getItemState(new NodeId(uuid));
+            return new PersistentNode(stateMgr, ntMgr, state);
+        } catch (ItemStateException e) {
+            throw new RepositoryException("Unable to getNode: " + e.toString());
+        }
+    }
+
+    /**
+     * Adds a new child node with the given name
+     *
+     * @param nodeName
+     * @param nodeTypeName
+     * @return
+     * @throws NoSuchNodeTypeException
+     * @throws ConstraintViolationException
+     * @throws RepositoryException
+     */
+    protected PersistentNode addNode(QName nodeName, QName nodeTypeName)
+            throws NoSuchNodeTypeException, ConstraintViolationException, RepositoryException {
+        NodeTypeImpl nodeType = ntMgr.getNodeType(nodeTypeName);
+        NodeDefImpl def;
+        try {
+            def = getApplicableChildNodeDef(name, nodeType == null ? null : nodeType.getQName());
+        } catch (RepositoryException re) {
+            // hack, use nt:unstructured as parent
+            try {
+                NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+                EffectiveNodeType ent = ntReg.buildEffectiveNodeType(new QName[]{NodeTypeRegistry.NT_UNSTRUCTURED});
+                ChildNodeDef cnd = ent.getApplicableChildNodeDef(name, nodeTypeName);
+                def = ntMgr.getNodeDef(new NodeDefId(cnd));
+            } catch (NodeTypeConflictException e) {
+                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();
+        }
+        return createChildNode(nodeName, def, nodeType, null);
+    }
+
+    /**
+     * creates a new child node
+     *
+     * @param name
+     * @param def
+     * @param nodeType
+     * @param uuid
+     * @return
+     * @throws RepositoryException
+     */
+    private PersistentNode createChildNode(QName name, NodeDefImpl def,
+                                           NodeTypeImpl nodeType, String uuid)
+            throws RepositoryException {
+
+        String parentUUID = nodeState.getUUID();
+        // create a new node state
+        PersistentNodeState state = null;
+        try {
+            if (uuid == null) {
+                uuid = UUID.randomUUID().toString();	// version 4 uuid
+            }
+            state = stateMgr.createNodeState(uuid, nodeType.getQName(), parentUUID);
+            state.setDefinitionId(new NodeDefId(def.unwrap()));
+        } catch (ItemStateException ise) {
+            String msg = "failed to add child node " + name + " to " + parentUUID;
+            throw new RepositoryException(msg, ise);
+        }
+
+        // create Node instance wrapping new node state
+        PersistentNode node = new PersistentNode(stateMgr, ntMgr, state);
+        // add new child node entry
+        nodeState.addChildNodeEntry(name, state.getUUID());
+        nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
+
+        // add 'auto-create' properties defined in node type
+        PropertyDef[] pda = nodeType.getAutoCreatePropertyDefs();
+        for (int i = 0; i < pda.length; i++) {
+            PropertyDefImpl pd = (PropertyDefImpl) pda[i];
+            node.getOrCreatePropertyState(pd.getQName(), pd.getRequiredType(), pd.isMultiple());
+        }
+
+        // recursively add 'auto-create' child nodes defined in node type
+        NodeDef[] nda = nodeType.getAutoCreateNodeDefs();
+        for (int i = 0; i < nda.length; i++) {
+            NodeDefImpl nd = (NodeDefImpl) nda[i];
+            node.createChildNode(nd.getQName(), nd, (NodeTypeImpl) nd.getDefaultPrimaryType(), null);
+        }
+
+        // store primary type
+        node.setPropertyValue(ItemImpl.PROPNAME_PRIMARYTYPE, InternalValue.create(nodeType.getQName()));
+        return node;
+    }
+
+    /**
+     * returns all child nodes
+     *
+     * @return
+     * @throws RepositoryException
+     */
+    protected PersistentNode[] getChildNodes() throws RepositoryException {
+        try {
+            List entries = nodeState.getChildNodeEntries();
+            PersistentNode[] children = new PersistentNode[entries.size()];
+            for (int i = 0; i < entries.size(); i++) {
+                NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) entries.get(i);
+                PersistentNodeState state = (PersistentNodeState) stateMgr.getItemState(new NodeId(entry.getUUID()));
+                children[i] = new PersistentNode(stateMgr, ntMgr, state);
+            }
+            return children;
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     * stores the persistent state recursively
+     *
+     * @throws RepositoryException
+     */
+    protected void store() throws RepositoryException {
+        try {
+            store(nodeState);
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     * stores the given persistent state recursively
+     *
+     * @param state
+     * @throws ItemStateException
+     */
+    private void store(PersistentNodeState state) throws ItemStateException {
+        if (state.isTransient()) {
+            // first store all transient properties
+            List props = state.getPropertyEntries();
+            for (int i = 0; i < props.size(); i++) {
+                NodeState.PropertyEntry entry = (NodeState.PropertyEntry) props.get(i);
+                PersistentPropertyState pstate = (PersistentPropertyState) stateMgr.getItemState(new PropertyId(state.getUUID(), entry.getName()));
+                if (pstate.isTransient()) {
+                    pstate.store();
+                }
+            }
+            // now store all child node entries
+            List nodes = state.getChildNodeEntries();
+            for (int i = 0; i < nodes.size(); i++) {
+                NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) nodes.get(i);
+                PersistentNodeState nstate = (PersistentNodeState) stateMgr.getItemState(new NodeId(entry.getUUID()));
+                store(nstate);
+            }
+            // and store itself
+            state.store();
+        }
+    }
+
+    /**
+     * reloads the persistent state recursively
+     *
+     * @throws RepositoryException
+     */
+    protected void reload() throws RepositoryException {
+        try {
+            reload(nodeState);
+            // refetch nodestate if discarded
+            nodeState = (PersistentNodeState) stateMgr.getItemState(nodeState.getId());
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     * reloads the given persistent state recursively
+     *
+     * @param state
+     * @throws ItemStateException
+     */
+    private void reload(PersistentNodeState state) throws ItemStateException {
+        if (state.isTransient()) {
+            // first discard all all transient properties
+            List props = state.getPropertyEntries();
+            for (int i = 0; i < props.size(); i++) {
+                NodeState.PropertyEntry entry = (NodeState.PropertyEntry) props.get(i);
+                PersistentPropertyState pstate = (PersistentPropertyState) stateMgr.getItemState(new PropertyId(state.getUUID(), entry.getName()));
+                if (pstate.isTransient()) {
+                    pstate.discard();
+                }
+            }
+            // now reload all child node entries
+            List nodes = state.getChildNodeEntries();
+            for (int i = 0; i < nodes.size(); i++) {
+                NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) nodes.get(i);
+                PersistentNodeState nstate = (PersistentNodeState) stateMgr.getItemState(new NodeId(entry.getUUID()));
+                reload(nstate);
+            }
+            // and reload itself
+            state.discard();
+        }
+    }
+
+    /**
+     * copies a property
+     *
+     * @param prop
+     * @throws RepositoryException
+     */
+    protected void copyFrom(PropertyImpl prop) throws RepositoryException {
+        if (prop.getDefinition().isMultiple()) {
+            InternalValue[] values = prop.internalGetValues();
+            setPropertyValues(prop.getQName(), values[0].getType(), values);
+        } else {
+            setPropertyValue(prop.getQName(), prop.internalGetValue());
+        }
+    }
+
+    /**
+     * sets the mixing node type and adds the respective property
+     *
+     * @param mixins
+     * @throws RepositoryException
+     */
+    protected void setMixinNodeTypes(QName[] mixins) throws RepositoryException {
+        HashSet set = new HashSet();
+        InternalValue[] values = new InternalValue[mixins.length];
+        for (int i = 0; i < mixins.length; i++) {
+            set.add(mixins[i]);
+            values[i] = InternalValue.create(mixins[i]);
+        }
+        nodeState.setMixinTypeNames(set);
+        setPropertyValues(ItemImpl.PROPNAME_MIXINTYPES, PropertyType.NAME, values);
+    }
+}

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java	Mon Dec 20 02:29:45 2004
@@ -18,31 +18,91 @@
 import org.apache.jackrabbit.core.QName;
 import org.apache.jackrabbit.core.nodetype.NodeDefId;
 import org.apache.jackrabbit.core.nodetype.PropDefId;
-import org.apache.jackrabbit.core.state.ItemStateProvider;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.state.*;
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.ItemId;
+import org.apache.jackrabbit.core.PropertyId;
+
+import javax.jcr.RepositoryException;
 
 /**
  * This Interface defines a virtual item state provider.
  */
 public interface VirtualItemStateProvider extends ItemStateProvider {
+
     /**
-     * Returns a predefined node definition id.
-     *
-     * @param nodename
+     * Checks if the id referrs to the root of a virtual tree.
+     * @param id
      * @return
      */
-    public NodeDefId getNodeDefId(QName nodename);
+    public boolean isVirtualRoot(ItemId id);
 
     /**
-     * Returns a predefined property definition id
-     *
-     * @param propname
+     * Returns the id of the root node of the virtual tree.
      * @return
      */
-    public PropDefId getPropDefId(QName propname);
+    public NodeId getVirtualRootId();
 
-    public boolean isVirtualRoot(ItemId id);
+    /**
+     * Checks if the node with the given id exists in this item state provider.
+     * @param id
+     * @return
+     */
+    public boolean hasNodeState(NodeId id);
+
+    /**
+     * Checks if the property with the given id exists in this item state provider.
+     * @param id
+     * @return
+     */
+    public boolean hasPropertyState(PropertyId id);
+
+    /**
+     * Returns the node state for the given node id
+     * @param id
+     * @return
+     * @throws ItemStateException
+     * @throws NoSuchItemStateException
+     */
+    public VirtualNodeState getNodeState(NodeId id)
+            throws ItemStateException, NoSuchItemStateException;
+
+    /**
+     * Returns the property state for the give property id
+     * @param id
+     * @return
+     * @throws ItemStateException
+     * @throws NoSuchItemStateException
+     */
+    public VirtualPropertyState getPropertyState(PropertyId id)
+            throws ItemStateException, NoSuchItemStateException;
+
+    /**
+     * Creats a new virtual property state
+     * @param parent
+     * @param name
+     * @param type
+     * @param multiValued
+     * @return
+     * @throws RepositoryException
+     */
+    public VirtualPropertyState createPropertyState(VirtualNodeState parent,
+                                                    QName name, int type,
+                                                    boolean multiValued)
+            throws RepositoryException;
+
+    /**
+     * Creates a new virtual node state
+     * @param parent
+     * @param name
+     * @param uuid
+     * @param nodeTypeName
+     * @return
+     * @throws RepositoryException
+     */
+    public VirtualNodeState createNodeState(VirtualNodeState parent, QName name,
+                                            String uuid, QName nodeTypeName)
+            throws RepositoryException;
 
-    public NodeId getVirtualRootId();
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java	Mon Dec 20 02:29:45 2004
@@ -23,51 +23,165 @@
 import org.apache.jackrabbit.core.state.NodeState;
 
 import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import java.util.HashMap;
+import java.util.HashSet;
 
 /**
  * This Class implements a virtual node state
  */
 public class VirtualNodeState extends NodeState {
 
-    protected VirtualItemStateProvider provider;
+    /**
+     * The virtual item state provide that created this node state
+     */
+    protected final VirtualItemStateProvider stateMgr;
+
+    /**
+     * map of property states of this node state
+     * key=propname, value={@link VirtualPropertyState}
+     */
+    private final HashMap properties = new HashMap();
 
     /**
+     * creates a new virtual node state
+     * @param stateMgr
+     * @param parentUUID
      * @param uuid
      * @param nodeTypeName
-     * @param parentUUID
+     * @param mixins
+     * @throws RepositoryException
      */
-    protected VirtualNodeState(VirtualItemStateProvider provider,
-                               String uuid, QName nodeTypeName, String parentUUID) {
+    public VirtualNodeState(VirtualItemStateProvider stateMgr,
+                                   String parentUUID,
+                                   String uuid,
+                                   QName nodeTypeName,
+                                   QName[] mixins)
+            throws RepositoryException {
         super(uuid, nodeTypeName, parentUUID, ItemState.STATUS_EXISTING);
+        this.stateMgr = stateMgr;
+
+        // add default properties
+        setPropertyValue(ItemImpl.PROPNAME_PRIMARYTYPE, InternalValue.create(nodeTypeName));
+        setMixinNodeTypes(mixins);
+    }
 
-        this.provider = provider;
+    /**
+     * Returns the properties of this node
+     *
+     * @return
+     */
+    public VirtualPropertyState[] getProperties() {
+        return (VirtualPropertyState[]) properties.values().toArray(new VirtualPropertyState[properties.size()]);
+    }
 
-        // add some props
-        addPropertyEntry(ItemImpl.PROPNAME_PRIMARYTYPE);
-        addPropertyEntry(ItemImpl.PROPNAME_MIXINTYPES);
-    }
-
-    public VirtualPropertyState getPropertyState(QName name)
-            throws NoSuchItemStateException {
-        if (name.equals(ItemImpl.PROPNAME_PRIMARYTYPE)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(ItemImpl.PROPNAME_PRIMARYTYPE));
-            state.setType(PropertyType.NAME);
-            state.setValues(InternalValue.create(new QName[]{getNodeTypeName()}));
-            return state;
-        } else if (name.equals(ItemImpl.PROPNAME_MIXINTYPES)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(ItemImpl.PROPNAME_MIXINTYPES));
-            state.setType(PropertyType.NAME);
-            state.setValues(InternalValue.create((QName[]) getMixinTypeNames().toArray(new QName[getMixinTypeNames().size()])));
-            return state;
-        } else if (name.equals(ItemImpl.PROPNAME_UUID)) {
-            VirtualPropertyState state = new VirtualPropertyState(name, getUUID());
-            state.setDefinitionId(provider.getPropDefId(ItemImpl.PROPNAME_UUID));
-            state.setType(PropertyType.STRING);
-            state.setValues(InternalValue.create(new String[]{getUUID()}));
-            return state;
+
+    /**
+     * Returns the values of the given property of <code>null</code>
+     *
+     * @param name
+     * @return
+     */
+    public InternalValue[] getPropertyValues(QName name) throws NoSuchItemStateException {
+        VirtualPropertyState ps = getProperty(name);
+        return ps==null ? null : ps.getValues();
+    }
+
+    /**
+     * Returns the value of the given property or <code>null</code>
+     *
+     * @param name
+     * @return
+     */
+    public InternalValue getPropertyValue(QName name) throws NoSuchItemStateException {
+        VirtualPropertyState ps = getProperty(name);
+        return ps==null || ps.getValues().length==0 ? null : ps.getValues()[0];
+    }
+
+    /**
+     * returns the property state of the given name
+     * @param name
+     * @return
+     * @throws NoSuchItemStateException
+     */
+    public VirtualPropertyState getProperty(QName name) throws NoSuchItemStateException {
+        return (VirtualPropertyState) properties.get(name);
+    }
+
+    /**
+     * Sets the property value
+     *
+     * @param name
+     * @param value
+     * @throws javax.jcr.RepositoryException
+     */
+    public void setPropertyValue(QName name, InternalValue value)
+            throws RepositoryException {
+        setPropertyValues(name, value.getType(), new InternalValue[]{value}, false);
+    }
+
+    /**
+     * Sets the property values
+     *
+     * @param name
+     * @param type
+     * @param values
+     * @throws RepositoryException
+     */
+    public void setPropertyValues(QName name, int type, InternalValue[] values)
+            throws RepositoryException {
+        setPropertyValues(name, type, values, true);
+    }
+
+    /**
+     * Sets the property values
+     *
+     * @param name
+     * @param type
+     * @param values
+     * @throws RepositoryException
+     */
+    public void setPropertyValues(QName name, int type, InternalValue[] values, boolean multiple)
+            throws RepositoryException {
+        VirtualPropertyState prop = getOrCreatePropertyState(name, type, multiple);
+        prop.setValues(values);
+    }
+
+    /**
+     * 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(QName name, int type, boolean multiValued)
+            throws RepositoryException {
+
+        VirtualPropertyState prop = (VirtualPropertyState) properties.get(name);
+        if (prop==null) {
+            prop = stateMgr.createPropertyState(this, name, type, multiValued);
+            properties.put(name, prop);
+            addPropertyEntry(name);
+        }
+        return prop;
+    }
+
+    /**
+     * sets the mixing node type and adds the respective property
+     *
+     * @param mixins
+     * @throws RepositoryException
+     */
+    public void setMixinNodeTypes(QName[] mixins) throws RepositoryException {
+        HashSet set = new HashSet();
+        InternalValue[] values = new InternalValue[mixins.length];
+        for (int i = 0; i < mixins.length; i++) {
+            set.add(mixins[i]);
+            values[i] = InternalValue.create(mixins[i]);
         }
-        throw new NoSuchItemStateException(name.toString());
+        setMixinTypeNames(set);
+        setPropertyValues(ItemImpl.PROPNAME_MIXINTYPES, PropertyType.NAME, values);
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java?view=diff&rev=122838&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java&r1=122837&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java&r2=122838
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualPropertyState.java	Mon Dec 20 02:29:45 2004
@@ -25,6 +25,7 @@
 public class VirtualPropertyState extends PropertyState {
 
     /**
+     * Creates a new virtual property state
      * @param name
      * @param parentUUID
      */