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/11/17 11:00:59 UTC

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

Author: tripod
Date: Wed Nov 17 02:00:58 2004
New Revision: 76106

Modified:
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.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/VersionIteratorImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/DefaultItemStateProvider.java
Log:
- JCR-17 Creating and saving a mix:versionable node creates two VersionHistory nodes
- JCR-18 Multithreading issue with versioning


Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java	Wed Nov 17 02:00:58 2004
@@ -795,15 +795,17 @@
         boolean createdTransientState = false;
         while (iter.hasNext()) {
             ItemState itemState = (ItemState) iter.next();
-            if (itemState.isNode() && itemState.getStatus() == ItemState.STATUS_NEW) {
+            if (itemState.isNode()) {
                 NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId());
                 if (node.isNodeType(NodeTypeRegistry.MIX_VERSIONABLE)) {
-                    VersionHistory hist = session.versionMgr.createVersionHistory(node);
-                    node.internalSetProperty(VersionManager.PROPNAME_VERSION_HISTORY, InternalValue.create(new UUID(hist.getUUID())));
-                    node.internalSetProperty(VersionManager.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(hist.getRootVersion().getUUID())));
-                    node.internalSetProperty(VersionManager.PROPNAME_IS_CHECKED_OUT, InternalValue.create(true));
-                    node.internalSetProperty(VersionManager.PROPNAME_PREDECESSORS, new InternalValue[]{InternalValue.create(new UUID(hist.getRootVersion().getUUID()))});
-                    createdTransientState = true;
+                    if (!node.hasProperty(VersionManager.PROPNAME_VERSION_HISTORY)) {
+                        VersionHistory hist = session.versionMgr.createVersionHistory(node);
+                        node.internalSetProperty(VersionManager.PROPNAME_VERSION_HISTORY, InternalValue.create(new UUID(hist.getUUID())));
+                        node.internalSetProperty(VersionManager.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(hist.getRootVersion().getUUID())));
+                        node.internalSetProperty(VersionManager.PROPNAME_IS_CHECKED_OUT, InternalValue.create(true));
+                        node.internalSetProperty(VersionManager.PROPNAME_PREDECESSORS, new InternalValue[]{InternalValue.create(new UUID(hist.getRootVersion().getUUID()))});
+                        createdTransientState = true;
+                    }
                 }
             }
         }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java	Wed Nov 17 02:00:58 2004
@@ -1597,7 +1597,7 @@
 
         // build effective node type of mixin's & primary type in order to detect conflicts
         NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
-        EffectiveNodeType entExisting, entNew;
+        EffectiveNodeType entExisting;
         try {
             // existing mixin's
             HashSet set = new HashSet(((NodeState) state).getMixinTypeNames());
@@ -1611,7 +1611,7 @@
             // add new mixin
             set.add(ntName);
             // try to build new effective node type (will throw in case of conflicts)
-            entNew = ntReg.buildEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
+            ntReg.buildEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
         } catch (NodeTypeConflictException ntce) {
             throw new ConstraintViolationException(ntce.getMessage());
         }
@@ -1651,18 +1651,6 @@
                 if (!entExisting.includesNodeType(declaringNT.getQName())) {
                     createChildNode(nd.getQName(), nd, (NodeTypeImpl) nd.getDefaultPrimaryType(), null);
                 }
