[dna-commits] DNA SVN: r761 - in trunk/dna-jcr/src: main/resources/org/jboss/dna/jcr and 1 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Fri Mar 6 11:51:56 EST 2009


Author: rhauch
Date: 2009-03-06 11:51:55 -0500 (Fri, 06 Mar 2009)
New Revision: 761

Added:
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
Modified:
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
   trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java
Log:
DNA-194 Implement update JCR capability

None of the nodes had a Node.getDefinition() implementation.  To properly implement this, I refactored how JcrSession was creating and populating nodes, and I added some utility methods to the JcrNodeTypeManager (which is now a separate package-protected class rather than an inner class).

This allows all of the Level 2 TCK unit tests to get further, but none of the other update functionality is implemented, so none of the Level 2 TCK tests run successfully.

I also made a number of utility methods final, in the hopes that they can be inlined since they are called very frequently.

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -71,10 +71,14 @@
     Map<Name, Property> properties;
     List<Path.Segment> children;
     private UUID uuid;
+    private final NodeDefinition definition;
 
-    AbstractJcrNode( JcrSession session ) {
+    AbstractJcrNode( JcrSession session,
+                     NodeDefinition definition ) {
         assert session != null;
+        assert definition != null;
         this.session = session;
+        this.definition = definition;
     }
 
     /**
@@ -112,26 +116,33 @@
         this.properties = properties;
     }
 
+    /**
+     * Utility mehtod to create a {@link Name} from the supplied string.
+     * 
+     * @param name the string
+     * @return the name, or null if the supplied string is null
+     */
     final Name nameFrom( String name ) {
         return session.getExecutionContext().getValueFactories().getNameFactory().create(name);
     }
 
+    final NamespaceRegistry namespaces() {
+        return session.getExecutionContext().getNamespaceRegistry();
+    }
+
     /**
      * {@inheritDoc}
      * 
      * @see javax.jcr.Node#getUUID()
      */
     public final String getUUID() throws RepositoryException {
-        // Return JCR UUID only if node is referenceable
-        try {
-            Property mixinsProp = getProperty("jcr:mixinTypes");
-            if (mixinsProp != null) {
-                for (Value value : mixinsProp.getValues()) {
-                    if ("mix:referenceable".equals(value.getString())) return getProperty("jcr:uuid").getString();
-                }
+        // Return "jcr:uuid" only if node is referenceable
+        Property mixinsProp = getProperty(JcrLexicon.MIXIN_TYPES);
+        if (mixinsProp != null) {
+            String referenceableMixinName = JcrMixLexicon.REFERENCEABLE.getString(namespaces());
+            for (Value value : mixinsProp.getValues()) {
+                if (referenceableMixinName.equals(value.getString())) return getProperty(JcrLexicon.UUID).getString();
             }
-        } catch (PathNotFoundException error) {
-            throw new UnsupportedRepositoryOperationException(error);
         }
         throw new UnsupportedRepositoryOperationException();
     }
@@ -175,7 +186,7 @@
      * @see javax.jcr.Node#getDefinition()
      */
     public NodeDefinition getDefinition() {
-        return null;
+        return definition;
     }
 
     /**
@@ -443,7 +454,7 @@
         if (children == null) {
             return new JcrEmptyNodeIterator();
         }
-        return new JcrChildNodeIterator(this, this.session.getExecutionContext().getNamespaceRegistry(), children);
+        return new JcrChildNodeIterator(this, namespaces(), children);
     }
 
     /**
@@ -461,7 +472,7 @@
 
         // Implementing exact-matching only for now to prototype types as properties
         List<Path.Segment> matchingChildren = new LinkedList<Path.Segment>();
-        NamespaceRegistry registry = session.executionContext.getNamespaceRegistry();
+        NamespaceRegistry registry = namespaces();
         boolean foundMatch = false;
         for (Path.Segment child : children) {
             String childName = child.getName().getString(registry);
@@ -480,7 +491,7 @@
                 }
             }
         }
-        return new JcrChildNodeIterator(this, this.session.executionContext.getNamespaceRegistry(), matchingChildren);
+        return new JcrChildNodeIterator(this, registry, matchingChildren);
     }
 
     /**

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -34,5 +34,6 @@
     public static final Name NAMESPACES = new BasicName(Namespace.URI, "namespaces");
     public static final Name NAMESPACE = new BasicName(Namespace.URI, "namespace");
     public static final Name URI = new BasicName(Namespace.URI, "uri");
+    public static final Name NODE_DEFINITON = new BasicName(Namespace.URI, "nodeDefinition");
 
 }

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -63,6 +63,7 @@
     public static I18n invalidNamePattern;
     public static I18n itemNotFoundWithUuid;
     public static I18n errorWhileFindingNodeWithUuid;
+    public static I18n nodeDefinitionCouldBeDeterminedForNode;
 
     public static I18n typeNotFound;
     public static I18n supertypeNotFound;

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -27,6 +27,7 @@
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeDefinition;
 import net.jcip.annotations.NotThreadSafe;
 import org.jboss.dna.graph.property.Path.Segment;
 
@@ -41,8 +42,9 @@
 
     JcrNode( JcrSession session,
              UUID parentUuid,
-             Segment segment ) {
-        super(session);
+             Segment segment,
+             NodeDefinition nodeDefinition ) {
+        super(session, nodeDefinition);
         assert parentUuid != null;
         assert segment != null;
         this.parentUuid = parentUuid;

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -150,6 +150,33 @@
     }
 
     /**
+     * Determine the best (most specific) {@link NodeDefinition} for a child with the supplied name and primary type. If the
+     * primary type is not supplied, then only the name is considered when finding a best match.
+     * 
+     * @param childName the name of the child
+     * @param primaryNodeTypeName the name of the primary node type for the child
+     * @return the {@link NodeDefinition} that best matches the child, or null if a child with the supplied name and primary type
+     *         are not allowed given this node type
+     */
+    JcrNodeDefinition findBestNodeDefinitionForChild( String childName,
+                                                      String primaryNodeTypeName ) {
+        // First, try to find a child node definition with the given name
+        JcrNodeDefinition childNode = getChildNodeDefinition(childName);
+
+        // If there are no named definitions in the type hierarchy, try to find a residual node definition
+        if (childNode == null) {
+            childNode = getChildNodeDefinition(RESIDUAL_ITEM_NAME);
+        }
+
+        // Check if the node can be added with the named child node definition
+        if (childNode != null && primaryNodeTypeName != null) {
+            NodeType primaryNodeType = getPrimaryNodeType(primaryNodeTypeName);
+            if (!checkTypeAgainstDefinition(primaryNodeType, childNode)) return null;
+        }
+        return childNode;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see javax.jcr.nodetype.NodeType#canAddChildNode(java.lang.String)
@@ -179,6 +206,15 @@
         return false;
     }
 
+    protected final NodeType getPrimaryNodeType( String primaryNodeTypeName ) {
+        try {
+            return session.getWorkspace().getNodeTypeManager().getNodeType(primaryNodeTypeName);
+        } catch (RepositoryException re) {
+            // If the node type doesn't exist, you can't add a child node with that type
+            return null;
+        }
+    }
+
     /**
      * {@inheritDoc}
      * 
@@ -190,11 +226,9 @@
         CheckArg.isNotNull(childNodeName, "childNodeName");
         CheckArg.isNotNull(primaryNodeTypeName, "primaryNodeTypeName");
 
-        NodeType primaryNodeType;
-        try {
-            primaryNodeType = session.getWorkspace().getNodeTypeManager().getNodeType(primaryNodeTypeName);
-        } catch (RepositoryException re) {
-            // If the node type doesn't exist, you can't add a child node with that type
+        NodeType primaryNodeType = getPrimaryNodeType(primaryNodeTypeName);
+        if (primaryNodeType == null) {
+            // The node type doesn't exist, so you can't add a child node with that type
             return false;
         }
 

Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java	                        (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -0,0 +1,145 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.jcr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.graph.property.Name;
+
+/**
+ * Local implementation of @{link NodeTypeManager}. Initialized with {@link NodeType} source data when it is created (in the
+ * {@link JcrWorkspace} constructor.
+ */
+ at NotThreadSafe
+class JcrNodeTypeManager implements NodeTypeManager {
+
+    private final Map<Name, JcrNodeType> primaryNodeTypes;
+    private final Map<Name, JcrNodeType> mixinNodeTypes;
+    private final JcrSession session;
+
+    JcrNodeTypeManager( JcrSession session,
+                        JcrNodeTypeSource source ) {
+        this.session = session;
+        Collection<JcrNodeType> primary = source.getPrimaryNodeTypes();
+        Collection<JcrNodeType> mixins = source.getMixinNodeTypes();
+
+        primaryNodeTypes = new HashMap<Name, JcrNodeType>(primary.size());
+        for (JcrNodeType nodeType : primary) {
+            primaryNodeTypes.put(nodeType.getInternalName(), nodeType);
+        }
+
+        mixinNodeTypes = new HashMap<Name, JcrNodeType>(mixins.size());
+        for (JcrNodeType nodeType : mixins) {
+            mixinNodeTypes.put(nodeType.getInternalName(), nodeType);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.nodetype.NodeTypeManager#getAllNodeTypes()
+     */
+    public NodeTypeIterator getAllNodeTypes() {
+
+        // TODO: Can revisit this approach later if it becomes a performance issue
+        /*
+         * Note also that this creates a subtle difference in behavior for concurrent modification
+         * between this method and the specific get*NodeTypes methods.  That is, if a type is added
+         * while an iterator from the corresponding specific get*NodeType method is being traversed,
+         * a ConcurrentModificationException will be thrown.  Because this iterator is based on a copy
+         * of the underlying maps, no exception would be thrown in the same case.
+         */
+
+        List<NodeType> allTypes = new ArrayList<NodeType>(primaryNodeTypes.size() + mixinNodeTypes.size());
+        allTypes.addAll(primaryNodeTypes.values());
+        allTypes.addAll(mixinNodeTypes.values());
+        return new JcrNodeTypeIterator(allTypes);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.nodetype.NodeTypeManager#getMixinNodeTypes()
+     */
+    public NodeTypeIterator getMixinNodeTypes() {
+        return new JcrNodeTypeIterator(mixinNodeTypes.values());
+    }
+
+    final JcrNodeType getNodeType( Name nodeTypeName ) {
+
+        JcrNodeType nodeType = primaryNodeTypes.get(nodeTypeName);
+        if (nodeType == null) {
+            nodeType = mixinNodeTypes.get(nodeTypeName);
+        }
+        return nodeType;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.nodetype.NodeTypeManager#getNodeType(java.lang.String)
+     */
+    public NodeType getNodeType( String nodeTypeName ) throws NoSuchNodeTypeException, RepositoryException {
+        Name ntName = session.getExecutionContext().getValueFactories().getNameFactory().create(nodeTypeName);
+        NodeType type = getNodeType(ntName);
+        if (type != null) return type;
+        throw new NoSuchNodeTypeException(JcrI18n.typeNotFound.text(nodeTypeName));
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.nodetype.NodeTypeManager#getPrimaryNodeTypes()
+     */
+    public NodeTypeIterator getPrimaryNodeTypes() {
+        return new JcrNodeTypeIterator(primaryNodeTypes.values());
+    }
+
+    /**
+     * Get the {@link NodeDefinition} for the root node.
+     * 
+     * @return the definition; never null
+     * @throws RepositoryException
+     * @throws NoSuchNodeTypeException
+     */
+    JcrNodeDefinition getRootNodeDefinition() throws NoSuchNodeTypeException, RepositoryException {
+        // TODO: Fix this
+        for (NodeDefinition definition : getNodeType("nt:unstructured").getChildNodeDefinitions()) {
+            if (definition.getName().equals(JcrNodeType.RESIDUAL_ITEM_NAME)) return (JcrNodeDefinition)definition;
+        }
+        assert false; // should not get here
+        return null;
+    }
+
+}


Property changes on: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -25,6 +25,7 @@
 
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
+import javax.jcr.nodetype.NodeDefinition;
 import net.jcip.annotations.NotThreadSafe;
 
 /**
@@ -33,8 +34,9 @@
 @NotThreadSafe
 final class JcrRootNode extends AbstractJcrNode {
 
-    JcrRootNode( JcrSession session ) {
-        super(session);
+    JcrRootNode( JcrSession session,
+                 NodeDefinition nodeDefinition ) {
+        super(session, nodeDefinition);
     }
 
     /**

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -51,6 +51,7 @@
 import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.jcr.Workspace;
+import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.nodetype.PropertyDefinition;
@@ -59,9 +60,10 @@
 import javax.security.auth.login.LoginException;
 import net.jcip.annotations.NotThreadSafe;
 import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.RepositorySourceException;
 import org.jboss.dna.graph.property.Name;
 import org.jboss.dna.graph.property.NameFactory;
 import org.jboss.dna.graph.property.NamespaceRegistry;
@@ -123,8 +125,9 @@
     private final ReferenceMap<UUID, Node> nodesByUuid;
     private final ReferenceMap<String, Node> nodesByJcrUuid;
     private boolean isLive;
-    private JcrRootNode rootNode;
+    private AbstractJcrNode rootNode;
     private PropertyDefinition anyMultiplePropertyDefinition;
+    private transient org.jboss.dna.graph.property.Property defaultPrimaryType;
 
     JcrSession( JcrRepository repository,
                 JcrWorkspace workspace,
@@ -165,6 +168,14 @@
         return this.executionContext;
     }
 
+    final JcrNodeTypeManager nodeTypeManager() {
+        return this.workspace.nodeTypeManager();
+    }
+
+    final NamespaceRegistry namespaces() {
+        return this.executionContext.getNamespaceRegistry();
+    }
+
     /**
      * Return an unmodifiable map of nodes given then UUID.
      * 
@@ -369,7 +380,7 @@
             Path parentPath = path.getParent();
             Name propertyName = path.getLastSegment().getName();
             try {
-                return getNode(parentPath).getProperty(propertyName.getString(executionContext.getNamespaceRegistry()));
+                return getNode(parentPath).getProperty(propertyName.getString(namespaces()));
             } catch (org.jboss.dna.graph.property.PathNotFoundException e2) {
                 // If the node isn't found, throw a PathNotFoundException
                 throw new PathNotFoundException(JcrI18n.pathNotFound.text(path));
@@ -387,25 +398,138 @@
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * Find or create a JCR Node for the given path. This method works for the root node, too.
+     * 
+     * @param path the path; may not be null
+     * @return the JCR node instance for the given path; never null
+     * @throws RepositoryException if there is a problem
+     */
     private Node getNode( Path path ) throws RepositoryException {
-        // Get node from source
+        boolean isRoot = path.isRoot();
+        if (isRoot && rootNode != null) return rootNode;
+
+        // Get node from source and get it's UUID ...
         org.jboss.dna.graph.Node graphNode = graph.getNodeAt(path);
-        // First check if node already exists. We don't need to check for changes since that will be handled by an observer
-        org.jboss.dna.graph.property.Property dnaUuidProp = graphNode.getPropertiesByName().get(JcrLexicon.UUID);
-        if (dnaUuidProp == null) dnaUuidProp = graphNode.getPropertiesByName().get(DnaLexicon.UUID);
-        if (dnaUuidProp != null) {
-            UUID uuid = executionContext.getValueFactories().getUuidFactory().create(dnaUuidProp.getValues()).next();
+
+        // Now get the DNA node's UUID ...
+        Location location = graphNode.getLocation();
+        ValueFactories factories = executionContext.getValueFactories();
+        UUID uuid = location.getUuid();
+        org.jboss.dna.graph.property.Property uuidProperty = null;
+        if (uuid != null) {
+            // Considered an identification property ...
+            uuidProperty = location.getIdProperty(JcrLexicon.UUID);
+            if (uuidProperty == null) uuidProperty = location.getIdProperty(DnaLexicon.UUID);
+        }
+        if (uuidProperty == null) {
+            uuidProperty = graphNode.getProperty(JcrLexicon.UUID);
+            if (uuidProperty != null) {
+                // Grab the first 'good' UUID value ...
+                for (Object uuidValue : uuidProperty) {
+                    try {
+                        uuid = factories.getUuidFactory().create(uuidValue);
+                        break;
+                    } catch (ValueFormatException e) {
+                        // Ignore; just continue with the next property value
+                    }
+                }
+            }
+            if (uuid == null) {
+                // Look for the DNA UUID property ...
+                org.jboss.dna.graph.property.Property dnaUuidProperty = graphNode.getProperty(DnaLexicon.UUID);
+                if (dnaUuidProperty != null) {
+                    // Grab the first 'good' UUID value ...
+                    for (Object uuidValue : dnaUuidProperty) {
+                        try {
+                            uuid = factories.getUuidFactory().create(uuidValue);
+                            break;
+                        } catch (ValueFormatException e) {
+                            // Ignore; just continue with the next property value
+                        }
+                    }
+                }
+            }
+        }
+        if (uuid == null) uuid = UUID.randomUUID();
+        if (uuidProperty == null) uuidProperty = executionContext.getPropertyFactory().create(JcrLexicon.UUID, uuid);
+
+        // See if there is already a JCR node object for this UUID ...
+        if (uuid != null && !isRoot) {
             Node node = getNode(uuid);
-            if (node != null) {
-                return node;
+            if (node != null) return node;
+        }
+
+        // Either the UUID is not known, or there was no node. Either way, we have to create the node ...
+        if (uuid == null) uuid = UUID.randomUUID();
+
+        // Look for the primary type of the node ...
+        String primaryTypeNameString = null;
+        NamespaceRegistry namespaces = namespaces();
+        org.jboss.dna.graph.property.Property primaryTypeProperty = graphNode.getProperty(JcrLexicon.PRIMARY_TYPE);
+        if (primaryTypeProperty != null && !primaryTypeProperty.isEmpty()) {
+            Name primaryTypeName = factories.getNameFactory().create(primaryTypeProperty.getFirstValue());
+            primaryTypeNameString = primaryTypeName.getString(namespaces);
+        } else {
+            // We have to have a primary type, so use the default ...
+            if (defaultPrimaryType == null) {
+                defaultPrimaryType = executionContext.getPropertyFactory().create(JcrLexicon.PRIMARY_TYPE,
+                                                                                  JcrNtLexicon.UNSTRUCTURED);
             }
+            primaryTypeProperty = defaultPrimaryType;
+            // We have to add this property to the graph node...
+            graphNode.getPropertiesByName().put(primaryTypeProperty.getName(), primaryTypeProperty);
         }
-        // If not create a new one & populate it
-        JcrNode node;
-        Path parentPath = path.getParent();
-        if (parentPath.isRoot()) node = new JcrNode(this, ((JcrRootNode)getRootNode()).internalUuid(), path.getLastSegment());
-        else node = new JcrNode(this, ((JcrNode)getNode(parentPath)).internalUuid(), path.getLastSegment());
-        populateNode(node, graphNode);
+        assert primaryTypeProperty.isEmpty() == false;
+
+        // Look for a node definition stored on the node ...
+        NodeDefinition definition = null;
+        org.jboss.dna.graph.property.Property nodeDefnProperty = graphNode.getProperty(DnaLexicon.NODE_DEFINITON);
+        if (nodeDefnProperty != null && !nodeDefnProperty.isEmpty()) {
+            Path nodeDefnPath = factories.getPathFactory().create(nodeDefnProperty.getFirstValue());
+            // Look up the node definition ...
+            Name nodeTypeName = nodeDefnPath.getSegment(0).getName();
+            JcrNodeType nodeType = nodeTypeManager().getNodeType(nodeTypeName);
+            if (nodeType != null && nodeDefnPath.size() > 1) {
+                // Look up the definition for the child name rule (in the second segment of the relative path) ...
+                String childNameRule = nodeDefnPath.getSegment(1).getString(namespaces);
+                definition = nodeType.findBestNodeDefinitionForChild(childNameRule, primaryTypeNameString);
+            }
+        }
+
+        AbstractJcrNode node = null;
+        if (isRoot) {
+            // The node definition should be set ...
+            if (definition == null) {
+                definition = nodeTypeManager().getRootNodeDefinition();
+                assert definition != null;
+            }
+
+            // Create the new node ...
+            node = new JcrRootNode(this, definition);
+        } else {
+            // Find the parent ...
+            AbstractJcrNode parent = (AbstractJcrNode)getNode(path.getParent());
+
+            // Find the node definition for this node ...
+            if (definition == null) {
+                // Look for the parent's node type, and look for a node definition based upon the name ...
+                JcrNodeType nodeType = (JcrNodeType)parent.getPrimaryNodeType();
+                String childName = path.getLastSegment().getName().getString(namespaces);
+                definition = nodeType.findBestNodeDefinitionForChild(childName, primaryTypeNameString);
+                if (definition == null) {
+                    String msg = JcrI18n.nodeDefinitionCouldBeDeterminedForNode.text(path, workspace.getName());
+                    throw new RepositorySourceException(msg);
+                }
+            }
+
+            // Now create the node object ...
+            node = new JcrNode(this, parent.internalUuid(), path.getLastSegment(), definition);
+        }
+
+        // Now populate the node and add to the cache ...
+        populateNode(node, graphNode, uuid, uuidProperty, primaryTypeProperty);
+        if (isRoot) rootNode = node;
         return node;
     }
 
@@ -443,21 +567,7 @@
         if (rootNode != null) {
             return rootNode;
         }
-        // Get root node from source
-        assert executionContext.getValueFactories() != null;
-        assert executionContext.getValueFactories().getPathFactory() != null;
-        rootNode = new JcrRootNode(this);
-
-        // Get root node from source
-        Path rootPath = executionContext.getValueFactories().getPathFactory().createRootPath();
-        org.jboss.dna.graph.Node dnaRootNode = graph.getNodeAt(rootPath);
-        if (dnaRootNode.getProperty(JcrLexicon.PRIMARY_TYPE) == null) {
-            // Add the primary type and update the source ...
-            graph.set(JcrLexicon.PRIMARY_TYPE).to(JcrNtLexicon.BASE).on(rootPath);
-            dnaRootNode = graph.getNodeAt(rootPath);
-        }
-        populateNode(rootNode, dnaRootNode);
-        return rootNode;
+        return getNode(executionContext.getValueFactories().getPathFactory().createRootPath());
     }
 
     /**
@@ -653,10 +763,16 @@
         return PropertyType.UNDEFINED;
     }
 
-    private void populateNode( AbstractJcrNode node,
-                               org.jboss.dna.graph.Node graphNode ) throws RepositoryException {
+    final void populateNode( AbstractJcrNode node,
+                             org.jboss.dna.graph.Node graphNode,
+                             UUID uuid,
+                             org.jboss.dna.graph.property.Property uuidProperty,
+                             org.jboss.dna.graph.property.Property primaryTypeProperty ) throws RepositoryException {
         assert node != null;
         assert graphNode != null;
+        assert uuid != null;
+        assert uuidProperty != null;
+        assert primaryTypeProperty != null;
 
         // --------------------------------------------------
         // Create JCR children for corresponding DNA children
@@ -670,35 +786,34 @@
         Map<Name, PropertyDefinition> propertyDefinitionsByPropertyName = new HashMap<Name, PropertyDefinition>();
         boolean referenceable = false;
 
-        NamespaceRegistry registry = executionContext.getNamespaceRegistry();
+        NamespaceRegistry registry = namespaces();
         ValueFactories factories = executionContext.getValueFactories();
         NameFactory nameFactory = factories.getNameFactory();
         NodeTypeManager nodeTypeManager = getWorkspace().getNodeTypeManager();
         List<PropertyDefinition> anyPropertyDefinitions = new LinkedList<PropertyDefinition>();
-        org.jboss.dna.graph.property.Property primaryTypeProperty = graphNode.getProperty(JcrLexicon.PRIMARY_TYPE);
-        if (primaryTypeProperty != null && !primaryTypeProperty.isEmpty()) {
-            Name primaryTypeName = nameFactory.create(primaryTypeProperty.getFirstValue());
-            String primaryTypeNameString = primaryTypeName.getString(registry);
-            NodeType primaryType = nodeTypeManager.getNodeType(primaryTypeNameString);
-            for (PropertyDefinition propertyDefn : primaryType.getPropertyDefinitions()) {
-                String nameString = propertyDefn.getName();
-                if ("*".equals(nameString)) {
-                    anyPropertyDefinitions.add(propertyDefn);
-                    continue;
-                }
-                Name name = nameFactory.create(nameString);
-                PropertyDefinition prev = propertyDefinitionsByPropertyName.put(name, propertyDefn);
-                if (prev != null) propertyDefinitionsByPropertyName.put(name, prev); // put the first one back ...
+        // Start with the primary type ...
+        Name primaryTypeName = nameFactory.create(primaryTypeProperty.getFirstValue());
+        String primaryTypeNameString = primaryTypeName.getString(registry);
+        NodeType primaryType = nodeTypeManager.getNodeType(primaryTypeNameString);
+        for (PropertyDefinition propertyDefn : primaryType.getPropertyDefinitions()) {
+            String nameString = propertyDefn.getName();
+            if ("*".equals(nameString)) {
+                anyPropertyDefinitions.add(propertyDefn);
+                continue;
             }
+            Name name = nameFactory.create(nameString);
+            PropertyDefinition prev = propertyDefinitionsByPropertyName.put(name, propertyDefn);
+            if (prev != null) propertyDefinitionsByPropertyName.put(name, prev); // put the first one back ...
         }
+        // The process the mixin types ...
         org.jboss.dna.graph.property.Property mixinTypesProperty = graphNode.getProperty(JcrLexicon.MIXIN_TYPES);
         if (mixinTypesProperty != null && !mixinTypesProperty.isEmpty()) {
             for (Object mixinTypeValue : mixinTypesProperty) {
                 Name mixinTypeName = nameFactory.create(mixinTypeValue);
                 if (!referenceable && JcrMixLexicon.REFERENCEABLE.equals(mixinTypeName)) referenceable = true;
                 String mixinTypeNameString = mixinTypeName.getString(registry);
-                NodeType primaryType = nodeTypeManager.getNodeType(mixinTypeNameString);
-                for (PropertyDefinition propertyDefn : primaryType.getPropertyDefinitions()) {
+                NodeType mixinType = nodeTypeManager.getNodeType(mixinTypeNameString);
+                for (PropertyDefinition propertyDefn : mixinType.getPropertyDefinitions()) {
                     String nameString = propertyDefn.getName();
                     if ("*".equals(nameString)) {
                         anyPropertyDefinitions.add(propertyDefn);
@@ -711,45 +826,9 @@
             }
         }
 
-        // Look for the UUID property ...
-        UUID uuid = null;
-        org.jboss.dna.graph.property.Property uuidProperty = graphNode.getProperty(JcrLexicon.UUID);
-        Name jcrUuidPropertyName = null;
-        Name dnaUuidPropertyName = null;
-        if (uuidProperty != null) {
-            jcrUuidPropertyName = uuidProperty.getName();
-            // Grab the first 'good' UUID value ...
-            for (Object uuidValue : uuidProperty) {
-                try {
-                    uuid = factories.getUuidFactory().create(uuidValue);
-                    break;
-                } catch (ValueFormatException e) {
-                    // Ignore; just continue with the next property value
-                }
-            }
-        }
-        if (uuid == null) {
-            // Look for the DNA UUID property ...
-            org.jboss.dna.graph.property.Property dnaUuidProperty = graphNode.getProperty(DnaLexicon.UUID);
-            if (dnaUuidProperty != null) {
-                dnaUuidPropertyName = dnaUuidProperty.getName();
-                // Grab the first 'good' UUID value ...
-                for (Object uuidValue : dnaUuidProperty) {
-                    try {
-                        uuid = factories.getUuidFactory().create(uuidValue);
-                        break;
-                    } catch (ValueFormatException e) {
-                        // Ignore; just continue with the next property value
-                    }
-                }
-            }
-        }
-
         // Now create the JCR property object wrapper around the "jcr:uuid" property ...
         Map<Name, Property> properties = new HashMap<Name, Property>();
-        if (uuid == null) uuid = UUID.randomUUID();
         if (referenceable) {
-            if (uuidProperty == null) uuidProperty = executionContext.getPropertyFactory().create(JcrLexicon.UUID, uuid);
             PropertyDefinition propertyDefinition = propertyDefinitionsByPropertyName.get(JcrLexicon.UUID);
             properties.put(JcrLexicon.UUID, new JcrSingleValueProperty(node, executionContext, propertyDefinition,
                                                                        PropertyType.STRING, uuidProperty));
@@ -760,7 +839,7 @@
             Name name = dnaProp.getName();
 
             // Skip the JCR and DNA UUID properties (using the EXACT Name instances on the Property) ...
-            if (name == jcrUuidPropertyName || name == dnaUuidPropertyName) continue;
+            if (JcrLexicon.UUID.equals(name) || DnaLexicon.UUID.equals(name)) continue;
 
             // Figure out the JCR property type for this property ...
             PropertyDefinition propertyDefinition = propertyDefinitionsByPropertyName.get(name);
@@ -826,10 +905,6 @@
             }
         }
 
-        if (referenceable) {
-            assert uuidProperty != null;
-        }
-
         // Now set the properties on the node ...
         node.setProperties(properties);
 

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -25,10 +25,6 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import javax.jcr.AccessDeniedException;
@@ -41,9 +37,6 @@
 import javax.jcr.Workspace;
 import javax.jcr.lock.LockException;
 import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeIterator;
 import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.observation.ObservationManager;
 import javax.jcr.query.QueryManager;
@@ -111,14 +104,13 @@
     /**
      * Reference to the JCR type manager for this workspace.
      */
-    private final NodeTypeManager nodeTypeManager;
+    private final JcrNodeTypeManager nodeTypeManager;
 
     /**
      * The {@link Session} instance that this corresponds with this workspace.
      */
     private final JcrSession session;
 
-    @SuppressWarnings( "synthetic-access" )
     JcrWorkspace( JcrRepository repository,
                   String workspaceName,
                   ExecutionContext context,
@@ -156,26 +148,31 @@
         this.session = new JcrSession(this.repository, this, this.context, sessionAttributes);
 
         // This must be initialized after the session
-        this.nodeTypeManager = new JcrNodeTypeManager(new DnaBuiltinNodeTypeSource(this.session,
+        this.nodeTypeManager = new JcrNodeTypeManager(this.session,
+                                                      new DnaBuiltinNodeTypeSource(this.session,
                                                                                    new JcrBuiltinNodeTypeSource(this.session)));
 
     }
 
-    String getSourceName() {
+    final String getSourceName() {
         return this.repository.getRepositorySourceName();
     }
 
+    final JcrNodeTypeManager nodeTypeManager() {
+        return this.nodeTypeManager;
+    }
+
     /**
      * {@inheritDoc}
      */
-    public String getName() {
+    public final String getName() {
         return name;
     }
 
     /**
      * {@inheritDoc}
      */
-    public Session getSession() {
+    public final Session getSession() {
         return this.session;
     }
 
@@ -184,7 +181,7 @@
      * 
      * @see javax.jcr.Workspace#getNamespaceRegistry()
      */
-    public NamespaceRegistry getNamespaceRegistry() {
+    public final NamespaceRegistry getNamespaceRegistry() {
         return workspaceRegistry;
     }
 
@@ -203,21 +200,21 @@
     /**
      * {@inheritDoc}
      */
-    public NodeTypeManager getNodeTypeManager() {
+    public final NodeTypeManager getNodeTypeManager() {
         return nodeTypeManager;
     }
 
     /**
      * {@inheritDoc}
      */
-    public ObservationManager getObservationManager() {
+    public final ObservationManager getObservationManager() {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      */
-    public QueryManager getQueryManager() {
+    public final QueryManager getQueryManager() {
         throw new UnsupportedOperationException();
     }
 
@@ -350,95 +347,4 @@
         throw new UnsupportedOperationException();
     }
 
-    /**
-     * Local implementation of @{link NodeTypeManager}. Initialized with {@link NodeType} source data when it is created (in the
-     * {@link JcrWorkspace} constructor.
-     */
-    @NotThreadSafe
-    private class JcrNodeTypeManager implements NodeTypeManager {
-
-        private final Map<Name, JcrNodeType> primaryNodeTypes;
-        private final Map<Name, JcrNodeType> mixinNodeTypes;
-
-        private JcrNodeTypeManager( JcrNodeTypeSource source ) {
-            Collection<JcrNodeType> primary = source.getPrimaryNodeTypes();
-            Collection<JcrNodeType> mixins = source.getMixinNodeTypes();
-
-            primaryNodeTypes = new HashMap<Name, JcrNodeType>(primary.size());
-            for (JcrNodeType nodeType : primary) {
-                primaryNodeTypes.put(nodeType.getInternalName(), nodeType);
-            }
-
-            mixinNodeTypes = new HashMap<Name, JcrNodeType>(mixins.size());
-            for (JcrNodeType nodeType : mixins) {
-                mixinNodeTypes.put(nodeType.getInternalName(), nodeType);
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see javax.jcr.nodetype.NodeTypeManager#getAllNodeTypes()
-         */
-        public NodeTypeIterator getAllNodeTypes() {
-
-            // TODO: Can revisit this approach later if it becomes a performance issue
-            /*
-             * Note also that this creates a subtle difference in behavior for concurrent modification
-             * between this method and the specific get*NodeTypes methods.  That is, if a type is added
-             * while an iterator from the corresponding specific get*NodeType method is being traversed,
-             * a ConcurrentModificationException will be thrown.  Because this iterator is based on a copy
-             * of the underlying maps, no exception would be thrown in the same case.
-             */
-
-            List<NodeType> allTypes = new ArrayList<NodeType>(primaryNodeTypes.size() + mixinNodeTypes.size());
-            allTypes.addAll(primaryNodeTypes.values());
-            allTypes.addAll(mixinNodeTypes.values());
-            return new JcrNodeTypeIterator(allTypes);
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see javax.jcr.nodetype.NodeTypeManager#getMixinNodeTypes()
-         */
-        public NodeTypeIterator getMixinNodeTypes() {
-            return new JcrNodeTypeIterator(mixinNodeTypes.values());
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see javax.jcr.nodetype.NodeTypeManager#getNodeType(java.lang.String)
-         */
-        @SuppressWarnings( "synthetic-access" )
-        public NodeType getNodeType( String nodeTypeName ) throws NoSuchNodeTypeException, RepositoryException {
-            Name ntName = session.getExecutionContext().getValueFactories().getNameFactory().create(nodeTypeName);
-
-            NodeType nodeType = primaryNodeTypes.get(ntName);
-
-            if (nodeType != null) {
-                return nodeType;
-            }
-
-            nodeType = mixinNodeTypes.get(ntName);
-
-            if (nodeType != null) {
-                return nodeType;
-            }
-
-            throw new NoSuchNodeTypeException(JcrI18n.typeNotFound.text(nodeTypeName));
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see javax.jcr.nodetype.NodeTypeManager#getPrimaryNodeTypes()
-         */
-        public NodeTypeIterator getPrimaryNodeTypes() {
-            return new JcrNodeTypeIterator(primaryNodeTypes.values());
-        }
-
-    }
-
 }

Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties	2009-03-06 16:51:55 UTC (rev 761)
@@ -53,6 +53,7 @@
 invalidNamePattern = The "{1}" name pattern contained the '{0}' character, which is not allowed in a name pattern
 itemNotFoundWithUuid = An item with UUID "{0}" could not be found in workspace "{1}"
 errorWhileFindingNodeWithUuid = Error while finding the item with UUID "{0}" in workspace "{1}"
+nodeDefinitionCouldBeDeterminedForNode = Unable to determine a valid node definition for the node "{0}" in workspace "{1}"
 
 REP_NAME_DESC = DNA Repository
 REP_VENDOR_DESC = JBoss - A division of Red Hat Middleware LLC

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -26,6 +26,7 @@
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsNull.notNullValue;
 import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.stub;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -46,6 +47,7 @@
 import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.Value;
 import javax.jcr.Workspace;
+import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.version.Version;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.property.Name;
@@ -83,7 +85,7 @@
         MockAbstractJcrNode( JcrSession session,
                              String name,
                              Node parent ) {
-            super(session);
+            super(session, mock(NodeDefinition.class));
             this.name = name;
             this.parent = parent;
         }

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -33,6 +33,7 @@
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
 import javax.jcr.Property;
+import javax.jcr.nodetype.NodeDefinition;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.property.Name;
 import org.jboss.dna.graph.property.NamespaceRegistry;
@@ -52,18 +53,22 @@
     private Node root;
     @Mock
     private JcrSession session;
+    @Mock
+    private NodeDefinition rootNodeDefinition;
+    @Mock
+    private NodeDefinition nodeDefinition;
 
     @Before
     public void before() throws Exception {
         MockitoAnnotations.initMocks(this);
-        root = new JcrRootNode(session);
+        root = new JcrRootNode(session, rootNodeDefinition);
         Segment segment = Mockito.mock(Segment.class);
         Name name = Mockito.mock(Name.class);
         stub(name.getString((NamespaceRegistry)anyObject())).toReturn("name");
         stub(segment.getName()).toReturn(name);
         stub(segment.getIndex()).toReturn(2);
         UUID uuid = UUID.randomUUID();
-        node = new JcrNode(session, uuid, segment);
+        node = new JcrNode(session, uuid, segment, nodeDefinition);
         ExecutionContext context = Mockito.mock(ExecutionContext.class);
         stub(session.getExecutionContext()).toReturn(context);
         stub(session.getNode(uuid)).toReturn(root);

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java	2009-03-05 18:20:33 UTC (rev 760)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java	2009-03-06 16:51:55 UTC (rev 761)
@@ -30,6 +30,7 @@
 import java.util.Map;
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.Property;
+import javax.jcr.nodetype.NodeDefinition;
 import org.jboss.dna.graph.property.Name;
 import org.junit.Before;
 import org.junit.Test;
@@ -44,13 +45,15 @@
     private JcrRootNode root;
     @Mock
     private JcrSession session;
+    @Mock
+    private NodeDefinition nodeDefinition;
     private Map<Name, Property> properties;
 
     @Before
     public void before() throws Exception {
         MockitoAnnotations.initMocks(this);
         properties = new HashMap<Name, Property>();
-        root = new JcrRootNode(session);
+        root = new JcrRootNode(session, nodeDefinition);
         root.setProperties(properties);
     }
 




More information about the dna-commits mailing list