[dna-commits] DNA SVN: r799 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/request and 4 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Wed Apr 1 18:27:52 EDT 2009


Author: rhauch
Date: 2009-04-01 18:27:52 -0400 (Wed, 01 Apr 2009)
New Revision: 799

Added:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ChangeRequest.java
Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CreateNodeRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/DeleteBranchRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RemovePropertiesRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RenameNodeRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UpdatePropertiesRequest.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.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/SessionCache.java
   trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
   trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties
Log:
DNA-194 Implement update JCR capability

Implemented Node.addNode(...) methods and Node.save().  Some enhancements to the Request classes were required to allow the SessionCache to easily figure out whether a request affected a particular branch.  Also enabled one TCK unit test.


Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -1925,10 +1925,26 @@
      * @see Results
      */
     public Batch batch() {
-        return new Batch();
+        return new Batch(new LinkedList<Request>());
     }
 
     /**
+     * Begin a batch of requests to perform various operations, but specify the queue where all accumulated requests should be
+     * placed. Use this approach when multiple operations are to be built and then executed with one submission to the underlying
+     * {@link #getSourceName() repository source}. The {@link Results results} are not available until the {@link Batch#execute()}
+     * method is invoked.
+     * 
+     * @param queue the queue where all batched requests should be placed
+     * @return the batch object used to build and accumulate multiple requests and to submit them all for processing at once.
+     * @see Batch#execute()
+     * @see Results
+     */
+    public Batch batch( LinkedList<Request> queue ) {
+        CheckArg.isNotNull(queue, "queue");
+        return new Batch(queue);
+    }
+
+    /**
      * Interface for creating multiple requests to perform various operations. Note that all the requests are accumulated until
      * the {@link #execute()} method is called. The results of all the operations are then available in the {@link Results} object
      * returned by the {@link #execute()}.
@@ -1937,12 +1953,13 @@
      */
     @Immutable
     public final class Batch implements Executable<Node> {
-        protected final CompositingRequestQueue requestQueue = new CompositingRequestQueue();
+        protected final CompositingRequestQueue requestQueue;
         protected final BatchConjunction nextRequests;
         protected final String workspaceName;
         protected boolean executed = false;
 
-        /*package*/Batch() {
+        /*package*/Batch( LinkedList<Request> queue ) {
+            this.requestQueue = new CompositingRequestQueue(queue);
             this.workspaceName = Graph.this.getCurrentWorkspaceName();
             this.nextRequests = new BatchConjunction() {
                 public Batch and() {
@@ -4737,8 +4754,13 @@
      */
     @NotThreadSafe
     /*package*/class CompositingRequestQueue implements RequestQueue {
-        private final LinkedList<Request> requests = new LinkedList<Request>();
+        private final LinkedList<Request> requests;
 
+        CompositingRequestQueue( LinkedList<Request> queue ) {
+            assert queue != null;
+            this.requests = queue;
+        }
+
         public Graph getGraph() {
             return Graph.this;
         }

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ChangeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ChangeRequest.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ChangeRequest.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -0,0 +1,50 @@
+/*
+ * 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.graph.request;
+
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.property.Path;
+
+/**
+ * 
+ */
+public interface ChangeRequest {
+
+    /**
+     * Determine if this request changes the branch at the given path.
+     * 
+     * @param workspace the name of the workspace; may not be null
+     * @param path the path; may not be null
+     * @return true if this request changes a node under the given path
+     */
+    boolean changes( String workspace,
+                     Path path );
+
+    /**
+     * Get the location of the top-most node that is to be changed by this request.
+     * 
+     * @return the location changed by this request
+     */
+    Location changedLocation();
+}


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

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -28,6 +28,7 @@
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.NodeConflictBehavior;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
 
 /**
  * Instruction that a branch be copied from one location into another. This request can copy a branch in one workspace into
@@ -35,7 +36,7 @@
  * 
  * @author Randall Hauch
  */
-public class CopyBranchRequest extends Request {
+public class CopyBranchRequest extends Request implements ChangeRequest {
 
     private static final long serialVersionUID = 1L;
 
@@ -246,6 +247,25 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
+     */
+    public boolean changes( String workspace,
+                            Path path ) {
+        return this.intoWorkspace.equals(workspace) && into.hasPath() && into.getPath().isAtOrBelow(path);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
+     */
+    public Location changedLocation() {
+        return into;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CreateNodeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CreateNodeRequest.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CreateNodeRequest.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -34,6 +34,7 @@
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.NodeConflictBehavior;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.Property;
 
 /**
@@ -41,7 +42,7 @@
  * 
  * @author Randall Hauch
  */
-public class CreateNodeRequest extends Request implements Iterable<Property> {
+public class CreateNodeRequest extends Request implements Iterable<Property>, ChangeRequest {
 
     private static final long serialVersionUID = 1L;
 
@@ -317,6 +318,25 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
+     */
+    public boolean changes( String workspace,
+                            Path path ) {
+        return this.workspaceName.equals(workspace) && under.hasPath() && under.getPath().isAtOrBelow(path);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
+     */
+    public Location changedLocation() {
+        return under;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/DeleteBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/DeleteBranchRequest.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/DeleteBranchRequest.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -26,13 +26,14 @@
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.property.Path;
 
 /**
  * Instruction that a branch be deleted.
  * 
  * @author Randall Hauch
  */
-public class DeleteBranchRequest extends Request {
+public class DeleteBranchRequest extends Request implements ChangeRequest {
 
     private static final long serialVersionUID = 1L;
 
@@ -114,6 +115,25 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
+     */
+    public boolean changes( String workspace,
+                            Path path ) {
+        return this.workspaceName.equals(workspace) && at.hasPath() && at.getPath().isAtOrBelow(path);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
+     */
+    public Location changedLocation() {
+        return at;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -34,7 +34,7 @@
  * 
  * @author Randall Hauch
  */
-public class MoveBranchRequest extends Request {
+public class MoveBranchRequest extends Request implements ChangeRequest {
 
     private static final long serialVersionUID = 1L;
 
@@ -207,6 +207,25 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
+     */
+    public boolean changes( String workspace,
+                            Path path ) {
+        return this.workspaceName.equals(workspace) && into.hasPath() && into.getPath().isAtOrBelow(path);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
+     */
+    public Location changedLocation() {
+        return into;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RemovePropertiesRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RemovePropertiesRequest.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RemovePropertiesRequest.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -32,13 +32,14 @@
 import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
 
 /**
  * Instruction to remove properties from the node at the specified location.
  * 
  * @author Randall Hauch
  */
-public class RemovePropertiesRequest extends Request implements Iterable<Name> {
+public class RemovePropertiesRequest extends Request implements Iterable<Name>, ChangeRequest {
 
     private static final long serialVersionUID = 1L;
 
@@ -196,6 +197,25 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
+     */
+    public boolean changes( String workspace,
+                            Path path ) {
+        return this.workspaceName.equals(workspace) && from.hasPath() && from.getPath().isAtOrBelow(path);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
+     */
+    public Location changedLocation() {
+        return from;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RenameNodeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RenameNodeRequest.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RenameNodeRequest.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -35,7 +35,7 @@
  * 
  * @author Randall Hauch
  */
-public class RenameNodeRequest extends Request {
+public class RenameNodeRequest extends Request implements ChangeRequest {
 
     private static final long serialVersionUID = 1L;
 
@@ -161,6 +161,25 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
+     */
+    public boolean changes( String workspace,
+                            Path path ) {
+        return this.workspaceName.equals(workspace) && at.hasPath() && at.getPath().getParent().isAtOrBelow(path);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
+     */
+    public Location changedLocation() {
+        return at;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UpdatePropertiesRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UpdatePropertiesRequest.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UpdatePropertiesRequest.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -35,6 +35,7 @@
 import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.Property;
 
 /**
@@ -42,7 +43,7 @@
  * 
  * @author Randall Hauch
  */
-public class UpdatePropertiesRequest extends Request implements Iterable<Property> {
+public class UpdatePropertiesRequest extends Request implements Iterable<Property>, ChangeRequest {
 
     private static final long serialVersionUID = 1L;
 
@@ -216,6 +217,16 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
+     */
+    public boolean changes( String workspace,
+                            Path path ) {
+        return this.workspaceName.equals(workspace) && on.hasPath() && on.getPath().isAtOrBelow(path);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override
@@ -234,6 +245,15 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
+     */
+    public Location changedLocation() {
+        return on;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#toString()
      */
     @Override

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-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -31,7 +31,9 @@
 import java.util.List;
 import java.util.UUID;
 import java.util.regex.Pattern;
+import javax.jcr.InvalidItemStateException;
 import javax.jcr.Item;
+import javax.jcr.ItemExistsException;
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.ItemVisitor;
 import javax.jcr.Node;
@@ -44,10 +46,13 @@
 import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.Value;
 import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.version.Version;
+import javax.jcr.version.VersionException;
 import javax.jcr.version.VersionHistory;
 import net.jcip.annotations.Immutable;
 import org.jboss.dna.common.i18n.I18n;
@@ -56,6 +61,7 @@
 import org.jboss.dna.graph.property.NamespaceRegistry;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.ValueFormatException;
+import org.jboss.dna.jcr.SessionCache.NodeEditor;
 import org.jboss.dna.jcr.cache.ChildNode;
 import org.jboss.dna.jcr.cache.Children;
 import org.jboss.dna.jcr.cache.NodeInfo;
@@ -88,6 +94,30 @@
         return cache.findNodeInfo(nodeUuid);
     }
 
+    final NodeEditor editorForParent() throws RepositoryException {
+        try {
+            return cache.getEditorFor(nodeInfo().getParent());
+        } catch (ItemNotFoundException err) {
+            String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
+            throw new RepositoryException(msg);
+        } catch (InvalidItemStateException err) {
+            String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
+            throw new RepositoryException(msg);
+        }
+    }
+
+    final NodeEditor editor() throws RepositoryException {
+        try {
+            return cache.getEditorFor(nodeUuid);
+        } catch (ItemNotFoundException err) {
+            String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
+            throw new RepositoryException(msg);
+        } catch (InvalidItemStateException err) {
+            String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
+            throw new RepositoryException(msg);
+        }
+    }
+
     @Override
     Path path() throws RepositoryException {
         return cache.getPathFor(nodeInfo());
@@ -380,7 +410,7 @@
         int indexOfFirstSlash = relativePath.indexOf('/');
         if (indexOfFirstSlash == 0) {
             // Not a relative path ...
-            throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath));
+            throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
         }
         if (indexOfFirstSlash != -1) {
             // We know it's a relative path with more than one segment ...
@@ -411,7 +441,7 @@
         int indexOfFirstSlash = relativePath.indexOf('/');
         if (indexOfFirstSlash == 0) {
             // Not a relative path ...
-            throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath));
+            throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
         }
         if (indexOfFirstSlash != -1) {
             Path path = pathFrom(relativePath).getNormalizedPath();
@@ -450,7 +480,7 @@
         int indexOfFirstSlash = relativePath.indexOf('/');
         if (indexOfFirstSlash == 0) {
             // Not a relative path ...
-            throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath));
+            throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
         }
         if (indexOfFirstSlash != -1) {
             // We know it's a relative path with more than one segment ...
@@ -547,22 +577,86 @@
     /**
      * {@inheritDoc}
      * 
-     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#addNode(java.lang.String)
      */
-    public final Node addNode( String relPath ) {
-        throw new UnsupportedOperationException();
+    public final Node addNode( String relPath )
+        throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException,
+        RepositoryException {
+        return addNode(relPath, null);
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @throws UnsupportedOperationException always
      * @see javax.jcr.Node#addNode(java.lang.String, java.lang.String)
      */
     public final Node addNode( String relPath,
-                               String primaryNodeTypeName ) {
-        throw new UnsupportedOperationException();
+                               String primaryNodeTypeName )
+        throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException,
+        RepositoryException {
+        // Determine the path ...
+        NodeEditor editor = null;
+        Path path = null;
+        try {
+            path = cache.pathFactory().create(relPath);
+        } catch (ValueFormatException e) {
+            throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
+        }
+        if (path.size() == 0) {
+            throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
+        }
+        if (path.getLastSegment().getIndex() > 1 || relPath.endsWith("]")) {
+            throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
+        }
+        if (path.size() != 1) {
+            // The only segment in the path is the child name ...
+            NodeInfo parentInfo = null;
+            Path parentPath = path.getParent();
+            try {
+                parentInfo = cache.findNodeInfo(nodeUuid, parentPath); // throws PathNotFoundException
+                editor = cache.getEditorFor(parentInfo.getUuid());
+            } catch (PathNotFoundException e) {
+                // We're going to throw an exception ... the question is which one ...
+                if (parentPath.size() > 1) {
+                    // Per the TCK, if relPath references a property, then we have to throw a ConstraintViolationException
+                    // So, if we can't find the parent, try for the parent's parent and see if the last segment of the parent's
+                    // path contains a property ...
+                    Path grandparentPath = parentPath.getParent();
+                    assert grandparentPath != null;
+                    try {
+                        NodeInfo grandparentInfo = cache.findNodeInfo(nodeUuid, grandparentPath); // throws PathNotFoundException
+                        if (grandparentInfo.getProperty(parentPath.getLastSegment().getName()) != null) {
+                            // Need to throw a ConstraintViolationException since the request was to add a child to
+                            // a property ...
+                            throw new ConstraintViolationException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
+                        }
+                    } catch (PathNotFoundException e2) {
+                        // eat, since the original exception is what we want ...
+                    }
+                }
+                // Otherwise, just throw the PathNotFoundException ...
+                throw e;
+            }
+        } else {
+            assert path.size() == 1;
+            editor = editor();
+        }
+        Name childName = path.getLastSegment().getName();
+
+        // Determine the name for the primary node type
+        Name childPrimaryTypeName = null;
+        if (primaryNodeTypeName != null) {
+            try {
+                childPrimaryTypeName = cache.nameFactory().create(primaryNodeTypeName);
+            } catch (ValueFormatException e) {
+                throw new RepositoryException(JcrI18n.invalidNodeTypeNameParameter.text(primaryNodeTypeName,
+                                                                                        "primaryNodeTypeName"));
+            }
+        }
+
+        // Create the child ...
+        ChildNode child = editor.createChild(childName, null, childPrimaryTypeName);
+        return cache.findJcrNode(child.getUuid());
     }
 
     /**
@@ -1001,10 +1095,9 @@
     /**
      * {@inheritDoc}
      * 
-     * @throws UnsupportedOperationException always
      * @see javax.jcr.Item#save()
      */
-    public void save() {
-        throw new UnsupportedOperationException();
+    public void save() throws RepositoryException {
+        cache.save(nodeUuid);
     }
 }

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-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -62,6 +62,7 @@
     public static I18n invalidRelativePath;
     public static I18n invalidPathParameter;
     public static I18n invalidNamePattern;
+    public static I18n invalidNodeTypeNameParameter;
     public static I18n noPrimaryItemNameDefinedOnPrimaryType;
     public static I18n primaryItemNameForPrimaryTypeIsNotValid;
     public static I18n primaryItemDoesNotExist;
@@ -75,6 +76,9 @@
     public static I18n errorWhileFindingNodeWithPath;
     public static I18n nodeDefinitionCouldNotBeDeterminedForNode;
     public static I18n missingNodeTypeForExistingNode;
+    public static I18n unableToCreateNodeWithPrimaryTypeThatDoesNotExist;
+    public static I18n unableToCreateNodeWithNoDefaultPrimaryTypeOnChildNodeDefinition;
+    public static I18n unableToSaveNodeThatWasCreatedSincePreviousSave;
 
     public static I18n unableToRemoveRootNode;
     public static I18n unableToMoveNodeToBeChildOfDecendent;
@@ -100,7 +104,7 @@
     // Query-related messages
     public static I18n notStoredQuery;
     public static I18n invalidQueryLanguage;
-    
+
     static {
         try {
             I18n.initialize(JcrI18n.class);

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-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -24,7 +24,6 @@
 package org.jboss.dna.jcr;
 
 import java.util.UUID;
-import javax.jcr.InvalidItemStateException;
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
@@ -93,16 +92,7 @@
      * @see javax.jcr.Item#remove()
      */
     public void remove() throws RepositoryException {
-        try {
-            SessionCache.NodeEditor editor = cache.getEditorFor(nodeInfo().getParent());
-            editor.destroyChild(nodeUuid);
-        } catch (ItemNotFoundException err) {
-            String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
-            throw new RepositoryException(msg);
-        } catch (InvalidItemStateException err) {
-            String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
-            throw new RepositoryException(msg);
-        }
+        editorForParent().destroyChild(nodeUuid);
     }
 
 }

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -27,6 +27,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -44,10 +45,12 @@
 import javax.jcr.Session;
 import javax.jcr.Value;
 import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
 import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.nodetype.PropertyDefinition;
 import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.i18n.I18n;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.Graph;
 import org.jboss.dna.graph.Location;
@@ -63,6 +66,8 @@
 import org.jboss.dna.graph.property.ValueFactories;
 import org.jboss.dna.graph.property.ValueFactory;
 import org.jboss.dna.graph.property.ValueFormatException;
+import org.jboss.dna.graph.request.ChangeRequest;
+import org.jboss.dna.graph.request.Request;
 import org.jboss.dna.jcr.cache.ChangedNodeInfo;
 import org.jboss.dna.jcr.cache.ChildNode;
 import org.jboss.dna.jcr.cache.Children;
@@ -141,7 +146,8 @@
     protected final HashMap<UUID, ChangedNodeInfo> changedNodes;
     protected final HashMap<UUID, NodeInfo> deletedNodes;
 
-    private Graph.Batch operations;
+    private LinkedList<Request> requests;
+    protected Graph.Batch operations;
 
     public SessionCache( JcrSession session,
                          String workspaceName,
@@ -174,6 +180,7 @@
         this.deletedNodes = new HashMap<UUID, NodeInfo>();
 
         // Create the batch operations ...
+        this.requests = new LinkedList<Request>();
         this.operations = this.store.batch();
     }
 
@@ -181,22 +188,26 @@
         return session;
     }
 
+    String workspaceName() {
+        return workspaceName;
+    }
+
     ExecutionContext context() {
         return context;
     }
 
-    String workspaceName() {
-        return workspaceName;
+    PathFactory pathFactory() {
+        return pathFactory;
     }
 
+    NameFactory nameFactory() {
+        return nameFactory;
+    }
+
     JcrNodeTypeManager nodeTypes() {
         return session.nodeTypeManager();
     }
 
-    final Graph.Batch operations() {
-        return operations;
-    }
-
     /**
      * Save any changes that have been accumulated by this session.
      * 
@@ -207,12 +218,17 @@
             // Execute the batched operations ...
             try {
                 operations.execute();
+            } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+                throw new PathNotFoundException(e.getLocalizedMessage(), e);
             } catch (RuntimeException e) {
-                throw new RepositoryException(e);
+                throw new RepositoryException(e.getLocalizedMessage(), e);
             }
 
             // Create a new batch for future operations ...
-            operations = store.batch();
+            // LinkedList<Request> oldRequests = this.requests;
+            this.requests = new LinkedList<Request>();
+            operations = store.batch(this.requests);
+
             // Remove all the cached items that have been changed or deleted ...
             for (UUID changedUuid : changedNodes.keySet()) {
                 cachedNodes.remove(changedUuid);
@@ -226,6 +242,77 @@
         }
     }
 
+    /**
+     * Save any changes to the identified node or its decendants. The supplied node may not have been deleted or created in this
+     * session since the last save operation.
+     * 
+     * @param nodeUuid the UUID of the node that is to be saved; may not be null
+     * @throws RepositoryException if any error resulting while saving the changes to the repository
+     */
+    public void save( UUID nodeUuid ) throws RepositoryException {
+        assert nodeUuid != null;
+        if (deletedNodes.containsKey(nodeUuid)) {
+            // This node was deleted in this session ...
+            throw new InvalidItemStateException(JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, workspaceName()));
+        }
+
+        // The node must not have been created since the last save ...
+        if (!cachedNodes.containsKey(nodeUuid)) {
+            // It is not cached, which means it WAS created ...
+            Path path = getPathFor(nodeUuid);
+            throw new RepositoryException(JcrI18n.unableToSaveNodeThatWasCreatedSincePreviousSave.text(path, workspaceName()));
+        }
+
+        if (operations.isExecuteRequired()) {
+            // Find the path of the given node ...
+            Path path = getPathFor(nodeUuid);
+
+            // Remove all of the enqueued requests for this branch ...
+            LinkedList<Request> branchRequests = new LinkedList<Request>();
+            LinkedList<Request> nonBranchRequests = new LinkedList<Request>();
+            Set<UUID> branchUuids = new HashSet<UUID>();
+            for (Request request : this.requests) {
+                assert request instanceof ChangeRequest;
+                ChangeRequest change = (ChangeRequest)request;
+                if (change.changes(workspaceName, path)) {
+                    branchRequests.add(request);
+                    // Record the UUID of the node being saved now ...
+                    UUID changedUuid = change.changedLocation().getUuid();
+                    assert changedUuid != null;
+                    branchUuids.add(changedUuid);
+                } else {
+                    nonBranchRequests.add(request);
+                }
+            }
+
+            if (branchRequests.isEmpty()) {
+                // None of the changes affected the branch given by the node ...
+                return;
+            }
+
+            // Now execute the branch ...
+            Graph.Batch branchBatch = store.batch(branchRequests);
+            try {
+                branchBatch.execute();
+
+                // Still have non-branch related requests that we haven't executed ...
+                this.requests = nonBranchRequests;
+                this.operations = store.batch(nonBranchRequests);
+
+                // Remove all the cached, changed or deleted items that were just saved ...
+                for (UUID changedUuid : branchUuids) {
+                    cachedNodes.remove(changedUuid);
+                    changedNodes.remove(changedUuid);
+                    deletedNodes.remove(changedUuid);
+                }
+            } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+                throw new PathNotFoundException(e.getLocalizedMessage(), e);
+            } catch (RuntimeException e) {
+                throw new RepositoryException(e.getLocalizedMessage(), e);
+            }
+        }
+    }
+
     public JcrRootNode findJcrRootNode() throws RepositoryException {
         return (JcrRootNode)findJcrNode(findNodeInfoForRoot().getUuid());
     }
@@ -498,7 +585,7 @@
 
             // Finally update the cached information and record the change ...
             node.setProperty(newProperty, context().getValueFactories());
-            operations().set(dnaProp).on(currentLocation);
+            operations.set(dnaProp).on(currentLocation);
         }
 
         /**
@@ -587,7 +674,7 @@
 
             // Finally update the cached information and record the change ...
             node.setProperty(newProperty, context().getValueFactories());
-            operations().set(dnaProp).on(currentLocation);
+            operations.set(dnaProp).on(currentLocation);
         }
 
         /**
@@ -598,7 +685,7 @@
          */
         public boolean removeProperty( Name name ) {
             if (node.removeProperty(name) != null) {
-                operations().remove(name).on(currentLocation);
+                operations.remove(name).on(currentLocation);
                 return true;
             }
             return false;
@@ -675,7 +762,7 @@
             existingNodeInfo.setParent(node.getUuid());
 
             // Now, record the operation to do this ...
-            operations().move(existingNodeEditor.currentLocation).into(currentLocation);
+            operations.move(existingNodeEditor.currentLocation).into(currentLocation);
 
             return newChild;
         }
@@ -686,17 +773,16 @@
          * @param name the name for the new child; may not be null
          * @param desiredUuid the desired UUID, or null if the UUID for the child should be generated automatically
          * @param primaryTypeName the name of the primary type for the new node
-         * @param nodeDefinitionId
          * @return the representation of the newly-created child, which includes the {@link ChildNode#getSnsIndex()
          *         same-name-sibling index}
          * @throws InvalidItemStateException if the specified child has been marked for deletion within this session
          * @throws ConstraintViolationException if moving the node into this node violates this node's definition
+         * @throws NoSuchNodeTypeException if the node type for the primary type could not be found
          * @throws RepositoryException if any other error occurs while reading information from the repository
          */
         public ChildNode createChild( Name name,
                                       UUID desiredUuid,
-                                      Name primaryTypeName,
-                                      NodeDefinitionId nodeDefinitionId )
+                                      Name primaryTypeName )
             throws InvalidItemStateException, ConstraintViolationException, RepositoryException {
             if (desiredUuid == null) desiredUuid = UUID.randomUUID();
 
@@ -708,10 +794,34 @@
                                                                                primaryTypeName,
                                                                                numSns,
                                                                                true);
+            // Make sure there was a valid child node definition ...
             if (definition == null) {
-                throw new ConstraintViolationException();
+                Path pathForChild = pathFactory.create(getPathFor(node), name, numSns + 1);
+                String msg = JcrI18n.nodeDefinitionCouldNotBeDeterminedForNode.text(pathForChild, workspaceName());
+                throw new ConstraintViolationException(msg);
             }
 
+            // Find the primary type ...
+            JcrNodeType primaryType = null;
+            if (primaryTypeName != null) {
+                primaryType = nodeTypes().getNodeType(primaryTypeName);
+                if (primaryType == null) {
+                    Path pathForChild = pathFactory.create(getPathFor(node), name, numSns + 1);
+                    I18n msg = JcrI18n.unableToCreateNodeWithPrimaryTypeThatDoesNotExist;
+                    throw new NoSuchNodeTypeException(msg.text(primaryTypeName, pathForChild, workspaceName()));
+                }
+            } else {
+                primaryType = (JcrNodeType)definition.getDefaultPrimaryType();
+                if (primaryType == null) {
+                    // There is no default primary type ...
+                    Path pathForChild = pathFactory.create(getPathFor(node), name, numSns + 1);
+                    I18n msg = JcrI18n.unableToCreateNodeWithNoDefaultPrimaryTypeOnChildNodeDefinition;
+                    String nodeTypeName = definition.getDeclaringNodeType().getName();
+                    throw new NoSuchNodeTypeException(msg.text(definition.getName(), nodeTypeName, pathForChild, workspaceName()));
+                }
+            }
+            primaryTypeName = primaryType.getInternalName();
+
             ChildNode result = node.addChild(name, desiredUuid, pathFactory);
 
             // ---------------------------------------------------------
@@ -723,7 +833,7 @@
             // Create the properties ...
             Map<Name, PropertyInfo> properties = new HashMap<Name, PropertyInfo>();
             Property primaryTypeProp = propertyFactory.create(JcrLexicon.PRIMARY_TYPE, primaryTypeName);
-            Property nodeDefinitionProp = propertyFactory.create(DnaLexicon.NODE_DEFINITON, nodeDefinitionId.getString());
+            Property nodeDefinitionProp = propertyFactory.create(DnaLexicon.NODE_DEFINITON, definition.getId().getString());
 
             // Create the property info for the "jcr:primaryType" child property ...
             JcrPropertyDefinition primaryTypeDefn = findBestPropertyDefintion(node.getPrimaryTypeName(),
@@ -759,10 +869,10 @@
             // ---------------------------------------
             // Now record the changes to the store ...
             // ---------------------------------------
-            Graph.Create<Graph.Batch> create = operations().createUnder(currentLocation)
-                                                           .nodeNamed(name)
-                                                           .with(desiredUuid)
-                                                           .with(primaryTypeProp);
+            Graph.Create<Graph.Batch> create = operations.createUnder(currentLocation)
+                                                         .nodeNamed(name)
+                                                         .with(desiredUuid)
+                                                         .with(primaryTypeProp);
             if (nodeDefnDefn != null) {
                 create = create.with(nodeDefinitionProp);
             }
@@ -787,7 +897,7 @@
                 // Now make the request to the source ...
                 Path childPath = pathFactory.create(currentLocation.getPath(), deleted.getSegment());
                 Location locationOfChild = Location.create(childPath, nodeUuid);
-                operations().delete(locationOfChild);
+                operations.delete(locationOfChild);
                 return true;
             }
             return false;
@@ -917,6 +1027,7 @@
      * @see #findNodeInfoForRoot()
      */
     NodeInfo findNodeInfo( UUID uuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
+        assert uuid != null;
         // See if we already have something in the cache ...
         NodeInfo info = findNodeInfoInCache(uuid);
         if (info == null) {
@@ -1326,16 +1437,16 @@
             definition = nodeTypes().getNodeDefinition(id);
         }
         // Figure out the node definition for this node ...
-        if (definition == null) {
-            if (isRoot) {
-                definition = nodeTypes().getRootNodeDefinition();
-            } else {
-                // We need the parent ...
-                Path path = location.getPath();
-                if (parentInfo == null) {
-                    Path parentPath = path.getParent();
-                    parentInfo = findNodeInfo(null, parentPath.getNormalizedPath());
-                }
+        if (isRoot) {
+            if (definition == null) definition = nodeTypes().getRootNodeDefinition();
+        } else {
+            // We need the parent ...
+            Path path = location.getPath();
+            if (parentInfo == null) {
+                Path parentPath = path.getParent();
+                parentInfo = findNodeInfo(null, parentPath.getNormalizedPath());
+            }
+            if (definition == null) {
                 Name childName = path.getLastSegment().getName();
                 int numExistingChildrenWithSameName = parentInfo.getChildren().getCountOfSameNameSiblingsWithName(childName);
                 definition = nodeTypes().findChildNodeDefinition(parentInfo.getPrimaryTypeName(),
@@ -1344,11 +1455,11 @@
                                                                  primaryTypeName,
                                                                  numExistingChildrenWithSameName,
                                                                  false);
-                if (definition == null) {
-                    String msg = JcrI18n.nodeDefinitionCouldNotBeDeterminedForNode.text(path, workspaceName);
-                    throw new RepositorySourceException(msg);
-                }
             }
+            if (definition == null) {
+                String msg = JcrI18n.nodeDefinitionCouldNotBeDeterminedForNode.text(path, workspaceName);
+                throw new RepositorySourceException(msg);
+            }
         }
 
         // ------------------------------------------------------

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-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties	2009-04-01 22:27:52 UTC (rev 799)
@@ -52,6 +52,7 @@
 invalidRelativePath = "{0}" is not a valid relative path
 invalidPathParameter = The "{1}" parameter value "{0}" was not a valid path
 invalidNamePattern = The "{1}" name pattern contained the '{0}' character, which is not allowed in a name pattern
+invalidNodeTypeNameParameter = The "{1}" parameter value "{0}" was not a valid node type name
 noPrimaryItemNameDefinedOnPrimaryType = The primary type "{0}" for node "{1}" in workspace "{2}" does not define a primary item name
 primaryItemNameForPrimaryTypeIsNotValid = The primary type "{0}" for node "{2}" in workspace "{3}" defines an invalid primary item name ("{1}")
 primaryItemDoesNotExist = The node "{2}" in workspace "{3}" does not have an item named "{1}" as defined by its primary type "{0}"
@@ -65,6 +66,9 @@
 errorWhileFindingNodeWithPath = Error while finding the node "{0}" in workspace "{1}"
 nodeDefinitionCouldNotBeDeterminedForNode = Unable to determine a valid node definition for the node "{0}" in workspace "{1}"
 missingNodeTypeForExistingNode = Missing primary node type "{0}" for node {1} in workspace "{2}"
+unableToCreateNodeWithPrimaryTypeThatDoesNotExist = Unable to create child "{1}" in workspace "{2}" because the node type "{0}" does not exist
+unableToCreateNodeWithNoDefaultPrimaryTypeOnChildNodeDefinition = Unable to create child "{2}" in workspace "{3}" because the node definition "{0}" on the "{1}" node type has no default primary type 
+unableToSaveNodeThatWasCreatedSincePreviousSave = Unable to save node "{0}" in workspace "{1}" because it was created since the last save
 
 unableToRemoveRootNode = Unable to remove the root node in workspace "{1}"
 unableToMoveNodeToBeChildOfDecendent = Node "{0}" in workspace "{2}" cannot be moved under a decendant node ("{1}") 

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java	2009-04-01 22:27:52 UTC (rev 799)
@@ -35,6 +35,7 @@
 import junit.framework.TestSuite;
 import org.apache.jackrabbit.test.JCRTestSuite;
 import org.apache.jackrabbit.test.RepositoryStub;
+import org.apache.jackrabbit.test.api.AddNodeTest;
 import org.apache.jackrabbit.test.api.RepositoryLoginTest;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
@@ -142,7 +143,7 @@
             // See https://jira.jboss.org/jira/browse/DNA-285
 
             // level 2 tests
-            // addTestSuite(AddNodeTest.class);
+            addTestSuite(AddNodeTest.class);
             // addTestSuite(NamespaceRegistryTest.class);
             // addTestSuite(ReferencesTest.class);
             // addTestSuite(SessionTest.class);

Modified: trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties
===================================================================
--- trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties	2009-04-01 16:10:43 UTC (rev 798)
+++ trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties	2009-04-01 22:27:52 UTC (rev 799)
@@ -7,3 +7,5 @@
 javax.jcr.tck.propertyname1=prop1
 javax.jcr.tck.propertyname2=prop2
 javax.jcr.tck.workspacename=
+javax.jcr.tck.nodetype=nt:unstructured
+javax.jcr.tck.nodetypenochildren=dna:namespace




More information about the dna-commits mailing list