-            }
-
-            // check for special node types
-            // todo consolidate version history creation code (currently in NodeImpl.addMixin & ItemImpl.initVersionHistories
-            if (!entExisting.includesNodeType(NodeTypeRegistry.MIX_VERSIONABLE) &&
-                    entNew.includesNodeType(NodeTypeRegistry.MIX_VERSIONABLE)) {
-                // node has become 'versionable', initialize version history
-                VersionHistory hist = session.versionMgr.createVersionHistory(this);
-                internalSetProperty(VersionManager.PROPNAME_VERSION_HISTORY, InternalValue.create(new UUID(hist.getUUID())));
-                internalSetProperty(VersionManager.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(hist.getRootVersion().getUUID())));
-                internalSetProperty(VersionManager.PROPNAME_IS_CHECKED_OUT, InternalValue.create(true));
-                internalSetProperty(VersionManager.PROPNAME_PREDECESSORS, new InternalValue[]{InternalValue.create(new UUID(hist.getRootVersion().getUUID()))});
             }
         } catch (RepositoryException re) {
             // try to undo the modifications by removing the mixin

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java	Wed Nov 17 02:00:58 2004
@@ -71,9 +71,6 @@
     // nt:version
     public static final QName NT_VERSION =
             new QName(NamespaceRegistryImpl.NS_NT_URI, "version");
-    // nt:frozen
-    public static final QName NT_FROZEN =
-            new QName(NamespaceRegistryImpl.NS_NT_URI, "frozen");
     // nt:frozenVersionableChild
     public static final QName NT_FROZEN_VERSIONABLE_CHILD =
             new QName(NamespaceRegistryImpl.NS_NT_URI, "frozenVersionableChild");
@@ -1022,8 +1019,8 @@
          * - apply and persist changes to affected nodes
          * - what else?
          */
-        /*unregisterNodeType(name);
-        return registerNodeType(ntd);*/
+        //unregisterNodeType(name);
+        //return registerNodeType(ntd);
         throw new RepositoryException("not yet implemented");
     }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml	Wed Nov 17 02:00:58 2004
@@ -219,7 +219,7 @@
                 <valueConstraint>nt:version</valueConstraint>
             </valueConstraints>
         </propertyDef>
-        <childNodeDef name="jcr:frozen" defaultPrimaryType="nt:base" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" sameNameSibs="false">
+        <childNodeDef name="jcr:frozen" defaultPrimaryType="nt:base" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="true" sameNameSibs="false">
             <requiredPrimaryTypes>
                 <requiredPrimaryType>nt:base</requiredPrimaryType>
             </requiredPrimaryTypes>
@@ -247,7 +247,7 @@
         <supertypes>
             <supertype>mix:referenceable</supertype>
         </supertypes>
-        <propertyDef name="jcr:versionHistory" type="Reference" autoCreate="false" mandatory="false" onParentVersion="IGNORE" protected="true" primaryItem="false" multiple="false">
+        <propertyDef name="jcr:versionHistory" type="Reference" autoCreate="false" mandatory="false" onParentVersion="COPY" protected="true" primaryItem="false" multiple="false">
             <valueConstraints>
                 <valueConstraint>nt:versionHistory</valueConstraint>
             </valueConstraints>
@@ -267,7 +267,7 @@
                 <valueConstraint>nt:version</valueConstraint>
             </valueConstraints>
         </propertyDef>
-        <propertyDef name="jcr:mergeFailed" type="Reference" autoCreate="false" mandatory="false" onParentVersion="IGNORE" protected="false" primaryItem="false" multiple="true">
+        <propertyDef name="jcr:mergeFailed" type="Reference" autoCreate="false" mandatory="false" onParentVersion="IGNORE" protected="true" primaryItem="false" multiple="true">
             <valueConstraints>
                 <valueConstraint>nt:version</valueConstraint>
             </valueConstraints>

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalFrozenNode.java	Wed Nov 17 02:00:58 2004
@@ -206,7 +206,7 @@
      * @return
      * @throws RepositoryException
      */
-    protected static PersistentNode checkin(PersistentNode parent, QName name, NodeImpl src, boolean initOnly)
+    protected static PersistentNode checkin(PersistentNode parent, QName name, NodeImpl src, boolean initOnly, boolean forceCopy)
             throws RepositoryException {
 
         // create new node
@@ -234,14 +234,8 @@
             PropertyIterator piter = src.getProperties();
             while (piter.hasNext()) {
                 PropertyImpl prop = (PropertyImpl) piter.nextProperty();
-    // ignore some properties that not have a OPV=Ignore yet
-                if (prop.getQName().equals(VersionManager.PROPNAME_VERSION_HISTORY)) {
-                    continue;
-                }
-                if (prop.getQName().equals(VersionManager.PROPNAME_PREDECESSORS)) {
-                    continue;
-                }
-                switch (prop.getDefinition().getOnParentVersion()) {
+                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());
@@ -260,7 +254,8 @@
             NodeIterator niter = src.getNodes();
             while (niter.hasNext()) {
                 NodeImpl child = (NodeImpl) niter.nextNode();
-                switch (child.getDefinition().getOnParentVersion()) {
+                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:
@@ -279,7 +274,7 @@
                         // else ignore
                         break;
                     case OnParentVersionAction.COPY:
-                        checkin(node, child.getQName(), child, false);
+                        checkin(node, child.getQName(), child, false, true);
                         break;
                 }
             }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/InternalVersionHistory.java	Wed Nov 17 02:00:58 2004
@@ -333,7 +333,7 @@
         vNode.setPropertyValues(VersionManager.PROPNAME_PREDECESSORS, PropertyType.STRING, predecessors);
 
         // checkin source node
-        InternalFrozenNode.checkin(vNode, PersistentVersionManager.NODENAME_FROZEN, src, false);
+        InternalFrozenNode.checkin(vNode, PersistentVersionManager.NODENAME_FROZEN, src, false, false);
 
         // and store
         store();
@@ -405,7 +405,7 @@
         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);
+        InternalFrozenNode.checkin(vNode, PersistentVersionManager.NODENAME_FROZEN, src, true, false);
 
         parent.store();
         return new InternalVersionHistory(vMgr, pNode);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/PersistentVersionManager.java
==============================================================================
--- 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	Wed Nov 17 02:00:58 2004
@@ -156,8 +156,8 @@
         QName historyNodeName = new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, uuid);
         if (historyRoot.hasNode(historyNodeName)) {
             historyRoot.removeNode(historyNodeName);
+            historyRoot.store();
         }
-        historyRoot.store();
 
         // create new history node in the persistent state
         InternalVersionHistory hist = InternalVersionHistory.create(this, historyRoot, uuid, historyNodeName, node);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionIteratorImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionIteratorImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionIteratorImpl.java	Wed Nov 17 02:00:58 2004
@@ -19,32 +19,26 @@
 import javax.jcr.Session;
 import javax.jcr.version.Version;
 import javax.jcr.version.VersionIterator;
-import java.util.HashSet;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.Stack;
+import java.util.*;
 
 /**
  * This Class implements a VersionIterator that iterates over a version
- * graph following the successor nodes.
+ * graph following the successor nodes. When this iterator is created, it gathers
+ * the id's of the versions and returns them when iterating. please note, that
+ * a version can be deleted while traversing this iterator and the 'nextVesion'
+ * would produce a  ConcurrentModificationException.
  */
 public class VersionIteratorImpl implements VersionIterator {
 
     /**
-     * the current position
-     */
-    private int pos = 0;
-
-    /**
-     * the traversal stack
+     * the id's of the versions to return
      */
-    private Stack successors = new Stack();
+    private LinkedList versions = new LinkedList();
 
     /**
-     * the set of versions already returned. due to the topology of the version
-     * graph it is possible to reach a version via different paths.
+     * the current position
      */
-    private Set visited = new HashSet();
+    private int pos = 0;
 
     /**
      * the session for wrapping the versions
@@ -59,25 +53,24 @@
      */
     public VersionIteratorImpl(Session session, InternalVersion rootVersion) {
         this.session = session;
-        successors.push(rootVersion);
+
+        addVersion(rootVersion);
     }
 
     /**
      * @see VersionIterator#nextVersion()
      */
     public Version nextVersion() {
-        if (successors.isEmpty()) {
+        if (versions.isEmpty()) {
             throw new NoSuchElementException();
         }
-        InternalVersion ret = (InternalVersion) successors.pop();
-        visited.add(ret);
+        String id = (String) versions.removeFirst();
         pos++;
-        push(ret.getSuccessors());
 
         try {
-            return (Version) session.getNodeByUUID(ret.getId());
+            return (Version) session.getNodeByUUID(id);
         } catch (RepositoryException e) {
-            throw new NoSuchElementException("Unable to provide element: " + e.toString());
+            throw new ConcurrentModificationException("Unable to provide element: " + e.toString());
         }
     }
 
@@ -95,7 +88,7 @@
      * @see VersionIterator#getSize()
      */
     public long getSize() {
-        return -1;
+        return versions.size();
     }
 
     /**
@@ -117,7 +110,7 @@
      * @see VersionIterator#hasNext()
      */
     public boolean hasNext() {
-        return !successors.isEmpty();
+        return !versions.isEmpty();
     }
 
     /**
@@ -128,14 +121,17 @@
     }
 
     /**
-     * Pushes the versions on the stack
-     *
-     * @param versions
-     */
-    private void push(InternalVersion[] versions) {
-        for (int i = 0; i < versions.length; i++) {
-            if (!visited.contains(versions[i])) {
-                successors.push(versions[i]);
+     * Adds the version 'v' to the list of versions to return and then calls
+     * it self recursively with all the verions prodecessors.
+     * @param v
+     */
+    private synchronized void addVersion(InternalVersion v) {
+        String id = v.getId();
+        if (!versions.contains(id)) {
+            versions.add(id);
+            InternalVersion[] vs = v.getSuccessors();
+            for (int i=0; i<vs.length; i++) {
+                addVersion(vs[i]);
             }
         }
     }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManager.java	Wed Nov 17 02:00:58 2004
@@ -25,11 +25,10 @@
 
 import javax.jcr.RepositoryException;
 import javax.jcr.PropertyType;
-import javax.jcr.Workspace;
 import javax.jcr.nodetype.NodeDef;
 import javax.jcr.version.VersionHistory;
 import javax.jcr.version.Version;
-import java.util.Iterator;
+import java.util.*;
 
 /**
  * This Class implements the session tied version manager. It is also repsonsible
@@ -124,7 +123,7 @@
      * @param base
      * @return
      */
-    public VirtualItemStateProvider getVirtualItemStateProvider(SessionImpl session, ItemStateProvider base) {
+    public synchronized VirtualItemStateProvider getVirtualItemStateProvider(SessionImpl session, ItemStateProvider base) {
         if (virtProvider==null) {
             try {
                 // check, if workspace of session has history root
@@ -255,22 +254,16 @@
      * @return
      * @throws RepositoryException
      */
-    public Version checkin(NodeImpl node) throws RepositoryException {
-        try {
-            InternalVersion version = vMgr.checkin(node);
-            vMgr.onVersionHistoryModified(version.getVersionHistory());
-
-            VirtualNodeState vhNode = (VirtualNodeState) virtProvider.getItemState(new NodeId(version.getVersionHistory().getId()));
-
-            // invalidate predecessors 'sucessors' properties
-            InternalVersion[] pred = version.getPredecessors();
-            for (int i=0; i<pred.length; i++) {
-                onVersionModified(pred[i]);
-            }
-            return (Version) node.getSession().getNodeByUUID(version.getId());
-        } catch (NoSuchItemStateException e) {
-            throw new RepositoryException(e);
+    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());
     }
 
     /**
@@ -279,7 +272,8 @@
      * @param v
      * @throws RepositoryException
      */
-    protected void onVersionModified(InternalVersion v) throws RepositoryException {
+    protected synchronized void onVersionModified(InternalVersion v)
+            throws RepositoryException {
         try {
             VirtualNodeState ns = (VirtualNodeState) virtProvider.getItemState(new NodeId(v.getId()));
             mapDynamicProperties(ns, v);
@@ -294,7 +288,8 @@
      * @param vh
      * @throws RepositoryException
      */
-    protected void onVersionHistoryModified(InternalVersionHistory vh) throws RepositoryException {
+    protected synchronized void onVersionHistoryModified(InternalVersionHistory vh)
+            throws RepositoryException {
         mapVersionHistory(vh);
     }
 
@@ -365,6 +360,7 @@
                 virtProvider.setPropertyValues(vNode, VersionManager.PROPNAME_FROZEN_MIXIN_TYPES, PropertyType.NAME, InternalValue.create(fNode.getFrozenMixinTypes()));
                 if (!version.isRootVersion()) {
                     // don't map for root verion
+                    //mapFrozenProperties(vNode, fNode);
                     mapFrozenNode(vNode, PersistentVersionManager.NODENAME_FROZEN, fNode);
                 }
             }
@@ -403,6 +399,30 @@
             succV[i] = InternalValue.create(new UUID(succ[i].getId()));
         }
         virtProvider.setPropertyValues(vNode, VersionManager.PROPNAME_SUCCESSORS, PropertyType.REFERENCE, succV);
+    }
+
+    private void mapFrozenProperties(VirtualNodeState  node, InternalFrozenNode fNode)
+            throws RepositoryException {
+        try {
+            // initialize the content
+            PersistentProperty[] props = fNode.getFrozenProperties();
+            for (int i=0; i<props.length; i++) {
+                virtProvider.setPropertyValues(node, props[i].getName(), props[i].getType(), props[i].getValues(), props[i].isMultiple());
+            }
+            InternalFreeze[] freezes = fNode.getFrozenChildNodes();
+            for (int i=0; i<freezes.length; i++) {
+                if (freezes[i] instanceof InternalFrozenVersionHistory) {
+                    InternalFrozenVersionHistory vh = (InternalFrozenVersionHistory) freezes[i];
+                    VirtualNodeState fChild = virtProvider.addNode(node.getId(), vh.getName(), null, NodeTypeRegistry.NT_FROZEN_VERSIONABLE_CHILD);
+                    virtProvider.setPropertyValue(fChild, VersionManager.PROPNAME_VERSION_HISTORY, InternalValue.create(UUID.fromString(vh.getVersionHistoryId())));
+                } else { // instance of InternalFrozenNode
+                    InternalFrozenNode fn = (InternalFrozenNode) freezes[i];
+                    mapFrozenNode(node, fn.getName(), fn);
+                }
+            }
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
     }
 
     /**

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/DefaultItemStateProvider.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/DefaultItemStateProvider.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/DefaultItemStateProvider.java	Wed Nov 17 02:00:58 2004
@@ -22,6 +22,7 @@
 import org.apache.log4j.Logger;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.PropertyType;
 import javax.jcr.nodetype.ConstraintViolationException;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -150,8 +151,16 @@
         try {
             def = getApplicableChildNodeDef(parent, name, nodeType == null ? null : nodeType.getQName());
         } catch (RepositoryException re) {
-            String msg = "no definition found in parent node's node type for new node";
-            throw new ConstraintViolationException(msg, re);
+            // 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
@@ -163,6 +172,7 @@
         setPropertyValue(ns, ItemImpl.PROPNAME_PRIMARYTYPE, InternalValue.create(nodeType.getQName()));
         if (mixins != null) {
             ns.setMixinTypeNames(new HashSet(Arrays.asList(mixins)));
+            setPropertyValues(ns, ItemImpl.PROPNAME_MIXINTYPES, PropertyType.NAME, InternalValue.create(mixins));
         }
         if (getEffectiveNodeType(ns).includesNodeType(NodeTypeRegistry.MIX_REFERENCEABLE)) {
             setPropertyValue(ns, ItemImpl.PROPNAME_UUID, InternalValue.create(ns.getUUID()));