From dna-commits at lists.jboss.org  Thu Feb 12 17:24:12 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Thu, 12 Feb 2009 17:24:12 -0500
Subject: [dna-commits] DNA SVN:  r722 - trunk.
Message-ID: <E1LXjye-0007T5-Kf@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-12 17:24:12 -0500 (Thu, 12 Feb 2009)
New Revision: 722

Modified:
   trunk/pom.xml
Log:
DNA-281 Connector support for workspaces

Changed the POM to remove several projects that are currently problematic because of some issues with the federation connector.

Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml	2009-01-29 16:58:14 UTC (rev 721)
+++ trunk/pom.xml	2009-02-12 22:24:12 UTC (rev 722)
@@ -114,7 +114,7 @@
 		<module>dna-common</module>
 		<module>dna-graph</module>
 		<module>dna-repository</module>
-		<module>dna-jcr</module>
+		<!--module>dna-jcr</module-->
 		<module>extensions/dna-classloader-maven</module>
 		<module>extensions/dna-sequencer-images</module>
 		<module>extensions/dna-sequencer-mp3</module>
@@ -130,10 +130,10 @@
 		<module>extensions/dna-connector-svn</module>
 		<module>extensions/dna-connector-store-jpa</module>
 		<module>extensions/dna-mimetype-detector-aperture</module>
-        <module>extensions/dna-common-jdbc</module> 
-        <module>extensions/dna-connector-jdbc-metadata</module> 
+		<module>extensions/dna-common-jdbc</module> 
+		<module>extensions/dna-connector-jdbc-metadata</module> 
 		<module>dna-integration-tests</module>
-		<module>docs/examples/gettingstarted</module>
+		<!--module>docs/examples/gettingstarted</module-->
 	</modules>
 
 	<profiles>



From dna-commits at lists.jboss.org  Fri Feb 13 11:35:07 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Fri, 13 Feb 2009 11:35:07 -0500
Subject: [dna-commits] DNA SVN: r724 - in trunk:
	dna-graph/src/test/java/org/jboss/dna/graph/property and 2
	other directories.
Message-ID: <E1LY10N-0008TG-UA@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-13 11:35:07 -0500 (Fri, 13 Feb 2009)
New Revision: 724

Added:
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/PropertyTypeTest.java
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/FakeRepositorySource.java
Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/PropertyType.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java
Log:
DNA-283 fileSystemPaths property value is ignored for FileSystemSources configured through XML

Changed RepositoryService to do a better job at figuring out how to convert the property values in the configuration repository into value(s) that are acceptable to the setter method. This uses the value factories to do the conversion, so RepositoryService really only works with RepositorySource implementations that have property setters that accept any of our known/supported property types or primitives (or arrays of those property types or primitives).

In order to do this, I added a new method added to PropertyType to discover the property type given a Class parameter.


Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/PropertyType.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/PropertyType.java	2009-02-12 22:27:44 UTC (rev 723)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/PropertyType.java	2009-02-13 16:35:07 UTC (rev 724)
@@ -32,6 +32,7 @@
 import java.util.List;
 import java.util.UUID;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.graph.GraphI18n;
 
 /**
@@ -119,6 +120,50 @@
     }
 
     /**
+     * Discover the most appropriate {@link PropertyType} whose values can be assigned to variables or parameters of the supplied
+     * type. This method does check whether the supplied {@link Class} is an array, in which case it just evalutes the
+     * {@link Class#getComponentType() component type} of the array.
+     * 
+     * @param clazz the class representing the type of a value or parameter; may not be null
+     * @return the PropertyType that best represents the type whose values can be used as a value in the supplied class, or null
+     *         if no matching PropertyType could be found
+     */
+    public static PropertyType discoverType( Class<?> clazz ) {
+        CheckArg.isNotNull(clazz, "clazz");
+        // Is the supplied class an array (or an array of arrays)?
+        while (clazz.isArray()) {
+            // Then just call extract the component type that of which we have an array ...
+            clazz = clazz.getComponentType();
+        }
+        // Try each property type, and see if its value type is an exact match ...
+        for (PropertyType type : PropertyType.values()) {
+            if (type.valueClass.equals(clazz)) return type;
+            // If the property type is capable of handling a primitive ...
+            switch (type) {
+                case LONG:
+                    if (Long.TYPE.equals(clazz) || Integer.TYPE.equals(clazz) || Short.TYPE.equals(clazz)) return type;
+                    if (Integer.class.equals(clazz) || Short.class.equals(clazz)) return type;
+                    break;
+                case DOUBLE:
+                    if (Double.TYPE.equals(clazz) || Float.TYPE.equals(clazz)) return type;
+                    if (Float.class.equals(clazz)) return type;
+                    break;
+                case BOOLEAN:
+                    if (Boolean.TYPE.equals(clazz)) return type;
+                    break;
+                default:
+                    break;
+            }
+        }
+        // No value class of the property type matched exactly, so now see if any property type is assignable to 'clazz' ...
+        for (PropertyType type : PropertyType.values()) {
+            if (clazz.isAssignableFrom(type.valueClass)) return type;
+        }
+        // Nothing works, ...
+        return null;
+    }
+
+    /**
      * Return an iterator over all the property type enumeration literals.
      * 
      * @return an immutable iterator

Added: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/PropertyTypeTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/PropertyTypeTest.java	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/PropertyTypeTest.java	2009-02-13 16:35:07 UTC (rev 724)
@@ -0,0 +1,220 @@
+/*
+ * 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.property;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.UUID;
+import org.junit.Test;
+
+/**
+ * 
+ */
+public class PropertyTypeTest {
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenPrimitiveClass() throws Exception {
+        assertThat(PropertyType.discoverType(Integer.TYPE), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(Long.TYPE), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(Short.TYPE), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(Boolean.TYPE), is(PropertyType.BOOLEAN));
+        assertThat(PropertyType.discoverType(Double.TYPE), is(PropertyType.DOUBLE));
+        assertThat(PropertyType.discoverType(Float.TYPE), is(PropertyType.DOUBLE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenNumberClass() throws Exception {
+        assertThat(PropertyType.discoverType(Integer.class), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(Long.class), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(Short.class), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(Boolean.class), is(PropertyType.BOOLEAN));
+        assertThat(PropertyType.discoverType(Double.class), is(PropertyType.DOUBLE));
+        assertThat(PropertyType.discoverType(Float.class), is(PropertyType.DOUBLE));
+        assertThat(PropertyType.discoverType(BigDecimal.class), is(PropertyType.DECIMAL));
+    }
+
+    @Test
+    public void shouldNotDiscoverPropertyTypeOfByteClass() {
+        assertThat(PropertyType.discoverType(Byte.class), is(nullValue()));
+    }
+
+    @Test
+    public void shouldNotDiscoverPropertyTypeOfBigIntegerClass() {
+        assertThat(PropertyType.discoverType(BigInteger.class), is(nullValue()));
+    }
+
+    @Test
+    public void shouldNotDiscoverPropertyTypeOfVoidClass() {
+        assertThat(PropertyType.discoverType(Void.TYPE), is(nullValue()));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenPrimitiveArrayClass() throws Exception {
+        assertThat(PropertyType.discoverType(new int[] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new long[] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new short[] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new boolean[] {}.getClass()), is(PropertyType.BOOLEAN));
+        assertThat(PropertyType.discoverType(new double[] {}.getClass()), is(PropertyType.DOUBLE));
+        assertThat(PropertyType.discoverType(new float[] {}.getClass()), is(PropertyType.DOUBLE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArrayOfPrimitiveArrayClass() throws Exception {
+        assertThat(PropertyType.discoverType(new int[][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new long[][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new short[][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new boolean[][] {}.getClass()), is(PropertyType.BOOLEAN));
+        assertThat(PropertyType.discoverType(new double[][] {}.getClass()), is(PropertyType.DOUBLE));
+        assertThat(PropertyType.discoverType(new float[][] {}.getClass()), is(PropertyType.DOUBLE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArrayOfArrayOfPrimitiveArrayClass() throws Exception {
+        assertThat(PropertyType.discoverType(new int[][][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new long[][][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new short[][][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new boolean[][][] {}.getClass()), is(PropertyType.BOOLEAN));
+        assertThat(PropertyType.discoverType(new double[][][] {}.getClass()), is(PropertyType.DOUBLE));
+        assertThat(PropertyType.discoverType(new float[][][] {}.getClass()), is(PropertyType.DOUBLE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenNumberArrayClass() throws Exception {
+        assertThat(PropertyType.discoverType(new Integer[] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new Long[] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new Short[] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new Boolean[] {}.getClass()), is(PropertyType.BOOLEAN));
+        assertThat(PropertyType.discoverType(new Double[] {}.getClass()), is(PropertyType.DOUBLE));
+        assertThat(PropertyType.discoverType(new Float[] {}.getClass()), is(PropertyType.DOUBLE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArrayOfNumberArrayClass() throws Exception {
+        assertThat(PropertyType.discoverType(new Integer[][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new Long[][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new Short[][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new Boolean[][] {}.getClass()), is(PropertyType.BOOLEAN));
+        assertThat(PropertyType.discoverType(new Double[][] {}.getClass()), is(PropertyType.DOUBLE));
+        assertThat(PropertyType.discoverType(new Float[][] {}.getClass()), is(PropertyType.DOUBLE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArrayOfArrayOfNumberArrayClass() throws Exception {
+        assertThat(PropertyType.discoverType(new Integer[][][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new Long[][][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new Short[][][] {}.getClass()), is(PropertyType.LONG));
+        assertThat(PropertyType.discoverType(new Boolean[][][] {}.getClass()), is(PropertyType.BOOLEAN));
+        assertThat(PropertyType.discoverType(new Double[][][] {}.getClass()), is(PropertyType.DOUBLE));
+        assertThat(PropertyType.discoverType(new Float[][][] {}.getClass()), is(PropertyType.DOUBLE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenStringClass() throws Exception {
+        assertThat(PropertyType.discoverType(String.class), is(PropertyType.STRING));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenPathClass() throws Exception {
+        assertThat(PropertyType.discoverType(Path.class), is(PropertyType.PATH));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenNameClass() throws Exception {
+        assertThat(PropertyType.discoverType(Name.class), is(PropertyType.NAME));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenReferenceClass() throws Exception {
+        assertThat(PropertyType.discoverType(Reference.class), is(PropertyType.REFERENCE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenDateTimeClass() throws Exception {
+        assertThat(PropertyType.discoverType(DateTime.class), is(PropertyType.DATE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenUriClass() throws Exception {
+        assertThat(PropertyType.discoverType(URI.class), is(PropertyType.URI));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenUuidClass() throws Exception {
+        assertThat(PropertyType.discoverType(UUID.class), is(PropertyType.UUID));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArraysOfStringClass() throws Exception {
+        assertThat(PropertyType.discoverType(new String[] {}.getClass()), is(PropertyType.STRING));
+        assertThat(PropertyType.discoverType(new String[][] {}.getClass()), is(PropertyType.STRING));
+        assertThat(PropertyType.discoverType(new String[][][] {}.getClass()), is(PropertyType.STRING));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArraysOfPathClass() throws Exception {
+        assertThat(PropertyType.discoverType(new Path[] {}.getClass()), is(PropertyType.PATH));
+        assertThat(PropertyType.discoverType(new Path[][] {}.getClass()), is(PropertyType.PATH));
+        assertThat(PropertyType.discoverType(new Path[][][] {}.getClass()), is(PropertyType.PATH));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArraysOfNameClass() throws Exception {
+        assertThat(PropertyType.discoverType(new Name[] {}.getClass()), is(PropertyType.NAME));
+        assertThat(PropertyType.discoverType(new Name[][] {}.getClass()), is(PropertyType.NAME));
+        assertThat(PropertyType.discoverType(new Name[][][] {}.getClass()), is(PropertyType.NAME));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArraysOfReferenceClass() throws Exception {
+        assertThat(PropertyType.discoverType(new Reference[] {}.getClass()), is(PropertyType.REFERENCE));
+        assertThat(PropertyType.discoverType(new Reference[][] {}.getClass()), is(PropertyType.REFERENCE));
+        assertThat(PropertyType.discoverType(new Reference[][][] {}.getClass()), is(PropertyType.REFERENCE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArraysOfDateTimeClass() throws Exception {
+        assertThat(PropertyType.discoverType(new DateTime[] {}.getClass()), is(PropertyType.DATE));
+        assertThat(PropertyType.discoverType(new DateTime[][] {}.getClass()), is(PropertyType.DATE));
+        assertThat(PropertyType.discoverType(new DateTime[][][] {}.getClass()), is(PropertyType.DATE));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArraysOfUriClass() throws Exception {
+        assertThat(PropertyType.discoverType(new URI[] {}.getClass()), is(PropertyType.URI));
+        assertThat(PropertyType.discoverType(new URI[][] {}.getClass()), is(PropertyType.URI));
+        assertThat(PropertyType.discoverType(new URI[][][] {}.getClass()), is(PropertyType.URI));
+    }
+
+    @Test
+    public void shouldDiscoverPropertyTypeGivenArraysOfUuidClass() throws Exception {
+        assertThat(PropertyType.discoverType(new UUID[] {}.getClass()), is(PropertyType.UUID));
+        assertThat(PropertyType.discoverType(new UUID[][] {}.getClass()), is(PropertyType.UUID));
+        assertThat(PropertyType.discoverType(new UUID[][][] {}.getClass()), is(PropertyType.UUID));
+    }
+
+}

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java	2009-02-12 22:27:44 UTC (rev 723)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java	2009-02-13 16:35:07 UTC (rev 724)
@@ -24,6 +24,7 @@
 package org.jboss.dna.repository;
 
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -31,6 +32,7 @@
 import org.jboss.dna.common.collection.Problems;
 import org.jboss.dna.common.collection.SimpleProblems;
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.Logger;
 import org.jboss.dna.common.util.Reflection;
 import org.jboss.dna.connector.federation.FederationException;
 import org.jboss.dna.graph.DnaLexicon;
@@ -44,6 +46,7 @@
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.PathNotFoundException;
 import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyType;
 import org.jboss.dna.graph.property.ValueFactories;
 import org.jboss.dna.graph.property.ValueFactory;
 import org.jboss.dna.repository.service.AbstractServiceAdministrator;
@@ -263,46 +266,123 @@
             problems.addError(err, RepositoryI18n.unableToInstantiateClassUsingClasspath, classname, classpath);
         }
 
-        // Try to set the name property to the local name of the node...
+        // We need to set the name using the local name of the node, so hack this by putting another name property
+        // into the map of properties. Since only the local name is used, we don't care what the namespace of the
+        // fake property name is, so create something bogus. However, it really won't hurt if this happens to override an existing
+        // property.
+        String fakeUri = DnaLexicon.Namespace.URI + "/300939b9dg93kd9gb";
+        Name nameName = context.getValueFactories().getNameFactory().create(fakeUri, "name");
+        Property nameProperty = context.getPropertyFactory().create(nameName, path.getLastSegment().getName().getLocalName());
+        properties.put(nameName, nameProperty);
+
+        // Now set all the properties that we can, ignoring any property that doesn't fit the pattern ...
         Reflection reflection = new Reflection(source.getClass());
-        try {
-            reflection.invokeSetterMethodOnTarget("name", source, path.getLastSegment().getName().getLocalName());
-        } catch (SecurityException err) {
-            // Do nothing ... assume not a JavaBean property
-        } catch (NoSuchMethodException err) {
-            // Do nothing ... assume not a JavaBean property
-        } catch (IllegalArgumentException err) {
-            // Do nothing ... assume not a JavaBean property
-        } catch (IllegalAccessException err) {
-            // Do nothing ... assume not a JavaBean property
-        } catch (InvocationTargetException err) {
-            // Do nothing ... assume not a JavaBean property
-        }
-
-        // Now set all the properties that we can, ignoring any property that doesn't fit pattern ...
         for (Map.Entry<Name, Property> entry : properties.entrySet()) {
             Name propertyName = entry.getKey();
             Property property = entry.getValue();
             String javaPropertyName = propertyName.getLocalName();
             if (property.isEmpty()) continue;
+
             Object value = null;
-            if (property.isSingle()) {
-                value = property.getValues().next();
-            } else if (property.isMultiple()) {
-                value = property.getValuesAsArray();
-            }
+            Method setter = null;
             try {
-                reflection.invokeSetterMethodOnTarget(javaPropertyName, source, value);
+                setter = reflection.findFirstMethod("set" + javaPropertyName, false);
+                if (setter == null) continue;
+                // Determine the type of the one parameter ...
+                Class<?>[] parameterTypes = setter.getParameterTypes();
+                if (parameterTypes.length != 1) continue; // not a valid JavaBean property
+                Class<?> paramType = parameterTypes[0];
+                PropertyType allowedType = PropertyType.discoverType(paramType);
+                if (allowedType == null) continue; // assume not a JavaBean property with usable type
+                ValueFactory<?> factory = context.getValueFactories().getValueFactory(allowedType);
+                if (paramType.isArray()) {
+                    if (paramType.getComponentType().isArray()) continue; // array of array, which we don't do
+                    Object[] values = factory.create(property.getValuesAsArray());
+                    // Convert to an array of primitives if that's what the signature requires ...
+                    Class<?> componentType = paramType.getComponentType();
+                    if (Integer.TYPE.equals(componentType)) {
+                        int[] primitiveValues = new int[values.length];
+                        for (int i = 0; i != values.length; ++i) {
+                            primitiveValues[i] = ((Long)values[i]).intValue();
+                        }
+                        value = primitiveValues;
+                    } else if (Short.TYPE.equals(componentType)) {
+                        short[] primitiveValues = new short[values.length];
+                        for (int i = 0; i != values.length; ++i) {
+                            primitiveValues[i] = ((Long)values[i]).shortValue();
+                        }
+                        value = primitiveValues;
+                    } else if (Long.TYPE.equals(componentType)) {
+                        long[] primitiveValues = new long[values.length];
+                        for (int i = 0; i != values.length; ++i) {
+                            primitiveValues[i] = ((Long)values[i]).longValue();
+                        }
+                        value = primitiveValues;
+                    } else if (Double.TYPE.equals(componentType)) {
+                        double[] primitiveValues = new double[values.length];
+                        for (int i = 0; i != values.length; ++i) {
+                            primitiveValues[i] = ((Double)values[i]).doubleValue();
+                        }
+                        value = primitiveValues;
+                    } else if (Float.TYPE.equals(componentType)) {
+                        float[] primitiveValues = new float[values.length];
+                        for (int i = 0; i != values.length; ++i) {
+                            primitiveValues[i] = ((Double)values[i]).floatValue();
+                        }
+                        value = primitiveValues;
+                    } else if (Boolean.TYPE.equals(componentType)) {
+                        boolean[] primitiveValues = new boolean[values.length];
+                        for (int i = 0; i != values.length; ++i) {
+                            primitiveValues[i] = ((Boolean)values[i]).booleanValue();
+                        }
+                        value = primitiveValues;
+                    } else {
+                        value = values;
+                    }
+                } else {
+                    value = factory.create(property.getFirstValue());
+                    // Convert to the correct primitive, if needed ...
+                    if (Integer.TYPE.equals(paramType)) {
+                        value = new Integer(((Long)value).intValue());
+                    } else if (Short.TYPE.equals(paramType)) {
+                        value = new Short(((Long)value).shortValue());
+                    } else if (Float.TYPE.equals(paramType)) {
+                        value = new Float(((Double)value).floatValue());
+                    }
+                }
+                // Invoke the method ...
+                String msg = "Setting property {0} to {1} on source at {2} in configuration repository {3} in workspace {4}";
+                Logger.getLogger(getClass()).trace(msg,
+                                                   javaPropertyName,
+                                                   value,
+                                                   path,
+                                                   configurationSourceName,
+                                                   configurationWorkspaceName);
+                setter.invoke(source, value);
             } catch (SecurityException err) {
-                // Do nothing ... assume not a JavaBean property
-            } catch (NoSuchMethodException err) {
-                // Do nothing ... assume not a JavaBean property
+                Logger.getLogger(getClass()).debug(err, "Error invoking {0}.{1}", source.getClass(), setter);
             } catch (IllegalArgumentException err) {
-                // Do nothing ... assume not a JavaBean property
+                // Do nothing ... assume not a JavaBean property (but log)
+                String msg = "Invalid argument invoking {0} with parameter {1} on source at {2} in configuration repository {3} in workspace {4}";
+                Logger.getLogger(getClass()).debug(err,
+                                                   msg,
+                                                   setter,
+                                                   value,
+                                                   path,
+                                                   configurationSourceName,
+                                                   configurationWorkspaceName);
             } catch (IllegalAccessException err) {
-                // Do nothing ... assume not a JavaBean property
+                Logger.getLogger(getClass()).debug(err, "Error invoking {0}.{1}", source.getClass(), setter);
             } catch (InvocationTargetException err) {
-                // Do nothing ... assume not a JavaBean property
+                // Do nothing ... assume not a JavaBean property (but log)
+                String msg = "Error invoking {0} with parameter {1} on source at {2} in configuration repository {3} in workspace {4}";
+                Logger.getLogger(getClass()).debug(err.getTargetException(),
+                                                   msg,
+                                                   setter,
+                                                   value,
+                                                   path,
+                                                   configurationSourceName,
+                                                   configurationWorkspaceName);
             }
         }
         return source;

Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/FakeRepositorySource.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/FakeRepositorySource.java	                        (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/FakeRepositorySource.java	2009-02-13 16:35:07 UTC (rev 724)
@@ -0,0 +1,204 @@
+/*
+ * 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.repository;
+
+import javax.naming.Reference;
+import org.apache.jackrabbit.spi.RepositoryService;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryContext;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.RepositorySourceCapabilities;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+
+/**
+ * A fake {@link RepositorySource} implementation that has a variety of parameters, used for testing whether
+ * {@link RepositoryService} can properly configure different kinds of properties.
+ */
+public class FakeRepositorySource implements RepositorySource {
+
+    /**
+     */
+    private static final long serialVersionUID = 1L;
+
+    private String name;
+    private int retryLimit;
+    private int intParam;
+    private short shortParam;
+    private boolean booleanParam;
+    private String stringParam;
+    private int[] intArrayParam;
+    private boolean[] booleanArrayParam;
+    private Long[] longObjectArrayParam;
+    private Boolean[] booleanObjectArrayParam;
+    private String[] stringArrayParam;
+
+    /**
+     * 
+     */
+    public FakeRepositorySource() {
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#getCapabilities()
+     */
+    public RepositorySourceCapabilities getCapabilities() {
+        return new RepositorySourceCapabilities();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#getConnection()
+     */
+    public RepositoryConnection getConnection() throws RepositorySourceException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#getName()
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name Sets name to the specified value.
+     */
+    public void setName( String name ) {
+        this.name = name;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#getRetryLimit()
+     */
+    public int getRetryLimit() {
+        return retryLimit;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#setRetryLimit(int)
+     */
+    public void setRetryLimit( int limit ) {
+        this.retryLimit = limit;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#initialize(org.jboss.dna.graph.connector.RepositoryContext)
+     */
+    public void initialize( RepositoryContext context ) throws RepositorySourceException {
+        // do nothing
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.naming.Referenceable#getReference()
+     */
+    public Reference getReference() {
+        throw new UnsupportedOperationException();
+    }
+
+    public int getIntParam() {
+        return intParam;
+    }
+
+    public void setIntParam( int intParam ) {
+        this.intParam = intParam;
+    }
+
+    public short getShortParam() {
+        return shortParam;
+    }
+
+    public void setShortParam( short shortParam ) {
+        this.shortParam = shortParam;
+    }
+
+    public boolean isBooleanParam() {
+        return booleanParam;
+    }
+
+    public void setBooleanParam( boolean booleanParam ) {
+        this.booleanParam = booleanParam;
+    }
+
+    public String getStringParam() {
+        return stringParam;
+    }
+
+    public void setStringParam( String stringParam ) {
+        this.stringParam = stringParam;
+    }
+
+    public int[] getIntArrayParam() {
+        return intArrayParam;
+    }
+
+    public void setIntArrayParam( int[] intArrayParam ) {
+        this.intArrayParam = intArrayParam;
+    }
+
+    public boolean[] getBooleanArrayParam() {
+        return booleanArrayParam;
+    }
+
+    public void setBooleanArrayParam( boolean[] booleanArrayParam ) {
+        this.booleanArrayParam = booleanArrayParam;
+    }
+
+    public Long[] getLongObjectArrayParam() {
+        return longObjectArrayParam;
+    }
+
+    public void setLongObjectArrayParam( Long[] longObjectArrayParam ) {
+        this.longObjectArrayParam = longObjectArrayParam;
+    }
+
+    public Boolean[] getBooleanObjectArrayParam() {
+        return booleanObjectArrayParam;
+    }
+
+    public void setBooleanObjectArrayParam( Boolean[] booleanObjectArrayParam ) {
+        this.booleanObjectArrayParam = booleanObjectArrayParam;
+    }
+
+    public String[] getStringArrayParam() {
+        return stringArrayParam;
+    }
+
+    public void setStringArrayParam( String[] stringArrayParam ) {
+        this.stringArrayParam = stringArrayParam;
+    }
+
+}

Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java	2009-02-12 22:27:44 UTC (rev 723)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java	2009-02-13 16:35:07 UTC (rev 724)
@@ -197,6 +197,7 @@
     @Test
     public void shouldStartUpAndCreateRepositoryUsingConfigurationRepositoryThatContainsNoSources() {
         // Set up the configuration repository ...
+        configRepository.useWorkspace("default");
         configRepository.create("/dna:sources");
         configRepository.create("/dna:sources/source A");
 
@@ -251,4 +252,49 @@
         // }
     }
 
+    @Test
+    public void shouldConfigureRepositorySourceWithSetterThatTakesArrayButWithSingleValues() {
+        RepositoryLibrary sources = new RepositoryLibrary(context);
+        sources.addSource(configRepositorySource);
+        service = new RepositoryService(sources, configSourceName, configWorkspaceName, context);
+
+        // Set up the configuration repository ...
+        configRepository.useWorkspace("default");
+        configRepository.create("/dna:system");
+        configRepository.create("/dna:system/dna:sources");
+        configRepository.create("/dna:system/dna:sources/source A");
+
+        final String className = FakeRepositorySource.class.getName();
+        configRepository.set(DnaLexicon.CLASSNAME).on("/dna:system/dna:sources/source A").to(className);
+        configRepository.set(DnaLexicon.CLASSPATH).on("/dna:system/dna:sources/source A").to("");
+        configRepository.set("retryLimit").on("/dna:system/dna:sources/source A").to(3);
+        configRepository.set("intParam").on("/dna:system/dna:sources/source A").to("3");
+        configRepository.set("shortParam").on("/dna:system/dna:sources/source A").to("32");
+        configRepository.set("booleanParam").on("/dna:system/dna:sources/source A").to("true");
+        configRepository.set("stringParam").on("/dna:system/dna:sources/source A").to("string value");
+        configRepository.set("intArrayParam").on("/dna:system/dna:sources/source A").to("3");
+        configRepository.set("booleanArrayParam").on("/dna:system/dna:sources/source A").to("true");
+        configRepository.set("longObjectArrayParam").on("/dna:system/dna:sources/source A").to("987654321");
+        configRepository.set("booleanObjectArrayParam").on("/dna:system/dna:sources/source A").to("true");
+        configRepository.set("stringArrayParam").on("/dna:system/dna:sources/source A").to("string value");
+
+        // Now, start up the service ...
+        service.getAdministrator().start();
+
+        // Get the source, which should be configured ...
+        RepositorySource repositorySourceA = service.getRepositorySourceManager().getSource("source A");
+        assertThat(repositorySourceA, is(instanceOf(FakeRepositorySource.class)));
+        FakeRepositorySource sourceA = (FakeRepositorySource)repositorySourceA;
+
+        assertThat(sourceA.getIntParam(), is(3));
+        assertThat(sourceA.getShortParam(), is((short)32));
+        assertThat(sourceA.isBooleanParam(), is(true));
+        assertThat(sourceA.getStringParam(), is("string value"));
+        assertThat(sourceA.getIntArrayParam(), is(new int[] {3}));
+        assertThat(sourceA.getBooleanArrayParam(), is(new boolean[] {true}));
+        assertThat(sourceA.getLongObjectArrayParam(), is(new Long[] {987654321L}));
+        assertThat(sourceA.getBooleanObjectArrayParam(), is(new Boolean[] {Boolean.TRUE}));
+        assertThat(sourceA.getStringArrayParam(), is(new String[] {"string value"}));
+    }
+
 }



From dna-commits at lists.jboss.org  Fri Feb 13 11:43:06 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Fri, 13 Feb 2009 11:43:06 -0500
Subject: [dna-commits] DNA SVN: r725 -
	trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector.
Message-ID: <E1LY186-0002h5-QB@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-13 11:43:06 -0500 (Fri, 13 Feb 2009)
New Revision: 725

Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySource.java
Log:
DNA-283 fileSystemPaths property value is ignored for FileSystemSources configured through XML

Updated the JavaDoc for RepositorySource to better explain the types of Java properties that work best: 

"Although any types can be used for these setters, other DNA components use reflection to set these properties and work best when the setters accept a single parameter that is a primitive, an array of primitives, a value compatible with PropertyType (e.g., Path, Name, URI, UUID, Reference, Binary, Long, Double, BigDecimal, DateTime, etc.), or an array of values that are compatible with PropertyType."

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySource.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySource.java	2009-02-13 16:35:07 UTC (rev 724)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySource.java	2009-02-13 16:43:06 UTC (rev 725)
@@ -24,8 +24,17 @@
 package org.jboss.dna.graph.connector;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
+import java.net.URI;
+import java.util.UUID;
 import javax.naming.Referenceable;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.property.Binary;
+import org.jboss.dna.graph.property.DateTime;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PropertyType;
+import org.jboss.dna.graph.property.Reference;
 import org.jboss.dna.graph.request.CacheableRequest;
 
 /**
@@ -34,7 +43,11 @@
  * <p>
  * Typically this interface is implemented by classes that provide standard-style getters and setters for the various properties
  * necessary for proper configuration via reflection or introspection. This interface expects nor defines any such properties,
- * leaving that entirely to the implementation classes.
+ * leaving that entirely to the implementation classes. Although any types can be used for these setters, other DNA components use
+ * reflection to set these properties and work best when the setters accept a single parameter that is a primitive, an array of
+ * primitives, a value compatible with {@link PropertyType} (e.g., {@link Path}, {@link Name}, {@link URI}, {@link UUID},
+ * {@link Reference}, {@link Binary}, {@link Long}, {@link Double}, {@link BigDecimal}, {@link DateTime}, etc.), or an array of
+ * values that are compatible with {@link PropertyType}.
  * </p>
  * <p>
  * Implementations should also provide a no-arg constructor so that it is possible to easily create instances and initialize using



From dna-commits at lists.jboss.org  Fri Feb 13 12:23:46 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Fri, 13 Feb 2009 12:23:46 -0500
Subject: [dna-commits] DNA SVN: r726 -
	trunk/dna-repository/src/test/java/org/jboss/dna/repository.
Message-ID: <E1LY1lS-0006vG-5P@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-13 12:23:46 -0500 (Fri, 13 Feb 2009)
New Revision: 726

Modified:
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/FakeRepositorySource.java
Log:
DNA-283 fileSystemPaths property value is ignored for FileSystemSources configured through XML

Corrected the JavaDoc for the test class, removing an incorrect import.

Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/FakeRepositorySource.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/FakeRepositorySource.java	2009-02-13 16:43:06 UTC (rev 725)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/FakeRepositorySource.java	2009-02-13 17:23:46 UTC (rev 726)
@@ -24,7 +24,6 @@
 package org.jboss.dna.repository;
 
 import javax.naming.Reference;
-import org.apache.jackrabbit.spi.RepositoryService;
 import org.jboss.dna.graph.connector.RepositoryConnection;
 import org.jboss.dna.graph.connector.RepositoryContext;
 import org.jboss.dna.graph.connector.RepositorySource;



From dna-commits at lists.jboss.org  Fri Feb 13 16:55:20 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Fri, 13 Feb 2009 16:55:20 -0500
Subject: [dna-commits] DNA SVN: r727 - in trunk:
	extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem
	and 1 other directory.
Message-ID: <E1LY60G-0004QE-Ah@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-13 16:55:20 -0500 (Fri, 13 Feb 2009)
New Revision: 727

Modified:
   trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java
   trunk/pom.xml
Log:
Corrected NPE in FileSystemSource, and added dna-connector-filesystem into the POM (not sure why it was missing)

Modified: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java	2009-02-13 17:23:46 UTC (rev 726)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java	2009-02-13 21:55:20 UTC (rev 727)
@@ -95,7 +95,7 @@
     private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
     private volatile int cacheTimeToLiveInMilliseconds = DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS * 1000;
     private volatile String defaultWorkspace;
-    private volatile String[] predefinedWorkspaces;
+    private volatile String[] predefinedWorkspaces = new String[] {};
     private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(SUPPORTS_SAME_NAME_SIBLINGS,
                                                                                                   DEFAULT_SUPPORTS_UPDATES,
                                                                                                   SUPPORTS_EVENTS,
@@ -375,6 +375,7 @@
             for (String predefined : this.predefinedWorkspaces) {
                 this.availableWorkspaceNames.add(predefined);
             }
+
             // Report the warnings for non-existant predefined workspaces
             reportWarnings = true;
             for (String path : this.availableWorkspaceNames) {

Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml	2009-02-13 17:23:46 UTC (rev 726)
+++ trunk/pom.xml	2009-02-13 21:55:20 UTC (rev 727)
@@ -126,6 +126,7 @@
 		<module>extensions/dna-sequencer-xml</module>
 		<module>extensions/dna-sequencer-zip</module>
 		<module>extensions/dna-connector-federation</module>
+		<module>extensions/dna-connector-filesystem</module>
 		<module>extensions/dna-connector-jbosscache</module>
 		<module>extensions/dna-connector-svn</module>
 		<module>extensions/dna-connector-store-jpa</module>



From dna-commits at lists.jboss.org  Mon Feb 16 11:34:26 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Mon, 16 Feb 2009 11:34:26 -0500
Subject: [dna-commits] DNA SVN: r728 -
	trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem.
Message-ID: <E1LZ6QM-0005ym-Gf@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-16 11:34:26 -0500 (Mon, 16 Feb 2009)
New Revision: 728

Modified:
   trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorCreateWorkspacesTest.java
Log:
DNA-284 FileSystemConnectorCreateWorkspacesTest Fails on Windows XP

Applied a patch that fixes the issue on XP.

Modified: trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorCreateWorkspacesTest.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorCreateWorkspacesTest.java	2009-02-13 21:55:20 UTC (rev 727)
+++ trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorCreateWorkspacesTest.java	2009-02-16 16:34:26 UTC (rev 728)
@@ -101,7 +101,11 @@
             workspaceNames.add(workspace.getName());
         }
         // The actual names should be the absolute paths to the directories representing the root ...
-        String absolutePathToRepositories = new File(".").getCanonicalPath() + "/src/test/resources/repositories/";
+        String absolutePathToRepositories = new File("./src/test/resources/repositories/").getCanonicalPath();
+        
+        // getCanonicalPath strips the trailing separator character, so we need to re-added it for each case
+        absolutePathToRepositories += File.separatorChar;	
+        
         assertThat(workspaceNames.remove(absolutePathToRepositories + "airplanes"), is(true));
         assertThat(workspaceNames.remove(absolutePathToRepositories + "cars"), is(true));
         assertThat(workspaceNames.isEmpty(), is(true));



From dna-commits at lists.jboss.org  Mon Feb 16 12:21:58 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Mon, 16 Feb 2009 12:21:58 -0500
Subject: [dna-commits] DNA SVN: r729 -
	trunk/extensions/dna-connector-jbosscache.
Message-ID: <E1LZ7AM-0004tu-Cu@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-16 12:21:58 -0500 (Mon, 16 Feb 2009)
New Revision: 729

Modified:
   trunk/extensions/dna-connector-jbosscache/pom.xml
Log:
DNA-253 Add support in the JBoss Cache connector for JBoss Cache 3.0. 

Applied the patch (thanks, Brian!), and verified that the build completes and all tests pass.

Modified: trunk/extensions/dna-connector-jbosscache/pom.xml
===================================================================
--- trunk/extensions/dna-connector-jbosscache/pom.xml	2009-02-16 16:34:26 UTC (rev 728)
+++ trunk/extensions/dna-connector-jbosscache/pom.xml	2009-02-16 17:21:58 UTC (rev 729)
@@ -50,7 +50,7 @@
     <dependency>
       <groupId>org.jboss.cache</groupId>
       <artifactId>jbosscache-core</artifactId>
-      <version>2.2.1.GA</version>
+      <version>3.0.2.GA</version>
     </dependency>
     <!-- 
     Testing (note the scope)



From dna-commits at lists.jboss.org  Fri Feb 20 10:40:37 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Fri, 20 Feb 2009 10:40:37 -0500
Subject: [dna-commits] DNA SVN: r730 -
	trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation.
Message-ID: <E1LaXUT-0002d0-QU@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-20 10:40:37 -0500 (Fri, 20 Feb 2009)
New Revision: 730

Modified:
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
Log:
DNA-282 Federation connector improperly handles root-level node with one projection of a non-root node from a single source

Minor change to a usage of CompositeRequest within the federation connector.

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java	2009-02-16 17:21:58 UTC (rev 729)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java	2009-02-20 15:40:37 UTC (rev 730)
@@ -655,13 +655,14 @@
                         contributions.add(contribution);
                     }
                 } else {
-                    List<ReadNodeRequest> fromSourceCommands = new ArrayList<ReadNodeRequest>(numPaths);
+                    List<Request> fromSourceCommands = new ArrayList<Request>(numPaths);
                     for (Path pathInSource : pathsInSource) {
                         fromSourceCommands.add(new ReadNodeRequest(new Location(pathInSource), workspace));
                     }
                     Request request = CompositeRequest.with(fromSourceCommands);
                     sourceConnection.execute(context, request);
-                    for (ReadNodeRequest fromSource : fromSourceCommands) {
+                    for (Request requestObj : fromSourceCommands) {
+                        ReadNodeRequest fromSource = (ReadNodeRequest)requestObj;
                         if (fromSource.hasError()) continue;
 
                         // Figure out how long we can cache this contribution ...



From dna-commits at lists.jboss.org  Fri Feb 20 11:20:01 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Fri, 20 Feb 2009 11:20:01 -0500
Subject: [dna-commits] DNA SVN: r731 - in trunk:
	dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory
	and 19 other directories.
Message-ID: <E1LaY6b-0005TM-5z@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-20 11:20:00 -0500 (Fri, 20 Feb 2009)
New Revision: 731

Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadAllChildrenRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadBlockOfChildrenRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadNextBlockOfChildrenRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadNodeRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/RequestProcessor.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/RepositorySourceLoadHarness.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/AbstractConnectorTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/request/AbstractRequestTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatingRequestProcessorTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java
   trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRequestProcessor.java
   trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQuery.java
   trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCacheTest.java
   trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/SVNRepositoryRequestProcessor.java
   trunk/extensions/dna-connector-svn/src/test/java/org/jboss/dna/connector/svn/SVNRepositoryConnectionTest.java
Log:
DNA-280 Create optimized versions of Location

Applied the patch to change from a constructor-based Location to a static factory method style.  This will allow us to create specialized subclasses, optimized for the different combinations of attributes.  Using a static factory method isn't much different than using a constructor - the caller still refers to the class at compile-time.  The factory methods are not there to allow someone else to replace or specialize the Location; it is there so that we can hide which of our implementations we want to use.

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-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -442,7 +442,7 @@
      *         be moved
      */
     public Move<Conjunction<Graph>> move( String fromPath ) {
-        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(createPath(fromPath)));
+        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, Location.create(createPath(fromPath)));
     }
 
     /**
@@ -458,7 +458,7 @@
      *         be moved
      */
     public Move<Conjunction<Graph>> move( Path from ) {
-        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(from));
+        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, Location.create(from));
     }
 
     /**
@@ -474,7 +474,7 @@
      *         be moved
      */
     public Move<Conjunction<Graph>> move( UUID from ) {
-        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(from));
+        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, Location.create(from));
     }
 
     /**
@@ -491,7 +491,7 @@
      *         be moved
      */
     public Move<Conjunction<Graph>> move( Property idProperty ) {
-        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(idProperty));
+        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, Location.create(idProperty));
     }
 
     /**
@@ -510,7 +510,7 @@
      */
     public Move<Conjunction<Graph>> move( Property firstIdProperty,
                                           Property... additionalIdProperties ) {
-        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(firstIdProperty,
+        return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, Location.create(firstIdProperty,
                                                                                                   additionalIdProperties));
     }
 
@@ -559,7 +559,7 @@
      *         be copied
      */
     public Copy<Graph> copy( String fromPath ) {
-        return new CopyAction<Graph>(this, this.requestQueue, new Location(createPath(fromPath)));
+        return new CopyAction<Graph>(this, this.requestQueue, Location.create(createPath(fromPath)));
     }
 
     /**
@@ -575,7 +575,7 @@
      *         be copied
      */
     public Copy<Graph> copy( Path from ) {
-        return new CopyAction<Graph>(this, this.requestQueue, new Location(from));
+        return new CopyAction<Graph>(this, this.requestQueue, Location.create(from));
     }
 
     /**
@@ -591,7 +591,7 @@
      *         be copied
      */
     public Copy<Graph> copy( UUID from ) {
-        return new CopyAction<Graph>(this, this.requestQueue, new Location(from));
+        return new CopyAction<Graph>(this, this.requestQueue, Location.create(from));
     }
 
     /**
@@ -608,7 +608,7 @@
      *         be copied
      */
     public Copy<Graph> copy( Property idProperty ) {
-        return new CopyAction<Graph>(this, this.requestQueue, new Location(idProperty));
+        return new CopyAction<Graph>(this, this.requestQueue, Location.create(idProperty));
     }
 
     /**
@@ -627,7 +627,7 @@
      */
     public Copy<Graph> copy( Property firstIdProperty,
                              Property... additionalIdProperties ) {
-        return new CopyAction<Graph>(this, this.requestQueue, new Location(firstIdProperty, additionalIdProperties));
+        return new CopyAction<Graph>(this, this.requestQueue, Location.create(firstIdProperty, additionalIdProperties));
     }
 
     /**
@@ -659,7 +659,7 @@
      * @return an object that may be used to start another request
      */
     public Conjunction<Graph> delete( String atPath ) {
-        this.requestQueue.submit(new DeleteBranchRequest(new Location(createPath(atPath)), getCurrentWorkspaceName()));
+        this.requestQueue.submit(new DeleteBranchRequest(Location.create(createPath(atPath)), getCurrentWorkspaceName()));
         return nextGraph;
     }
 
@@ -670,7 +670,7 @@
      * @return an object that may be used to start another request
      */
     public Conjunction<Graph> delete( Path at ) {
-        this.requestQueue.submit(new DeleteBranchRequest(new Location(at), getCurrentWorkspaceName()));
+        this.requestQueue.submit(new DeleteBranchRequest(Location.create(at), getCurrentWorkspaceName()));
         return nextGraph;
     }
 
@@ -681,7 +681,7 @@
      * @return an object that may be used to start another request
      */
     public Conjunction<Graph> delete( UUID at ) {
-        this.requestQueue.submit(new DeleteBranchRequest(new Location(at), getCurrentWorkspaceName()));
+        this.requestQueue.submit(new DeleteBranchRequest(Location.create(at), getCurrentWorkspaceName()));
         return nextGraph;
     }
 
@@ -693,7 +693,7 @@
      * @return an object that may be used to start another request
      */
     public Conjunction<Graph> delete( Property idProperty ) {
-        this.requestQueue.submit(new DeleteBranchRequest(new Location(idProperty), getCurrentWorkspaceName()));
+        this.requestQueue.submit(new DeleteBranchRequest(Location.create(idProperty), getCurrentWorkspaceName()));
         return nextGraph;
     }
 
@@ -707,7 +707,7 @@
      */
     public Conjunction<Graph> delete( Property firstIdProperty,
                                       Property... additionalIdProperties ) {
-        this.requestQueue.submit(new DeleteBranchRequest(new Location(firstIdProperty, additionalIdProperties),
+        this.requestQueue.submit(new DeleteBranchRequest(Location.create(firstIdProperty, additionalIdProperties),
                                                          getCurrentWorkspaceName()));
         return nextGraph;
     }
@@ -727,7 +727,7 @@
         Path at = createPath(atPath);
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), getCurrentWorkspaceName(), child));
+        this.requestQueue.submit(new CreateNodeRequest(Location.create(parent), getCurrentWorkspaceName(), child));
         return nextGraph;
     }
 
@@ -748,7 +748,7 @@
         Path at = createPath(atPath);
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), getCurrentWorkspaceName(), child, properties));
+        this.requestQueue.submit(new CreateNodeRequest(Location.create(parent), getCurrentWorkspaceName(), child, properties));
         return nextGraph;
     }
 
@@ -767,7 +767,7 @@
         CheckArg.isNotNull(at, "at");
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), getCurrentWorkspaceName(), child));
+        this.requestQueue.submit(new CreateNodeRequest(Location.create(parent), getCurrentWorkspaceName(), child));
         return nextGraph;
     }
 
@@ -788,7 +788,7 @@
         CheckArg.isNotNull(at, "at");
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), getCurrentWorkspaceName(), child, properties));
+        this.requestQueue.submit(new CreateNodeRequest(Location.create(parent), getCurrentWorkspaceName(), child, properties));
         return nextGraph;
     }
 
@@ -809,7 +809,7 @@
         CheckArg.isNotNull(at, "at");
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), getCurrentWorkspaceName(), child, properties));
+        this.requestQueue.submit(new CreateNodeRequest(Location.create(parent), getCurrentWorkspaceName(), child, properties));
         return nextGraph;
     }
 
@@ -870,28 +870,28 @@
             }
 
             public Conjunction<Graph> on( String path ) {
-                return on(new Location(createPath(path)));
+                return on(Location.create(createPath(path)));
             }
 
             public Conjunction<Graph> on( Path path ) {
-                return on(new Location(path));
+                return on(Location.create(path));
             }
 
             public Conjunction<Graph> on( Property idProperty ) {
-                return on(new Location(idProperty));
+                return on(Location.create(idProperty));
             }
 
             public Conjunction<Graph> on( Property firstIdProperty,
                                           Property... additionalIdProperties ) {
-                return on(new Location(firstIdProperty, additionalIdProperties));
+                return on(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public Conjunction<Graph> on( Iterable<Property> idProperties ) {
-                return on(new Location(idProperties));
+                return on(Location.create(idProperties));
             }
 
             public Conjunction<Graph> on( UUID uuid ) {
-                return on(new Location(uuid));
+                return on(Location.create(uuid));
             }
         };
     }
@@ -1072,28 +1072,28 @@
             }
 
             public SetValuesTo<Conjunction<Graph>> on( String path ) {
-                return on(new Location(createPath(path)));
+                return on(Location.create(createPath(path)));
             }
 
             public SetValuesTo<Conjunction<Graph>> on( Path path ) {
-                return on(new Location(path));
+                return on(Location.create(path));
             }
 
             public SetValuesTo<Conjunction<Graph>> on( Property idProperty ) {
-                return on(new Location(idProperty));
+                return on(Location.create(idProperty));
             }
 
             public SetValuesTo<Conjunction<Graph>> on( Property firstIdProperty,
                                                        Property... additionalIdProperties ) {
-                return on(new Location(firstIdProperty, additionalIdProperties));
+                return on(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public SetValuesTo<Conjunction<Graph>> on( Iterable<Property> idProperties ) {
-                return on(new Location(idProperties));
+                return on(Location.create(idProperties));
             }
 
             public SetValuesTo<Conjunction<Graph>> on( UUID uuid ) {
-                return on(new Location(uuid));
+                return on(Location.create(uuid));
             }
 
             public On<Conjunction<Graph>> to( Node node ) {
@@ -1240,28 +1240,28 @@
             }
 
             public Conjunction<Graph> on( String path ) {
-                return on(new Location(createPath(path)));
+                return on(Location.create(createPath(path)));
             }
 
             public Conjunction<Graph> on( Path path ) {
-                return on(new Location(path));
+                return on(Location.create(path));
             }
 
             public Conjunction<Graph> on( Property idProperty ) {
-                return on(new Location(idProperty));
+                return on(Location.create(idProperty));
             }
 
             public Conjunction<Graph> on( Property firstIdProperty,
                                           Property... additionalIdProperties ) {
-                return on(new Location(firstIdProperty, additionalIdProperties));
+                return on(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public Conjunction<Graph> on( Iterable<Property> idProperties ) {
-                return on(new Location(idProperties));
+                return on(Location.create(idProperties));
             }
 
             public Conjunction<Graph> on( UUID uuid ) {
-                return on(new Location(uuid));
+                return on(Location.create(uuid));
             }
         };
     }
@@ -1287,28 +1287,28 @@
             }
 
             public Conjunction<Graph> on( String path ) {
-                return on(new Location(createPath(path)));
+                return on(Location.create(createPath(path)));
             }
 
             public Conjunction<Graph> on( Path path ) {
-                return on(new Location(path));
+                return on(Location.create(path));
             }
 
             public Conjunction<Graph> on( Property idProperty ) {
-                return on(new Location(idProperty));
+                return on(Location.create(idProperty));
             }
 
             public Conjunction<Graph> on( Property firstIdProperty,
                                           Property... additionalIdProperties ) {
-                return on(new Location(firstIdProperty, additionalIdProperties));
+                return on(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public Conjunction<Graph> on( Iterable<Property> idProperties ) {
-                return on(new Location(idProperties));
+                return on(Location.create(idProperties));
             }
 
             public Conjunction<Graph> on( UUID uuid ) {
-                return on(new Location(uuid));
+                return on(Location.create(uuid));
             }
         };
     }
@@ -1328,28 +1328,28 @@
             }
 
             public Collection<Property> on( String path ) {
-                return on(new Location(createPath(path)));
+                return on(Location.create(createPath(path)));
             }
 
             public Collection<Property> on( Path path ) {
-                return on(new Location(path));
+                return on(Location.create(path));
             }
 
             public Collection<Property> on( Property idProperty ) {
-                return on(new Location(idProperty));
+                return on(Location.create(idProperty));
             }
 
             public Collection<Property> on( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
-                return on(new Location(firstIdProperty, additionalIdProperties));
+                return on(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public Collection<Property> on( Iterable<Property> idProperties ) {
-                return on(new Location(idProperties));
+                return on(Location.create(idProperties));
             }
 
             public Collection<Property> on( UUID uuid ) {
-                return on(new Location(uuid));
+                return on(Location.create(uuid));
             }
         };
     }
@@ -1370,28 +1370,28 @@
             }
 
             public Map<Name, Property> on( String path ) {
-                return on(new Location(createPath(path)));
+                return on(Location.create(createPath(path)));
             }
 
             public Map<Name, Property> on( Path path ) {
-                return on(new Location(path));
+                return on(Location.create(path));
             }
 
             public Map<Name, Property> on( Property idProperty ) {
-                return on(new Location(idProperty));
+                return on(Location.create(idProperty));
             }
 
             public Map<Name, Property> on( Property firstIdProperty,
                                            Property... additionalIdProperties ) {
-                return on(new Location(firstIdProperty, additionalIdProperties));
+                return on(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public Map<Name, Property> on( Iterable<Property> idProperties ) {
-                return on(new Location(idProperties));
+                return on(Location.create(idProperties));
             }
 
             public Map<Name, Property> on( UUID uuid ) {
-                return on(new Location(uuid));
+                return on(Location.create(uuid));
             }
         };
     }
@@ -1406,28 +1406,28 @@
     public Children<List<Location>> getChildren() {
         return new Children<List<Location>>() {
             public List<Location> of( String path ) {
-                return of(new Location(createPath(path)));
+                return of(Location.create(createPath(path)));
             }
 
             public List<Location> of( Path path ) {
-                return of(new Location(path));
+                return of(Location.create(path));
             }
 
             public List<Location> of( Property idProperty ) {
-                return of(new Location(idProperty));
+                return of(Location.create(idProperty));
             }
 
             public List<Location> of( Property firstIdProperty,
                                       Property... additionalIdProperties ) {
-                return of(new Location(firstIdProperty, additionalIdProperties));
+                return of(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public List<Location> of( Iterable<Property> idProperties ) {
-                return of(new Location(idProperties));
+                return of(Location.create(idProperties));
             }
 
             public List<Location> of( UUID uuid ) {
-                return of(new Location(uuid));
+                return of(Location.create(uuid));
             }
 
             public List<Location> of( Location at ) {
@@ -1441,24 +1441,24 @@
                     public Under<List<Location>> startingAt( final int startingIndex ) {
                         return new Under<List<Location>>() {
                             public List<Location> under( String path ) {
-                                return under(new Location(createPath(path)));
+                                return under(Location.create(createPath(path)));
                             }
 
                             public List<Location> under( Path path ) {
-                                return under(new Location(path));
+                                return under(Location.create(path));
                             }
 
                             public List<Location> under( Property idProperty ) {
-                                return under(new Location(idProperty));
+                                return under(Location.create(idProperty));
                             }
 
                             public List<Location> under( Property firstIdProperty,
                                                          Property... additionalIdProperties ) {
-                                return under(new Location(firstIdProperty, additionalIdProperties));
+                                return under(Location.create(firstIdProperty, additionalIdProperties));
                             }
 
                             public List<Location> under( UUID uuid ) {
-                                return under(new Location(uuid));
+                                return under(Location.create(uuid));
                             }
 
                             public List<Location> under( Location at ) {
@@ -1480,24 +1480,24 @@
                     }
 
                     public List<Location> startingAfter( String pathOfPreviousSibling ) {
-                        return startingAfter(new Location(createPath(pathOfPreviousSibling)));
+                        return startingAfter(Location.create(createPath(pathOfPreviousSibling)));
                     }
 
                     public List<Location> startingAfter( Path pathOfPreviousSibling ) {
-                        return startingAfter(new Location(pathOfPreviousSibling));
+                        return startingAfter(Location.create(pathOfPreviousSibling));
                     }
 
                     public List<Location> startingAfter( UUID uuidOfPreviousSibling ) {
-                        return startingAfter(new Location(uuidOfPreviousSibling));
+                        return startingAfter(Location.create(uuidOfPreviousSibling));
                     }
 
                     public List<Location> startingAfter( Property idPropertyOfPreviousSibling ) {
-                        return startingAfter(new Location(idPropertyOfPreviousSibling));
+                        return startingAfter(Location.create(idPropertyOfPreviousSibling));
                     }
 
                     public List<Location> startingAfter( Property firstIdProperyOfPreviousSibling,
                                                          Property... additionalIdPropertiesOfPreviousSibling ) {
-                        return startingAfter(new Location(firstIdProperyOfPreviousSibling,
+                        return startingAfter(Location.create(firstIdProperyOfPreviousSibling,
                                                           additionalIdPropertiesOfPreviousSibling));
                     }
                 };
@@ -1527,28 +1527,28 @@
     public On<Property> getProperty( final Name name ) {
         return new On<Property>() {
             public Property on( String path ) {
-                return on(new Location(createPath(path)));
+                return on(Location.create(createPath(path)));
             }
 
             public Property on( Path path ) {
-                return on(new Location(path));
+                return on(Location.create(path));
             }
 
             public Property on( Property idProperty ) {
-                return on(new Location(idProperty));
+                return on(Location.create(idProperty));
             }
 
             public Property on( Property firstIdProperty,
                                 Property... additionalIdProperties ) {
-                return on(new Location(firstIdProperty, additionalIdProperties));
+                return on(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public Property on( Iterable<Property> idProperties ) {
-                return on(new Location(idProperties));
+                return on(Location.create(idProperties));
             }
 
             public Property on( UUID uuid ) {
-                return on(new Location(uuid));
+                return on(Location.create(uuid));
             }
 
             public Property on( Location at ) {
@@ -1566,7 +1566,7 @@
      * @return the node that is read from the repository
      */
     public Node getNodeAt( UUID uuid ) {
-        return getNodeAt(new Location(uuid));
+        return getNodeAt(Location.create(uuid));
     }
 
     /**
@@ -1588,7 +1588,7 @@
      * @return the node that is read from the repository
      */
     public Node getNodeAt( String path ) {
-        return getNodeAt(new Location(createPath(path)));
+        return getNodeAt(Location.create(createPath(path)));
     }
 
     /**
@@ -1598,7 +1598,7 @@
      * @return the node that is read from the repository
      */
     public Node getNodeAt( Path path ) {
-        return getNodeAt(new Location(path));
+        return getNodeAt(Location.create(path));
     }
 
     /**
@@ -1608,7 +1608,7 @@
      * @return the node that is read from the repository
      */
     public Node getNodeAt( Property idProperty ) {
-        return getNodeAt(new Location(idProperty));
+        return getNodeAt(Location.create(idProperty));
     }
 
     /**
@@ -1620,7 +1620,7 @@
      */
     public Node getNodeAt( Property firstIdProperty,
                            Property... additionalIdProperties ) {
-        return getNodeAt(new Location(firstIdProperty, additionalIdProperties));
+        return getNodeAt(Location.create(firstIdProperty, additionalIdProperties));
     }
 
     /**
@@ -1630,7 +1630,7 @@
      * @return the node that is read from the repository
      */
     public Node getNodeAt( Iterable<Property> idProperties ) {
-        return getNodeAt(new Location(idProperties));
+        return getNodeAt(Location.create(idProperties));
     }
 
     /**
@@ -1664,28 +1664,28 @@
             }
 
             public Subgraph at( String path ) {
-                return at(new Location(createPath(path)));
+                return at(Location.create(createPath(path)));
             }
 
             public Subgraph at( Path path ) {
-                return at(new Location(path));
+                return at(Location.create(path));
             }
 
             public Subgraph at( UUID uuid ) {
-                return at(new Location(uuid));
+                return at(Location.create(uuid));
             }
 
             public Subgraph at( Property idProperty ) {
-                return at(new Location(idProperty));
+                return at(Location.create(idProperty));
             }
 
             public Subgraph at( Property firstIdProperty,
                                 Property... additionalIdProperties ) {
-                return at(new Location(firstIdProperty, additionalIdProperties));
+                return at(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public Subgraph at( Iterable<Property> idProperties ) {
-                return at(new Location(idProperties));
+                return at(Location.create(idProperties));
             }
         };
     }
@@ -1708,28 +1708,28 @@
             }
 
             public Conjunction<Graph> into( String path ) throws IOException, SAXException {
-                return into(new Location(createPath(path)));
+                return into(Location.create(createPath(path)));
             }
 
             public Conjunction<Graph> into( Path path ) throws IOException, SAXException {
-                return into(new Location(path));
+                return into(Location.create(path));
             }
 
             public Conjunction<Graph> into( Property idProperty ) throws IOException, SAXException {
-                return into(new Location(idProperty));
+                return into(Location.create(idProperty));
             }
 
             public Conjunction<Graph> into( Property firstIdProperty,
                                             Property... additionalIdProperties ) throws IOException, SAXException {
-                return into(new Location(firstIdProperty, additionalIdProperties));
+                return into(Location.create(firstIdProperty, additionalIdProperties));
             }
 
             public Conjunction<Graph> into( Iterable<Property> idProperties ) throws IOException, SAXException {
-                return into(new Location(idProperties));
+                return into(Location.create(idProperties));
             }
 
             public Conjunction<Graph> into( UUID uuid ) throws IOException, SAXException {
-                return into(new Location(uuid));
+                return into(Location.create(uuid));
             }
 
             @SuppressWarnings( "synthetic-access" )
@@ -1892,7 +1892,7 @@
          */
         public Move<BatchConjunction> move( String fromPath ) {
             assertNotExecuted();
-            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(createPath(fromPath)));
+            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, Location.create(createPath(fromPath)));
         }
 
         /**
@@ -1909,7 +1909,7 @@
          */
         public Move<BatchConjunction> move( Path from ) {
             assertNotExecuted();
-            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(from));
+            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, Location.create(from));
         }
 
         /**
@@ -1926,7 +1926,7 @@
          */
         public Move<BatchConjunction> move( UUID from ) {
             assertNotExecuted();
-            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(from));
+            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, Location.create(from));
         }
 
         /**
@@ -1944,7 +1944,7 @@
          */
         public Move<BatchConjunction> move( Property idProperty ) {
             assertNotExecuted();
-            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(idProperty));
+            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, Location.create(idProperty));
         }
 
         /**
@@ -1964,7 +1964,7 @@
         public Move<BatchConjunction> move( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
             assertNotExecuted();
-            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(firstIdProperty,
+            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, Location.create(firstIdProperty,
                                                                                                        additionalIdProperties));
         }
 
@@ -1983,7 +1983,7 @@
          */
         public Move<BatchConjunction> move( Iterable<Property> idProperties ) {
             assertNotExecuted();
-            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(idProperties));
+            return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, Location.create(idProperties));
         }
 
         /**
@@ -2034,7 +2034,7 @@
          */
         public Copy<BatchConjunction> copy( String fromPath ) {
             assertNotExecuted();
-            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(createPath(fromPath)));
+            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, Location.create(createPath(fromPath)));
         }
 
         /**
@@ -2051,7 +2051,7 @@
          */
         public Copy<BatchConjunction> copy( Path from ) {
             assertNotExecuted();
-            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(from));
+            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, Location.create(from));
         }
 
         /**
@@ -2068,7 +2068,7 @@
          */
         public Copy<BatchConjunction> copy( UUID from ) {
             assertNotExecuted();
-            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(from));
+            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, Location.create(from));
         }
 
         /**
@@ -2086,7 +2086,7 @@
          */
         public Copy<BatchConjunction> copy( Property idProperty ) {
             assertNotExecuted();
-            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(idProperty));
+            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, Location.create(idProperty));
         }
 
         /**
@@ -2106,7 +2106,7 @@
         public Copy<BatchConjunction> copy( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
             assertNotExecuted();
-            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(firstIdProperty,
+            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, Location.create(firstIdProperty,
                                                                                                   additionalIdProperties));
         }
 
@@ -2125,7 +2125,7 @@
          */
         public Copy<BatchConjunction> copy( Iterable<Property> idProperties ) {
             assertNotExecuted();
-            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(idProperties));
+            return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, Location.create(idProperties));
         }
 
         /**
@@ -2172,7 +2172,7 @@
          */
         public BatchConjunction delete( String atPath ) {
             assertNotExecuted();
-            this.requestQueue.submit(new DeleteBranchRequest(new Location(createPath(atPath)), getCurrentWorkspaceName()));
+            this.requestQueue.submit(new DeleteBranchRequest(Location.create(createPath(atPath)), getCurrentWorkspaceName()));
             return nextRequests;
         }
 
@@ -2188,7 +2188,7 @@
          */
         public BatchConjunction delete( Path at ) {
             assertNotExecuted();
-            this.requestQueue.submit(new DeleteBranchRequest(new Location(at), getCurrentWorkspaceName()));
+            this.requestQueue.submit(new DeleteBranchRequest(Location.create(at), getCurrentWorkspaceName()));
             return nextRequests;
         }
 
@@ -2204,7 +2204,7 @@
          */
         public BatchConjunction delete( UUID at ) {
             assertNotExecuted();
-            this.requestQueue.submit(new DeleteBranchRequest(new Location(at), getCurrentWorkspaceName()));
+            this.requestQueue.submit(new DeleteBranchRequest(Location.create(at), getCurrentWorkspaceName()));
             return nextRequests;
         }
 
@@ -2220,7 +2220,7 @@
          */
         public BatchConjunction delete( Property idProperty ) {
             assertNotExecuted();
-            this.requestQueue.submit(new DeleteBranchRequest(new Location(idProperty), getCurrentWorkspaceName()));
+            this.requestQueue.submit(new DeleteBranchRequest(Location.create(idProperty), getCurrentWorkspaceName()));
             return nextRequests;
         }
 
@@ -2239,7 +2239,7 @@
         public BatchConjunction delete( Property firstIdProperty,
                                         Property... additionalIdProperties ) {
             assertNotExecuted();
-            this.requestQueue.submit(new DeleteBranchRequest(new Location(firstIdProperty, additionalIdProperties),
+            this.requestQueue.submit(new DeleteBranchRequest(Location.create(firstIdProperty, additionalIdProperties),
                                                              getCurrentWorkspaceName()));
             return nextRequests;
         }
@@ -2257,7 +2257,7 @@
          */
         public BatchConjunction delete( Iterable<Property> idProperties ) {
             assertNotExecuted();
-            this.requestQueue.submit(new DeleteBranchRequest(new Location(idProperties), getCurrentWorkspaceName()));
+            this.requestQueue.submit(new DeleteBranchRequest(Location.create(idProperties), getCurrentWorkspaceName()));
             return nextRequests;
         }
 
@@ -2277,7 +2277,7 @@
             Path at = createPath(atPath);
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<Batch>(this, requestQueue, new Location(parent), getCurrentWorkspaceName(), name);
+            return new CreateAction<Batch>(this, requestQueue, Location.create(parent), getCurrentWorkspaceName(), name);
         }
 
         /**
@@ -2298,7 +2298,7 @@
             Path at = createPath(atPath);
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<Batch>(this, requestQueue, new Location(parent), getCurrentWorkspaceName(), name).with(property);
+            return new CreateAction<Batch>(this, requestQueue, Location.create(parent), getCurrentWorkspaceName(), name).with(property);
         }
 
         /**
@@ -2321,7 +2321,7 @@
             Path at = createPath(atPath);
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<Batch>(this, requestQueue, new Location(parent), getCurrentWorkspaceName(), name).with(firstProperty,
+            return new CreateAction<Batch>(this, requestQueue, Location.create(parent), getCurrentWorkspaceName(), name).with(firstProperty,
                                                                                                                            additionalProperties);
         }
 
@@ -2341,7 +2341,7 @@
             CheckArg.isNotNull(at, "at");
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<Batch>(this, requestQueue, new Location(parent), getCurrentWorkspaceName(), name);
+            return new CreateAction<Batch>(this, requestQueue, Location.create(parent), getCurrentWorkspaceName(), name);
         }
 
         /**
@@ -2362,7 +2362,7 @@
             CheckArg.isNotNull(at, "at");
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            CreateAction<Batch> action = new CreateAction<Batch>(this, requestQueue, new Location(parent),
+            CreateAction<Batch> action = new CreateAction<Batch>(this, requestQueue, Location.create(parent),
                                                                  getCurrentWorkspaceName(), name);
             for (Property property : properties) {
                 action.and(property);
@@ -2388,7 +2388,7 @@
             CheckArg.isNotNull(at, "at");
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<Batch>(this, requestQueue, new Location(parent), getCurrentWorkspaceName(), name).with(property);
+            return new CreateAction<Batch>(this, requestQueue, Location.create(parent), getCurrentWorkspaceName(), name).with(property);
         }
 
         /**
@@ -2411,7 +2411,7 @@
             CheckArg.isNotNull(at, "at");
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<Batch>(this, requestQueue, new Location(parent), getCurrentWorkspaceName(), name).with(firstProperty,
+            return new CreateAction<Batch>(this, requestQueue, Location.create(parent), getCurrentWorkspaceName(), name).with(firstProperty,
                                                                                                                            additionalProperties);
         }
 
@@ -2442,28 +2442,28 @@
                 }
 
                 public BatchConjunction on( String path ) {
-                    return on(new Location(createPath(path)));
+                    return on(Location.create(createPath(path)));
                 }
 
                 public BatchConjunction on( Path path ) {
-                    return on(new Location(path));
+                    return on(Location.create(path));
                 }
 
                 public BatchConjunction on( Property idProperty ) {
-                    return on(new Location(idProperty));
+                    return on(Location.create(idProperty));
                 }
 
                 public BatchConjunction on( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
-                    return on(new Location(firstIdProperty, additionalIdProperties));
+                    return on(Location.create(firstIdProperty, additionalIdProperties));
                 }
 
                 public BatchConjunction on( Iterable<Property> idProperties ) {
-                    return on(new Location(idProperties));
+                    return on(Location.create(idProperties));
                 }
 
                 public BatchConjunction on( UUID uuid ) {
-                    return on(new Location(uuid));
+                    return on(Location.create(uuid));
                 }
             };
         }
@@ -2644,28 +2644,28 @@
                 }
 
                 public SetValuesTo<BatchConjunction> on( String path ) {
-                    return on(new Location(createPath(path)));
+                    return on(Location.create(createPath(path)));
                 }
 
                 public SetValuesTo<BatchConjunction> on( Path path ) {
-                    return on(new Location(path));
+                    return on(Location.create(path));
                 }
 
                 public SetValuesTo<BatchConjunction> on( Property idProperty ) {
-                    return on(new Location(idProperty));
+                    return on(Location.create(idProperty));
                 }
 
                 public SetValuesTo<BatchConjunction> on( Property firstIdProperty,
                                                          Property... additionalIdProperties ) {
-                    return on(new Location(firstIdProperty, additionalIdProperties));
+                    return on(Location.create(firstIdProperty, additionalIdProperties));
                 }
 
                 public SetValuesTo<BatchConjunction> on( Iterable<Property> idProperties ) {
-                    return on(new Location(idProperties));
+                    return on(Location.create(idProperties));
                 }
 
                 public SetValuesTo<BatchConjunction> on( UUID uuid ) {
-                    return on(new Location(uuid));
+                    return on(Location.create(uuid));
                 }
 
                 public On<BatchConjunction> to( Node value ) {
@@ -2812,28 +2812,28 @@
                 }
 
                 public BatchConjunction on( String path ) {
-                    return on(new Location(createPath(path)));
+                    return on(Location.create(createPath(path)));
                 }
 
                 public BatchConjunction on( Path path ) {
-                    return on(new Location(path));
+                    return on(Location.create(path));
                 }
 
                 public BatchConjunction on( Property idProperty ) {
-                    return on(new Location(idProperty));
+                    return on(Location.create(idProperty));
                 }
 
                 public BatchConjunction on( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
-                    return on(new Location(firstIdProperty, additionalIdProperties));
+                    return on(Location.create(firstIdProperty, additionalIdProperties));
                 }
 
                 public BatchConjunction on( Iterable<Property> idProperties ) {
-                    return on(new Location(idProperties));
+                    return on(Location.create(idProperties));
                 }
 
                 public BatchConjunction on( UUID uuid ) {
-                    return on(new Location(uuid));
+                    return on(Location.create(uuid));
                 }
             };
         }
@@ -2858,28 +2858,28 @@
                 }
 
                 public BatchConjunction on( String path ) {
-                    return on(new Location(createPath(path)));
+                    return on(Location.create(createPath(path)));
                 }
 
                 public BatchConjunction on( Path path ) {
-                    return on(new Location(path));
+                    return on(Location.create(path));
                 }
 
                 public BatchConjunction on( Property idProperty ) {
-                    return on(new Location(idProperty));
+                    return on(Location.create(idProperty));
                 }
 
                 public BatchConjunction on( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
-                    return on(new Location(firstIdProperty, additionalIdProperties));
+                    return on(Location.create(firstIdProperty, additionalIdProperties));
                 }
 
                 public BatchConjunction on( Iterable<Property> idProperties ) {
-                    return on(new Location(idProperties));
+                    return on(Location.create(idProperties));
                 }
 
                 public BatchConjunction on( UUID uuid ) {
-                    return on(new Location(uuid));
+                    return on(Location.create(uuid));
                 }
             };
         }
@@ -2895,7 +2895,7 @@
          * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
          */
         public BatchConjunction read( UUID uuid ) {
-            return read(new Location(uuid));
+            return read(Location.create(uuid));
         }
 
         /**
@@ -2926,7 +2926,7 @@
          * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
          */
         public BatchConjunction read( String path ) {
-            return read(new Location(createPath(path)));
+            return read(Location.create(createPath(path)));
         }
 
         /**
@@ -2940,7 +2940,7 @@
          * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
          */
         public BatchConjunction read( Path path ) {
-            return read(new Location(path));
+            return read(Location.create(path));
         }
 
         /**
@@ -2954,7 +2954,7 @@
          * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
          */
         public BatchConjunction read( Property idProperty ) {
-            return read(new Location(idProperty));
+            return read(Location.create(idProperty));
         }
 
         /**
@@ -2971,7 +2971,7 @@
          */
         public BatchConjunction read( Property firstIdProperty,
                                       Property... additionalIdProperties ) {
-            return read(new Location(firstIdProperty, additionalIdProperties));
+            return read(Location.create(firstIdProperty, additionalIdProperties));
         }
 
         /**
@@ -2985,7 +2985,7 @@
          * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
          */
         public BatchConjunction read( Iterable<Property> idProperties ) {
-            return read(new Location(idProperties));
+            return read(Location.create(idProperties));
         }
 
         /**
@@ -3020,28 +3020,28 @@
             assertNotExecuted();
             return new On<BatchConjunction>() {
                 public BatchConjunction on( String path ) {
-                    return on(new Location(createPath(path)));
+                    return on(Location.create(createPath(path)));
                 }
 
                 public BatchConjunction on( Path path ) {
-                    return on(new Location(path));
+                    return on(Location.create(path));
                 }
 
                 public BatchConjunction on( Property idProperty ) {
-                    return on(new Location(idProperty));
+                    return on(Location.create(idProperty));
                 }
 
                 public BatchConjunction on( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
-                    return on(new Location(firstIdProperty, additionalIdProperties));
+                    return on(Location.create(firstIdProperty, additionalIdProperties));
                 }
 
                 public BatchConjunction on( Iterable<Property> idProperties ) {
-                    return on(new Location(idProperties));
+                    return on(Location.create(idProperties));
                 }
 
                 public BatchConjunction on( UUID uuid ) {
-                    return on(new Location(uuid));
+                    return on(Location.create(uuid));
                 }
 
                 public BatchConjunction on( Location at ) {
@@ -3072,28 +3072,28 @@
                 }
 
                 public BatchConjunction on( String path ) {
-                    return on(new Location(createPath(path)));
+                    return on(Location.create(createPath(path)));
                 }
 
                 public BatchConjunction on( Path path ) {
-                    return on(new Location(path));
+                    return on(Location.create(path));
                 }
 
                 public BatchConjunction on( Property idProperty ) {
-                    return on(new Location(idProperty));
+                    return on(Location.create(idProperty));
                 }
 
                 public BatchConjunction on( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
-                    return on(new Location(firstIdProperty, additionalIdProperties));
+                    return on(Location.create(firstIdProperty, additionalIdProperties));
                 }
 
                 public BatchConjunction on( Iterable<Property> idProperties ) {
-                    return on(new Location(idProperties));
+                    return on(Location.create(idProperties));
                 }
 
                 public BatchConjunction on( UUID uuid ) {
-                    return on(new Location(uuid));
+                    return on(Location.create(uuid));
                 }
             };
         }
@@ -3112,28 +3112,28 @@
             assertNotExecuted();
             return new Of<BatchConjunction>() {
                 public BatchConjunction of( String path ) {
-                    return of(new Location(createPath(path)));
+                    return of(Location.create(createPath(path)));
                 }
 
                 public BatchConjunction of( Path path ) {
-                    return of(new Location(path));
+                    return of(Location.create(path));
                 }
 
                 public BatchConjunction of( Property idProperty ) {
-                    return of(new Location(idProperty));
+                    return of(Location.create(idProperty));
                 }
 
                 public BatchConjunction of( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
-                    return of(new Location(firstIdProperty, additionalIdProperties));
+                    return of(Location.create(firstIdProperty, additionalIdProperties));
                 }
 
                 public BatchConjunction of( Iterable<Property> idProperties ) {
-                    return of(new Location(idProperties));
+                    return of(Location.create(idProperties));
                 }
 
                 public BatchConjunction of( UUID uuid ) {
-                    return of(new Location(uuid));
+                    return of(Location.create(uuid));
                 }
 
                 public BatchConjunction of( Location at ) {
@@ -3165,28 +3165,28 @@
                 }
 
                 public BatchConjunction at( String path ) {
-                    return at(new Location(createPath(path)));
+                    return at(Location.create(createPath(path)));
                 }
 
                 public BatchConjunction at( Path path ) {
-                    return at(new Location(path));
+                    return at(Location.create(path));
                 }
 
                 public BatchConjunction at( UUID uuid ) {
-                    return at(new Location(uuid));
+                    return at(Location.create(uuid));
                 }
 
                 public BatchConjunction at( Property idProperty ) {
-                    return at(new Location(idProperty));
+                    return at(Location.create(idProperty));
                 }
 
                 public BatchConjunction at( Property firstIdProperty,
                                             Property... additionalIdProperties ) {
-                    return at(new Location(firstIdProperty, additionalIdProperties));
+                    return at(Location.create(firstIdProperty, additionalIdProperties));
                 }
 
                 public BatchConjunction at( Iterable<Property> idProperties ) {
-                    return at(new Location(idProperties));
+                    return at(Location.create(idProperties));
                 }
             };
         }
@@ -3384,7 +3384,7 @@
      */
     public interface To<Next> {
         /**
-         * Finish the request by specifying the new location where the node should be copied/moved. Unlike
+         * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike
          * {@link Into#into(Location)}, which specifies the location of the parent and which assumes the new node should have the
          * same name as the original, this method allows the caller to specify a new name for the new node.
          * 
@@ -3395,7 +3395,7 @@
         Next to( Location desiredLocation );
 
         /**
-         * Finish the request by specifying the new location where the node should be copied/moved. Unlike
+         * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike
          * {@link Into#into(String)}, which specifies the location of the parent and which assumes the new node should have the
          * same name as the original, this method allows the caller to specify a new name for the new node.
          * 
@@ -3406,7 +3406,7 @@
         Next to( String desiredPath );
 
         /**
-         * Finish the request by specifying the new location where the node should be copied/moved. Unlike {@link Into#into(Path)}
+         * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike {@link Into#into(Path)}
          * , which specifies the location of the parent and which assumes the new node should have the same name as the original,
          * this method allows the caller to specify a new name for the new node.
          * 
@@ -4284,7 +4284,7 @@
         ImportInto<Next> skippingRootElement( boolean skip );
 
         /**
-         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * Finish the import by specifying the Location.create into which the node should be copied/moved.
          * 
          * @param to the location of the new parent
          * @return the interface for additional requests or actions
@@ -4294,7 +4294,7 @@
         Next into( Location to ) throws IOException, SAXException;
 
         /**
-         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * Finish the import by specifying the Location.create into which the node should be copied/moved.
          * 
          * @param toPath the path of the new parent
          * @return the interface for additional requests or actions
@@ -4304,7 +4304,7 @@
         Next into( String toPath ) throws IOException, SAXException;
 
         /**
-         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * Finish the import by specifying the Location.create into which the node should be copied/moved.
          * 
          * @param to the path of the new parent
          * @return the interface for additional requests or actions
@@ -4314,7 +4314,7 @@
         Next into( Path to ) throws IOException, SAXException;
 
         /**
-         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * Finish the import by specifying the Location.create into which the node should be copied/moved.
          * 
          * @param to the UUID of the new parent
          * @return the interface for additional requests or actions
@@ -4324,7 +4324,7 @@
         Next into( UUID to ) throws IOException, SAXException;
 
         /**
-         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * Finish the import by specifying the Location.create into which the node should be copied/moved.
          * 
          * @param idProperty the property that uniquely identifies the new parent
          * @return the interface for additional requests or actions
@@ -4334,7 +4334,7 @@
         Next into( Property idProperty ) throws IOException, SAXException;
 
         /**
-         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * Finish the import by specifying the Location.create into which the node should be copied/moved.
          * 
          * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
          *        new parent
@@ -4348,7 +4348,7 @@
                    Property... additionalIdProperties ) throws IOException, SAXException;
 
         /**
-         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * Finish the import by specifying the Location.create into which the node should be copied/moved.
          * 
          * @param idProperties the properties that uniquely identifies the new parent
          * @return the interface for additional requests or actions
@@ -4985,33 +4985,33 @@
         }
 
         public Move<T> and( String from ) {
-            this.from.add(new Location(createPath(from)));
+            this.from.add(Location.create(createPath(from)));
             return this;
         }
 
         public Move<T> and( Path from ) {
-            this.from.add(new Location(from));
+            this.from.add(Location.create(from));
             return this;
         }
 
         public Move<T> and( Property firstFrom,
                             Property... additionalFroms ) {
-            this.from.add(new Location(firstFrom, additionalFroms));
+            this.from.add(Location.create(firstFrom, additionalFroms));
             return this;
         }
 
         public Move<T> and( Iterable<Property> idPropertiesFrom ) {
-            this.from.add(new Location(idPropertiesFrom));
+            this.from.add(Location.create(idPropertiesFrom));
             return this;
         }
 
         public Move<T> and( Property from ) {
-            this.from.add(new Location(from));
+            this.from.add(Location.create(from));
             return this;
         }
 
         public Move<T> and( UUID from ) {
-            this.from.add(new Location(from));
+            this.from.add(Location.create(from));
             return this;
         }
 
@@ -5043,24 +5043,24 @@
         }
 
         public T into( Path into ) {
-            return submit(new Location(into));
+            return submit(Location.create(into));
         }
 
         public T into( UUID into ) {
-            return submit(new Location(into));
+            return submit(Location.create(into));
         }
 
         public T into( Property firstIdProperty,
                        Property... additionalIdProperties ) {
-            return submit(new Location(firstIdProperty, additionalIdProperties));
+            return submit(Location.create(firstIdProperty, additionalIdProperties));
         }
 
         public T into( Property into ) {
-            return submit(new Location(into));
+            return submit(Location.create(into));
         }
 
         public T into( String into ) {
-            return submit(new Location(createPath(into)));
+            return submit(Location.create(createPath(into)));
         }
 
         @Override
@@ -5086,33 +5086,33 @@
         }
 
         public Copy<T> and( String from ) {
-            this.from.add(new Location(createPath(from)));
+            this.from.add(Location.create(createPath(from)));
             return this;
         }
 
         public Copy<T> and( Path from ) {
-            this.from.add(new Location(from));
+            this.from.add(Location.create(from));
             return this;
         }
 
         public Copy<T> and( Property firstFrom,
                             Property... additionalFroms ) {
-            this.from.add(new Location(firstFrom, additionalFroms));
+            this.from.add(Location.create(firstFrom, additionalFroms));
             return this;
         }
 
         public Copy<T> and( Iterable<Property> idProperties ) {
-            this.from.add(new Location(idProperties));
+            this.from.add(Location.create(idProperties));
             return this;
         }
 
         public Copy<T> and( Property from ) {
-            this.from.add(new Location(from));
+            this.from.add(Location.create(from));
             return this;
         }
 
         public Copy<T> and( UUID from ) {
-            this.from.add(new Location(from));
+            this.from.add(Location.create(from));
             return this;
         }
 
@@ -5146,24 +5146,24 @@
         }
 
         public T into( Path into ) {
-            return submit(new Location(into), null);
+            return submit(Location.create(into), null);
         }
 
         public T into( UUID into ) {
-            return submit(new Location(into), null);
+            return submit(Location.create(into), null);
         }
 
         public T into( Property firstIdProperty,
                        Property... additionalIdProperties ) {
-            return submit(new Location(firstIdProperty, additionalIdProperties), null);
+            return submit(Location.create(firstIdProperty, additionalIdProperties), null);
         }
 
         public T into( Property into ) {
-            return submit(new Location(into), null);
+            return submit(Location.create(into), null);
         }
 
         public T into( String into ) {
-            return submit(new Location(createPath(into)), null);
+            return submit(Location.create(createPath(into)), null);
         }
 
         public T to( Location desiredLocation ) {
@@ -5175,7 +5175,7 @@
                 throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredLocation));
             }
             Path parent = desiredPath.getParent();
-            return submit(new Location(parent), desiredPath.getLastSegment().getName());
+            return submit(Location.create(parent), desiredPath.getLastSegment().getName());
         }
 
         public T to( Path desiredPath ) {
@@ -5183,7 +5183,7 @@
                 throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredPath));
             }
             Path parent = desiredPath.getParent();
-            return submit(new Location(parent), desiredPath.getLastSegment().getName());
+            return submit(Location.create(parent), desiredPath.getLastSegment().getName());
         }
 
         public T to( String desiredPath ) {

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -47,6 +47,9 @@
 @Immutable
 public class Location implements Iterable<Property> {
 
+    /**
+     * Simple shared iterator instance that is used when there are no properties.
+     */
     private static final Iterator<Property> NO_ID_PROPERTIES_ITERATOR = new Iterator<Property>() {
         public boolean hasNext() {
             return false;
@@ -61,32 +64,31 @@
         }
     };
 
-    private final Path path;
-    private final List<Property> idProperties;
-
     /**
      * Create a location defined by a path.
      * 
      * @param path the path
+     * @return a new <code>Location</code> with the given path and no identification properties
      * @throws IllegalArgumentException if <code>path</code> is null
      */
-    public Location( Path path ) {
+    public static Location create( Path path ) {
         CheckArg.isNotNull(path, "path");
-        this.path = path;
-        this.idProperties = null;
+
+        return new Location(path, null);
     }
 
     /**
      * Create a location defined by a UUID.
      * 
      * @param uuid the UUID
+     * @return a new <code>Location</code> with no path and a single identification property with the name {@link DnaLexicon#UUID}
+     *         and the given <code>uuid</code> for a value.
      * @throws IllegalArgumentException if <code>uuid</code> is null
      */
-    public Location( UUID uuid ) {
+    public static Location create( UUID uuid ) {
         CheckArg.isNotNull(uuid, "uuid");
-        this.path = null;
         Property idProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-        this.idProperties = Collections.singletonList(idProperty);
+        return new Location(null, Collections.singletonList(idProperty));
     }
 
     /**
@@ -94,18 +96,20 @@
      * 
      * @param path the path
      * @param uuid the UUID, or null if there is no UUID
+     * @return a new <code>Location</code> with the given path (if any) and a single identification property with the name
+     *         {@link DnaLexicon#UUID} and the given <code>uuid</code> (if it is present) for a value.
      * @throws IllegalArgumentException if <code>path</code> is null
      */
-    public Location( Path path,
-                     UUID uuid ) {
+    public static Location create( Path path,
+                                   UUID uuid ) {
         CheckArg.isNotNull(uuid, "uuid");
-        this.path = path;
+        List<Property> idProperties = null;
         if (uuid != null) {
             Property idProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-            this.idProperties = Collections.singletonList(idProperty);
-        } else {
-            this.idProperties = null;
+            idProperties = Collections.singletonList(idProperty);
         }
+
+        return new Location(path, idProperties);
     }
 
     /**
@@ -113,14 +117,14 @@
      * 
      * @param path the path
      * @param idProperty the identification property
+     * @return a new <code>Location</code> with the given path and identification property (if it is present).
      * @throws IllegalArgumentException if <code>path</code> or <code>idProperty</code> is null
      */
-    public Location( Path path,
-                     Property idProperty ) {
+    public static Location create( Path path,
+                                   Property idProperty ) {
         CheckArg.isNotNull(path, "path");
         CheckArg.isNotNull(idProperty, "idProperty");
-        this.path = path;
-        this.idProperties = idProperty != null ? Collections.singletonList(idProperty) : null;
+        return new Location(path, idProperty != null ? Collections.singletonList(idProperty) : null);
     }
 
     /**
@@ -129,21 +133,21 @@
      * @param path the path
      * @param firstIdProperty the first identification property
      * @param remainingIdProperties the remaining identification property
+     * @return a new <code>Location</code> with the given path and identification properties.
      * @throws IllegalArgumentException if any of the arguments are null
      */
-    public Location( Path path,
-                     Property firstIdProperty,
-                     Property... remainingIdProperties ) {
+    public static Location create( Path path,
+                                   Property firstIdProperty,
+                                   Property... remainingIdProperties ) {
         CheckArg.isNotNull(path, "path");
         CheckArg.isNotNull(firstIdProperty, "firstIdProperty");
         CheckArg.isNotNull(remainingIdProperties, "remainingIdProperties");
-        this.path = path;
         List<Property> idProperties = new ArrayList<Property>(1 + remainingIdProperties.length);
         idProperties.add(firstIdProperty);
         for (Property property : remainingIdProperties) {
             idProperties.add(property);
         }
-        this.idProperties = Collections.unmodifiableList(idProperties);
+        return new Location(path, Collections.unmodifiableList(idProperties));
     }
 
     /**
@@ -151,30 +155,30 @@
      * 
      * @param path the path
      * @param idProperties the iterator over the identification properties
+     * @return a new <code>Location</code> with the given path and identification properties
      * @throws IllegalArgumentException if any of the arguments are null
      */
-    public Location( Path path,
-                     Iterable<Property> idProperties ) {
+    public static Location create( Path path,
+                                   Iterable<Property> idProperties ) {
         CheckArg.isNotNull(path, "path");
         CheckArg.isNotNull(idProperties, "idProperties");
-        this.path = path;
         List<Property> idPropertiesList = new ArrayList<Property>();
         for (Property property : idProperties) {
             idPropertiesList.add(property);
         }
-        this.idProperties = Collections.unmodifiableList(idPropertiesList);
+        return new Location(path, Collections.unmodifiableList(idPropertiesList));
     }
 
     /**
      * Create a location defined by a single identification property.
      * 
      * @param idProperty the identification property
+     * @return a new <code>Location</code> with no path and the given identification property.
      * @throws IllegalArgumentException if <code>idProperty</code> is null
      */
-    public Location( Property idProperty ) {
+    public static Location create( Property idProperty ) {
         CheckArg.isNotNull(idProperty, "idProperty");
-        this.path = null;
-        this.idProperties = Collections.singletonList(idProperty);
+        return new Location(null, Collections.singletonList(idProperty));
     }
 
     /**
@@ -182,47 +186,47 @@
      * 
      * @param firstIdProperty the first identification property
      * @param remainingIdProperties the remaining identification property
+     * @return a new <code>Location</code> with no path and the given and identification properties.
      * @throws IllegalArgumentException if any of the arguments are null
      */
-    public Location( Property firstIdProperty,
-                     Property... remainingIdProperties ) {
+    public static Location create( Property firstIdProperty,
+                                   Property... remainingIdProperties ) {
         CheckArg.isNotNull(firstIdProperty, "firstIdProperty");
         CheckArg.isNotNull(remainingIdProperties, "remainingIdProperties");
-        this.path = null;
         List<Property> idProperties = new ArrayList<Property>(1 + remainingIdProperties.length);
         idProperties.add(firstIdProperty);
         for (Property property : remainingIdProperties) {
             idProperties.add(property);
         }
-        this.idProperties = Collections.unmodifiableList(idProperties);
+        return new Location(null, Collections.unmodifiableList(idProperties));
     }
 
     /**
      * Create a location defined by a path and an iterator over identification properties.
      * 
      * @param idProperties the iterator over the identification properties
+     * @return a new <code>Location</code> with no path and the given identification properties.
      * @throws IllegalArgumentException if any of the arguments are null
      */
-    public Location( Iterable<Property> idProperties ) {
+    public static Location create( Iterable<Property> idProperties ) {
         CheckArg.isNotNull(idProperties, "idProperties");
-        this.path = null;
         List<Property> idPropertiesList = new ArrayList<Property>();
         for (Property property : idProperties) {
             idPropertiesList.add(property);
         }
-        this.idProperties = Collections.unmodifiableList(idPropertiesList);
+        return new Location(null, Collections.unmodifiableList(idPropertiesList));
     }
 
     /**
      * Create a location defined by multiple identification properties.
      * 
      * @param idProperties the identification properties
+     * @return a new <code>Location</code> with no path and the given identification properties.
      * @throws IllegalArgumentException if <code>idProperties</code> is null or empty
      */
-    public Location( List<Property> idProperties ) {
+    public static Location create( List<Property> idProperties ) {
         CheckArg.isNotEmpty(idProperties, "idProperties");
-        this.path = null;
-        this.idProperties = idProperties;
+        return new Location(null, idProperties);
     }
 
     /**
@@ -230,12 +234,27 @@
      * 
      * @param path the path
      * @param idProperties the identification properties
+     * @return a new <code>Location</code> with the given path and identification properties
      * @throws IllegalArgumentException if <code>path</code> is null, or if <code>idProperties</code> is empty
      */
+    protected static Location create( Path path,
+                                      List<Property> idProperties ) {
+        CheckArg.isNotNull(path, "path");
+        CheckArg.isNotEmpty(idProperties, "idProperties");
+        return new Location(path, idProperties);
+    }
+
+    private final Path path;
+    private final List<Property> idProperties;
+
+    /**
+     * Create a new location with a given path and set of identification properties.
+     * 
+     * @param path the path
+     * @param idProperties the identification properties
+     */
     protected Location( Path path,
                         List<Property> idProperties ) {
-        CheckArg.isNotNull(path, "path");
-        CheckArg.isNotEmpty(idProperties, "idProperties");
         this.path = path;
         this.idProperties = idProperties;
     }
@@ -250,7 +269,6 @@
      */
     protected Location( Location original,
                         Property newIdProperty ) {
-        CheckArg.isNotNull(original, "original");
         this.path = original.getPath();
         if (original.hasIdProperties()) {
             List<Property> originalIdProperties = original.getIdProperties();
@@ -279,7 +297,6 @@
      */
     protected Location( Location original,
                         Path newPath ) {
-        CheckArg.isNotNull(original, "original");
         this.path = newPath != null ? newPath : original.getPath();
         this.idProperties = original.idProperties;
     }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -130,7 +130,7 @@
                                                   copyMap);
         Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName());
         Location oldLocation = getActualLocation(request.from().getPath(), node);
-        Location newLocation = new Location(newPath, newNode.getUuid());
+        Location newLocation = Location.create(newPath, newNode.getUuid());
         request.setActualLocations(oldLocation, newLocation);
     }
 
@@ -198,7 +198,7 @@
         node.setParent(newParent);
         newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName());
         Location oldLocation = getActualLocation(request.from().getPath(), node);
-        Location newLocation = new Location(newPath, node.getUuid());
+        Location newLocation = Location.create(newPath, node.getUuid());
         request.setActualLocations(oldLocation, newLocation);
     }
 
@@ -238,7 +238,7 @@
             request.setError(new InvalidWorkspaceException(msg));
         } else {
             InMemoryNode root = workspace.getRoot();
-            request.setActualRootLocation(new Location(pathFactory.createRootPath(), root.getUuid()));
+            request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
             request.setActualWorkspaceName(workspace.getName());
         }
     }
@@ -278,7 +278,7 @@
         InMemoryRepository.Workspace original = getWorkspace(request, request.workspaceName());
         if (original != null) {
             Path path = getExecutionContext().getValueFactories().getPathFactory().createRootPath();
-            request.setActualRootLocation(new Location(path, original.getRoot().getUuid()));
+            request.setActualRootLocation(Location.create(path, original.getRoot().getUuid()));
             request.setActualWorkspaceName(original.getName());
         }
     }
@@ -310,7 +310,7 @@
                         request.setError(new InvalidWorkspaceException(msg));
                     } else {
                         InMemoryNode root = target.getRoot();
-                        request.setActualRootLocation(new Location(pathFactory.createRootPath(), root.getUuid()));
+                        request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
                         request.setActualWorkspaceName(target.getName());
                     }
                     return;
@@ -328,7 +328,7 @@
             request.setError(new InvalidWorkspaceException(msg));
         } else {
             InMemoryNode root = target.getRoot();
-            request.setActualRootLocation(new Location(pathFactory.createRootPath(), root.getUuid()));
+            request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
             request.setActualWorkspaceName(target.getName());
         }
     }
@@ -346,7 +346,7 @@
             }
             path = pathFactory.createAbsolutePath(segments);
         }
-        return new Location(path, node.getUuid());
+        return Location.create(path, node.getUuid());
     }
 
     protected InMemoryRepository.Workspace getWorkspace( Request request,

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadAllChildrenRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadAllChildrenRequest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadAllChildrenRequest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -137,7 +137,7 @@
     public void addChild( Path pathToChild,
                           Property firstIdProperty,
                           Property... remainingIdProperties ) {
-        Location child = new Location(pathToChild, firstIdProperty, remainingIdProperties);
+        Location child = Location.create(pathToChild, firstIdProperty, remainingIdProperties);
         this.children.add(child);
     }
 
@@ -153,7 +153,7 @@
      */
     public void addChild( Path pathToChild,
                           Property idProperty ) {
-        Location child = new Location(pathToChild, idProperty);
+        Location child = Location.create(pathToChild, idProperty);
         this.children.add(child);
     }
 

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadBlockOfChildrenRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadBlockOfChildrenRequest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadBlockOfChildrenRequest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -184,7 +184,7 @@
     public void addChild( Path pathToChild,
                           Property firstIdProperty,
                           Property... remainingIdProperties ) {
-        Location child = new Location(pathToChild, firstIdProperty, remainingIdProperties);
+        Location child = Location.create(pathToChild, firstIdProperty, remainingIdProperties);
         this.children.add(child);
     }
 
@@ -200,7 +200,7 @@
      */
     public void addChild( Path pathToChild,
                           Property idProperty ) {
-        Location child = new Location(pathToChild, idProperty);
+        Location child = Location.create(pathToChild, idProperty);
         this.children.add(child);
     }
 

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadNextBlockOfChildrenRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadNextBlockOfChildrenRequest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadNextBlockOfChildrenRequest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -152,7 +152,7 @@
     public void addChild( Path pathToChild,
                           Property firstIdProperty,
                           Property... remainingIdProperties ) {
-        Location child = new Location(pathToChild, firstIdProperty, remainingIdProperties);
+        Location child = Location.create(pathToChild, firstIdProperty, remainingIdProperties);
         this.children.add(child);
     }
 
@@ -168,7 +168,7 @@
      */
     public void addChild( Path pathToChild,
                           Property idProperty ) {
-        Location child = new Location(pathToChild, idProperty);
+        Location child = Location.create(pathToChild, idProperty);
         this.children.add(child);
     }
 

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadNodeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadNodeRequest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/ReadNodeRequest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -184,7 +184,7 @@
     public void addChild( Path pathToChild,
                           Property firstIdProperty,
                           Property... remainingIdProperties ) {
-        Location child = new Location(pathToChild, firstIdProperty, remainingIdProperties);
+        Location child = Location.create(pathToChild, firstIdProperty, remainingIdProperties);
         this.children.add(child);
     }
 
@@ -200,7 +200,7 @@
      */
     public void addChild( Path pathToChild,
                           Property idProperty ) {
-        Location child = new Location(pathToChild, idProperty);
+        Location child = Location.create(pathToChild, idProperty);
         this.children.add(child);
     }
 

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/RequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/RequestProcessor.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/RequestProcessor.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -433,7 +433,7 @@
         assert parentPath != null;
 
         // Convert the request to a ReadAllChildrenRequest and execute it ...
-        ReadAllChildrenRequest readAll = new ReadAllChildrenRequest(new Location(parentPath), request.inWorkspace());
+        ReadAllChildrenRequest readAll = new ReadAllChildrenRequest(Location.create(parentPath), request.inWorkspace());
         process(readAll);
         if (readAll.hasError()) {
             request.setError(readAll.getError());
@@ -649,7 +649,7 @@
      * This method does nothing if the request is null. Unless overridden, this method converts the rename into a
      * {@link MoveBranchRequest move}. However, this only works if the <code>request</code> has a {@link Location#hasPath() path}
      * for its {@link RenameNodeRequest#at() location}. (If not, this method throws an {@link UnsupportedOperationException} and
-     * must be overriddent.)
+     * must be overridden.)
      * </p>
      * 
      * @param request the rename request
@@ -661,7 +661,7 @@
             throw new UnsupportedOperationException();
         }
         Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(from.getPath(), request.toName());
-        Location to = new Location(newPath);
+        Location to = Location.create(newPath);
         MoveBranchRequest move = new MoveBranchRequest(from, to, request.inWorkspace());
         process(move);
         // Set the actual locations ...

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -88,7 +88,7 @@
     @Test
     public void shouldImportXmlContentAndGenerateTheCorrectCommands() throws Exception {
         System.out.println(xmlContent);
-        Graph.Batch batch = importer.importXml(xmlContent, new Location(destinationPath));
+        Graph.Batch batch = importer.importXml(xmlContent, Location.create(destinationPath));
         batch.execute();
         // 'lastExecutedCommand'
         assertThat(lastExecutedRequest, is(instanceOf(CompositeRequest.class)));
@@ -156,7 +156,7 @@
             lastExecutedRequest = request;
             if (request instanceof VerifyWorkspaceRequest) {
                 VerifyWorkspaceRequest workspaceRequest = (VerifyWorkspaceRequest)request;
-                workspaceRequest.setActualRootLocation(new Location(context.getValueFactories().getPathFactory().createRootPath()));
+                workspaceRequest.setActualRootLocation(Location.create(context.getValueFactories().getPathFactory().createRootPath()));
                 workspaceRequest.setActualWorkspaceName("default");
             }
         }

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -123,7 +123,7 @@
         Name idProperty2Name = createName("id2");
         validIdProperty1 = context.getPropertyFactory().create(idProperty1Name, "1");
         validIdProperty2 = context.getPropertyFactory().create(idProperty2Name, "2");
-        validLocation = new Location(validPath);
+        validLocation = Location.create(validPath);
 
         properties = new HashMap<Location, Collection<Property>>();
         children = new HashMap<Location, List<Location>>();
@@ -330,17 +330,17 @@
     public void shouldMoveNode() {
         graph.move(validPath).into(validIdProperty1, validIdProperty2);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsMove(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
+        assertNextRequestIsMove(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
         assertNoMoreRequests();
 
         graph.move(validPathString).into(validIdProperty1, validIdProperty2);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsMove(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
+        assertNextRequestIsMove(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
         assertNoMoreRequests();
 
         graph.move(validUuid).into(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsMove(new Location(validUuid), new Location(validPath));
+        assertNextRequestIsMove(Location.create(validUuid), Location.create(validPath));
         assertNoMoreRequests();
     }
 
@@ -348,17 +348,17 @@
     public void shouldCopyNode() {
         graph.copy(validPath).into(validIdProperty1, validIdProperty2);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCopy(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
+        assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
         assertNoMoreRequests();
 
         graph.copy(validPathString).into(validIdProperty1, validIdProperty2);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCopy(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
+        assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
         assertNoMoreRequests();
 
         graph.copy(validUuid).into(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCopy(new Location(validUuid), new Location(validPath));
+        assertNextRequestIsCopy(Location.create(validUuid), Location.create(validPath));
         assertNoMoreRequests();
     }
 
@@ -366,27 +366,27 @@
     public void shouldDeleteNode() {
         graph.delete(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsDelete(new Location(validPath));
+        assertNextRequestIsDelete(Location.create(validPath));
         assertNoMoreRequests();
 
         graph.delete(validPathString);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsDelete(new Location(validPath));
+        assertNextRequestIsDelete(Location.create(validPath));
         assertNoMoreRequests();
 
         graph.delete(validUuid);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsDelete(new Location(validUuid));
+        assertNextRequestIsDelete(Location.create(validUuid));
         assertNoMoreRequests();
 
         graph.delete(validIdProperty1);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsDelete(new Location(validIdProperty1));
+        assertNextRequestIsDelete(Location.create(validIdProperty1));
         assertNoMoreRequests();
 
         graph.delete(validIdProperty1, validIdProperty2);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsDelete(new Location(validIdProperty1, validIdProperty2));
+        assertNextRequestIsDelete(Location.create(validIdProperty1, validIdProperty2));
         assertNoMoreRequests();
     }
 
@@ -394,32 +394,32 @@
     public void shouldCreateNode() {
         graph.create(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c");
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c");
         assertNoMoreRequests();
 
         graph.create(validPath, validIdProperty1);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", validIdProperty1);
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1);
         assertNoMoreRequests();
 
         graph.create(validPath, validIdProperty1, validIdProperty2);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", validIdProperty1, validIdProperty2);
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1, validIdProperty2);
         assertNoMoreRequests();
 
         graph.create(validPathString);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c");
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c");
         assertNoMoreRequests();
 
         graph.create(validPathString, validIdProperty1);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", validIdProperty1);
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1);
         assertNoMoreRequests();
 
         graph.create(validPathString, validIdProperty1, validIdProperty2);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", validIdProperty1, validIdProperty2);
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1, validIdProperty2);
         assertNoMoreRequests();
     }
 
@@ -432,107 +432,107 @@
 
     @Test
     public void shouldGetPropertiesOnNode() {
-        setPropertiesToReadOn(new Location(validPath), validIdProperty1, validIdProperty2);
+        setPropertiesToReadOn(Location.create(validPath), validIdProperty1, validIdProperty2);
         Collection<Property> props = graph.getProperties().on(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadProperties(new Location(validPath), validIdProperty1, validIdProperty2);
+        assertNextRequestReadProperties(Location.create(validPath), validIdProperty1, validIdProperty2);
         assertNoMoreRequests();
         assertThat(props, hasItems(validIdProperty1, validIdProperty2));
 
-        setPropertiesToReadOn(new Location(validPath));
+        setPropertiesToReadOn(Location.create(validPath));
         props = graph.getProperties().on(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadProperties(new Location(validPath));
+        assertNextRequestReadProperties(Location.create(validPath));
         assertNoMoreRequests();
         assertThat(props.size(), is(0));
     }
 
     @Test
     public void shouldGetPropertiesByNameOnNode() {
-        setPropertiesToReadOn(new Location(validPath), validIdProperty1, validIdProperty2);
+        setPropertiesToReadOn(Location.create(validPath), validIdProperty1, validIdProperty2);
         Map<Name, Property> propsByName = graph.getPropertiesByName().on(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadProperties(new Location(validPath), validIdProperty1, validIdProperty2);
+        assertNextRequestReadProperties(Location.create(validPath), validIdProperty1, validIdProperty2);
         assertNoMoreRequests();
         assertThat(propsByName.get(validIdProperty1.getName()), is(validIdProperty1));
         assertThat(propsByName.get(validIdProperty2.getName()), is(validIdProperty2));
 
-        setPropertiesToReadOn(new Location(validPath));
+        setPropertiesToReadOn(Location.create(validPath));
         propsByName = graph.getPropertiesByName().on(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadProperties(new Location(validPath));
+        assertNextRequestReadProperties(Location.create(validPath));
         assertNoMoreRequests();
         assertThat(propsByName.isEmpty(), is(true));
     }
 
     @Test
     public void shouldGetPropertyOnNode() {
-        setPropertiesToReadOn(new Location(validPath), validIdProperty1, validIdProperty2);
+        setPropertiesToReadOn(Location.create(validPath), validIdProperty1, validIdProperty2);
         graph.getProperty(validIdProperty2.getName()).on(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadProperty(new Location(validPath), validIdProperty2);
+        assertNextRequestReadProperty(Location.create(validPath), validIdProperty2);
         assertNoMoreRequests();
 
-        setPropertiesToReadOn(new Location(validPath), validIdProperty1, validIdProperty2);
+        setPropertiesToReadOn(Location.create(validPath), validIdProperty1, validIdProperty2);
         graph.getProperty(validIdProperty2.getName().getString(context.getNamespaceRegistry())).on(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadProperty(new Location(validPath), validIdProperty2);
+        assertNextRequestReadProperty(Location.create(validPath), validIdProperty2);
         assertNoMoreRequests();
     }
 
     @Test
     public void shouldGetChildrenOnNode() {
-        Location child1 = new Location(createPath(validPath, "x"));
-        Location child2 = new Location(createPath(validPath, "y"));
-        Location child3 = new Location(createPath(validPath, "z"));
-        setChildrenToReadOn(new Location(validPath), child1, child2, child3);
+        Location child1 = Location.create(createPath(validPath, "x"));
+        Location child2 = Location.create(createPath(validPath, "y"));
+        Location child3 = Location.create(createPath(validPath, "z"));
+        setChildrenToReadOn(Location.create(validPath), child1, child2, child3);
         List<Location> children = graph.getChildren().of(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadChildren(new Location(validPath), child1, child2, child3);
+        assertNextRequestReadChildren(Location.create(validPath), child1, child2, child3);
         assertNoMoreRequests();
         assertThat(children, hasItems(child1, child2, child3));
 
-        setChildrenToReadOn(new Location(validPath));
+        setChildrenToReadOn(Location.create(validPath));
         children = graph.getChildren().of(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadChildren(new Location(validPath));
+        assertNextRequestReadChildren(Location.create(validPath));
         assertNoMoreRequests();
         assertThat(children.isEmpty(), is(true));
     }
 
     @Test
     public void shouldGetChildrenInBlockAtStartingIndex() {
-        Location child1 = new Location(createPath(validPath, "x"));
-        Location child2 = new Location(createPath(validPath, "y"));
-        Location child3 = new Location(createPath(validPath, "z"));
-        setChildrenToReadOn(new Location(validPath), child1, child2, child3);
+        Location child1 = Location.create(createPath(validPath, "x"));
+        Location child2 = Location.create(createPath(validPath, "y"));
+        Location child3 = Location.create(createPath(validPath, "z"));
+        setChildrenToReadOn(Location.create(validPath), child1, child2, child3);
         List<Location> children = graph.getChildren().inBlockOf(2).startingAt(0).under(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadBlockOfChildren(new Location(validPath), 0, 2, child1, child2);
+        assertNextRequestReadBlockOfChildren(Location.create(validPath), 0, 2, child1, child2);
         assertNoMoreRequests();
         assertThat(children, hasItems(child1, child2));
 
         children = graph.getChildren().inBlockOf(2).startingAt(1).under(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadBlockOfChildren(new Location(validPath), 1, 2, child2, child3);
+        assertNextRequestReadBlockOfChildren(Location.create(validPath), 1, 2, child2, child3);
         assertNoMoreRequests();
         assertThat(children, hasItems(child2, child3));
 
         children = graph.getChildren().inBlockOf(2).startingAt(2).under(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadBlockOfChildren(new Location(validPath), 2, 2, child3);
+        assertNextRequestReadBlockOfChildren(Location.create(validPath), 2, 2, child3);
         assertNoMoreRequests();
         assertThat(children, hasItems(child3));
 
         children = graph.getChildren().inBlockOf(2).startingAt(20).under(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadBlockOfChildren(new Location(validPath), 20, 2);
+        assertNextRequestReadBlockOfChildren(Location.create(validPath), 20, 2);
         assertNoMoreRequests();
         assertThat(children.isEmpty(), is(true));
 
         children = graph.getChildren().inBlockOf(20).startingAt(0).under(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadBlockOfChildren(new Location(validPath), 0, 20, child1, child2, child3);
+        assertNextRequestReadBlockOfChildren(Location.create(validPath), 0, 20, child1, child2, child3);
         assertNoMoreRequests();
         assertThat(children, hasItems(child1, child2, child3));
     }
@@ -542,26 +542,26 @@
         Path pathX = createPath(validPath, "x");
         Path pathY = createPath(validPath, "y");
         Path pathZ = createPath(validPath, "z");
-        Location child1 = new Location(pathX);
-        Location child2 = new Location(pathY);
-        Location child3 = new Location(pathZ);
-        setChildrenToReadOn(new Location(validPath), child1, child2, child3);
+        Location child1 = Location.create(pathX);
+        Location child2 = Location.create(pathY);
+        Location child3 = Location.create(pathZ);
+        setChildrenToReadOn(Location.create(validPath), child1, child2, child3);
 
         List<Location> children = graph.getChildren().inBlockOf(2).startingAfter(pathX);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadNextBlockOfChildren(new Location(pathX), 2, child2, child3);
+        assertNextRequestReadNextBlockOfChildren(Location.create(pathX), 2, child2, child3);
         assertNoMoreRequests();
         assertThat(children, hasItems(child2, child3));
 
         children = graph.getChildren().inBlockOf(3).startingAfter(pathX);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadNextBlockOfChildren(new Location(pathX), 3, child2, child3);
+        assertNextRequestReadNextBlockOfChildren(Location.create(pathX), 3, child2, child3);
         assertNoMoreRequests();
         assertThat(children, hasItems(child2, child3));
 
         children = graph.getChildren().inBlockOf(2).startingAfter(pathY);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadNextBlockOfChildren(new Location(pathY), 2, child3);
+        assertNextRequestReadNextBlockOfChildren(Location.create(pathY), 2, child3);
         assertNoMoreRequests();
         assertThat(children, hasItems(child3));
     }
@@ -569,86 +569,86 @@
     @Test
     public void shouldSetPropertiesWithEitherOnOrToMethodsCalledFirst() {
         graph.set("propName").on(validPath).to(3.0f);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", 3.0f));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", 3.0f));
 
         graph.set("propName").to(3.0f).on(validPath);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", 3.0f));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", 3.0f));
     }
 
     @Test
     public void shouldSetPropertyValueToPrimitiveTypes() {
         graph.set("propName").on(validPath).to(3.0F);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", new Float(3.0f)));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", new Float(3.0f)));
 
         graph.set("propName").on(validPath).to(1.0D);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", new Double(1.0)));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", new Double(1.0)));
 
         graph.set("propName").on(validPath).to(false);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", Boolean.FALSE));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", Boolean.FALSE));
 
         graph.set("propName").on(validPath).to(3);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", new Integer(3)));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", new Integer(3)));
 
         graph.set("propName").on(validPath).to(5L);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", new Long(5)));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", new Long(5)));
 
         graph.set("propName").on(validPath).to(validPath);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", validPath));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", validPath));
 
         graph.set("propName").on(validPath).to(validPath.getLastSegment().getName());
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName",
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName",
                                                                                   validPath.getLastSegment().getName()));
         Date now = new Date();
         graph.set("propName").on(validPath).to(now);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", now));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", now));
 
         DateTime dtNow = context.getValueFactories().getDateFactory().create(now);
         graph.set("propName").on(validPath).to(dtNow);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", dtNow));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", dtNow));
 
         Calendar calNow = Calendar.getInstance();
         calNow.setTime(now);
         graph.set("propName").on(validPath).to(calNow);
-        assertNextRequestUpdateProperties(new Location(validPath), createProperty("propName", dtNow));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", dtNow));
 
     }
 
     @Test
     public void shouldReadNode() {
-        Location child1 = new Location(createPath(validPath, "x"));
-        Location child2 = new Location(createPath(validPath, "y"));
-        Location child3 = new Location(createPath(validPath, "z"));
-        setChildrenToReadOn(new Location(validPath), child1, child2, child3);
-        setPropertiesToReadOn(new Location(validPath), validIdProperty1, validIdProperty2);
+        Location child1 = Location.create(createPath(validPath, "x"));
+        Location child2 = Location.create(createPath(validPath, "y"));
+        Location child3 = Location.create(createPath(validPath, "z"));
+        setChildrenToReadOn(Location.create(validPath), child1, child2, child3);
+        setPropertiesToReadOn(Location.create(validPath), validIdProperty1, validIdProperty2);
         Node node = graph.getNodeAt(validPath);
         assertThat(node, is(notNullValue()));
         assertThat(node.getChildren(), hasItems(child1, child2));
         assertThat(node.getProperties(), hasItems(validIdProperty1, validIdProperty2));
-        assertThat(node.getLocation(), is(new Location(validPath)));
+        assertThat(node.getLocation(), is(Location.create(validPath)));
         assertThat(node.getGraph(), is(sameInstance(graph)));
         assertThat(node.getPropertiesByName().get(validIdProperty1.getName()), is(validIdProperty1));
         assertThat(node.getPropertiesByName().get(validIdProperty2.getName()), is(validIdProperty2));
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadNode(new Location(validPath));
+        assertNextRequestReadNode(Location.create(validPath));
         assertNoMoreRequests();
     }
 
     @Test
     public void shouldReadSubgraph() {
-        Location child1 = new Location(createPath(validPath, "x"));
-        Location child2 = new Location(createPath(validPath, "y"));
-        Location child3 = new Location(createPath(validPath, "z"));
-        setChildrenToReadOn(new Location(validPath), child1, child2, child3);
-        Location child11 = new Location(createPath(child1.getPath(), "h"));
-        Location child12 = new Location(createPath(child1.getPath(), "i"));
-        Location child13 = new Location(createPath(child1.getPath(), "j"));
+        Location child1 = Location.create(createPath(validPath, "x"));
+        Location child2 = Location.create(createPath(validPath, "y"));
+        Location child3 = Location.create(createPath(validPath, "z"));
+        setChildrenToReadOn(Location.create(validPath), child1, child2, child3);
+        Location child11 = Location.create(createPath(child1.getPath(), "h"));
+        Location child12 = Location.create(createPath(child1.getPath(), "i"));
+        Location child13 = Location.create(createPath(child1.getPath(), "j"));
         setChildrenToReadOn(child1, child11, child12, child13);
-        Location child121 = new Location(createPath(child12.getPath(), "m"));
-        Location child122 = new Location(createPath(child12.getPath(), "n"));
-        Location child123 = new Location(createPath(child12.getPath(), "o"));
+        Location child121 = Location.create(createPath(child12.getPath(), "m"));
+        Location child122 = Location.create(createPath(child12.getPath(), "n"));
+        Location child123 = Location.create(createPath(child12.getPath(), "o"));
         setChildrenToReadOn(child12, child121, child122, child123);
 
-        setPropertiesToReadOn(new Location(validPath), validIdProperty1, validIdProperty2);
+        setPropertiesToReadOn(Location.create(validPath), validIdProperty1, validIdProperty2);
         setPropertiesToReadOn(child1, validIdProperty1);
         setPropertiesToReadOn(child2, validIdProperty2);
         setPropertiesToReadOn(child11, validIdProperty1);
@@ -659,10 +659,10 @@
         Subgraph subgraph = graph.getSubgraphOfDepth(2).at(validPath);
         assertThat(subgraph, is(notNullValue()));
         assertThat(subgraph.getMaximumDepth(), is(2));
-        assertThat(subgraph.getLocation(), is(new Location(validPath)));
+        assertThat(subgraph.getLocation(), is(Location.create(validPath)));
 
         // Get nodes by absolute path
-        Node root = subgraph.getNode(new Location(validPath));
+        Node root = subgraph.getNode(Location.create(validPath));
         assertThat(root.getChildren(), hasItems(child1, child2, child3));
         assertThat(root.getProperties(), hasItems(validIdProperty1, validIdProperty2));
 
@@ -707,26 +707,26 @@
     public void shouldMoveNodeInBatches() {
         graph.batch().move(validPath).into(validIdProperty1, validIdProperty2).execute();
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsMove(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
+        assertNextRequestIsMove(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
         assertNoMoreRequests();
 
         graph.batch().move(validPathString).into(validIdProperty1, validIdProperty2).execute();
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsMove(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
+        assertNextRequestIsMove(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
         assertNoMoreRequests();
 
         graph.batch().move(validUuid).into(validPath).execute();
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsMove(new Location(validUuid), new Location(validPath));
+        assertNextRequestIsMove(Location.create(validUuid), Location.create(validPath));
         assertNoMoreRequests();
 
         graph.batch().move(validPath).into(validIdProperty1, validIdProperty2).and().move(validPathString).into(validIdProperty1,
                                                                                                                 validIdProperty2).and().move(validUuid).into(validPath).execute();
         assertThat(numberOfExecutions, is(1));
         extractRequestsFromComposite();
-        assertNextRequestIsMove(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
-        assertNextRequestIsMove(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
-        assertNextRequestIsMove(new Location(validUuid), new Location(validPath));
+        assertNextRequestIsMove(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
+        assertNextRequestIsMove(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
+        assertNextRequestIsMove(Location.create(validUuid), Location.create(validPath));
         assertNoMoreRequests();
     }
 
@@ -734,45 +734,45 @@
     public void shouldCopyNodeInBatches() {
         graph.batch().copy(validPath).into(validIdProperty1, validIdProperty2).execute();
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCopy(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
+        assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
         assertNoMoreRequests();
 
         graph.batch().copy(validPathString).into(validIdProperty1, validIdProperty2).execute();
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCopy(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
+        assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
         assertNoMoreRequests();
 
         graph.batch().copy(validUuid).into(validPath).execute();
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCopy(new Location(validUuid), new Location(validPath));
+        assertNextRequestIsCopy(Location.create(validUuid), Location.create(validPath));
         assertNoMoreRequests();
 
         graph.batch().copy(validPath).into(validIdProperty1, validIdProperty2).and().copy(validPathString).into(validIdProperty1,
                                                                                                                 validIdProperty2).and().copy(validUuid).into(validPath).execute();
         assertThat(numberOfExecutions, is(1));
         extractRequestsFromComposite();
-        assertNextRequestIsCopy(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
-        assertNextRequestIsCopy(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
-        assertNextRequestIsCopy(new Location(validUuid), new Location(validPath));
+        assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
+        assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
+        assertNextRequestIsCopy(Location.create(validUuid), Location.create(validPath));
         assertNoMoreRequests();
     }
 
     @Test
     public void shouldReadNodesInBatches() {
-        Location child1 = new Location(createPath(validPath, "x"));
-        Location child2 = new Location(createPath(validPath, "y"));
-        Location child3 = new Location(createPath(validPath, "z"));
-        setChildrenToReadOn(new Location(validPath), child1, child2, child3);
-        Location child11 = new Location(createPath(child1.getPath(), "h"));
-        Location child12 = new Location(createPath(child1.getPath(), "i"));
-        Location child13 = new Location(createPath(child1.getPath(), "j"));
+        Location child1 = Location.create(createPath(validPath, "x"));
+        Location child2 = Location.create(createPath(validPath, "y"));
+        Location child3 = Location.create(createPath(validPath, "z"));
+        setChildrenToReadOn(Location.create(validPath), child1, child2, child3);
+        Location child11 = Location.create(createPath(child1.getPath(), "h"));
+        Location child12 = Location.create(createPath(child1.getPath(), "i"));
+        Location child13 = Location.create(createPath(child1.getPath(), "j"));
         setChildrenToReadOn(child1, child11, child12, child13);
-        Location child121 = new Location(createPath(child12.getPath(), "m"));
-        Location child122 = new Location(createPath(child12.getPath(), "n"));
-        Location child123 = new Location(createPath(child12.getPath(), "o"));
+        Location child121 = Location.create(createPath(child12.getPath(), "m"));
+        Location child122 = Location.create(createPath(child12.getPath(), "n"));
+        Location child123 = Location.create(createPath(child12.getPath(), "o"));
         setChildrenToReadOn(child12, child121, child122, child123);
 
-        setPropertiesToReadOn(new Location(validPath), validIdProperty1, validIdProperty2);
+        setPropertiesToReadOn(Location.create(validPath), validIdProperty1, validIdProperty2);
         setPropertiesToReadOn(child1, validIdProperty1);
         setPropertiesToReadOn(child2, validIdProperty2);
         setPropertiesToReadOn(child11, validIdProperty1);
@@ -783,7 +783,7 @@
         results = graph.batch().read(validPath).and().read(child11).and().read(child12).execute();
         assertThat(numberOfExecutions, is(1));
         extractRequestsFromComposite();
-        assertNextRequestReadNode(new Location(validPath));
+        assertNextRequestReadNode(Location.create(validPath));
         assertNextRequestReadNode(child11);
         assertNextRequestReadNode(child12);
         assertNoMoreRequests();
@@ -793,7 +793,7 @@
         assertThat(node, is(notNullValue()));
         assertThat(node.getChildren(), hasItems(child1, child2, child3));
         assertThat(node.getProperties(), hasItems(validIdProperty1, validIdProperty2));
-        assertThat(node.getLocation(), is(new Location(validPath)));
+        assertThat(node.getLocation(), is(Location.create(validPath)));
         assertThat(node.getGraph(), is(sameInstance(graph)));
         assertThat(node.getPropertiesByName().get(validIdProperty1.getName()), is(validIdProperty1));
         assertThat(node.getPropertiesByName().get(validIdProperty2.getName()), is(validIdProperty2));
@@ -820,17 +820,17 @@
     // ----------------------------------------------------------------------------------------------------------------
     @Test( expected = AssertionError.class )
     public void shouldPropertyCheckReadPropertiesUsingTestHarness1() {
-        setPropertiesToReadOn(new Location(validPath), validIdProperty1);
+        setPropertiesToReadOn(Location.create(validPath), validIdProperty1);
         graph.getProperties().on(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadProperties(new Location(validPath), validIdProperty1, validIdProperty2); // wrong!
+        assertNextRequestReadProperties(Location.create(validPath), validIdProperty1, validIdProperty2); // wrong!
     }
 
     @Test( expected = AssertionError.class )
     public void shouldPropertyCheckReadPropertiesUsingTestHarness2() {
         graph.getProperties().on(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestReadProperties(new Location(validPath), validIdProperty1, validIdProperty2); // wrong!
+        assertNextRequestReadProperties(Location.create(validPath), validIdProperty1, validIdProperty2); // wrong!
     }
 
     // ----------------------------------------------------------------------------------------------------------------
@@ -863,8 +863,8 @@
     public void shouldMoveNodesThroughMultipleMoveRequests() {
         graph.move(validPath).into(validIdProperty1, validIdProperty2).and().move(validUuid).into(validPathString);
         assertThat(numberOfExecutions, is(2));
-        assertNextRequestIsMove(new Location(validPath), new Location(validIdProperty1, validIdProperty2));
-        assertNextRequestIsMove(new Location(validUuid), new Location(createPath(validPathString)));
+        assertNextRequestIsMove(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
+        assertNextRequestIsMove(Location.create(validUuid), Location.create(createPath(validPathString)));
         assertNoMoreRequests();
     }
 
@@ -875,7 +875,7 @@
 
         graph.move(validPath).into(validUuid);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsMove(new Location(validPath), new Location(validUuid));
+        assertNextRequestIsMove(Location.create(validPath), Location.create(validUuid));
         assertNoMoreRequests();
     }
 
@@ -946,7 +946,7 @@
                 Name childName = request.desiredName();
                 if (childName == null) childName = createName("child");
                 Path childPath = context.getValueFactories().getPathFactory().create(request.into().getPath(), childName);
-                Location newChild = actualLocationOf(new Location(childPath));
+                Location newChild = actualLocationOf(Location.create(childPath));
                 // Just update the actual location
                 request.setActualLocations(actualLocationOf(request.from()), newChild);
             } else {
@@ -961,7 +961,7 @@
             Location parent = actualLocationOf(request.under()); // just make sure it has a path ...
             Name name = request.named();
             Path childPath = context.getValueFactories().getPathFactory().create(parent.getPath(), name);
-            request.setActualLocationOfNode(new Location(childPath));
+            request.setActualLocationOfNode(Location.create(childPath));
         }
 
         @Override
@@ -1012,7 +1012,7 @@
             String workspaceName = request.workspaceName();
             if (workspaceName == null) workspaceName = "default";
             request.setActualWorkspaceName(workspaceName);
-            request.setActualRootLocation(new Location(context.getValueFactories().getPathFactory().createRootPath()));
+            request.setActualRootLocation(Location.create(context.getValueFactories().getPathFactory().createRootPath()));
         }
 
         @Override
@@ -1021,7 +1021,7 @@
             String workspaceName = request.desiredNameOfNewWorkspace();
             if (workspaceName == null) workspaceName = "default";
             request.setActualWorkspaceName(workspaceName);
-            request.setActualRootLocation(new Location(context.getValueFactories().getPathFactory().createRootPath()));
+            request.setActualRootLocation(Location.create(context.getValueFactories().getPathFactory().createRootPath()));
         }
 
         @Override
@@ -1039,7 +1039,7 @@
             String workspaceName = request.desiredNameOfTargetWorkspace();
             assert workspaceName != null;
             request.setActualWorkspaceName(workspaceName);
-            request.setActualRootLocation(new Location(context.getValueFactories().getPathFactory().createRootPath()));
+            request.setActualRootLocation(Location.create(context.getValueFactories().getPathFactory().createRootPath()));
         }
 
         private Location actualLocationOf( Location location ) {
@@ -1047,7 +1047,7 @@
             if (location.hasPath()) return location;
             // Otherwise, create a new location with an artificial path ...
             Path path = context.getValueFactories().getPathFactory().create("/a/b/c/d");
-            return new Location(path, location.getIdProperties());
+            return Location.create(path, location.getIdProperties());
         }
     }
 

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/RepositorySourceLoadHarness.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/RepositorySourceLoadHarness.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/RepositorySourceLoadHarness.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -217,7 +217,7 @@
                 if (i % 2 == 0) {
                     Thread.yield();
                 }
-                connection.execute(context, new ReadNodeRequest(new Location(RootPath.INSTANCE), "workspace1"));
+                connection.execute(context, new ReadNodeRequest(Location.create(RootPath.INSTANCE), "workspace1"));
                 int int2 = random(this.hashCode() ^ (int)System.nanoTime() + i);
                 total += Math.min(Math.abs(Math.max(int1, int2) + int1 * int2 / 3), count);
             }

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/AbstractConnectorTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/AbstractConnectorTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/AbstractConnectorTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -278,7 +278,7 @@
      * @return the location
      */
     protected Location location( String path ) {
-        return new Location(path(path));
+        return Location.create(path(path));
     }
 
     /**
@@ -288,7 +288,7 @@
      * @return the location
      */
     protected Location location( UUID uuid ) {
-        return new Location(uuid);
+        return Location.create(uuid);
     }
 
     protected UUID getRootNodeUuid() {

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/request/AbstractRequestTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/request/AbstractRequestTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/request/AbstractRequestTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -65,21 +65,21 @@
         Name idProperty2Name = createName("id2");
         Property idProperty1 = context.getPropertyFactory().create(idProperty1Name, "1");
         Property idProperty2 = context.getPropertyFactory().create(idProperty2Name, "2");
-        validPathLocation = new Location(validPath);
-        validUuidLocation = new Location(validUuid);
-        validPropsLocation = new Location(idProperty1, idProperty2);
+        validPathLocation = Location.create(validPath);
+        validUuidLocation = Location.create(validUuid);
+        validPropsLocation = Location.create(idProperty1, idProperty2);
 
-        validPathLocation1 = new Location(validPath);
-        validUuidLocation1 = new Location(validUuid);
-        validPropsLocation1 = new Location(idProperty1, idProperty2);
+        validPathLocation1 = Location.create(validPath);
+        validUuidLocation1 = Location.create(validUuid);
+        validPropsLocation1 = Location.create(idProperty1, idProperty2);
 
         validPath = createPath("/a/c/d");
         validUuid = UUID.randomUUID();
         idProperty1 = context.getPropertyFactory().create(idProperty1Name, "3");
         idProperty2 = context.getPropertyFactory().create(idProperty2Name, "4");
-        validPathLocation2 = new Location(validPath);
-        validUuidLocation2 = new Location(validUuid);
-        validPropsLocation2 = new Location(idProperty1, idProperty2);
+        validPathLocation2 = Location.create(validPath);
+        validUuidLocation2 = Location.create(validUuid);
+        validPropsLocation2 = Location.create(idProperty1, idProperty2);
 
         validProperty1 = context.getPropertyFactory().create(createName("fooProperty"), "foo");
         validProperty2 = context.getPropertyFactory().create(createName("barProperty"), "bar");

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -441,7 +441,7 @@
             assert path != null;
             Path parent = path.getParent();
             Name child = path.getLastSegment().getName();
-            requests.add(new CreateNodeRequest(new Location(parent), workspace, child, properties));
+            requests.add(new CreateNodeRequest(Location.create(parent), workspace, child, properties));
         }
 
         public void create( final Path path,
@@ -449,7 +449,7 @@
                             final Property... additionalProperties ) {
             Path parent = path.getParent();
             Name child = path.getLastSegment().getName();
-            Location location = new Location(parent);
+            Location location = Location.create(parent);
             if (firstProperty == null) {
                 requests.add(new CreateNodeRequest(location, workspace, child));
             } else {

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -299,7 +299,7 @@
         FederatedWorkspace workspace = getWorkspace(request, request.workspaceName());
         if (workspace != null) {
             request.setActualWorkspaceName(workspace.getName());
-            Location root = new Location(getExecutionContext().getValueFactories().getPathFactory().createRootPath());
+            Location root = Location.create(getExecutionContext().getValueFactories().getPathFactory().createRootPath());
             ReadNodeRequest nodeInfo = getNode(root, workspace);
             if (nodeInfo.hasError()) return;
             request.setActualRootLocation(nodeInfo.getActualLocationOfNode());
@@ -385,7 +385,7 @@
                     // Load the nodes along the path below the existing ancestor, down to (but excluding) the desired path
                     Path pathToLoad = ancestor;
                     while (!pathToLoad.equals(lowestExistingAncestor)) {
-                        Location locationToLoad = new Location(pathToLoad);
+                        Location locationToLoad = Location.create(pathToLoad);
                         loadContributionsFromSources(locationToLoad, workspace, null, contributions); // sourceNames may be
                         // null or empty
                         FederatedNode mergedNode = createFederatedNode(locationToLoad, workspace, contributions, true);
@@ -584,14 +584,14 @@
                 // use those to figure out the children of the nodes.
                 Contribution contribution = null;
                 List<Path> topLevelPaths = projection.getTopLevelPathsInRepository(pathFactory);
-                Location input = new Location(path);
+                Location input = Location.create(path);
                 switch (topLevelPaths.size()) {
                     case 0:
                         break;
                     case 1: {
                         Path topLevelPath = topLevelPaths.iterator().next();
                         if (path.isAncestorOf(topLevelPath)) {
-                            Location child = new Location(topLevelPath);
+                            Location child = Location.create(topLevelPath);
                             contribution = Contribution.createPlaceholder(source, workspace, input, expirationTime, child);
                         }
                         break;
@@ -601,7 +601,7 @@
                         List<Location> children = new ArrayList<Location>(topLevelPaths.size());
                         for (Path topLevelPath : topLevelPaths) {
                             if (path.isAncestorOf(topLevelPath)) {
-                                children.add(new Location(topLevelPath));
+                                children.add(Location.create(topLevelPath));
                             }
                         }
                         if (children.size() > 0) {
@@ -618,7 +618,7 @@
                 final int numPaths = pathsInSource.size();
                 if (numPaths == 1) {
                     Path pathInSource = pathsInSource.iterator().next();
-                    ReadNodeRequest fromSource = new ReadNodeRequest(new Location(pathInSource), workspace);
+                    ReadNodeRequest fromSource = new ReadNodeRequest(Location.create(pathInSource), workspace);
                     sourceConnection.execute(getExecutionContext(), fromSource);
                     if (!fromSource.hasError()) {
                         Collection<Property> properties = fromSource.getProperties();
@@ -657,7 +657,7 @@
                 } else {
                     List<Request> fromSourceCommands = new ArrayList<Request>(numPaths);
                     for (Path pathInSource : pathsInSource) {
-                        fromSourceCommands.add(new ReadNodeRequest(new Location(pathInSource), workspace));
+                        fromSourceCommands.add(new ReadNodeRequest(Location.create(pathInSource), workspace));
                     }
                     Request request = CompositeRequest.with(fromSourceCommands);
                     sourceConnection.execute(context, request);
@@ -721,7 +721,7 @@
         Name childName = null;
         if (!path.isRoot()) {
             // This is not the root node, so we need to create the node ...
-            final Location parentLocation = new Location(path.getParent());
+            final Location parentLocation = Location.create(path.getParent());
             childName = path.getLastSegment().getName();
             requests.add(new CreateNodeRequest(parentLocation, cacheWorkspace, childName, NodeConflictBehavior.REPLACE,
                                                mergedNode.getProperties()));

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -110,7 +110,7 @@
                     if (!childNames.containsKey(childName)) {
                         childNames.put(childName, 1);
                         Path pathToChild = pathFactory.create(location.getPath(), childName);
-                        federatedNode.addChild(new Location(pathToChild));
+                        federatedNode.addChild(Location.create(pathToChild));
                     }
                 }
             } else {
@@ -140,7 +140,7 @@
                         index = previousValue;
                     }
                     Path pathToChild = pathFactory.create(location.getPath(), childName, index);
-                    federatedNode.addChild(new Location(pathToChild));
+                    federatedNode.addChild(Location.create(pathToChild));
                 }
 
                 // Add in the properties ...

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -187,7 +187,7 @@
             // locations may have more than just paths. So, create a list of actual locations that just have paths ...
             List<Location> actualPathOnlyChildren = new ArrayList<Location>(childLocations.size());
             for (Location actualChild : childLocations) {
-                actualPathOnlyChildren.add(new Location(actualChild.getPath()));
+                actualPathOnlyChildren.add(Location.create(actualChild.getPath()));
             }
             // Now create the array of expected locations (that each contain only a path) ...
             Location[] expectedChildren = new Location[children.length];
@@ -196,7 +196,7 @@
             for (String child : children) {
                 Path.Segment segment = context.getValueFactories().getPathFactory().createSegment(child);
                 Path childPath = context.getValueFactories().getPathFactory().create(parentPath, segment);
-                expectedChildren[i++] = new Location(childPath);
+                expectedChildren[i++] = Location.create(childPath);
             }
             assertThat(actualPathOnlyChildren, hasItems(expectedChildren));
         }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatingRequestProcessorTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatingRequestProcessorTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatingRequestProcessorTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -263,15 +263,15 @@
 
         Path path = pathFactory.createRootPath();
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(new Location(path), defaultWorkspace, null, contributions);
+        executor.loadContributionsFromSources(Location.create(path), defaultWorkspace, null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
         assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
         assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
 
-        Location childA = new Location(pathFactory.create(path, "a"));
-        Location childB = new Location(pathFactory.create(path, "b"));
+        Location childA = Location.create(pathFactory.create(path, "a"));
+        Location childB = Location.create(pathFactory.create(path, "b"));
         assertThat(contributions.get(0).getChildren(), hasItems(childA, childB));
         assertThat(contributions.get(1).getChildren(), hasItems(childA));
         assertThat(contributions.get(2).getChildren(), hasItems(nodeX, nodeB));
@@ -283,7 +283,7 @@
         Iterator<Location> iter = contribution.getChildren();
         for (String childName : childNames) {
             Path expectedChildPath = context.getValueFactories().getPathFactory().create(location.getPath(), childName);
-            Location expectedChild = new Location(expectedChildPath);
+            Location expectedChild = Location.create(expectedChildPath);
             Location next = iter.next();
             if (!next.isSame(expectedChild)) {
                 assertThat(next, is(expectedChild));
@@ -311,7 +311,7 @@
 
         Path path = pathFactory.create("/x/y"); // from source 3
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(new Location(path), defaultWorkspace, null, contributions);
+        executor.loadContributionsFromSources(Location.create(path), defaultWorkspace, null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
@@ -324,7 +324,7 @@
 
         path = pathFactory.create("/x"); // from source 3
         contributions.clear();
-        executor.loadContributionsFromSources(new Location(path), defaultWorkspace, null, contributions);
+        executor.loadContributionsFromSources(Location.create(path), defaultWorkspace, null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
@@ -383,7 +383,7 @@
 
         Path path = pathFactory.create("/b"); // from source 2 and source 3
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(new Location(path), defaultWorkspace, null, contributions);
+        executor.loadContributionsFromSources(Location.create(path), defaultWorkspace, null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
@@ -396,7 +396,7 @@
 
         path = pathFactory.create("/b/by"); // from source 3
         contributions.clear();
-        executor.loadContributionsFromSources(new Location(path), defaultWorkspace, null, contributions);
+        executor.loadContributionsFromSources(Location.create(path), defaultWorkspace, null, contributions);
 
         assertThat(contributions.size(), is(2)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source2.getName()));
@@ -457,7 +457,7 @@
 
         Path path = pathFactory.create("/a"); // from sources 1, 2 and 3
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(new Location(path), defaultWorkspace, null, contributions);
+        executor.loadContributionsFromSources(Location.create(path), defaultWorkspace, null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
@@ -470,7 +470,7 @@
 
         path = pathFactory.create("/a/ay"); // from source 3
         contributions.clear();
-        executor.loadContributionsFromSources(new Location(path), defaultWorkspace, null, contributions);
+        executor.loadContributionsFromSources(Location.create(path), defaultWorkspace, null, contributions);
 
         assertThat(contributions.size(), is(1)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source3.getName()));
@@ -481,7 +481,7 @@
     public void shouldFailToLoadNodeFromSourcesWhenTheNodeDoesNotAppearInAnyOfTheSources() throws Exception {
         Path nonExistant = pathFactory.create("/nonExistant/Node/In/AnySource");
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(new Location(nonExistant), defaultWorkspace, null, contributions);
+        executor.loadContributionsFromSources(Location.create(nonExistant), defaultWorkspace, null, contributions);
         // All of the contributions should be empty ...
         for (Contribution contribution : contributions) {
             assertThat(contribution.isEmpty(), is(true));
@@ -539,7 +539,7 @@
 
         Path path = pathFactory.create("/a"); // from sources 1, 2 and 3
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(new Location(path), defaultWorkspace, null, contributions);
+        executor.loadContributionsFromSources(Location.create(path), defaultWorkspace, null, contributions);
 
         // Check when the contributions expire ...
         DateTime nowInUtc = executor.getCurrentTimeInUtc();

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -71,32 +71,32 @@
         child2 = mock(Location.class);
         child3 = mock(Location.class);
         children = Arrays.asList(child1, child2, child3);
-        contribution = new MultiChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, children);
+        contribution = new MultiChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, children);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new MultiChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, children);
+        contribution = new MultiChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, children);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new MultiChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, children);
+        contribution = new MultiChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullChildren() {
         children = null;
-        contribution = new MultiChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, children);
+        contribution = new MultiChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowEmptyChildren() {
         children = Collections.emptyList();
-        contribution = new MultiChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, children);
+        contribution = new MultiChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, children);
     }
 
     @Test
@@ -111,7 +111,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new MultiChildContribution(sourceName, workspaceName, new Location(pathInSource), NOW, children);
+        contribution = new MultiChildContribution(sourceName, workspaceName, Location.create(pathInSource), NOW, children);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -75,14 +75,14 @@
         property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
         property3 = new BasicSingleValueProperty(new BasicName(nsUri, "property3"), "value3");
         properties = Arrays.asList(property1, property2, property3);
-        contribution = new MultiPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new MultiPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      properties);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new MultiPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new MultiPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      properties);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
@@ -90,21 +90,21 @@
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new MultiPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new MultiPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      properties);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullProperties() {
         properties = null;
-        contribution = new MultiPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new MultiPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      properties);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowEmptyProperties() {
         properties = Collections.emptyList();
-        contribution = new MultiPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new MultiPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      properties);
     }
 
@@ -120,7 +120,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new MultiPropertyContribution(sourceName, workspaceName, new Location(pathInSource), NOW, properties);
+        contribution = new MultiPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), NOW, properties);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -84,14 +84,14 @@
         child2 = mock(Location.class);
         child3 = mock(Location.class);
         children = Arrays.asList(child1, child2, child3);
-        contribution = new NodeContribution(sourceName, workspaceName, new Location(pathInSource), expiration, properties,
+        contribution = new NodeContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, properties,
                                             children);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new NodeContribution(sourceName, workspaceName, new Location(pathInSource), expiration, properties,
+        contribution = new NodeContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, properties,
                                             children);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
@@ -99,35 +99,35 @@
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new NodeContribution(sourceName, workspaceName, new Location(pathInSource), expiration, properties,
+        contribution = new NodeContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, properties,
                                             children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullProperties() {
         properties = null;
-        contribution = new NodeContribution(sourceName, workspaceName, new Location(pathInSource), expiration, properties,
+        contribution = new NodeContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, properties,
                                             children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowEmptyProperties() {
         properties = Collections.emptyList();
-        contribution = new NodeContribution(sourceName, workspaceName, new Location(pathInSource), expiration, properties,
+        contribution = new NodeContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, properties,
                                             children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullChildren() {
         children = null;
-        contribution = new NodeContribution(sourceName, workspaceName, new Location(pathInSource), expiration, properties,
+        contribution = new NodeContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, properties,
                                             children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowEmptyChildren() {
         children = Collections.emptyList();
-        contribution = new NodeContribution(sourceName, workspaceName, new Location(pathInSource), expiration, properties,
+        contribution = new NodeContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, properties,
                                             children);
     }
 
@@ -143,7 +143,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new NodeContribution(sourceName, workspaceName, new Location(pathInSource), NOW, properties, children);
+        contribution = new NodeContribution(sourceName, workspaceName, Location.create(pathInSource), NOW, properties, children);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -62,26 +62,26 @@
         pathInSource = RootPath.INSTANCE;
         expiration = TOMORROW;
         child1 = mock(Location.class);
-        contribution = new OneChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, child1);
+        contribution = new OneChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, child1);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new OneChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, child1);
+        contribution = new OneChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, child1);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new OneChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, child1);
+        contribution = new OneChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, child1);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullChildren() {
         child1 = null;
-        contribution = new OneChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, child1);
+        contribution = new OneChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, child1);
     }
 
     @Test
@@ -96,7 +96,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new OneChildContribution(sourceName, workspaceName, new Location(pathInSource), NOW, child1);
+        contribution = new OneChildContribution(sourceName, workspaceName, Location.create(pathInSource), NOW, child1);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -67,26 +67,26 @@
         expiration = TOMORROW;
         String nsUri = "http://www.jboss.org/default";
         property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
-        contribution = new OnePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration, property1);
+        contribution = new OnePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, property1);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new OnePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration, property1);
+        contribution = new OnePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, property1);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new OnePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration, property1);
+        contribution = new OnePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, property1);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullFirstProperty() {
         property1 = null;
-        contribution = new OnePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration, property1);
+        contribution = new OnePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, property1);
     }
 
     @Test
@@ -101,7 +101,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new OnePropertyContribution(sourceName, workspaceName, new Location(pathInSource), NOW, property1);
+        contribution = new OnePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), NOW, property1);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -71,14 +71,14 @@
         property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
         property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
         property3 = new BasicSingleValueProperty(new BasicName(nsUri, "property3"), "value3");
-        contribution = new ThreePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new ThreePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      property1, property2, property3);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new ThreePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new ThreePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      property1, property2, property3);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
@@ -86,28 +86,28 @@
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new ThreePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new ThreePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      property1, property2, property3);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullFirstProperty() {
         property1 = null;
-        contribution = new ThreePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new ThreePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      property1, property2, property3);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullSecondProperty() {
         property2 = null;
-        contribution = new ThreePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new ThreePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      property1, property2, property3);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullThirdProperty() {
         property3 = null;
-        contribution = new ThreePropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration,
+        contribution = new ThreePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration,
                                                      property1, property2, property3);
     }
 
@@ -123,7 +123,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new ThreePropertyContribution(sourceName, workspaceName, new Location(pathInSource), NOW, property1,
+        contribution = new ThreePropertyContribution(sourceName, workspaceName, Location.create(pathInSource), NOW, property1,
                                                      property2, property3);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -64,32 +64,32 @@
         expiration = TOMORROW;
         child1 = mock(Location.class);
         child2 = mock(Location.class);
-        contribution = new TwoChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, child1, child2);
+        contribution = new TwoChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, child1, child2);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new TwoChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, child1, child2);
+        contribution = new TwoChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, child1, child2);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new TwoChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, child1, child2);
+        contribution = new TwoChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, child1, child2);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullFirstChild() {
         child1 = null;
-        contribution = new TwoChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, child1, child2);
+        contribution = new TwoChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, child1, child2);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullSecondChild() {
         child2 = null;
-        contribution = new TwoChildContribution(sourceName, workspaceName, new Location(pathInSource), expiration, child1, child2);
+        contribution = new TwoChildContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, child1, child2);
     }
 
     @Test
@@ -104,7 +104,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new TwoChildContribution(sourceName, workspaceName, new Location(pathInSource), NOW, child1, child2);
+        contribution = new TwoChildContribution(sourceName, workspaceName, Location.create(pathInSource), NOW, child1, child2);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -69,14 +69,14 @@
         String nsUri = "http://www.jboss.org/default";
         property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
         property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
-        contribution = new TwoPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration, property1,
+        contribution = new TwoPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, property1,
                                                    property2);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new TwoPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration, property1,
+        contribution = new TwoPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, property1,
                                                    property2);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
@@ -84,21 +84,21 @@
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new TwoPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration, property1,
+        contribution = new TwoPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, property1,
                                                    property2);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullFirstProperty() {
         property1 = null;
-        contribution = new TwoPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration, property1,
+        contribution = new TwoPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, property1,
                                                    property2);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullSecondProperty() {
         property2 = null;
-        contribution = new TwoPropertyContribution(sourceName, workspaceName, new Location(pathInSource), expiration, property1,
+        contribution = new TwoPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), expiration, property1,
                                                    property2);
     }
 
@@ -114,7 +114,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new TwoPropertyContribution(sourceName, workspaceName, new Location(pathInSource), NOW, property1,
+        contribution = new TwoPropertyContribution(sourceName, workspaceName, Location.create(pathInSource), NOW, property1,
                                                    property2);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -45,7 +45,7 @@
     @Before
     public void beforeEach() {
         MockitoAnnotations.initMocks(this);
-        location = new Location(mock(Path.class));
+        location = Location.create(mock(Path.class));
         node = new FederatedNode(location, "workspace");
     }
 

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -75,12 +75,12 @@
         context.getNamespaceRegistry().register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
         context.getNamespaceRegistry().register(JcrLexicon.Namespace.PREFIX, JcrLexicon.Namespace.URI);
         parentPath = context.getValueFactories().getPathFactory().create("/a/b/c");
-        node = new FederatedNode(new Location(parentPath), "some workspace");
+        node = new FederatedNode(Location.create(parentPath), "some workspace");
         stub(contribution.getSourceName()).toReturn("source name");
         children = new LinkedList<Location>();
         for (int i = 0; i != 10; ++i) {
             Path childPath = context.getValueFactories().getPathFactory().create(parentPath, "a" + i);
-            children.add(new Location(childPath));
+            children.add(Location.create(childPath));
         }
         properties = new HashMap<Name, Property>();
         for (int i = 0; i != 10; ++i) {

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -74,7 +74,7 @@
         context.getNamespaceRegistry().register("jcr", "http://www.jcr.org");
         parentPath = context.getValueFactories().getPathFactory().create("/a/b/c");
         workspaceName = "some workspace";
-        node = new FederatedNode(new Location(parentPath), workspaceName);
+        node = new FederatedNode(Location.create(parentPath), workspaceName);
     }
 
     @Test
@@ -202,7 +202,7 @@
     protected Matcher<List<Location>> hasChildLocations( String... childNames ) {
         List<Location> locations = new ArrayList<Location>();
         for (String childName : childNames) {
-            locations.add(new Location(context.getValueFactories().getPathFactory().create(parentPath, childName)));
+            locations.add(Location.create(context.getValueFactories().getPathFactory().create(parentPath, childName)));
         }
         return equalTo(locations);
     }
@@ -211,7 +211,7 @@
         Location[] locations = new Location[childNames.length];
         int index = 0;
         for (String childName : childNames) {
-            locations[index++] = new Location(context.getValueFactories().getPathFactory().create(parentPath, childName));
+            locations[index++] = Location.create(context.getValueFactories().getPathFactory().create(parentPath, childName));
         }
         return IsIteratorContaining.hasItems(locations);
     }
@@ -242,7 +242,7 @@
                                        List<Contribution> contributions ) {
             this.context = context;
             this.mockContribution = Mockito.mock(Contribution.class);
-            stub(mockContribution.getLocationInSource()).toReturn(new Location(parentPath));
+            stub(mockContribution.getLocationInSource()).toReturn(Location.create(parentPath));
             stub(mockContribution.getSourceName()).toReturn(name);
             stub(mockContribution.getChildren()).toAnswer(new Answer<Iterator<Location>>() {
                 public Iterator<Location> answer( InvocationOnMock invocation ) throws Throwable {
@@ -273,7 +273,7 @@
         public ContributionBuilder addChildren( String... pathsForChildren ) {
             for (String childPath : pathsForChildren) {
                 Path path = context.getValueFactories().getPathFactory().create(parentPath, childPath);
-                children.add(new Location(path));
+                children.add(Location.create(path));
             }
             return this;
         }

Modified: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRequestProcessor.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRequestProcessor.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -148,7 +148,7 @@
             for (String localName : parent.list(filenameFilter)) {
                 Name childName = nameFactory.create(defaultNamespaceUri, localName);
                 Path childPath = pathFactory.create(parentPath, childName);
-                request.addChild(new Location(childPath));
+                request.addChild(Location.create(childPath));
             }
         } else {
             // The parent is a java.io.File, and the path may refer to the node that is either the "nt:file" parent
@@ -156,7 +156,7 @@
             if (!parentPath.getLastSegment().getName().equals(JcrLexicon.CONTENT)) {
                 // This node represents the "nt:file" parent node, so the only child is the "jcr:content" node ...
                 Path contentPath = pathFactory().create(parentPath, JcrLexicon.CONTENT);
-                Location content = new Location(contentPath);
+                Location content = Location.create(contentPath);
                 request.addChild(content);
             }
             // otherwise, the path ends in "jcr:content", and there are no children
@@ -357,7 +357,7 @@
         File directory = new File(workspaceName);
         if (directory.exists() && directory.isDirectory() && directory.canRead()) {
             request.setActualWorkspaceName(getCanonicalWorkspaceName(directory));
-            request.setActualRootLocation(new Location(pathFactory().createRootPath()));
+            request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
         } else {
             request.setError(new InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));
         }
@@ -425,7 +425,7 @@
         File directory = new File(workspaceName);
         if (directory.exists() && directory.isDirectory() && directory.canRead()) {
             request.setActualWorkspaceName(getCanonicalWorkspaceName(directory));
-            request.setActualRootLocation(new Location(pathFactory().createRootPath()));
+            request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
             availableWorkspaceNames.add(workspaceName);
         } else {
             request.setError(new InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));

Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -116,10 +116,10 @@
         Path.Segment[] childList = (Path.Segment[])node.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
         if (childList != null) {
             for (Path.Segment child : childList) {
-                request.addChild(new Location(pathFactory.create(nodePath, child)));
+                request.addChild(Location.create(pathFactory.create(nodePath, child)));
             }
         }
-        request.setActualLocationOfNode(new Location(nodePath));
+        request.setActualLocationOfNode(Location.create(nodePath));
         setCacheableInfo(request);
     }
 
@@ -142,7 +142,7 @@
             Property property = propertyFactory.create(propertyName, values);
             request.addProperty(property);
         }
-        request.setActualLocationOfNode(new Location(nodePath));
+        request.setActualLocationOfNode(Location.create(nodePath));
         setCacheableInfo(request);
     }
 
@@ -177,7 +177,7 @@
             node.put(propName, value);
         }
         Path nodePath = pathFactory.create(parent, newSegment);
-        request.setActualLocationOfNode(new Location(nodePath));
+        request.setActualLocationOfNode(Location.create(nodePath));
     }
 
     @Override
@@ -206,7 +206,7 @@
             }
             node.put(propName, value);
         }
-        request.setActualLocationOfNode(new Location(nodePath));
+        request.setActualLocationOfNode(Location.create(nodePath));
     }
 
     @Override
@@ -242,7 +242,7 @@
                                            getExecutionContext());
 
         Path newPath = pathFactory.create(newParentPath, newSegment);
-        request.setActualLocations(new Location(nodePath), new Location(newPath));
+        request.setActualLocations(Location.create(nodePath), Location.create(newPath));
     }
 
     @Override
@@ -255,7 +255,7 @@
         if (node == null) return;
 
         node.getParent().removeChild(node.getFqn().getLastElement());
-        request.setActualLocationOfNode(new Location(nodePath));
+        request.setActualLocationOfNode(Location.create(nodePath));
     }
 
     @Override
@@ -281,7 +281,7 @@
         assert removed;
 
         Path newPath = pathFactory.create(newParentPath, newSegment);
-        request.setActualLocations(new Location(nodePath), new Location(newPath));
+        request.setActualLocations(Location.create(nodePath), Location.create(newPath));
     }
 
     /**
@@ -305,7 +305,7 @@
                 uuid = uuidFactory.create();
                 cache.put(rootName, DnaLexicon.UUID, uuid);
             }
-            request.setActualRootLocation(new Location(pathFactory.createRootPath()));
+            request.setActualRootLocation(Location.create(pathFactory.createRootPath()));
             request.setActualWorkspaceName(workspaceName);
         }
     }
@@ -347,7 +347,7 @@
             uuid = uuidFactory.create();
             cache.put(rootName, DnaLexicon.UUID, uuid);
         }
-        request.setActualRootLocation(new Location(pathFactory.createRootPath()));
+        request.setActualRootLocation(Location.create(pathFactory.createRootPath()));
         request.setActualWorkspaceName(workspaceName);
     }
 
@@ -482,7 +482,7 @@
                     fqn = null;
                 }
             }
-            request.setError(new PathNotFoundException(new Location(path), lowestExisting,
+            request.setError(new PathNotFoundException(Location.create(path), lowestExisting,
                                                        JBossCacheConnectorI18n.nodeDoesNotExist.text(nodePath)));
             node = null;
         }

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -265,7 +265,7 @@
         String parentUuid = null;
         ChildEntity parentEntity = null;
         if (parent == null) {
-            return new Location(pathFactory.createRootPath(), UUID.fromString(childUuid));
+            return Location.create(pathFactory.createRootPath(), UUID.fromString(childUuid));
         }
         parentPath = parent.location.getPath();
         parentUuid = parent.uuid;
@@ -357,7 +357,7 @@
 
         // Set the actual path, regardless of the supplied path...
         Path path = pathFactory.create(parentPath, childName, nextSnsIndex);
-        Location actualLocation = new Location(path, UUID.fromString(childUuid));
+        Location actualLocation = Location.create(path, UUID.fromString(childUuid));
 
         // Finally, update the cache with the information we know ...
         if (childrenOfParent != null) {
@@ -515,7 +515,7 @@
             int sns = child.getSameNameSiblingIndex();
             Path childPath = pathFactory.create(parentPath, childName, sns);
             String childUuidString = child.getId().getChildUuidString();
-            Location childLocation = new Location(childPath, UUID.fromString(childUuidString));
+            Location childLocation = Location.create(childPath, UUID.fromString(childUuidString));
             childLocations.add(childLocation);
         }
         // Update the cache ...
@@ -572,7 +572,7 @@
                     int sns = child.getSameNameSiblingIndex();
                     Path childPath = pathFactory.create(parentPath, childName, sns);
                     String childUuidString = child.getId().getChildUuidString();
-                    Location childLocation = new Location(childPath, UUID.fromString(childUuidString));
+                    Location childLocation = Location.create(childPath, UUID.fromString(childUuidString));
                     request.addChild(childLocation);
                 }
                 // Do not update the cache, since we don't know all of the children.
@@ -668,7 +668,7 @@
                         int sns = child.getSameNameSiblingIndex();
                         Path childPath = pathFactory.create(parentPath, childName, sns);
                         String childUuidString = child.getId().getChildUuidString();
-                        Location childLocation = new Location(childPath, UUID.fromString(childUuidString));
+                        Location childLocation = Location.create(childPath, UUID.fromString(childUuidString));
                         request.addChild(childLocation);
                         if (allChildren != null) {
                             // We're going to cache the results, so add this child ...
@@ -1015,7 +1015,7 @@
                     assert children != null;
                     Path childPath = pathFactory.create(parent, childName, sns);
                     String childUuidString = child.getId().getChildUuidString();
-                    Location childLocation = new Location(childPath, UUID.fromString(childUuidString));
+                    Location childLocation = Location.create(childPath, UUID.fromString(childUuidString));
                     locationsByUuid.put(childUuidString, childLocation);
                     children.add(childLocation);
                 }
@@ -1285,7 +1285,7 @@
                     Map<Location, List<Reference>> invalidRefs = new HashMap<Location, List<Reference>>();
                     for (ReferenceEntity entity : invalidReferences) {
                         UUID fromUuid = UUID.fromString(entity.getId().getFromUuidString());
-                        ActualLocation actualFromLocation = getActualLocation(workspaceId, new Location(fromUuid));
+                        ActualLocation actualFromLocation = getActualLocation(workspaceId, Location.create(fromUuid));
                         Location fromLocation = actualFromLocation.location;
                         List<Reference> refs = invalidRefs.get(fromLocation);
                         if (refs == null) {
@@ -1441,7 +1441,7 @@
         if (workspace != null) {
             Long workspaceId = workspace.getId();
             assert workspaceId != null;
-            ActualLocation actual = getActualLocation(workspaceId, new Location(pathFactory.createRootPath()));
+            ActualLocation actual = getActualLocation(workspaceId, Location.create(pathFactory.createRootPath()));
             request.setActualRootLocation(actual.location);
             request.setActualWorkspaceName(workspace.getName());
         }
@@ -1494,7 +1494,7 @@
         WorkspaceEntity entity = workspaces.create(name);
         request.setActualWorkspaceName(entity.getName());
         // Create the root node ...
-        Location root = new Location(pathFactory.createRootPath());
+        Location root = Location.create(pathFactory.createRootPath());
         request.setActualRootLocation(getActualLocation(entity.getId(), root).location);
     }
 
@@ -1592,7 +1592,7 @@
         }
 
         // Finish up the request ...
-        Location root = new Location(pathFactory.createRootPath(), rootNodeUuid);
+        Location root = Location.create(pathFactory.createRootPath(), rootNodeUuid);
         request.setActualRootLocation(getActualLocation(intoWorkspace.getId(), root).location);
     }
 
@@ -1688,7 +1688,7 @@
                     for (ReferenceEntity entity : references) {
                         ReferenceId id = entity.getId();
                         UUID fromUuid = UUID.fromString(id.getFromUuidString());
-                        Location location = new Location(fromUuid);
+                        Location location = Location.create(fromUuid);
                         location = getActualLocation(id.getWorkspaceId(), location).location;
                         List<Reference> refs = invalidRefs.get(location);
                         if (refs == null) {
@@ -1778,7 +1778,7 @@
         // See if the reference is by UUID ...
         try {
             UUID uuid = uuidFactory.create(reference);
-            ActualLocation actualLocation = getActualLocation(workspaceId, new Location(uuid));
+            ActualLocation actualLocation = getActualLocation(workspaceId, Location.create(uuid));
             return actualLocation.uuid;
         } catch (ValueFormatException e) {
             // Unknown kind of reference, which we don't track
@@ -1860,7 +1860,7 @@
                 }
             }
             Path fullPath = pathFactory.createAbsolutePath(segments);
-            Location newLocation = new Location(fullPath, uuidProperty);
+            Location newLocation = Location.create(fullPath, uuidProperty);
             cache.addNewNode(workspaceId, newLocation);
             return new ActualLocation(newLocation, nodeUuidString, originalEntity);
         }

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQuery.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQuery.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQuery.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -272,7 +272,7 @@
         pathByUuid.put(subgraphRootUuid, subgraphRootPath);
         UUID uuid = UUID.fromString(subgraphRootUuid);
         if (includeRoot) {
-            locations.add(new Location(subgraphRootPath, uuid));
+            locations.add(Location.create(subgraphRootPath, uuid));
         }
 
         // Now iterate over the child nodes in the subgraph (we've already included the root) ...
@@ -290,7 +290,7 @@
             String childUuid = entity.getId().getChildUuidString();
             pathByUuid.put(childUuid, childPath);
             uuid = UUID.fromString(childUuid);
-            locations.add(new Location(childPath, uuid));
+            locations.add(Location.create(childPath, uuid));
 
         }
         return locations;

Modified: trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCacheTest.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCacheTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCacheTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -68,30 +68,30 @@
         workspaceId = 10L;
 
         Path parent = pathFactory.create("/a/b/c");
-        location = new Location(parent, UUID.randomUUID());
-        children = new Location[] {new Location(pathFactory.create(parent, "d1"), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, "d2"), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, "d3"), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, "d4"), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, name("e"), 1), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, name("e"), 2), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, name("e"), 3), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, name("e"), 4), UUID.randomUUID())};
+        location = Location.create(parent, UUID.randomUUID());
+        children = new Location[] {Location.create(pathFactory.create(parent, "d1"), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, "d2"), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, "d3"), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, "d4"), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, name("e"), 1), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, name("e"), 2), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, name("e"), 3), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, name("e"), 4), UUID.randomUUID())};
         childrenList = new LinkedList<Location>();
         for (Location loc : children) {
             childrenList.add(loc);
         }
 
         parent = pathFactory.create("/a/b/c/e[2]");
-        location2 = new Location(parent, children[5].getUuid());
-        children2 = new Location[] {new Location(pathFactory.create(parent, "f1"), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, "f2"), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, "f3"), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, "f4"), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, name("g"), 1), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, name("g"), 2), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, name("g"), 3), UUID.randomUUID()),
-            new Location(pathFactory.create(parent, name("g"), 4), UUID.randomUUID())};
+        location2 = Location.create(parent, children[5].getUuid());
+        children2 = new Location[] {Location.create(pathFactory.create(parent, "f1"), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, "f2"), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, "f3"), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, "f4"), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, name("g"), 1), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, name("g"), 2), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, name("g"), 3), UUID.randomUUID()),
+            Location.create(pathFactory.create(parent, name("g"), 4), UUID.randomUUID())};
         childrenList2 = new LinkedList<Location>();
         for (Location loc : children2) {
             childrenList2.add(loc);
@@ -169,7 +169,7 @@
         // The cache knows about the children of "/a/b/c" and "/a/b/c/e[2]".
         // This test moves "/a/b/c/e[2]" into "/a/b/c/d3"
         Location oldLocation = location2;
-        Location newLocation = new Location(pathFactory.create("/a/b/c/d3/e[1]"));
+        Location newLocation = Location.create(pathFactory.create("/a/b/c/d3/e[1]"));
         assertThat(oldLocation.getPath().getString(namespaces), is("/a/b/c/e[2]"));
         assertThat(newLocation.getPath().getString(namespaces), is("/a/b/c/d3/e[1]"));
         cache.addNewNode(workspaceId, location);
@@ -294,7 +294,7 @@
         // The cache knows about the children of "/a/b/c" and "/a/b/c/e[2]".
         // This test removes "/a/b/c/e[2]"
         Location oldLocation = location2;
-        Location newLocation = new Location(pathFactory.create("/a/b/c/d3/e[1]"));
+        Location newLocation = Location.create(pathFactory.create("/a/b/c/d3/e[1]"));
         assertThat(oldLocation.getPath().getString(namespaces), is("/a/b/c/e[2]"));
         assertThat(newLocation.getPath().getString(namespaces), is("/a/b/c/d3/e[1]"));
         cache.addNewNode(workspaceId, location);
@@ -359,9 +359,9 @@
         for (Location childLocation : children2) {
             locationsToRemove.add(childLocation);
         }
-        locationsToRemove.add(new Location(pathFactory.create(children2[6].getPath(), "m1")));
-        locationsToRemove.add(new Location(pathFactory.create(children2[6].getPath(), "m2")));
-        locationsToRemove.add(new Location(pathFactory.create(children2[6].getPath(), "m3")));
+        locationsToRemove.add(Location.create(pathFactory.create(children2[6].getPath(), "m1")));
+        locationsToRemove.add(Location.create(pathFactory.create(children2[6].getPath(), "m2")));
+        locationsToRemove.add(Location.create(pathFactory.create(children2[6].getPath(), "m3")));
 
         // Remove the branch ...
         assertThat(cache.removeBranch(workspaceId, locationsToRemove), is(true));

Modified: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/SVNRepositoryRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/SVNRepositoryRequestProcessor.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/SVNRepositoryRequestProcessor.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -216,7 +216,7 @@
                     Name childName = nameFactory().create(defaultNamespaceUri, localName);
                     String url = entry.getURL().toString();
                     Property idProperty = propertyFactory().create(childName, url);
-                    request.addChild(new Location(pathFactory().create(nodePath, JcrLexicon.CONTENT), idProperty));
+                    request.addChild(Location.create(pathFactory().create(nodePath, JcrLexicon.CONTENT), idProperty));
                 }
             } else if (kind == SVNNodeKind.DIR) { // the requested node is a directory.
                 final Collection<SVNDirEntry> dirEntries = getRepository().getDir(requestedNodePath,
@@ -231,7 +231,7 @@
                             Name childName = nameFactory().create(defaultNamespaceUri, localName);
                             String url = dirEntry.getURL().toString();
                             Property idProperty = propertyFactory().create(childName, url);
-                            Location location = new Location(pathFactory().create(newPath, JcrLexicon.CONTENT), idProperty);
+                            Location location = Location.create(pathFactory().create(newPath, JcrLexicon.CONTENT), idProperty);
                             request.addChild(location);
                         }
                     } else if (dirEntry.getKind() == SVNNodeKind.DIR) {
@@ -373,7 +373,7 @@
         // This does the job of converting a null workspace name to a valid workspace
         String workspaceName = request.workspaceName();
         if (workspaceName == null) workspaceName = "default";
-        request.setActualRootLocation(new Location(pathFactory().createRootPath()));
+        request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
         request.setActualWorkspaceName(workspaceName);
     }
 
@@ -531,11 +531,11 @@
             kind = getRepository().checkPath(myPath, -1);
             if (kind == SVNNodeKind.NONE) {
                 // node does not exist or requested node is not correct.
-                throw new PathNotFoundException(new Location(requestedPath), null,
+                throw new PathNotFoundException(Location.create(requestedPath), null,
                                                 SVNRepositoryConnectorI18n.nodeDoesNotExist.text(myPath));
             } else if (kind == SVNNodeKind.UNKNOWN) {
                 // node is unknown
-                throw new PathNotFoundException(new Location(requestedPath), null,
+                throw new PathNotFoundException(Location.create(requestedPath), null,
                                                 SVNRepositoryConnectorI18n.nodeIsActuallyUnknow.text(myPath));
             }
         } catch (SVNException e) {

Modified: trunk/extensions/dna-connector-svn/src/test/java/org/jboss/dna/connector/svn/SVNRepositoryConnectionTest.java
===================================================================
--- trunk/extensions/dna-connector-svn/src/test/java/org/jboss/dna/connector/svn/SVNRepositoryConnectionTest.java	2009-02-20 15:40:37 UTC (rev 730)
+++ trunk/extensions/dna-connector-svn/src/test/java/org/jboss/dna/connector/svn/SVNRepositoryConnectionTest.java	2009-02-20 16:20:00 UTC (rev 731)
@@ -222,7 +222,7 @@
     @Test
     public void shouldNotHaveProperties() {
         // Root location does not need properties.
-        Location root = new Location(pathFactory.create("/"));
+        Location root = Location.create(pathFactory.create("/"));
         Collection<Property> nilProperties = graph.getProperties().on(root);
         assertThat(nilProperties, is(notNullValue()));
         assertThat(nilProperties.isEmpty(), is(true));
@@ -231,7 +231,7 @@
     @Test
     public void shouldJustCatchThePropertiesOnLocation() {
         // directory nodeA has "jcr:primaryType" with value "nt:folder" and also "jcr:created" with value folder created date
-        Location nodeA = new Location(pathFactory.create("/nodeA"));
+        Location nodeA = Location.create(pathFactory.create("/nodeA"));
         Collection<Property> nodeAProperties = graph.getProperties().on(nodeA);
         assertThat(nodeAProperties, is(notNullValue()));
         assertThat(nodeAProperties.isEmpty(), is(false));
@@ -239,7 +239,7 @@
 
         // file itemA.txt has "jcr:primaryType" property whose value is "nt:file" and also "jcr:created" with value folder created
         // date
-        Location itemA1 = new Location(pathFactory.create("/nodeA/itemA1.txt"));
+        Location itemA1 = Location.create(pathFactory.create("/nodeA/itemA1.txt"));
         Collection<Property> itemA1Properties = graph.getProperties().on(itemA1);
         assertThat(itemA1Properties, is(notNullValue()));
         assertThat(itemA1Properties.isEmpty(), is(false));
@@ -250,7 +250,7 @@
         // "jcr:data" property whose value are the contents of the file
         // and a few other properties, like "jcr:encoding", "jcr:mimeType" and "jcr:lastModified" and
         // also "jcr:created" property
-        Location content = new Location(pathFactory.create("/nodeA/itemA2.txt/jcr:content"));
+        Location content = Location.create(pathFactory.create("/nodeA/itemA2.txt/jcr:content"));
         Collection<Property> itemA2ContentProperties = graph.getProperties().on(content);
         assertThat(itemA2ContentProperties, is(notNullValue()));
         assertThat(itemA2ContentProperties.isEmpty(), is(false));



From dna-commits at lists.jboss.org  Fri Feb 20 12:09:38 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Fri, 20 Feb 2009 12:09:38 -0500
Subject: [dna-commits] DNA SVN: r732 - in trunk/dna-jcr/src/test: resources
	and 1 other directory.
Message-ID: <E1LaYsc-0004LR-LI@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-20 12:09:38 -0500 (Fri, 20 Feb 2009)
New Revision: 732

Added:
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JackrabbitJcrTckTest.java
   trunk/dna-jcr/src/test/resources/repositoryJackRabbitTck.xml
   trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties
Log:
DNA-88 Incorporate JCR TCK tests

Applied the patch that added the TCK unit tests to our unit tests.  We don't pass many of the Level 1 tests, so I commented out those tests that we don't currently pass.  I also created DNA-285 to capture that we want to uncomment these and pass all Level 1 unit tests.

Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JackrabbitJcrTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JackrabbitJcrTckTest.java	                        (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JackrabbitJcrTckTest.java	2009-02-20 17:09:38 UTC (rev 732)
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ *
+ * JBoss DNA is free software. 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.io.File;
+import java.net.URI;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.Collections;
+import java.util.Properties;
+import javax.jcr.Credentials;
+import javax.jcr.Repository;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.jackrabbit.test.JCRTestSuite;
+import org.apache.jackrabbit.test.RepositoryStub;
+import org.jboss.dna.graph.DnaLexicon;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.GraphImporter;
+import org.jboss.dna.graph.JcrNtLexicon;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.property.Path;
+
+/**
+ * Test suite to wrap Apache Jackrabbit JCR technology compatibility kit (TCK) tests.
+ */
+public class JackrabbitJcrTckTest {
+
+    /**
+     * Wrapper so that the Jackrabbit TCK test suite gets picked up by the DNA Maven test target.
+     * 
+     * @return a new instance of {@link JCRTestSuite}.
+     */
+    public static Test suite() {
+        // Uncomment this to execute all tests
+        // return new JCRTestSuite();
+
+        // Uncomment this to execute level one tests only
+        return new JcrLevelOneTestSuite();
+    }
+
+    /** Test suite that includes all of the Jackrabbit TCK API tests <b>except</b> the level two tests. */
+    private static class JcrLevelOneTestSuite extends TestSuite {
+        public JcrLevelOneTestSuite() {
+            super("JCR 1.0 Level 1 API tests");
+
+            // We currently don't pass the tests in those suites that are commented out
+            // See https://jira.jboss.org/jira/browse/DNA-285
+
+            addTestSuite(org.apache.jackrabbit.test.api.RootNodeTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.NodeReadMethodsTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.PropertyTypeTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.NodeDiscoveringNodeTypesTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.BinaryPropertyTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.BooleanPropertyTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.DatePropertyTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.DoublePropertyTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.LongPropertyTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.NamePropertyTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.PathPropertyTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.ReferencePropertyTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.StringPropertyTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.UndefinedPropertyTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.NamespaceRegistryReadMethodsTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.NamespaceRemappingTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.NodeIteratorTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.PropertyReadMethodsTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.RepositoryDescriptorTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.SessionReadMethodsTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.WorkspaceReadMethodsTest.class);
+            addTestSuite(org.apache.jackrabbit.test.api.ReferenceableRootNodesTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.ExportSysViewTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.ExportDocViewTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.RepositoryLoginTest.class);
+
+            // These might not all be level one tests
+            // addTestSuite(org.apache.jackrabbit.test.api.query.XPathPosIndexTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.XPathDocOrderTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.XPathOrderByTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.XPathJcrPathTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.DerefQueryLevel1Test.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.GetLanguageTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.GetPersistentQueryPathLevel1Test.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.GetStatementTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.GetSupportedQueryLanguagesTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.GetPropertyNamesTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.PredicatesTest.class);
+            // addTestSuite(org.apache.jackrabbit.test.api.query.SimpleSelectionTest.class);
+
+            // The tests in this suite are level one
+            // addTest(org.apache.jackrabbit.test.api.nodetype.TestAll.suite());
+        }
+
+    }
+
+    /**
+     * Concrete implementation of {@link RepositoryStub} based on DNA-specific configuration.
+     */
+    public static class InMemoryRepositoryStub extends RepositoryStub {
+        private Repository repository;
+        protected RepositoryConnection connection;
+        protected AccessControlContext accessControlContext = AccessController.getContext();
+
+        private Credentials credentials = new Credentials() {
+            private static final long serialVersionUID = 1L;
+
+            @SuppressWarnings( "unused" )
+            public AccessControlContext getAccessControlContext() {
+                return accessControlContext;
+            }
+        };
+
+        protected ExecutionContext executionContext = new ExecutionContext() {
+
+            @Override
+            public ExecutionContext create( AccessControlContext accessControlContext ) {
+                return executionContext;
+            }
+        };
+
+        protected RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
+            public RepositoryConnection createConnection( String sourceName ) {
+                return connection;
+            }
+        };
+
+        public InMemoryRepositoryStub( Properties env ) {
+            super(env);
+
+            // Create the in-memory (DNA) repository
+            InMemoryRepositorySource source = new InMemoryRepositorySource();
+
+            // Various calls will fail if you do not set a non-null name for the source
+            source.setName("TestRepositorySource");
+
+            // Wrap a connection to the in-memory (DNA) repository in a (JCR) repository
+            connection = source.getConnection();
+            repository = new JcrRepository(Collections.<String, String>emptyMap(), executionContext.create(accessControlContext),
+                                           connectionFactory);
+
+            // Set up some sample nodes in the graph to match the expected test configuration
+            try {
+
+                // TODO: Should there be an easier way to define these since they will be needed for all JCR repositories?
+                executionContext.getNamespaceRegistry().register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
+                executionContext.getNamespaceRegistry().register(JcrLexicon.Namespace.PREFIX, JcrLexicon.Namespace.URI);
+                executionContext.getNamespaceRegistry().register(JcrNtLexicon.Namespace.PREFIX, JcrNtLexicon.Namespace.URI);
+                executionContext.getNamespaceRegistry().register("sv", "http://www.jcp.org/jcr/sv/1.0");
+
+                Path destinationPath = executionContext.getValueFactories().getPathFactory().create("/");
+                Graph graph = Graph.create(source.getName(), connectionFactory, executionContext);
+                GraphImporter importer = new GraphImporter(graph);
+
+                URI xmlContent = new File("src/test/resources/repositoryJackrabbitTck.xml").toURI();
+                Graph.Batch batch = importer.importXml(xmlContent, Location.create(destinationPath));
+                batch.execute();
+
+            } catch (Exception ex) {
+                // The TCK tries to quash this exception. Print it out to be more obvious.
+                ex.printStackTrace();
+                throw new IllegalStateException("Repository initialization failed.", ex);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see org.apache.jackrabbit.test.RepositoryStub#getSuperuserCredentials()
+         */
+        @Override
+        public Credentials getSuperuserCredentials() {
+            // TODO: Why must we override this method? The default TCK implementation just returns a particular instance of
+            // SimpleCredentials.
+            return credentials;
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see org.apache.jackrabbit.test.RepositoryStub#getReadOnlyCredentials()
+         */
+        @Override
+        public Credentials getReadOnlyCredentials() {
+            // TODO: Why must we override this method? The default TCK implementation just returns a particular instance of
+            // SimpleCredentials.
+            return credentials;
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see org.apache.jackrabbit.test.RepositoryStub#getRepository()
+         */
+        @Override
+        public Repository getRepository() {
+            return repository;
+        }
+
+    }
+
+}


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

Added: trunk/dna-jcr/src/test/resources/repositoryJackRabbitTck.xml
===================================================================
--- trunk/dna-jcr/src/test/resources/repositoryJackRabbitTck.xml	                        (rev 0)
+++ trunk/dna-jcr/src/test/resources/repositoryJackRabbitTck.xml	2009-02-20 17:09:38 UTC (rev 732)
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ 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.
+  ~
+  ~ JBoss DNA is free software. 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 distribution; if not, write to:
+  ~ Free Software Foundation, Inc.
+  ~ 51 Franklin Street, Fifth Floor
+  ~ Boston, MA  02110-1301  USA
+  -->
+<testroot xmlns:jcr="http://www.jcp.org/jcr/1.0">
+	<node jcr:name="node1" prop1="foo" />
+	<node jcr:name="node2" prop2="bar" />
+	<node jcr:name="node3" />
+	<node jcr:name="node4" />
+</testroot>
\ No newline at end of file


Property changes on: trunk/dna-jcr/src/test/resources/repositoryJackRabbitTck.xml
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties
===================================================================
--- trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties	                        (rev 0)
+++ trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties	2009-02-20 17:09:38 UTC (rev 732)
@@ -0,0 +1,9 @@
+javax.jcr.tck.repository_stub_impl=org.jboss.dna.jcr.JackrabbitJcrTckTest$InMemoryRepositoryStub
+javax.jcr.tck.testroot=/testroot
+javax.jcr.tck.nodename1=node1
+javax.jcr.tck.nodename2=node2
+javax.jcr.tck.nodename3=node3
+javax.jcr.tck.nodename4=node4
+javax.jcr.tck.propertyname1=prop1
+javax.jcr.tck.propertyname2=prop2
+javax.jcr.tck.workspacename=test


Property changes on: trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties
___________________________________________________________________
Name: svn:mime-type
   + text/plain



From dna-commits at lists.jboss.org  Mon Feb 23 10:55:51 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Mon, 23 Feb 2009 10:55:51 -0500
Subject: [dna-commits] DNA SVN: r733 - in trunk/dna-graph/src:
	test/java/org/jboss/dna/graph and 1 other directory.
Message-ID: <E1Lbd9r-00087b-Oz@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-23 10:55:50 -0500 (Mon, 23 Feb 2009)
New Revision: 733

Added:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java
Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
Log:
DNA-280 Create optimized versions of Location

Applied the patch to add different Location implementations, specialized for the more frequent use cases.

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java	2009-02-20 17:09:38 UTC (rev 732)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java	2009-02-23 15:55:50 UTC (rev 733)
@@ -24,12 +24,13 @@
 package org.jboss.dna.graph;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.UUID;
+
 import net.jcip.annotations.Immutable;
+
 import org.jboss.dna.common.text.TextEncoder;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.HashCode;
@@ -45,12 +46,12 @@
  * @author Randall Hauch
  */
 @Immutable
-public class Location implements Iterable<Property> {
+public abstract class Location implements Iterable<Property> {
 
     /**
      * Simple shared iterator instance that is used when there are no properties.
      */
-    private static final Iterator<Property> NO_ID_PROPERTIES_ITERATOR = new Iterator<Property>() {
+    protected static final Iterator<Property> NO_ID_PROPERTIES_ITERATOR = new Iterator<Property>() {
         public boolean hasNext() {
             return false;
         }
@@ -74,7 +75,7 @@
     public static Location create( Path path ) {
         CheckArg.isNotNull(path, "path");
 
-        return new Location(path, null);
+        return new PathLocation(path);
     }
 
     /**
@@ -88,7 +89,7 @@
     public static Location create( UUID uuid ) {
         CheckArg.isNotNull(uuid, "uuid");
         Property idProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-        return new Location(null, Collections.singletonList(idProperty));
+        return new PathPropertyLocation(null, idProperty);
     }
 
     /**
@@ -103,13 +104,7 @@
     public static Location create( Path path,
                                    UUID uuid ) {
         CheckArg.isNotNull(uuid, "uuid");
-        List<Property> idProperties = null;
-        if (uuid != null) {
-            Property idProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-            idProperties = Collections.singletonList(idProperty);
-        }
-
-        return new Location(path, idProperties);
+        return new PathPropertyLocation(path, new BasicSingleValueProperty(DnaLexicon.UUID, uuid));
     }
 
     /**
@@ -124,7 +119,7 @@
                                    Property idProperty ) {
         CheckArg.isNotNull(path, "path");
         CheckArg.isNotNull(idProperty, "idProperty");
-        return new Location(path, idProperty != null ? Collections.singletonList(idProperty) : null);
+        return new PathPropertyLocation(path, idProperty);
     }
 
     /**
@@ -147,7 +142,7 @@
         for (Property property : remainingIdProperties) {
             idProperties.add(property);
         }
-        return new Location(path, Collections.unmodifiableList(idProperties));
+        return new PathPropertiesLocation(path, idProperties);
     }
 
     /**
@@ -166,7 +161,7 @@
         for (Property property : idProperties) {
             idPropertiesList.add(property);
         }
-        return new Location(path, Collections.unmodifiableList(idPropertiesList));
+        return new PathPropertiesLocation(path, idPropertiesList);
     }
 
     /**
@@ -178,7 +173,7 @@
      */
     public static Location create( Property idProperty ) {
         CheckArg.isNotNull(idProperty, "idProperty");
-        return new Location(null, Collections.singletonList(idProperty));
+        return new PathPropertyLocation(null, idProperty);
     }
 
     /**
@@ -198,7 +193,7 @@
         for (Property property : remainingIdProperties) {
             idProperties.add(property);
         }
-        return new Location(null, Collections.unmodifiableList(idProperties));
+        return new PathPropertiesLocation(null, idProperties);
     }
 
     /**
@@ -214,7 +209,7 @@
         for (Property property : idProperties) {
             idPropertiesList.add(property);
         }
-        return new Location(null, Collections.unmodifiableList(idPropertiesList));
+        return new PathPropertiesLocation(null, idPropertiesList);
     }
 
     /**
@@ -226,89 +221,15 @@
      */
     public static Location create( List<Property> idProperties ) {
         CheckArg.isNotEmpty(idProperties, "idProperties");
-        return new Location(null, idProperties);
+        return new PathPropertiesLocation(null, idProperties);
     }
 
     /**
-     * Create a location defined by a path and multiple identification properties.
-     * 
-     * @param path the path
-     * @param idProperties the identification properties
-     * @return a new <code>Location</code> with the given path and identification properties
-     * @throws IllegalArgumentException if <code>path</code> is null, or if <code>idProperties</code> is empty
-     */
-    protected static Location create( Path path,
-                                      List<Property> idProperties ) {
-        CheckArg.isNotNull(path, "path");
-        CheckArg.isNotEmpty(idProperties, "idProperties");
-        return new Location(path, idProperties);
-    }
-
-    private final Path path;
-    private final List<Property> idProperties;
-
-    /**
-     * Create a new location with a given path and set of identification properties.
-     * 
-     * @param path the path
-     * @param idProperties the identification properties
-     */
-    protected Location( Path path,
-                        List<Property> idProperties ) {
-        this.path = path;
-        this.idProperties = idProperties;
-    }
-
-    /**
-     * Create a location from another but adding the supplied identification property. The new identification property will
-     * replace any existing identification property with the same name on the original.
-     * 
-     * @param original the original location
-     * @param newIdProperty the new identification property
-     * @throws IllegalArgumentException if <code>original</code> is null
-     */
-    protected Location( Location original,
-                        Property newIdProperty ) {
-        this.path = original.getPath();
-        if (original.hasIdProperties()) {
-            List<Property> originalIdProperties = original.getIdProperties();
-            if (newIdProperty == null) {
-                this.idProperties = original.idProperties;
-            } else {
-                List<Property> idProperties = new ArrayList<Property>(originalIdProperties.size() + 1);
-                for (Property property : originalIdProperties) {
-                    if (!newIdProperty.getName().equals(property.getName())) idProperties.add(property);
-                }
-                idProperties.add(newIdProperty);
-                this.idProperties = Collections.unmodifiableList(idProperties);
-            }
-        } else {
-            this.idProperties = Collections.singletonList(newIdProperty);
-        }
-    }
-
-    /**
-     * Create a location from another but adding the supplied identification property. The new identification property will
-     * replace any existing identification property with the same name on the original.
-     * 
-     * @param original the original location
-     * @param newPath the new path for the location
-     * @throws IllegalArgumentException if <code>original</code> is null
-     */
-    protected Location( Location original,
-                        Path newPath ) {
-        this.path = newPath != null ? newPath : original.getPath();
-        this.idProperties = original.idProperties;
-    }
-
-    /**
      * Get the path that (at least in part) defines this location.
      * 
      * @return the path, or null if this location is not defined with a path
      */
-    public Path getPath() {
-        return path;
-    }
+    public abstract Path getPath();
 
     /**
      * Return whether this location is defined (at least in part) by a path.
@@ -316,7 +237,7 @@
      * @return true if a {@link #getPath() path} helps define this location
      */
     public boolean hasPath() {
-        return path != null;
+        return getPath() != null;
     }
 
     /**
@@ -324,9 +245,7 @@
      * 
      * @return the identification properties, or null if this location is not defined with identification properties
      */
-    public List<Property> getIdProperties() {
-        return idProperties;
-    }
+    public abstract List<Property> getIdProperties();
 
     /**
      * Return whether this location is defined (at least in part) with identification properties.
@@ -334,7 +253,7 @@
      * @return true if a {@link #getIdProperties() identification properties} help define this location
      */
     public boolean hasIdProperties() {
-        return idProperties != null && idProperties.size() != 0;
+        return getIdProperties() != null && getIdProperties().size() != 0;
     }
 
     /**
@@ -346,8 +265,8 @@
      */
     public Property getIdProperty( Name name ) {
         CheckArg.isNotNull(name, "name");
-        if (idProperties != null) {
-            for (Property property : idProperties) {
+        if (getIdProperties() != null) {
+            for (Property property : getIdProperties()) {
                 if (property.getName().equals(name)) return property;
             }
         }
@@ -449,7 +368,7 @@
      * @see java.lang.Iterable#iterator()
      */
     public Iterator<Property> iterator() {
-        return idProperties != null ? idProperties.iterator() : NO_ID_PROPERTIES_ITERATOR;
+        return getIdProperties() != null ? getIdProperties().iterator() : NO_ID_PROPERTIES_ITERATOR;
     }
 
     /**
@@ -459,7 +378,7 @@
      */
     @Override
     public int hashCode() {
-        return HashCode.compute(path, idProperties);
+        return HashCode.compute(getPath(), getIdProperties());
     }
 
     /**
@@ -624,22 +543,14 @@
      * @param newIdProperty the new identification property, which may be null
      * @return the new location, or this location if the new identification property is null or empty
      */
-    public Location with( Property newIdProperty ) {
-        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
-        return new Location(this, newIdProperty);
-    }
-
+    public abstract Location with( Property newIdProperty );
     /**
      * Create a copy of this location that uses the supplied path.
      * 
      * @param newPath the new path for the location
      * @return the new location, or this location if the path is equal to this location's path
      */
-    public Location with( Path newPath ) {
-        if (newPath == null) return this;
-        if (!this.path.equals(newPath)) return new Location(this, newPath);
-        return this;
-    }
+    public abstract Location with( Path newPath );
 
     /**
      * Create a copy of this location that adds the supplied UUID as an identification property. The new identification property
@@ -648,14 +559,6 @@
      * @param uuid the new UUID, which may be null
      * @return the new location, or this location if the new identification property is null or empty
      */
-    public Location with( UUID uuid ) {
-        if (uuid == null) return this;
-        Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-        if (this.hasIdProperties()) {
-            Property existing = this.getIdProperty(DnaLexicon.UUID);
-            if (existing != null && existing.equals(newProperty)) return this;
-        }
-        return new Location(this, newProperty);
-    }
+    public abstract Location with( UUID uuid );
 
 }

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java	2009-02-23 15:55:50 UTC (rev 733)
@@ -0,0 +1,178 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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;
+
+import java.util.List;
+import java.util.UUID;
+
+import net.jcip.annotations.Immutable;
+
+import org.jboss.dna.common.text.TextEncoder;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+
+/**
+ * Special location type optimized for use when only a path is specified.
+ * This class should never be directly instantiated by users of the DNA framework.
+ * Instead, use @{link Location#create} to create the correct location.
+ *
+ * @see Location
+ */
+ at Immutable
+class PathLocation extends Location {
+
+	private final Path path;
+	private final int hashCode;
+
+	PathLocation(Path path) {
+		CheckArg.isNotNull(path, "path");
+
+		this.path = path;
+		
+		// Paths are immutable, so PathLocations are immutable...
+		// ... so we can cache the hash code.
+		hashCode = HashCode.compute(path);
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getPath()
+     */
+	@Override
+	public final Path getPath() {
+		return path;
+	}
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasPath()
+     */	
+	@Override
+	public final boolean hasPath() {
+		return true;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperties()
+     */	
+	@Override
+	public final List<Property> getIdProperties() {
+		return null;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */	
+	@Override
+	public final boolean hasIdProperties() {
+		return false;
+	}
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getUuid()
+     */	
+	@Override
+	public final UUID getUuid() {
+		return null;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hashCode()
+     */	
+	@Override
+	public int hashCode() {
+		return hashCode;
+	}
+		
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getString(NamespaceRegistry, TextEncoder, TextEncoder)
+     */	
+	@Override
+	public String getString(NamespaceRegistry namespaceRegistry, TextEncoder encoder, TextEncoder delimiterEncoder) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("{ ");
+		sb.append(path.getString(namespaceRegistry, encoder, delimiterEncoder));
+		sb.append(" }");
+		return sb.toString();
+	}
+
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Property)
+     */	
+	@Override
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+        return Location.create(path, newIdProperty);
+    }
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Path)
+     */	
+	@Override
+    public Location with( Path newPath ) {
+        if (newPath == null) return this;
+        if (!this.getPath().equals(newPath)) return Location.create(newPath);
+        return this;
+    }	
+	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(UUID)
+     */
+	@Override
+    public Location with( UUID uuid ) {
+        if (uuid == null) return this;
+        Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+        if (this.hasIdProperties()) {
+            Property existing = this.getIdProperty(DnaLexicon.UUID);
+            if (existing != null && existing.equals(newProperty)) return this;
+        }
+        return Location.create(path, uuid);
+    }	
+}


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

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java	2009-02-23 15:55:50 UTC (rev 733)
@@ -0,0 +1,173 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import net.jcip.annotations.Immutable;
+
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+
+/**
+ * General purpose location type that supports a path and zero or more properties.
+ * This class should never be directly instantiated by users of the DNA framework.
+ * Instead, use @{link Location#create} to create the correct location.
+ *
+ * @see Location
+ */
+ at Immutable
+class PathPropertiesLocation extends Location {
+
+    private final Path path;
+    private final List<Property> idProperties;
+
+    private final int hashCode;
+    
+    /**
+     * Create a new location with a given path and set of identification properties.
+     * 
+     * @param path the path
+     * @param idProperties the identification properties
+     */
+	PathPropertiesLocation( Path path, List<Property> idProperties ) {
+		// The path could be null
+		// CheckArg.isNotNull(path, "path");
+		// If the properties are a null, a PathLocation should be used instead.
+		CheckArg.isNotNull(idProperties, "idProperties");
+		
+	    this.path = path;
+	    this.idProperties = Collections.unmodifiableList(idProperties);
+	    
+	    // Paths are immutable, Properties are immutable, the idProperties list 
+	    // is wrapped in an unmodifiableList by the Location factory methods...
+	    // ... so we can cache the hash code.
+	    
+	    hashCode = HashCode.compute(path, idProperties);
+	}
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getPath()
+     */
+	@Override
+	public final Path getPath() {
+		return path;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperties()
+     */	
+	@Override
+	public final List<Property> getIdProperties() {
+		return idProperties;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */	
+	@Override
+	public final boolean hasIdProperties() {
+		return idProperties.size() > 0;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hashCode()
+     */	
+	@Override
+	public int hashCode() {
+		return hashCode;
+	}	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Property)
+     */	
+	@Override
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+
+	    List<Property> newIdProperties;
+	    
+	    if (hasIdProperties()) {
+        	newIdProperties = new ArrayList<Property>(idProperties.size() + 1);
+            for (Property property : idProperties) {
+                if (!newIdProperty.getName().equals(property.getName())) newIdProperties.add(property);
+            }
+            newIdProperties.add(newIdProperty);
+            newIdProperties = Collections.unmodifiableList(newIdProperties);
+	    } else {
+	    	return Location.create(path, newIdProperty);
+	    }
+	    
+	    return new PathPropertiesLocation(path, newIdProperties);        
+    }    
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Path)
+     */	
+	@Override
+    public Location with( Path newPath ) {
+        if (newPath == null) return this;
+        if (!this.getPath().equals(newPath)) return Location.create(newPath, idProperties);
+        return this;
+    }	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(UUID)
+     */
+	@Override
+    public Location with( UUID uuid ) {
+        if (uuid == null) return this;
+        Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+        if (this.hasIdProperties()) {
+            Property existing = this.getIdProperty(DnaLexicon.UUID);
+            if (existing != null && existing.equals(newProperty)) return this;
+        }
+        
+        List<Property> newIdProperties = new ArrayList<Property>(idProperties.size() + 1);
+        newIdProperties.addAll(idProperties);
+        newIdProperties.add(newProperty);
+        
+        return Location.create(path, newIdProperties);
+    }	
+}


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

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java	2009-02-23 15:55:50 UTC (rev 733)
@@ -0,0 +1,197 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import net.jcip.annotations.Immutable;
+
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+
+/**
+ * General purpose location type that supports a path and a property.
+ * This class should never be directly instantiated by users of the DNA framework.
+ * Instead, use @{link Location#create} to create the correct location.
+ *
+ * @see Location
+ */
+ at Immutable
+class PathPropertyLocation extends Location {
+
+    private final Path path;
+    private final Property idProperty;
+    private final List<Property> idProperties;
+
+    private final int hashCode;
+    
+    /**
+     * Create a new location with a given path and identification property.
+     * 
+     * @param path the path
+     * @param idProperty the identification property
+     */
+    PathPropertyLocation( Path path, Property idProperty ) {
+		// The path could be null
+		// CheckArg.isNotNull(path, "path");
+		// If the properties are a null, a PathLocation should be used instead.
+		CheckArg.isNotNull(idProperty, "idProperty");
+		
+	    this.path = path;
+	    this.idProperty = idProperty;
+	    this.idProperties = Collections.singletonList(idProperty);
+	    
+	    // Paths are immutable, Properties are immutable, the idProperties list 
+	    // is wrapped in an unmodifiableList by the Location factory methods...
+	    // ... so we can cache the hash code.
+	    
+	    hashCode = HashCode.compute(path, idProperties);
+	}
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getPath()
+     */
+	@Override
+	public final Path getPath() {
+		return path;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperties()
+     */	
+	@Override
+	public final List<Property> getIdProperties() {
+		return idProperties;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */	
+	@Override
+	public final boolean hasIdProperties() {
+		return true;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperty(Name)
+     */	
+	@Override
+    public final Property getIdProperty( Name name ) {
+        CheckArg.isNotNull(name, "name");
+	    if (idProperty.getName().equals(name)) return idProperty;
+
+	    return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getUuid()
+     */	
+	@Override
+    public UUID getUuid() {
+		if (DnaLexicon.UUID.equals(idProperty.getName())) {
+            Object value = idProperty.getFirstValue();
+            if (value instanceof UUID) return (UUID)value;
+        }
+        return null;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hashCode()
+     */	
+	@Override
+	public int hashCode() {
+		return hashCode;
+	}	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Property)
+     */	
+	@Override
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+        
+        // A new property with same name overrides the old property with the same name
+        if (newIdProperty.getName().equals(idProperty.getName())) return Location.create(path, newIdProperty);
+        
+        List<Property> newIdProperties = new ArrayList<Property>(2);
+        newIdProperties.add(idProperty);
+        newIdProperties.add(newIdProperty);
+                
+        return Location.create(path, newIdProperties);
+    }    
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Path)
+     */	
+	@Override
+    public Location with( Path newPath ) {
+        if (newPath == null && path == null) return this;
+        if (path != null && (path.equals(newPath))) return this;
+        
+        return Location.create(newPath, idProperty);
+    }	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(UUID)
+     */
+	@Override
+    public Location with( UUID uuid ) {
+        if (uuid == null) return this;
+        
+        // A new property with same name overrides the old property with the same name
+        if (idProperty.getName().equals(DnaLexicon.UUID)) return Location.create(path, uuid);
+        
+        List<Property> newIdProperties = new ArrayList<Property>(2);
+        newIdProperties.add(idProperty);
+        newIdProperties.add(new BasicSingleValueProperty(DnaLexicon.UUID, uuid));
+        
+        return Location.create(path, newIdProperties);
+    }	
+}


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

Added: trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java	2009-02-23 15:55:50 UTC (rev 733)
@@ -0,0 +1,235 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.jboss.dna.common.text.NoOpEncoder;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+import org.jboss.dna.graph.property.basic.NameValueFactory;
+import org.jboss.dna.graph.property.basic.PathValueFactory;
+import org.jboss.dna.graph.property.basic.StringValueFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+/**
+ * Tests <code>Location</code> class and factory constructors.
+ */
+public class LocationTest {
+
+	private static final NoOpEncoder NO_OP_ENCODER = new NoOpEncoder();
+	private static final StringValueFactory STRING_VALUE_FACTORY = new StringValueFactory(NO_OP_ENCODER, NO_OP_ENCODER);
+	private static final NameValueFactory NAME_VALUE_FACTORY = new NameValueFactory(new BasicNamespaceRegistry("http://www.jboss.org/dna/1.0"), NO_OP_ENCODER, STRING_VALUE_FACTORY);
+	
+	private PathFactory pathFactory = new PathValueFactory(NO_OP_ENCODER, 
+			STRING_VALUE_FACTORY, NAME_VALUE_FACTORY);
+	
+	private static UUID uuid = UUID.randomUUID();
+	
+	private Path pathA = pathFactory.create("/A");
+	private Path pathABC = pathFactory.create("/A/B/C");
+
+	private static Property propA = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("A"), "Value A");
+	private static Property propB = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("B"), "Value B");
+	private static Property propU = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+	
+	private static List<Property> propListAB;
+	private static List<Property> propListABU;
+	
+	
+    @BeforeClass
+    public static void beforeAny() { 
+    	propListAB = new ArrayList<Property>();
+    	propListAB.add(propA);
+    	propListAB.add(propB);
+
+    	propListABU = new ArrayList<Property>();
+    	propListABU.add(propA);
+    	propListABU.add(propB);
+    	propListABU.add(propU);
+
+    }
+    
+    @Test
+    public void locationsWithSamePathsAreEqual() {
+    	Location locationA1 = Location.create(pathA);
+    	Location locationA2 = Location.create(pathA);
+    	
+    	assertThat("Locations created with identical paths must be equal", locationA1, is(locationA2));
+    	
+    	Location locationABC1 = Location.create(pathABC);
+    	Location locationABC2 = Location.create(pathABC);
+    	
+    	assertThat("Locations created with identical non-trivial paths must be equal", locationABC1, is(locationABC2));
+    }
+
+    @Test
+    public void locationsWithSamePathsAreSame() {
+    	Location locationA1 = Location.create(pathA);
+    	Location locationA2 = Location.create(pathA);
+    	
+    	assertThat("isSame must return true for locations created with identical paths", locationA1.isSame(locationA2), is(true));
+    	
+    	Location locationABC1 = Location.create(pathABC);
+    	Location locationABC2 = Location.create(pathABC);
+    	
+    	assertThat("isSame must return true for locations created with identical, non-trivial paths", locationABC1.isSame(locationABC2), is(true));
+    }
+
+    @Test
+    public void locationsWithSamePathsAndSamePropertyAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathA, propA);
+    	
+    	assertThat("Locations created with identical paths and different property must be equal", locationA1, is(locationA2));
+    }    
+
+    @Test
+    public void locationsWithSamePathsAndSamePropertyAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathA, propA);
+    	
+    	assertThat("isSame must return true for locations created with identical paths and property", locationA1.isSame(locationA2), is(true));
+    }   
+    
+    @Test
+    public void locationsWithSamePathsAndDifferentPropertyAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathA, propB);
+    	
+    	assertThat("Locations created with identical paths and different property must not be equal", locationA1, not(locationA2));
+    }    
+
+    @Test
+    public void locationsWithSamePathsAndDifferentPropertyAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathA, propB);
+    	
+    	assertThat("isSame must not return true for locations created with identical paths and property", locationA1.isSame(locationA2), is(false));
+    }    
+    
+    @Test
+    public void locationsWithDifferentPathsAndSamePropertyAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathABC, propA);
+    	
+    	assertThat("Locations created with different paths and the same property must not be equal", locationA1, not(locationA2));
+    }    
+
+    @Test
+    public void locationsWithDifferentPathsAndSamePropertyAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathABC, propA);
+    	
+    	assertThat("isSame must not return true for locations created with different paths and the same property", locationA1.isSame(locationA2), is(false));
+    }      
+
+    @Test
+    public void locationsWithSamePathsAndSamePropertiesAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathA, propListAB);
+    	
+    	assertThat("Locations created with identical paths and different properties must be equal", locationA1, is(locationA2));
+    }    
+
+    @Test
+    public void locationsWithSamePathsAndSamePropertiesAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathA, propListAB);
+    	
+    	assertThat("isSame must return true for locations created with identical paths and properties", locationA1.isSame(locationA2), is(true));
+    }   
+    
+    @Test
+    public void locationsWithSamePathsAndDifferentPropertiesAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathA, propListABU);
+    	
+    	assertThat("Locations created with identical paths and different properties must not be equal", locationA1, not(locationA2));
+    }    
+
+    @Test
+    public void locationsWithSamePathsAndDifferentPropertiesAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathA, propListABU);
+    	
+    	assertThat("isSame must not return true for locations created with identical paths and different properties", locationA1.isSame(locationA2), is(false));
+    }    
+    
+    @Test
+    public void locationsWithDifferentPathsAndSamePropertiesAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathABC, propListAB);
+    	
+    	assertThat("Locations created with identical paths and different properties must not be equal", locationA1, not(locationA2));
+    }    
+
+    @Test
+    public void locationsWithDifferentPathsAndSamePropertiesAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathABC, propListAB);
+    	
+    	assertThat("isSame must not return true for locations created with different paths and the same properties", locationA1.isSame(locationA2), is(false));
+    }    
+    
+    @Test
+    public void testTransitivityOfWithOperationForPathAndUUID() {
+    	Location locationA1 = Location.create(pathA);
+    	locationA1 = locationA1.with(uuid);
+    	
+    	Location locationU1 = Location.create(uuid);
+    	locationU1 = locationU1.with(pathA);
+    	
+    	assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true));
+    	assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true));
+    	assertThat("With() operation must be transitive for getString", locationA1.getString().equals(locationU1.getString()), is(true));
+    	assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true));
+    }
+        
+    @Test
+    public void testTransitivityOfWithOperationForPathAndProperty() {
+    	Location locationA1 = Location.create(pathA);
+    	locationA1 = locationA1.with(propB);
+    	
+    	Location locationU1 = Location.create(propB);
+    	locationU1 = locationU1.with(pathA);
+    	
+    	assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true));
+    	assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true));
+    	assertThat("With() operation must be transitive for getString", locationA1.getString().equals(locationU1.getString()), is(true));
+    	assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true));
+    } 
+
+}


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



From dna-commits at lists.jboss.org  Mon Feb 23 12:56:28 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Mon, 23 Feb 2009 12:56:28 -0500
Subject: [dna-commits] DNA SVN: r734 -
	trunk/dna-graph/src/main/java/org/jboss/dna/graph.
Message-ID: <E1Lbf2a-0003c4-IF@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-23 12:56:28 -0500 (Mon, 23 Feb 2009)
New Revision: 734

Added:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPath.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperties.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperty.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithUuid.java
Removed:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java
Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
Log:
DNA-280 Create optimized versions of Location

Minor changes and improvements, including removal of duplicate CheckArg method calls.  Renamed *Location classes to Location* to follow some other naming patterns ("convention" is too harsh).  Also added LocationWithUuid, since we'll have a lot of Location objects that have only the UUID (not nearly as much as path+uuid, which is covered by LocationWithPathAndProperty).

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java	2009-02-23 15:55:50 UTC (rev 733)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java	2009-02-23 17:56:28 UTC (rev 734)
@@ -24,13 +24,13 @@
 package org.jboss.dna.graph;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.Set;
 import java.util.UUID;
-
 import net.jcip.annotations.Immutable;
-
 import org.jboss.dna.common.text.TextEncoder;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.HashCode;
@@ -75,7 +75,7 @@
     public static Location create( Path path ) {
         CheckArg.isNotNull(path, "path");
 
-        return new PathLocation(path);
+        return new LocationWithPath(path);
     }
 
     /**
@@ -88,8 +88,7 @@
      */
     public static Location create( UUID uuid ) {
         CheckArg.isNotNull(uuid, "uuid");
-        Property idProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-        return new PathPropertyLocation(null, idProperty);
+        return new LocationWithUuid(uuid);
     }
 
     /**
@@ -104,7 +103,7 @@
     public static Location create( Path path,
                                    UUID uuid ) {
         CheckArg.isNotNull(uuid, "uuid");
-        return new PathPropertyLocation(path, new BasicSingleValueProperty(DnaLexicon.UUID, uuid));
+        return new LocationWithPathAndProperty(path, new BasicSingleValueProperty(DnaLexicon.UUID, uuid));
     }
 
     /**
@@ -119,7 +118,7 @@
                                    Property idProperty ) {
         CheckArg.isNotNull(path, "path");
         CheckArg.isNotNull(idProperty, "idProperty");
-        return new PathPropertyLocation(path, idProperty);
+        return new LocationWithPathAndProperty(path, idProperty);
     }
 
     /**
@@ -138,11 +137,13 @@
         CheckArg.isNotNull(firstIdProperty, "firstIdProperty");
         CheckArg.isNotNull(remainingIdProperties, "remainingIdProperties");
         List<Property> idProperties = new ArrayList<Property>(1 + remainingIdProperties.length);
+        Set<Name> names = new HashSet<Name>();
+        names.add(firstIdProperty.getName());
         idProperties.add(firstIdProperty);
         for (Property property : remainingIdProperties) {
-            idProperties.add(property);
+            if (names.add(property.getName())) idProperties.add(property);
         }
-        return new PathPropertiesLocation(path, idProperties);
+        return new LocationWithPathAndProperties(path, idProperties);
     }
 
     /**
@@ -158,10 +159,18 @@
         CheckArg.isNotNull(path, "path");
         CheckArg.isNotNull(idProperties, "idProperties");
         List<Property> idPropertiesList = new ArrayList<Property>();
+        Set<Name> names = new HashSet<Name>();
         for (Property property : idProperties) {
-            idPropertiesList.add(property);
+            if (names.add(property.getName())) idPropertiesList.add(property);
         }
-        return new PathPropertiesLocation(path, idPropertiesList);
+        switch (idPropertiesList.size()) {
+            case 0:
+                return new LocationWithPath(path);
+            case 1:
+                return new LocationWithPathAndProperty(path, idPropertiesList.get(0));
+            default:
+                return new LocationWithPathAndProperties(path, idPropertiesList);
+        }
     }
 
     /**
@@ -173,7 +182,7 @@
      */
     public static Location create( Property idProperty ) {
         CheckArg.isNotNull(idProperty, "idProperty");
-        return new PathPropertyLocation(null, idProperty);
+        return new LocationWithPathAndProperty(null, idProperty);
     }
 
     /**
@@ -189,11 +198,13 @@
         CheckArg.isNotNull(firstIdProperty, "firstIdProperty");
         CheckArg.isNotNull(remainingIdProperties, "remainingIdProperties");
         List<Property> idProperties = new ArrayList<Property>(1 + remainingIdProperties.length);
+        Set<Name> names = new HashSet<Name>();
+        names.add(firstIdProperty.getName());
         idProperties.add(firstIdProperty);
         for (Property property : remainingIdProperties) {
-            idProperties.add(property);
+            if (names.add(property.getName())) idProperties.add(property);
         }
-        return new PathPropertiesLocation(null, idProperties);
+        return new LocationWithPathAndProperties(null, idProperties);
     }
 
     /**
@@ -206,14 +217,25 @@
     public static Location create( Iterable<Property> idProperties ) {
         CheckArg.isNotNull(idProperties, "idProperties");
         List<Property> idPropertiesList = new ArrayList<Property>();
+        Set<Name> names = new HashSet<Name>();
         for (Property property : idProperties) {
-            idPropertiesList.add(property);
+            if (names.add(property.getName())) idPropertiesList.add(property);
         }
-        return new PathPropertiesLocation(null, idPropertiesList);
+        switch (idPropertiesList.size()) {
+            case 0:
+                CheckArg.isNotEmpty(idPropertiesList, "idProperties");
+                assert false;
+                return null; // never get here
+            case 1:
+                return new LocationWithPathAndProperty(null, idPropertiesList.get(0));
+            default:
+                return new LocationWithPathAndProperties(null, idPropertiesList);
+        }
     }
 
     /**
-     * Create a location defined by multiple identification properties.
+     * Create a location defined by multiple identification properties. This method does not check whether the identification
+     * properties are duplicated.
      * 
      * @param idProperties the identification properties
      * @return a new <code>Location</code> with no path and the given identification properties.
@@ -221,7 +243,7 @@
      */
     public static Location create( List<Property> idProperties ) {
         CheckArg.isNotEmpty(idProperties, "idProperties");
-        return new PathPropertiesLocation(null, idProperties);
+        return new LocationWithPathAndProperties(null, idProperties);
     }
 
     /**
@@ -544,6 +566,7 @@
      * @return the new location, or this location if the new identification property is null or empty
      */
     public abstract Location with( Property newIdProperty );
+
     /**
      * Create a copy of this location that uses the supplied path.
      * 

Copied: trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPath.java (from rev 733, trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java)
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPath.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPath.java	2009-02-23 17:56:28 UTC (rev 734)
@@ -0,0 +1,164 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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;
+
+import java.util.List;
+import java.util.UUID;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.text.TextEncoder;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+
+/**
+ * Special location type optimized for use when only a path is specified. This class should never be directly instantiated by
+ * users of the DNA framework. Instead, use @{link Location#create} to create the correct location.
+ * 
+ * @see Location
+ */
+ at Immutable
+class LocationWithPath extends Location {
+
+    private final Path path;
+    private final int hashCode;
+
+    LocationWithPath( Path path ) {
+        assert path != null;
+        this.path = path;
+
+        // Paths are immutable, so PathLocations are immutable...
+        // ... so we can cache the hash code.
+        hashCode = HashCode.compute(path);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getPath()
+     */
+    @Override
+    public final Path getPath() {
+        return path;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasPath()
+     */
+    @Override
+    public final boolean hasPath() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperties()
+     */
+    @Override
+    public final List<Property> getIdProperties() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */
+    @Override
+    public final boolean hasIdProperties() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getUuid()
+     */
+    @Override
+    public final UUID getUuid() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return hashCode;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getString(NamespaceRegistry, TextEncoder, TextEncoder)
+     */
+    @Override
+    public String getString( NamespaceRegistry namespaceRegistry,
+                             TextEncoder encoder,
+                             TextEncoder delimiterEncoder ) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{ ");
+        sb.append(path.getString(namespaceRegistry, encoder, delimiterEncoder));
+        sb.append(" }");
+        return sb.toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Property)
+     */
+    @Override
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+        return Location.create(path, newIdProperty);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Path)
+     */
+    @Override
+    public Location with( Path newPath ) {
+        if (newPath == null || path.equals(newPath)) return this;
+        return Location.create(newPath);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(UUID)
+     */
+    @Override
+    public Location with( UUID uuid ) {
+        if (uuid == null) return this;
+        return Location.create(path, uuid);
+    }
+}


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

Copied: trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperties.java (from rev 733, trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java)
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperties.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperties.java	2009-02-23 17:56:28 UTC (rev 734)
@@ -0,0 +1,161 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+
+/**
+ * General purpose location type that supports a path and zero or more properties. This class should never be directly
+ * instantiated by users of the DNA framework. Instead, use @{link Location#create} to create the correct location.
+ * 
+ * @see Location
+ */
+ at Immutable
+class LocationWithPathAndProperties extends Location {
+
+    private final Path path;
+    private final List<Property> idProperties;
+
+    private final int hashCode;
+
+    /**
+     * Create a new location with a given path and set of identification properties.
+     * 
+     * @param path the path
+     * @param idProperties the identification properties
+     */
+    LocationWithPathAndProperties( Path path,
+                            List<Property> idProperties ) {
+        assert idProperties != null;
+        assert !idProperties.isEmpty();
+        this.path = path;
+        this.idProperties = Collections.unmodifiableList(idProperties);
+        // Paths are immutable, Properties are immutable, the idProperties list
+        // is wrapped in an unmodifiableList by the Location factory methods...
+        // ... so we can cache the hash code.
+        hashCode = HashCode.compute(path, idProperties);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getPath()
+     */
+    @Override
+    public final Path getPath() {
+        return path;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperties()
+     */
+    @Override
+    public final List<Property> getIdProperties() {
+        return idProperties;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */
+    @Override
+    public final boolean hasIdProperties() {
+        return idProperties.size() > 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return hashCode;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Property)
+     */
+    @Override
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+
+        List<Property> newIdProperties;
+
+        if (hasIdProperties()) {
+            newIdProperties = new ArrayList<Property>(idProperties.size() + 1);
+            for (Property property : idProperties) {
+                if (!newIdProperty.getName().equals(property.getName())) newIdProperties.add(property);
+            }
+            newIdProperties.add(newIdProperty);
+            newIdProperties = Collections.unmodifiableList(newIdProperties);
+            return new LocationWithPathAndProperties(path, newIdProperties);
+        }
+        return Location.create(path, newIdProperty);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Path)
+     */
+    @Override
+    public Location with( Path newPath ) {
+        if (newPath == null || this.getPath().equals(newPath)) return this;
+        return Location.create(newPath, idProperties);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(UUID)
+     */
+    @Override
+    public Location with( UUID uuid ) {
+        if (uuid == null) return this;
+        Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+        if (this.hasIdProperties()) {
+            Property existing = this.getIdProperty(DnaLexicon.UUID);
+            if (existing != null && existing.equals(newProperty)) return this;
+        }
+
+        List<Property> newIdProperties = new ArrayList<Property>(idProperties.size() + 1);
+        newIdProperties.addAll(idProperties);
+        newIdProperties.add(newProperty);
+        return Location.create(path, newIdProperties);
+    }
+}


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

Copied: trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperty.java (from rev 733, trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java)
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperty.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperty.java	2009-02-23 17:56:28 UTC (rev 734)
@@ -0,0 +1,182 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+
+/**
+ * General purpose location type that supports a path and a property. This class should never be directly instantiated by users of
+ * the DNA framework. Instead, use @{link Location#create} to create the correct location.
+ * 
+ * @see Location
+ */
+ at Immutable
+class LocationWithPathAndProperty extends Location {
+
+    private final Path path;
+    private final List<Property> idProperties;
+
+    private final int hashCode;
+
+    /**
+     * Create a new location with a given path and identification property.
+     * 
+     * @param path the path
+     * @param idProperty the identification property
+     */
+    LocationWithPathAndProperty( Path path,
+                                 Property idProperty ) {
+        assert idProperty != null;
+        assert !idProperty.isEmpty();
+        // The path could be null
+        this.path = path;
+        this.idProperties = Collections.singletonList(idProperty);
+
+        // Paths are immutable, Properties are immutable, the idProperties list
+        // is wrapped in an unmodifiableList by the Location factory methods...
+        // ... so we can cache the hash code.
+        hashCode = HashCode.compute(path, idProperties);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getPath()
+     */
+    @Override
+    public final Path getPath() {
+        return path;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperties()
+     */
+    @Override
+    public final List<Property> getIdProperties() {
+        return idProperties;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */
+    @Override
+    public final boolean hasIdProperties() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperty(Name)
+     */
+    @Override
+    public final Property getIdProperty( Name name ) {
+        CheckArg.isNotNull(name, "name");
+        Property property = idProperties.get(0); // this is fast
+        return property.getName().equals(name) ? property : null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getUuid()
+     */
+    @Override
+    public UUID getUuid() {
+        Property property = idProperties.get(0); // this is fast
+        if (DnaLexicon.UUID.equals(property.getName())) {
+            Object value = property.getFirstValue();
+            if (value instanceof UUID) return (UUID)value;
+            if (value instanceof String) return UUID.fromString((String)value);
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return hashCode;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Property)
+     */
+    @Override
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+        Property idProperty = idProperties.get(0); // fast
+        if (newIdProperty.getName().equals(idProperty.getName())) {
+            return path == null ? Location.create(newIdProperty) : Location.create(path, newIdProperty);
+        }
+        return path == null ? Location.create(idProperty, newIdProperty) : Location.create(path, idProperty, newIdProperty);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Path)
+     */
+    @Override
+    public Location with( Path newPath ) {
+        if (newPath == null && path == null) return this;
+        if (path != null && (path.equals(newPath))) return this;
+        Property idProperty = idProperties.get(0); // fast
+        return Location.create(newPath, idProperty);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(UUID)
+     */
+    @Override
+    public Location with( UUID uuid ) {
+        if (uuid == null) return this;
+        Property idProperty = idProperties.get(0); // fast
+        if (DnaLexicon.UUID.equals(idProperty.getName())) {
+            return path == null ? Location.create(uuid) : Location.create(path, uuid);
+        }
+        Property newUuidProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+        return path == null ? Location.create(idProperty, newUuidProperty) : Location.create(path, idProperty, newUuidProperty);
+    }
+}


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

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithUuid.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithUuid.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithUuid.java	2009-02-23 17:56:28 UTC (rev 734)
@@ -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.graph;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+
+/**
+ * Special location type optimized for use when only a {@link UUID} is specified. This class should never be directly instantiated
+ * by users of the DNA framework. Instead, use @{link Location#create} to create the correct location.
+ * 
+ * @see Location
+ */
+ at Immutable
+public class LocationWithUuid extends Location {
+
+    private final UUID uuid;
+    private final int hashCode;
+    private final List<Property> properties;
+
+    LocationWithUuid( UUID uuid ) {
+        assert uuid != null;
+        this.uuid = uuid;
+        Property uuidProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+        this.properties = Collections.singletonList(uuidProperty);
+        this.hashCode = HashCode.compute(null, this.properties);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.Location#getIdProperties()
+     */
+    @Override
+    public List<Property> getIdProperties() {
+        return properties;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.Location#getPath()
+     */
+    @Override
+    public Path getPath() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */
+    @Override
+    public final boolean hasIdProperties() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.Location#hasPath()
+     */
+    @Override
+    public boolean hasPath() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.Location#getUuid()
+     */
+    @Override
+    public UUID getUuid() {
+        return this.uuid;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.Location#with(org.jboss.dna.graph.property.Property)
+     */
+    @Override
+    public Location with( Property newIdProperty ) {
+        return Location.create(getIdProperties().get(0), newIdProperty);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.Location#with(org.jboss.dna.graph.property.Path)
+     */
+    @Override
+    public Location with( Path newPath ) {
+        return Location.create(newPath, uuid);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.Location#with(java.util.UUID)
+     */
+    @Override
+    public Location with( UUID uuid ) {
+        return new LocationWithUuid(uuid);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.Location#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return hashCode;
+    }
+}


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

Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java	2009-02-23 15:55:50 UTC (rev 733)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java	2009-02-23 17:56:28 UTC (rev 734)
@@ -1,178 +0,0 @@
-/*
- * 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. 
- *
- * JBoss DNA is free software. 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;
-
-import java.util.List;
-import java.util.UUID;
-
-import net.jcip.annotations.Immutable;
-
-import org.jboss.dna.common.text.TextEncoder;
-import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.common.util.HashCode;
-import org.jboss.dna.graph.property.NamespaceRegistry;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
-
-/**
- * Special location type optimized for use when only a path is specified.
- * This class should never be directly instantiated by users of the DNA framework.
- * Instead, use @{link Location#create} to create the correct location.
- *
- * @see Location
- */
- at Immutable
-class PathLocation extends Location {
-
-	private final Path path;
-	private final int hashCode;
-
-	PathLocation(Path path) {
-		CheckArg.isNotNull(path, "path");
-
-		this.path = path;
-		
-		// Paths are immutable, so PathLocations are immutable...
-		// ... so we can cache the hash code.
-		hashCode = HashCode.compute(path);
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getPath()
-     */
-	@Override
-	public final Path getPath() {
-		return path;
-	}
-
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#hasPath()
-     */	
-	@Override
-	public final boolean hasPath() {
-		return true;
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getIdProperties()
-     */	
-	@Override
-	public final List<Property> getIdProperties() {
-		return null;
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#hasIdProperties()
-     */	
-	@Override
-	public final boolean hasIdProperties() {
-		return false;
-	}
-
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getUuid()
-     */	
-	@Override
-	public final UUID getUuid() {
-		return null;
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#hashCode()
-     */	
-	@Override
-	public int hashCode() {
-		return hashCode;
-	}
-		
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getString(NamespaceRegistry, TextEncoder, TextEncoder)
-     */	
-	@Override
-	public String getString(NamespaceRegistry namespaceRegistry, TextEncoder encoder, TextEncoder delimiterEncoder) {
-		StringBuilder sb = new StringBuilder();
-		sb.append("{ ");
-		sb.append(path.getString(namespaceRegistry, encoder, delimiterEncoder));
-		sb.append(" }");
-		return sb.toString();
-	}
-
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#with(Property)
-     */	
-	@Override
-    public Location with( Property newIdProperty ) {
-        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
-        return Location.create(path, newIdProperty);
-    }
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#with(Path)
-     */	
-	@Override
-    public Location with( Path newPath ) {
-        if (newPath == null) return this;
-        if (!this.getPath().equals(newPath)) return Location.create(newPath);
-        return this;
-    }	
-	
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#with(UUID)
-     */
-	@Override
-    public Location with( UUID uuid ) {
-        if (uuid == null) return this;
-        Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-        if (this.hasIdProperties()) {
-            Property existing = this.getIdProperty(DnaLexicon.UUID);
-            if (existing != null && existing.equals(newProperty)) return this;
-        }
-        return Location.create(path, uuid);
-    }	
-}

Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java	2009-02-23 15:55:50 UTC (rev 733)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java	2009-02-23 17:56:28 UTC (rev 734)
@@ -1,173 +0,0 @@
-/*
- * 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. 
- *
- * JBoss DNA is free software. 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;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
-
-import net.jcip.annotations.Immutable;
-
-import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.common.util.HashCode;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
-
-/**
- * General purpose location type that supports a path and zero or more properties.
- * This class should never be directly instantiated by users of the DNA framework.
- * Instead, use @{link Location#create} to create the correct location.
- *
- * @see Location
- */
- at Immutable
-class PathPropertiesLocation extends Location {
-
-    private final Path path;
-    private final List<Property> idProperties;
-
-    private final int hashCode;
-    
-    /**
-     * Create a new location with a given path and set of identification properties.
-     * 
-     * @param path the path
-     * @param idProperties the identification properties
-     */
-	PathPropertiesLocation( Path path, List<Property> idProperties ) {
-		// The path could be null
-		// CheckArg.isNotNull(path, "path");
-		// If the properties are a null, a PathLocation should be used instead.
-		CheckArg.isNotNull(idProperties, "idProperties");
-		
-	    this.path = path;
-	    this.idProperties = Collections.unmodifiableList(idProperties);
-	    
-	    // Paths are immutable, Properties are immutable, the idProperties list 
-	    // is wrapped in an unmodifiableList by the Location factory methods...
-	    // ... so we can cache the hash code.
-	    
-	    hashCode = HashCode.compute(path, idProperties);
-	}
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getPath()
-     */
-	@Override
-	public final Path getPath() {
-		return path;
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getIdProperties()
-     */	
-	@Override
-	public final List<Property> getIdProperties() {
-		return idProperties;
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#hasIdProperties()
-     */	
-	@Override
-	public final boolean hasIdProperties() {
-		return idProperties.size() > 0;
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#hashCode()
-     */	
-	@Override
-	public int hashCode() {
-		return hashCode;
-	}	
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#with(Property)
-     */	
-	@Override
-    public Location with( Property newIdProperty ) {
-        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
-
-	    List<Property> newIdProperties;
-	    
-	    if (hasIdProperties()) {
-        	newIdProperties = new ArrayList<Property>(idProperties.size() + 1);
-            for (Property property : idProperties) {
-                if (!newIdProperty.getName().equals(property.getName())) newIdProperties.add(property);
-            }
-            newIdProperties.add(newIdProperty);
-            newIdProperties = Collections.unmodifiableList(newIdProperties);
-	    } else {
-	    	return Location.create(path, newIdProperty);
-	    }
-	    
-	    return new PathPropertiesLocation(path, newIdProperties);        
-    }    
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#with(Path)
-     */	
-	@Override
-    public Location with( Path newPath ) {
-        if (newPath == null) return this;
-        if (!this.getPath().equals(newPath)) return Location.create(newPath, idProperties);
-        return this;
-    }	
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#with(UUID)
-     */
-	@Override
-    public Location with( UUID uuid ) {
-        if (uuid == null) return this;
-        Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-        if (this.hasIdProperties()) {
-            Property existing = this.getIdProperty(DnaLexicon.UUID);
-            if (existing != null && existing.equals(newProperty)) return this;
-        }
-        
-        List<Property> newIdProperties = new ArrayList<Property>(idProperties.size() + 1);
-        newIdProperties.addAll(idProperties);
-        newIdProperties.add(newProperty);
-        
-        return Location.create(path, newIdProperties);
-    }	
-}

Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java	2009-02-23 15:55:50 UTC (rev 733)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java	2009-02-23 17:56:28 UTC (rev 734)
@@ -1,197 +0,0 @@
-/*
- * 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. 
- *
- * JBoss DNA is free software. 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;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
-
-import net.jcip.annotations.Immutable;
-
-import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.common.util.HashCode;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
-
-/**
- * General purpose location type that supports a path and a property.
- * This class should never be directly instantiated by users of the DNA framework.
- * Instead, use @{link Location#create} to create the correct location.
- *
- * @see Location
- */
- at Immutable
-class PathPropertyLocation extends Location {
-
-    private final Path path;
-    private final Property idProperty;
-    private final List<Property> idProperties;
-
-    private final int hashCode;
-    
-    /**
-     * Create a new location with a given path and identification property.
-     * 
-     * @param path the path
-     * @param idProperty the identification property
-     */
-    PathPropertyLocation( Path path, Property idProperty ) {
-		// The path could be null
-		// CheckArg.isNotNull(path, "path");
-		// If the properties are a null, a PathLocation should be used instead.
-		CheckArg.isNotNull(idProperty, "idProperty");
-		
-	    this.path = path;
-	    this.idProperty = idProperty;
-	    this.idProperties = Collections.singletonList(idProperty);
-	    
-	    // Paths are immutable, Properties are immutable, the idProperties list 
-	    // is wrapped in an unmodifiableList by the Location factory methods...
-	    // ... so we can cache the hash code.
-	    
-	    hashCode = HashCode.compute(path, idProperties);
-	}
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getPath()
-     */
-	@Override
-	public final Path getPath() {
-		return path;
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getIdProperties()
-     */	
-	@Override
-	public final List<Property> getIdProperties() {
-		return idProperties;
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#hasIdProperties()
-     */	
-	@Override
-	public final boolean hasIdProperties() {
-		return true;
-	}
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getIdProperty(Name)
-     */	
-	@Override
-    public final Property getIdProperty( Name name ) {
-        CheckArg.isNotNull(name, "name");
-	    if (idProperty.getName().equals(name)) return idProperty;
-
-	    return null;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#getUuid()
-     */	
-	@Override
-    public UUID getUuid() {
-		if (DnaLexicon.UUID.equals(idProperty.getName())) {
-            Object value = idProperty.getFirstValue();
-            if (value instanceof UUID) return (UUID)value;
-        }
-        return null;
-    }
-
-    
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#hashCode()
-     */	
-	@Override
-	public int hashCode() {
-		return hashCode;
-	}	
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#with(Property)
-     */	
-	@Override
-    public Location with( Property newIdProperty ) {
-        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
-        
-        // A new property with same name overrides the old property with the same name
-        if (newIdProperty.getName().equals(idProperty.getName())) return Location.create(path, newIdProperty);
-        
-        List<Property> newIdProperties = new ArrayList<Property>(2);
-        newIdProperties.add(idProperty);
-        newIdProperties.add(newIdProperty);
-                
-        return Location.create(path, newIdProperties);
-    }    
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#with(Path)
-     */	
-	@Override
-    public Location with( Path newPath ) {
-        if (newPath == null && path == null) return this;
-        if (path != null && (path.equals(newPath))) return this;
-        
-        return Location.create(newPath, idProperty);
-    }	
-	
-    /**
-     * {@inheritDoc}
-     * 
-     * @see Location#with(UUID)
-     */
-	@Override
-    public Location with( UUID uuid ) {
-        if (uuid == null) return this;
-        
-        // A new property with same name overrides the old property with the same name
-        if (idProperty.getName().equals(DnaLexicon.UUID)) return Location.create(path, uuid);
-        
-        List<Property> newIdProperties = new ArrayList<Property>(2);
-        newIdProperties.add(idProperty);
-        newIdProperties.add(new BasicSingleValueProperty(DnaLexicon.UUID, uuid));
-        
-        return Location.create(path, newIdProperties);
-    }	
-}



From dna-commits at lists.jboss.org  Mon Feb 23 13:26:27 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Mon, 23 Feb 2009 13:26:27 -0500
Subject: [dna-commits] DNA SVN: r735 - in
	trunk/extensions/dna-sequencer-msoffice:
	src/main/java/org/jboss/dna/sequencer/msoffice/excel and 1
	other directory.
Message-ID: <E1LbfVb-0004i3-KB@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-23 13:26:27 -0500 (Mon, 23 Feb 2009)
New Revision: 735

Modified:
   trunk/extensions/dna-sequencer-msoffice/pom.xml
   trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/excel/ExcelMetadataReader.java
Log:
DNA-153 Add support for Microsoft Word document metadata

Applied the "Upgrade_POI_to_Latest" patch (see attachments), which looks good.  Uploaded "org.apache.poi:poi:3.2-FINAL" and "org.apache.poi:poi-scratchpad:3.2-FINAL" artifacts to the JBoss Maven 2 repository.

Modified: trunk/extensions/dna-sequencer-msoffice/pom.xml
===================================================================
--- trunk/extensions/dna-sequencer-msoffice/pom.xml	2009-02-23 17:56:28 UTC (rev 734)
+++ trunk/extensions/dna-sequencer-msoffice/pom.xml	2009-02-23 18:26:27 UTC (rev 735)
@@ -31,12 +31,12 @@
     <dependency>
         <groupId>org.apache.poi</groupId>
         <artifactId>poi</artifactId>
-        <version>3.1-beta2</version>
+        <version>3.2-FINAL</version>
     </dependency>
     <dependency>
         <groupId>org.apache.poi</groupId>
         <artifactId>poi-scratchpad</artifactId>
-        <version>3.1-beta2</version>
+        <version>3.2-FINAL</version>
     </dependency>
     <dependency>
       <groupId>junit</groupId>

Modified: trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/excel/ExcelMetadataReader.java
===================================================================
--- trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/excel/ExcelMetadataReader.java	2009-02-23 17:56:28 UTC (rev 734)
+++ trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/excel/ExcelMetadataReader.java	2009-02-23 18:26:27 UTC (rev 735)
@@ -27,7 +27,11 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
-import org.apache.poi.hssf.extractor.ExcelExtractor;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFComment;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 
@@ -37,18 +41,78 @@
  */
 public class ExcelMetadataReader {
 
+	/** The character to output after each row. */
+	private static final char ROW_DELIMITER_CHAR = '\n';
+	/** The character to output after each cell (column). */
+	private static final char CELL_DELIMITER_CHAR = '\t';
+	
     public static ExcelMetadata instance( InputStream stream ) throws IOException {
         ExcelMetadata metadata = new ExcelMetadata();
         HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(stream));
-        ExcelExtractor extractor = new ExcelExtractor(wb);
 
-        extractor.setFormulasNotResults(true);
-        extractor.setIncludeSheetNames(false);
-        metadata.setText(extractor.getText());
+        StringBuffer buff = new StringBuffer();
         List<String> sheets = new ArrayList<String>();
-        for (int i = 0; i < wb.getNumberOfSheets(); i++) {
-            sheets.add(wb.getSheetName(i));
+        
+        for (int sheetInd = 0; sheetInd < wb.getNumberOfSheets(); sheetInd++) {
+            sheets.add(wb.getSheetName(sheetInd));
+
+            HSSFSheet worksheet = wb.getSheetAt(sheetInd);
+            int lastRowNum = worksheet.getLastRowNum();
+            
+            for (int rowNum = worksheet.getFirstRowNum(); rowNum <= lastRowNum; rowNum++) {
+            	HSSFRow row = worksheet.getRow(rowNum);
+            	
+            	// Empty rows are returned as null
+            	if (row == null) {
+            		continue;
+            	}
+            	
+            	int lastCellNum = row.getLastCellNum();
+            	for (int cellNum = row.getFirstCellNum(); cellNum < lastCellNum; cellNum++) {
+            		HSSFCell cell = row.getCell(cellNum);
+            		
+            		/*
+            		 * Builds a string of body content from all string, numeric,
+            		 * and formula values in the body of each worksheet.
+            		 * 
+            		 *  This code currently duplicates the POI 3.1 ExcelExtractor behavior of
+            		 *  combining the body text from all worksheets into a single string.
+            		 */
+            		switch (cell.getCellType()) {
+	            		case HSSFCell.CELL_TYPE_STRING:
+	            			buff.append(cell.getRichStringCellValue().getString());
+	            			break;
+	            		case HSSFCell.CELL_TYPE_NUMERIC:
+	            			buff.append(cell.getNumericCellValue());
+	            			break;
+	            		case HSSFCell.CELL_TYPE_FORMULA:
+	            			buff.append(cell.getCellFormula());
+	            			break;
+            		}
+
+            		HSSFComment comment = cell.getCellComment();
+            		if (comment != null) {
+            			// Filter out row delimiter characters from comment
+            			String commentText = comment.getString().getString().replace(ROW_DELIMITER_CHAR, ' ');
+            			
+            			buff.append(" [");
+            			buff.append(commentText);
+            			buff.append(" by ");
+            			buff.append(comment.getAuthor());
+            			buff.append(']');
+            		}
+            		
+            		if (cellNum < lastCellNum - 1) {
+            			buff.append(CELL_DELIMITER_CHAR);
+            		}
+            		else {
+            			buff.append(ROW_DELIMITER_CHAR);
+            		}
+            	}
+            }
         }
+        
+        metadata.setText(buff.toString());
         metadata.setSheets(sheets);
         return metadata;
     }



From dna-commits at lists.jboss.org  Mon Feb 23 13:53:59 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Mon, 23 Feb 2009 13:53:59 -0500
Subject: [dna-commits] DNA SVN: r736 - in
	trunk/extensions/dna-sequencer-msoffice/src:
	main/java/org/jboss/dna/sequencer/msoffice/word and 3 other
	directories.
Message-ID: <E1LbfwF-0004Be-Ss@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-23 13:53:59 -0500 (Mon, 23 Feb 2009)
New Revision: 736

Added:
   trunk/extensions/dna-sequencer-msoffice/src/test/java/org/jboss/dna/sequencer/msoffice/word/
   trunk/extensions/dna-sequencer-msoffice/src/test/java/org/jboss/dna/sequencer/msoffice/word/WordMetadataTest.java
Modified:
   trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/MSOfficeMetadataSequencer.java
   trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/word/WordMetadata.java
   trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/word/WordMetadataReader.java
   trunk/extensions/dna-sequencer-msoffice/src/test/resources/word.doc
Log:
DNA-153 Add support for Microsoft Word document metadata

Applied the "Extract_Word_Headers" patch and copied the new "word.doc" file into the "src/test/resources" folder (see attachments).  Looks good; all tests now pass.

Modified: trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/MSOfficeMetadataSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/MSOfficeMetadataSequencer.java	2009-02-23 18:26:27 UTC (rev 735)
+++ trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/MSOfficeMetadataSequencer.java	2009-02-23 18:53:59 UTC (rev 736)
@@ -25,6 +25,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Iterator;
 import java.util.List;
 import org.jboss.dna.graph.sequencer.SequencerContext;
 import org.jboss.dna.graph.sequencer.SequencerOutput;
@@ -33,6 +34,7 @@
 import org.jboss.dna.sequencer.msoffice.excel.ExcelMetadataReader;
 import org.jboss.dna.sequencer.msoffice.powerpoint.PowerPointMetadataReader;
 import org.jboss.dna.sequencer.msoffice.powerpoint.SlideMetadata;
+import org.jboss.dna.sequencer.msoffice.word.WordMetadata;
 import org.jboss.dna.sequencer.msoffice.word.WordMetadataReader;
 
 /**
@@ -110,6 +112,11 @@
     // Excel specific
     public static final String EXCEL_FULL_CONTENT = "msoffice:full_contents";
     public static final String EXCEL_SHEET_NAME = "msoffice:sheet_name";
+    
+    // Word specific
+    public static final String WORD_HEADING_NODE = "msoffice:heading";
+    public static final String WORD_HEADING_NAME = "msoffice:heading_name";
+    public static final String WORD_HEADING_LEVEL = "msoffice:heading_level";
 
     /**
      * {@inheritDoc}
@@ -167,7 +174,16 @@
         if (mimeType.equals("application/vnd.ms-word")) {
             // Sometime in the future this will sequence WORD Table of contents.
             try {
-                /*WordMetadata wordMetadata =*/WordMetadataReader.invoke(stream);
+                WordMetadata wordMetadata = WordMetadataReader.instance(stream);
+
+                for (Iterator<WordMetadata.WordHeading> iter = wordMetadata.getHeadings().iterator(); iter.hasNext(); ) {
+                    WordMetadata.WordHeading heading = iter.next();
+                    
+                    output.setProperty(METADATA_NODE + "/" + WORD_HEADING_NODE, WORD_HEADING_NAME, heading.getText());
+                	output.setProperty(METADATA_NODE + "/" + WORD_HEADING_NODE, WORD_HEADING_LEVEL, heading.getHeaderLevel());
+                	
+                }
+                
             } catch (IOException e) {
                 // There was an error reading, so log and continue ...
                 context.getLogger(this.getClass()).debug(e, "Error while extracting the Word document metadata");

Modified: trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/word/WordMetadata.java
===================================================================
--- trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/word/WordMetadata.java	2009-02-23 18:26:27 UTC (rev 735)
+++ trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/word/WordMetadata.java	2009-02-23 18:53:59 UTC (rev 736)
@@ -24,10 +24,49 @@
 
 package org.jboss.dna.sequencer.msoffice.word;
 
+import java.util.List;
+
 /**
  * @author Michael Trezzi
  */
 public class WordMetadata {
 
+	private List<WordMetadata.WordHeading> headings;
 
+	public List<WordMetadata.WordHeading> getHeadings() {
+		return headings;
+	}
+
+	public void setHeadings(List<WordMetadata.WordHeading> headings) {
+		this.headings = headings;
+	}
+
+
+	public static class WordHeading {
+		private String text;
+		private int headingLevel;
+
+		public WordHeading(String text, int headerLevel) {
+			super();
+			this.text = text;
+			this.headingLevel = headerLevel;
+		}
+
+		public String getText() {
+			return text;
+		}
+		
+		public void setText(String text) {
+			this.text = text;
+		}
+		
+		public int getHeaderLevel() {
+			return headingLevel;
+		}
+		
+		public void setHeaderLevel(int headerLevel) {
+			this.headingLevel = headerLevel;
+		}
+		
+	}
 }

Modified: trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/word/WordMetadataReader.java
===================================================================
--- trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/word/WordMetadataReader.java	2009-02-23 18:26:27 UTC (rev 735)
+++ trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/word/WordMetadataReader.java	2009-02-23 18:53:59 UTC (rev 736)
@@ -26,22 +26,65 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.model.StyleSheet;
+import org.apache.poi.hwpf.usermodel.Paragraph;
+import org.apache.poi.hwpf.usermodel.Range;
+import org.jboss.dna.common.util.Logger;
 
 /**
- * Reades table of contents from Word document
+ * Infers table of contents from Word document by reading all paragraphs
+ * with style <code>Heading*</code>.  This is analogous to the default 
+ * behavior of Word when generating a table of contents.
  * 
  * @author Michael Trezzi
  */
 public class WordMetadataReader {
 
-    @SuppressWarnings( "null" )
-    public static WordMetadata invoke( InputStream stream ) throws IOException {
-        WordMetadata metadata = new WordMetadata();
+	private static final Logger log = Logger.getLogger(WordMetadataReader.class);
+	
+	/** Prefix for styles that will be extracted and treated as outline information for the document */
+	private static final String HEADER_PREFIX = "Heading";
+	
+    public static WordMetadata instance( InputStream stream ) throws IOException {
+        WordMetadata metadata = new WordMetadata();        
+        List<WordMetadata.WordHeading> headings = new ArrayList<WordMetadata.WordHeading>();
+
         HWPFDocument document = new HWPFDocument(stream);
-        if (document != null) {
-            // TODO
+        Range range = document.getRange();
+
+        StyleSheet stylesheet = document.getStyleSheet();
+        
+        for (int i = 0; i < range.numParagraphs(); i++) {
+        	Paragraph paragraph = range.getParagraph(i);
+        	
+        	String styleName = stylesheet.getStyleDescription(paragraph.getStyleIndex()).getName();
+        	
+        	if (styleName.startsWith(HEADER_PREFIX)) {
+        		String rawLevelNum = styleName.substring(HEADER_PREFIX.length() + 1).trim();
+				int levelNum = 0;
+        		
+        		try {
+        			levelNum = Integer.parseInt(rawLevelNum);
+        		}
+        		catch (NumberFormatException nfe) {
+        			log.debug("Could not parse heading level from: " + styleName);
+        		}
+
+        		String text = Paragraph.stripFields(paragraph.text());
+        		
+        		if ('\r' == text.charAt(text.length() - 1)) {
+        			text = text.substring(0, text.length() - 1);
+        		}
+        		
+        		headings.add(new WordMetadata.WordHeading(text, levelNum));
+        	}
         }
+        
+        metadata.setHeadings(headings);
         return metadata;
     }
 }

Added: trunk/extensions/dna-sequencer-msoffice/src/test/java/org/jboss/dna/sequencer/msoffice/word/WordMetadataTest.java
===================================================================
--- trunk/extensions/dna-sequencer-msoffice/src/test/java/org/jboss/dna/sequencer/msoffice/word/WordMetadataTest.java	                        (rev 0)
+++ trunk/extensions/dna-sequencer-msoffice/src/test/java/org/jboss/dna/sequencer/msoffice/word/WordMetadataTest.java	2009-02-23 18:53:59 UTC (rev 736)
@@ -0,0 +1,76 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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.sequencer.msoffice.word;
+
+import static org.hamcrest.core.Is.is;
+import org.junit.After;
+import static org.junit.Assert.assertThat;
+import org.junit.Test;
+import java.io.InputStream;
+import java.util.List;
+
+public class WordMetadataTest {
+
+	private static final String[] TEST_HEADERS_TEXT = new String[] { 
+		"Test Heading 1", "Test Heading 1.1", "Test Heading 1.2", "Test Heading 1.2.1",  
+		"Test Heading 2", "Test Heading 2.1", "Test Heading 2.2",  
+	};
+	private static final int[] TEST_HEADERS_LEVEL = new int[] { 
+		1, 2, 2, 3, 1, 2, 2
+	};
+	
+    private WordMetadata wordMetadata;
+    private InputStream imageStream;
+
+    @After
+    public void afterEach() throws Exception {
+        if (imageStream != null) {
+            try {
+                imageStream.close();
+            } finally {
+                imageStream = null;
+            }
+        }
+    }
+
+    protected InputStream getTestDocument( String resourcePath ) {
+        return this.getClass().getResourceAsStream("/" + resourcePath);
+    }
+
+    @Test
+    public void shouldBeAbleToParseHeadingsForWord() throws Exception {
+    	
+    	wordMetadata = WordMetadataReader.instance(this.getTestDocument("word.doc"));
+    	List<WordMetadata.WordHeading> headings = wordMetadata.getHeadings();
+    	
+    	assertThat(headings.size(), is(TEST_HEADERS_TEXT.length));
+    	
+    	for (int i = 0; i < headings.size(); i++) {
+    		assertThat(headings.get(i).getText(), is(TEST_HEADERS_TEXT[i]));
+    		assertThat(headings.get(i).getHeaderLevel(), is(TEST_HEADERS_LEVEL[i]));
+    	}
+
+    }
+}


Property changes on: trunk/extensions/dna-sequencer-msoffice/src/test/java/org/jboss/dna/sequencer/msoffice/word/WordMetadataTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/extensions/dna-sequencer-msoffice/src/test/resources/word.doc
===================================================================
(Binary files differ)



From dna-commits at lists.jboss.org  Tue Feb 24 09:40:06 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Tue, 24 Feb 2009 09:40:06 -0500
Subject: [dna-commits] DNA SVN: r737 -
	trunk/extensions/dna-connector-jbosscache.
Message-ID: <E1LbyS6-00081K-32@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-24 09:40:05 -0500 (Tue, 24 Feb 2009)
New Revision: 737

Modified:
   trunk/extensions/dna-connector-jbosscache/pom.xml
Log:
DNA-253 Add support in the JBoss Cache connector for JBoss Cache 3.0. 

Updated to JBoss Cache 3.0.3.GA (just released today).

Modified: trunk/extensions/dna-connector-jbosscache/pom.xml
===================================================================
--- trunk/extensions/dna-connector-jbosscache/pom.xml	2009-02-23 18:53:59 UTC (rev 736)
+++ trunk/extensions/dna-connector-jbosscache/pom.xml	2009-02-24 14:40:05 UTC (rev 737)
@@ -50,7 +50,7 @@
     <dependency>
       <groupId>org.jboss.cache</groupId>
       <artifactId>jbosscache-core</artifactId>
-      <version>3.0.2.GA</version>
+      <version>3.0.3.GA</version>
     </dependency>
     <!-- 
     Testing (note the scope)



From dna-commits at lists.jboss.org  Fri Feb 27 17:21:50 2009
From: dna-commits at lists.jboss.org (dna-commits at lists.jboss.org)
Date: Fri, 27 Feb 2009 17:21:50 -0500
Subject: [dna-commits] DNA SVN: r738 - in trunk:
	dna-graph/src/main/java/org/jboss/dna/graph/property/basic
	and 8 other directories.
Message-ID: <E1LdB5a-0007di-O5@committer01.frg.pub.inap.atl.jboss.com>

Author: rhauch
Date: 2009-02-27 17:21:50 -0500 (Fri, 27 Feb 2009)
New Revision: 738

Added:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/GraphNamespaceRegistry.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/SimpleNamespaceRegistry.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/ThreadSafeNamespaceRegistry.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/AbstractNamespaceRegistryTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/GraphNamespaceRegistryTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/SimpleNamespaceRegistryTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/ThreadSafeNamespaceRegistryTest.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java
   trunk/dna-jcr/src/test/resources/cars.xml
Removed:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/BasicNamespaceRegistry.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicNamespaceRegistryTest.java
Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/DnaLexicon.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/LocalNamespaceRegistry.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/AbstractValueComparatorsTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicNameTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathOldTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathSegmentTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/InMemoryBinaryValueFactoryTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/LocalNamespaceRegistryTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/NameValueFactoryTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/PathValueFactoryTest.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNamespaceRegistry.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.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/JackrabbitJcrTckTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNamespaceRegistryTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java
   trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
Log:
DNA-286 Implement namespace management

This change provides a new implementation of the NamespaceRegistry interface of the JCR API, along with refactoring the implementations of DNA's NamespaceRegistry.  In particular, a new GraphNamespaceRegistry class was added that stores the namespace mappings in the graph content (under a location provided into the constructor).  This allowed the new JcrNamespaceRegistry to simply delegate to that and do the simple mapping from DNA's interface to JCR's.  (The refactoring also changed a number of test cases that were directly instantiating a namespace registry.)

The other major change to the JCR implementation is the proper implementation of a session-specific (non-shared and non-persistent) namespace registry, on top of the shared (in a content-sense, not shared objects) and persistent registry that is in the JcrWorkspace.  This required changing how the JcrSession and JcrWorkspace objects are created.  The result is that now namespace mappings can be set on the session, and these override those in the workspace (that would be used for all sessions that use that repository's workspace).

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/DnaLexicon.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/DnaLexicon.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/DnaLexicon.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -42,4 +42,5 @@
     public static final Name CLASSPATH = new BasicName(Namespace.URI, "classpath");
     public static final Name PROJECTION_RULES = new BasicName(Namespace.URI, "projectionRules");
     public static final Name TIME_TO_EXPIRE = new BasicName(Namespace.URI, "timeToExpire");
+    public static final Name NAMESPACE_URI = new BasicName(Namespace.URI, "uri");
 }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -42,9 +42,10 @@
 import org.jboss.dna.graph.property.Property;
 import org.jboss.dna.graph.property.PropertyFactory;
 import org.jboss.dna.graph.property.ValueFactories;
-import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
 import org.jboss.dna.graph.property.basic.BasicPropertyFactory;
+import org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry;
 import org.jboss.dna.graph.property.basic.StandardValueFactories;
+import org.jboss.dna.graph.property.basic.ThreadSafeNamespaceRegistry;
 
 /**
  * An ExecutionContext is a representation of the environment or context in which a component or operation is operating. Some
@@ -150,8 +151,8 @@
      *        {@link AccessController#getContext() current calling context}.
      * @param accessControlContext the access control context, or null if a {@link LoginContext} is provided or if the
      *        {@link AccessController#getContext() current calling context} should be used
-     * @param namespaceRegistry the namespace registry implementation, or null if a {@link BasicNamespaceRegistry} instance should
-     *        be used
+     * @param namespaceRegistry the namespace registry implementation, or null if a thread-safe version of
+     *        {@link SimpleNamespaceRegistry} instance should be used
      * @param valueFactories the {@link ValueFactories} implementation, or null if a {@link StandardValueFactories} instance
      *        should be used
      * @param propertyFactory the {@link PropertyFactory} implementation, or null if a {@link BasicPropertyFactory} instance
@@ -175,7 +176,8 @@
         } else {
             this.subject = loginContext.getSubject();
         }
-        this.namespaceRegistry = namespaceRegistry == null ? new BasicNamespaceRegistry() : namespaceRegistry;
+        this.namespaceRegistry = namespaceRegistry != null ? namespaceRegistry : new ThreadSafeNamespaceRegistry(
+                                                                                                                 new SimpleNamespaceRegistry());
         this.valueFactories = valueFactories == null ? new StandardValueFactories(this.namespaceRegistry) : valueFactories;
         this.propertyFactory = propertyFactory == null ? new BasicPropertyFactory(this.valueFactories) : propertyFactory;
         this.classLoaderFactory = classLoaderFactory == null ? new StandardClassLoaderFactory() : classLoaderFactory;

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-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -511,7 +511,7 @@
     public Move<Conjunction<Graph>> move( Property firstIdProperty,
                                           Property... additionalIdProperties ) {
         return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, Location.create(firstIdProperty,
-                                                                                                  additionalIdProperties));
+                                                                                                     additionalIdProperties));
     }
 
     /**
@@ -713,6 +713,134 @@
     }
 
     /**
+     * Begin the request to create a node located at the supplied path, and return an interface used to either add properties for
+     * the new node, or complete/submit the request and return the location, node, or graph.
+     * <p>
+     * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
+     * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
+     * parent or new node.
+     * </p>
+     * 
+     * @param atPath the path to the node that is to be created.
+     * @return an object that may be used to start another request
+     */
+    public CreateAt<Graph> createAt( String atPath ) {
+        return createAt(createPath(atPath));
+    }
+
+    /**
+     * Begin the request to create a node located at the supplied path, and return an interface used to either add properties for
+     * the new node, or complete/submit the request and return the location, node, or graph.
+     * <p>
+     * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
+     * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
+     * parent or new node.
+     * </p>
+     * 
+     * @param at the path to the node that is to be created.
+     * @return an object that may be used to start another request
+     */
+    public CreateAt<Graph> createAt( final Path at ) {
+        CheckArg.isNotNull(at, "at");
+        final Path parent = at.getParent();
+        final Name childName = at.getLastSegment().getName();
+        final String workspaceName = getCurrentWorkspaceName();
+        return new CreateAt<Graph>() {
+            private final List<Property> properties = new LinkedList<Property>();
+
+            public CreateAt<Graph> and( UUID uuid ) {
+                PropertyFactory factory = queue().getGraph().getContext().getPropertyFactory();
+                properties.add(factory.create(DnaLexicon.UUID, uuid));
+                return this;
+            }
+
+            public CreateAt<Graph> and( Property property ) {
+                properties.add(property);
+                return this;
+            }
+
+            public CreateAt<Graph> and( Iterable<Property> properties ) {
+                for (Property property : properties) {
+                    this.properties.add(property);
+                }
+                return this;
+            }
+
+            public CreateAt<Graph> and( String name,
+                                        Object... values ) {
+                ExecutionContext context = queue().getGraph().getContext();
+                PropertyFactory factory = context.getPropertyFactory();
+                NameFactory nameFactory = context.getValueFactories().getNameFactory();
+                properties.add(factory.create(nameFactory.create(name), values));
+                return this;
+            }
+
+            public CreateAt<Graph> and( Name name,
+                                        Object... values ) {
+                ExecutionContext context = queue().getGraph().getContext();
+                PropertyFactory factory = context.getPropertyFactory();
+                properties.add(factory.create(name, values));
+                return this;
+            }
+
+            public CreateAt<Graph> and( Property property,
+                                        Property... additionalProperties ) {
+                properties.add(property);
+                for (Property additionalProperty : additionalProperties) {
+                    properties.add(additionalProperty);
+                }
+                return this;
+            }
+
+            public CreateAt<Graph> with( UUID uuid ) {
+                return and(uuid);
+            }
+
+            public CreateAt<Graph> with( Property property ) {
+                return and(property);
+            }
+
+            public CreateAt<Graph> with( Iterable<Property> properties ) {
+                return and(properties);
+            }
+
+            public CreateAt<Graph> with( Property property,
+                                         Property... additionalProperties ) {
+                return and(property, additionalProperties);
+            }
+
+            public CreateAt<Graph> with( String name,
+                                         Object... values ) {
+                return and(name, values);
+            }
+
+            public CreateAt<Graph> with( Name name,
+                                         Object... values ) {
+                return and(name, values);
+            }
+
+            public Location getLocation() {
+                Location parentLoc = Location.create(parent);
+                CreateNodeRequest request = new CreateNodeRequest(parentLoc, workspaceName, childName, this.properties);
+                queue().submit(request); // immediate
+                return request.getActualLocationOfNode();
+            }
+
+            public Node getNode() {
+                Location parentLoc = Location.create(parent);
+                CreateNodeRequest request = new CreateNodeRequest(parentLoc, workspaceName, childName, this.properties);
+                queue().submit(request); // immediate
+                return getNodeAt(request.getActualLocationOfNode());
+            }
+
+            public Graph and() {
+                queue().submit(new CreateNodeRequest(Location.create(parent), workspaceName, childName, this.properties));
+                return Graph.this;
+            }
+        };
+    }
+
+    /**
      * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
      * <p>
      * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
@@ -739,16 +867,13 @@
      * parent or new node.
      * </p>
      * 
-     * @param atPath the path to the node that is to be created.
-     * @param properties the properties for the new node
+     * @param at the path to the node that is to be created.
      * @return an object that may be used to start another request
      */
-    public Conjunction<Graph> create( String atPath,
-                                      Property... properties ) {
-        Path at = createPath(atPath);
+    public Conjunction<Graph> create( final Path at ) {
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(Location.create(parent), getCurrentWorkspaceName(), child, properties));
+        this.requestQueue.submit(new CreateNodeRequest(Location.create(parent), getCurrentWorkspaceName(), child));
         return nextGraph;
     }
 
@@ -760,14 +885,16 @@
      * parent or new node.
      * </p>
      * 
-     * @param at the path to the node that is to be created.
+     * @param atPath the path to the node that is to be created.
+     * @param properties the properties for the new node
      * @return an object that may be used to start another request
      */
-    public Conjunction<Graph> create( Path at ) {
-        CheckArg.isNotNull(at, "at");
+    public Conjunction<Graph> create( String atPath,
+                                      Property... properties ) {
+        Path at = createPath(atPath);
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(Location.create(parent), getCurrentWorkspaceName(), child));
+        this.requestQueue.submit(new CreateNodeRequest(Location.create(parent), getCurrentWorkspaceName(), child, properties));
         return nextGraph;
     }
 
@@ -1498,7 +1625,7 @@
                     public List<Location> startingAfter( Property firstIdProperyOfPreviousSibling,
                                                          Property... additionalIdPropertiesOfPreviousSibling ) {
                         return startingAfter(Location.create(firstIdProperyOfPreviousSibling,
-                                                          additionalIdPropertiesOfPreviousSibling));
+                                                             additionalIdPropertiesOfPreviousSibling));
                     }
                 };
             }
@@ -1965,7 +2092,7 @@
                                             Property... additionalIdProperties ) {
             assertNotExecuted();
             return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, Location.create(firstIdProperty,
-                                                                                                       additionalIdProperties));
+                                                                                                          additionalIdProperties));
         }
 
         /**
@@ -2107,7 +2234,7 @@
                                             Property... additionalIdProperties ) {
             assertNotExecuted();
             return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, Location.create(firstIdProperty,
-                                                                                                  additionalIdProperties));
+                                                                                                     additionalIdProperties));
         }
 
         /**
@@ -2322,7 +2449,7 @@
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
             return new CreateAction<Batch>(this, requestQueue, Location.create(parent), getCurrentWorkspaceName(), name).with(firstProperty,
-                                                                                                                           additionalProperties);
+                                                                                                                              additionalProperties);
         }
 
         /**
@@ -2412,7 +2539,7 @@
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
             return new CreateAction<Batch>(this, requestQueue, Location.create(parent), getCurrentWorkspaceName(), name).with(firstProperty,
-                                                                                                                           additionalProperties);
+                                                                                                                              additionalProperties);
         }
 
         /**
@@ -3406,9 +3533,9 @@
         Next to( String desiredPath );
 
         /**
-         * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike {@link Into#into(Path)}
-         * , which specifies the location of the parent and which assumes the new node should have the same name as the original,
-         * this method allows the caller to specify a new name for the new node.
+         * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike
+         * {@link Into#into(Path)} , which specifies the location of the parent and which assumes the new node should have the
+         * same name as the original, this method allows the caller to specify a new name for the new node.
          * 
          * @param desiredPath the path for the new node
          * @return the interface for additional requests or actions
@@ -3530,6 +3657,14 @@
         Create<Next> with( Property property );
 
         /**
+         * Specify property that should the new node should have. This is an alias for {@link #and(Iterable)}.
+         * 
+         * @param properties the properties that should be added
+         * @return this same interface so additional properties may be added
+         */
+        Create<Next> with( Iterable<Property> properties );
+
+        /**
          * Specify a property that should the new node should have. This is an alias for {@link #and(String, Object...)}.
          * 
          * @param propertyName the name of the property
@@ -3576,6 +3711,15 @@
         Create<Next> and( Property property );
 
         /**
+         * Specify property that should the new node should have. This is equivalent to calling {@link #and(Property)} for each of
+         * the properties in the supplied {@link Iterable}.
+         * 
+         * @param properties the properties that should be added
+         * @return this same interface so additional properties may be added
+         */
+        Create<Next> and( Iterable<Property> properties );
+
+        /**
          * Specify a property that should the new node should have.
          * 
          * @param propertyName the name of the property
@@ -3607,6 +3751,137 @@
     }
 
     /**
+     * The interface for defining additional properties on a new node.
+     * 
+     * @param <Next> The interface that is to be returned when this create request is completed
+     * @author Randall Hauch
+     */
+    public interface CreateAt<Next> extends Conjunction<Next> {
+        /**
+         * Specify the UUID that should the new node should have. This is an alias for {@link #and(UUID)}.
+         * 
+         * @param uuid the UUID
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> with( UUID uuid );
+
+        /**
+         * Specify a property that should the new node should have. This is an alias for {@link #and(Property)}.
+         * 
+         * @param property the property
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> with( Property property );
+
+        /**
+         * Specify property that should the new node should have. This is an alias for {@link #and(Iterable)}.
+         * 
+         * @param properties the properties that should be added
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> with( Iterable<Property> properties );
+
+        /**
+         * Specify a property that should the new node should have. This is an alias for {@link #and(String, Object...)}.
+         * 
+         * @param propertyName the name of the property
+         * @param values the property values
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> with( String propertyName,
+                             Object... values );
+
+        /**
+         * Specify a property that should the new node should have. This is an alias for {@link #and(Name, Object...)}.
+         * 
+         * @param propertyName the name of the property
+         * @param values the property values
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> with( Name propertyName,
+                             Object... values );
+
+        /**
+         * Specify properties that should the new node should have. This is an alias for {@link #and(Property, Property...)}.
+         * 
+         * @param firstProperty the first property
+         * @param additionalProperties the additional property
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> with( Property firstProperty,
+                             Property... additionalProperties );
+
+        /**
+         * Specify the UUID that should the new node should have.
+         * 
+         * @param uuid the UUID
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> and( UUID uuid );
+
+        /**
+         * Specify a property that should the new node should have.
+         * 
+         * @param property the property
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> and( Property property );
+
+        /**
+         * Specify property that should the new node should have. This is equivalent to calling {@link #and(Property)} for each of
+         * the properties in the supplied {@link Iterable}.
+         * 
+         * @param properties the properties that should be added
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> and( Iterable<Property> properties );
+
+        /**
+         * Specify a property that should the new node should have.
+         * 
+         * @param propertyName the name of the property
+         * @param values the property values
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> and( String propertyName,
+                            Object... values );
+
+        /**
+         * Specify a property that should the new node should have.
+         * 
+         * @param propertyName the name of the property
+         * @param values the property values
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> and( Name propertyName,
+                            Object... values );
+
+        /**
+         * Specify properties that should the new node should have.
+         * 
+         * @param firstProperty the first property
+         * @param additionalProperties the additional property
+         * @return this same interface so additional properties may be added
+         */
+        CreateAt<Next> and( Property firstProperty,
+                            Property... additionalProperties );
+
+        /**
+         * Complete this request, submit it, and return the actual location of the created node.
+         * 
+         * @return the actual location of the just-created node; never null
+         */
+        Location getLocation();
+
+        /**
+         * Complete this request, submit it, and return the actual node that was created.
+         * 
+         * @return the actual node that was just created; never null
+         */
+        Node getNode();
+    }
+
+    /**
      * The interface for defining the node upon which a request operates.
      * 
      * @param <Next> The interface that is to be returned when the request is completed
@@ -5225,6 +5500,13 @@
             return this;
         }
 
+        public Create<T> and( Iterable<Property> properties ) {
+            for (Property property : properties) {
+                this.properties.add(property);
+            }
+            return this;
+        }
+
         public Create<T> and( String name,
                               Object... values ) {
             ExecutionContext context = queue().getGraph().getContext();
@@ -5259,6 +5541,10 @@
             return and(property);
         }
 
+        public Create<T> with( Iterable<Property> properties ) {
+            return and(properties);
+        }
+
         public Create<T> with( Property property,
                                Property... additionalProperties ) {
             return and(property, additionalProperties);

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -112,14 +112,62 @@
         CheckArg.isNotNull(uri, "uri");
         CheckArg.isNotNull(location, "location");
         CheckArg.isNotNull(location.getPath(), "location.getPath()");
+        InputStream stream = null;
+        try {
+            stream = uri.toURL().openStream();
+            return importXml(stream, location, skip);
+        } finally {
+            if (stream != null) stream.close();
+        }
+    }
 
+    /**
+     * Read the content from the supplied URI and import into the repository at the supplied location. This method does <i>not</i>
+     * close the stream.
+     * 
+     * @param stream the stream containing the content to be imported
+     * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+     *        be null
+     * @return the batch of requests for creating the graph content that represents the imported content
+     * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
+     * @throws IOException if there is a problem reading the content
+     * @throws SAXException if there is a problem with the SAX Parser
+     * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
+     *         source}
+     */
+    public Graph.Batch importXml( InputStream stream,
+                                  Location location ) throws IOException, SAXException, RepositorySourceException {
+        return importXml(stream, location, false);
+    }
+
+    /**
+     * Read the content from the supplied URI and import into the repository at the supplied location. This method does <i>not</i>
+     * close the stream.
+     * 
+     * @param stream the stream containing the content to be imported
+     * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+     *        be null
+     * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
+     * @return the batch of requests for creating the graph content that represents the imported content
+     * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
+     * @throws IOException if there is a problem reading the content
+     * @throws SAXException if there is a problem with the SAX Parser
+     * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
+     *         source}
+     */
+    public Graph.Batch importXml( InputStream stream,
+                                  Location location,
+                                  boolean skip ) throws IOException, SAXException, RepositorySourceException {
+        CheckArg.isNotNull(stream, "uri");
+        CheckArg.isNotNull(location, "location");
+        CheckArg.isNotNull(location.getPath(), "location.getPath()");
+
         // Create the destination for the XmlHandler ...
         Graph.Batch batch = graph.batch();
         XmlHandler.Destination destination = new CreateOnGraphInBatch(batch);
 
         // Determine where the content is to be placed ...
         Path parentPath = location.getPath();
-        InputStream stream = null;
         Name nameAttribute = JcrLexicon.NAME;
         Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
         Name typeAttributeValue = null;
@@ -132,21 +180,54 @@
         XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
         XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
                                             typeAttributeValue, scoping);
-        try {
-            stream = uri.toURL().openStream();
-            XMLReader reader = XMLReaderFactory.createXMLReader();
-            reader.setContentHandler(handler);
-            reader.setErrorHandler(handler);
-            reader.parse(new InputSource(stream));
-        } finally {
-            if (stream != null) stream.close();
-        }
+        XMLReader reader = XMLReaderFactory.createXMLReader();
+        reader.setContentHandler(handler);
+        reader.setErrorHandler(handler);
+        reader.parse(new InputSource(stream));
+        if (stream != null) stream.close();
         return batch;
     }
 
+    /**
+     * Return an {@link XmlHandler} that can be used to import content directly into the supplied location. The operations
+     * resulting from the {@link XmlHandler} operations are batched until the {@link XmlHandler#endDocument()} is called, at which
+     * point all enqueued operations are submitted to the graph.
+     * 
+     * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+     *        be null
+     * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
+     * @return the {@link XmlHandler} that can be used to import content
+     * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
+     */
+    public XmlHandler getHandlerForImportingXml( Location location,
+                                                 boolean skip ) {
+        CheckArg.isNotNull(location, "location");
+        CheckArg.isNotNull(location.getPath(), "location.getPath()");
+
+        // Create the destination for the XmlHandler ...
+        Graph.Batch batch = graph.batch();
+        XmlHandler.Destination destination = new SubmitToGraphInBatch(batch);
+
+        // Determine where the content is to be placed ...
+        Path parentPath = location.getPath();
+        Name nameAttribute = JcrLexicon.NAME;
+        Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
+        Name typeAttributeValue = null;
+        NamespaceRegistry reg = graph.getContext().getNamespaceRegistry();
+        if (reg.isRegisteredNamespaceUri(JcrNtLexicon.Namespace.URI)) {
+            typeAttributeValue = JcrNtLexicon.UNSTRUCTURED;
+        }
+
+        TextDecoder decoder = null;
+        XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
+        XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
+                                            typeAttributeValue, scoping);
+        return handler;
+    }
+
     @NotThreadSafe
-    protected final static class CreateOnGraphInBatch implements Destination {
-        private final Graph.Batch batch;
+    protected static class CreateOnGraphInBatch implements Destination {
+        protected final Graph.Batch batch;
 
         protected CreateOnGraphInBatch( Graph.Batch batch ) {
             assert batch != null;
@@ -181,4 +262,17 @@
         }
     }
 
+    @NotThreadSafe
+    protected final static class SubmitToGraphInBatch extends CreateOnGraphInBatch {
+        protected SubmitToGraphInBatch( Graph.Batch batch ) {
+            super(batch);
+        }
+
+        @Override
+        public void submit() {
+            super.submit();
+            batch.execute();
+        }
+    }
+
 }

Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/BasicNamespaceRegistry.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/BasicNamespaceRegistry.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/BasicNamespaceRegistry.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -1,275 +0,0 @@
-/*
- * 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. 
- *
- * JBoss DNA is free software. 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.property.basic;
-
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import net.jcip.annotations.GuardedBy;
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.property.NamespaceRegistry;
-
-/**
- * @author Randall Hauch
- */
- at ThreadSafe
-public class BasicNamespaceRegistry implements NamespaceRegistry {
-
-    public static final String DEFAULT_NAMESPACE_URI = "";
-    public static final String DEFAULT_PREFIX_TEMPLATE = "ns##000";
-    public static final String DEFAULT_PREFIX_NUMBER_FORMAT = "##000";
-
-    private final ReadWriteLock registryLock = new ReentrantReadWriteLock();
-    private final Map<String, String> namespacesByPrefix = new HashMap<String, String>();
-    private final Map<String, String> prefixesByNamespace = new HashMap<String, String>();
-    private String generatedPrefixTemplate = DEFAULT_PREFIX_TEMPLATE;
-    private int nextGeneratedPrefixNumber = 1;
-
-    /**
-     * 
-     */
-    public BasicNamespaceRegistry() {
-        this(DEFAULT_NAMESPACE_URI);
-    }
-
-    /**
-     * @param defaultNamespaceUri the namespace URI to use for the default prefix
-     */
-    public BasicNamespaceRegistry( final String defaultNamespaceUri ) {
-        register("", defaultNamespaceUri);
-    }
-
-    /**
-     * @return prefixTemplate
-     */
-    public String getGeneratedPrefixTemplate() {
-        Lock lock = this.registryLock.readLock();
-        try {
-            lock.lock();
-            return this.generatedPrefixTemplate;
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * @param prefixTemplate Sets prefixTemplate to the specified value.
-     */
-    public void setGeneratedPrefixTemplate( String prefixTemplate ) {
-        if (prefixTemplate == null) prefixTemplate = DEFAULT_PREFIX_TEMPLATE;
-        Lock lock = this.registryLock.writeLock();
-        try {
-            lock.lock();
-            this.generatedPrefixTemplate = prefixTemplate;
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String getNamespaceForPrefix( String prefix ) {
-        CheckArg.isNotNull(prefix, "prefix");
-        Lock lock = this.registryLock.readLock();
-        try {
-            lock.lock();
-            return this.namespacesByPrefix.get(prefix);
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String getPrefixForNamespaceUri( String namespaceUri,
-                                            boolean generateIfMissing ) {
-        CheckArg.isNotNull(namespaceUri, "namespaceUri");
-        String prefix = null;
-        Lock lock = this.registryLock.readLock();
-        try {
-            lock.lock();
-            prefix = this.prefixesByNamespace.get(namespaceUri);
-        } finally {
-            lock.unlock();
-        }
-        if (prefix == null && generateIfMissing) {
-            // Get a write lock ...
-            lock = this.registryLock.writeLock();
-            try {
-                lock.lock();
-                // Since we got a new lock, we need to check again ...
-                prefix = this.prefixesByNamespace.get(namespaceUri);
-                if (prefix == null) {
-                    // Now we can genereate a prefix and register it ...
-                    prefix = this.generatePrefix();
-                    this.register(prefix, namespaceUri);
-                }
-                return prefix;
-            } finally {
-                lock.unlock();
-            }
-        }
-        return prefix;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean isRegisteredNamespaceUri( String namespaceUri ) {
-        CheckArg.isNotNull(namespaceUri, "namespaceUri");
-        Lock lock = this.registryLock.readLock();
-        try {
-            lock.lock();
-            return this.prefixesByNamespace.containsKey(namespaceUri);
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String getDefaultNamespaceUri() {
-        Lock lock = this.registryLock.readLock();
-        try {
-            lock.lock();
-            return this.namespacesByPrefix.get("");
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String register( String prefix,
-                            String namespaceUri ) {
-        CheckArg.isNotNull(namespaceUri, "namespaceUri");
-        String previousNamespaceForPrefix = null;
-        namespaceUri = namespaceUri.trim();
-        Lock lock = this.registryLock.writeLock();
-        try {
-            lock.lock();
-            if (prefix == null) prefix = generatePrefix();
-            prefix = prefix.trim();
-            prefix = prefix.replaceFirst("^:+", "");
-            prefix = prefix.replaceFirst(":+$", "");
-            previousNamespaceForPrefix = this.namespacesByPrefix.put(prefix, namespaceUri);
-            String previousPrefix = this.prefixesByNamespace.put(namespaceUri, prefix);
-            if (previousPrefix != null && !previousPrefix.equals(prefix)) {
-                this.namespacesByPrefix.remove(previousPrefix);
-            }
-            if (previousNamespaceForPrefix != null && !previousNamespaceForPrefix.equals(namespaceUri)) {
-                this.prefixesByNamespace.remove(previousNamespaceForPrefix);
-            }
-        } finally {
-            lock.unlock();
-        }
-        return previousNamespaceForPrefix;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.property.NamespaceRegistry#unregister(java.lang.String)
-     */
-    public boolean unregister( String namespaceUri ) {
-        CheckArg.isNotNull(namespaceUri, "namespaceUri");
-        namespaceUri = namespaceUri.trim();
-        Lock lock = this.registryLock.writeLock();
-        try {
-            lock.lock();
-            String prefix = this.prefixesByNamespace.remove(namespaceUri);
-            if (prefix == null) return false;
-            this.namespacesByPrefix.remove(prefix);
-        } finally {
-            lock.unlock();
-        }
-        return true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public Set<String> getRegisteredNamespaceUris() {
-        Set<String> result = new HashSet<String>();
-        Lock lock = this.registryLock.readLock();
-        try {
-            lock.lock();
-            result.addAll(this.prefixesByNamespace.keySet());
-        } finally {
-            lock.unlock();
-        }
-        return Collections.unmodifiableSet(result);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.property.NamespaceRegistry#getNamespaces()
-     */
-    public Set<Namespace> getNamespaces() {
-        Set<Namespace> result = new HashSet<Namespace>();
-        Lock lock = this.registryLock.readLock();
-        try {
-            lock.lock();
-            for (Map.Entry<String, String> entry : this.namespacesByPrefix.entrySet()) {
-                result.add(new BasicNamespace(entry.getKey(), entry.getValue()));
-            }
-        } finally {
-            lock.unlock();
-        }
-        return Collections.unmodifiableSet(result);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see java.lang.Object#toString()
-     */
-    @Override
-    public String toString() {
-        List<Namespace> namespaces = new ArrayList<Namespace>(getNamespaces());
-        Collections.sort(namespaces);
-        return namespaces.toString();
-    }
-
-    @GuardedBy( "registryLock" )
-    protected String generatePrefix() {
-        DecimalFormat formatter = new DecimalFormat(this.generatedPrefixTemplate);
-        return formatter.format(nextGeneratedPrefixNumber++);
-    }
-
-}

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/GraphNamespaceRegistry.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/GraphNamespaceRegistry.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/GraphNamespaceRegistry.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,382 @@
+/*
+ * 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.property.basic;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.DnaLexicon;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.Node;
+import org.jboss.dna.graph.Subgraph;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.PathNotFoundException;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.ValueFactory;
+
+/**
+ * A {@link NamespaceRegistry} implementation that stores the namespaces in a Graph as individual nodes for each namespace, under
+ * a parent supplied by the constructor.
+ * 
+ * @See {@link ThreadSafeNamespaceRegistry}
+ */
+ at NotThreadSafe
+public class GraphNamespaceRegistry implements NamespaceRegistry {
+
+    public static final Name DEFAULT_URI_PROPERTY_NAME = DnaLexicon.NAMESPACE_URI;
+    public static final String GENERATED_PREFIX = "ns";
+
+    private SimpleNamespaceRegistry cache;
+    private final Graph store;
+    private final Path parentOfNamespaceNodes;
+    private final Name uriPropertyName;
+    private final List<Property> namespaceProperties;
+
+    public GraphNamespaceRegistry( Graph store,
+                                   Path parentOfNamespaceNodes,
+                                   Name uriPropertyName,
+                                   Property... additionalProperties ) {
+        this.cache = new SimpleNamespaceRegistry();
+        this.store = store;
+        this.parentOfNamespaceNodes = parentOfNamespaceNodes;
+        this.uriPropertyName = uriPropertyName != null ? uriPropertyName : DEFAULT_URI_PROPERTY_NAME;
+        List<Property> properties = Collections.emptyList();
+        if (additionalProperties != null && additionalProperties.length != 0) {
+            properties = new ArrayList<Property>(additionalProperties.length);
+            Set<Name> propertyNames = new HashSet<Name>();
+            for (Property property : additionalProperties) {
+                if (!propertyNames.contains(property.getName())) properties.add(property);
+            }
+        }
+        this.namespaceProperties = Collections.unmodifiableList(properties);
+        initializeCacheFromStore(cache);
+
+        // Load in the namespaces from the execution context used by the store ...
+        for (Namespace namespace : store.getContext().getNamespaceRegistry().getNamespaces()) {
+            register(namespace.getPrefix(), namespace.getNamespaceUri());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getNamespaceForPrefix( String prefix ) {
+        CheckArg.isNotNull(prefix, "prefix");
+        // Try the cache first ...
+        String uri = cache.getNamespaceForPrefix(prefix);
+        if (uri == null) {
+            // See if the store has it ...
+            uri = readUriFor(prefix);
+            if (uri != null) {
+                // update the cache ...
+                cache.register(prefix, uri);
+            }
+        }
+        return uri;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getPrefixForNamespaceUri( String namespaceUri,
+                                            boolean generateIfMissing ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        // Try the cache first ...
+        String prefix = cache.getPrefixForNamespaceUri(namespaceUri, false);
+        if (prefix == null && generateIfMissing) {
+            prefix = readPrefixFor(namespaceUri, generateIfMissing);
+            if (prefix != null) {
+                cache.register(prefix, namespaceUri);
+            }
+        }
+        return prefix;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRegisteredNamespaceUri( String namespaceUri ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        if (cache.isRegisteredNamespaceUri(namespaceUri)) return true;
+        // Otherwise it was not found in the cache, so check the store ...
+        String prefix = readPrefixFor(namespaceUri, false);
+        if (prefix != null) {
+            cache.register(prefix, namespaceUri);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getDefaultNamespaceUri() {
+        return this.getNamespaceForPrefix("");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String register( String prefix,
+                            String namespaceUri ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        namespaceUri = namespaceUri.trim();
+        // Register it in the cache first ...
+        String previousCachedUriForPrefix = this.cache.register(prefix, namespaceUri);
+        // And register it in the source ...
+        String previousPersistentUriForPrefix = doRegister(prefix, namespaceUri);
+        return previousCachedUriForPrefix != null ? previousPersistentUriForPrefix : previousPersistentUriForPrefix;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.NamespaceRegistry#unregister(java.lang.String)
+     */
+    public boolean unregister( String namespaceUri ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        namespaceUri = namespaceUri.trim();
+        // Remove it from the cache ...
+        boolean found = this.cache.unregister(namespaceUri);
+        // Then from the source ...
+        return doUnregister(namespaceUri) || found;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<String> getRegisteredNamespaceUris() {
+        // Just return what's in the cache ...
+        return cache.getRegisteredNamespaceUris();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.NamespaceRegistry#getNamespaces()
+     */
+    public Set<Namespace> getNamespaces() {
+        // Just return what's in the cache ...
+        return cache.getNamespaces();
+    }
+
+    public void refresh() {
+        SimpleNamespaceRegistry newCache = new SimpleNamespaceRegistry();
+        initializeCacheFromStore(newCache);
+        this.cache = newCache;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        List<Namespace> namespaces = new ArrayList<Namespace>(getNamespaces());
+        Collections.sort(namespaces);
+        return namespaces.toString();
+    }
+
+    protected void initializeCacheFromStore( NamespaceRegistry cache ) {
+        // Read the store ...
+        try {
+            Subgraph nsGraph = store.getSubgraphOfDepth(2).at(parentOfNamespaceNodes);
+            ValueFactory<String> stringFactory = store.getContext().getValueFactories().getStringFactory();
+            for (Location nsLocation : nsGraph.getRoot().getChildren()) {
+                Node ns = nsGraph.getNode(nsLocation);
+                // This node is a namespace ...
+                String uri = stringFactory.create(ns.getProperty(uriPropertyName).getFirstValue());
+                if (uri != null) {
+                    String prefix = getPrefixFor(nsLocation.getPath());
+                    cache.register(prefix, uri);
+                }
+            }
+        } catch (PathNotFoundException e) {
+            // Nothing to read
+        }
+    }
+
+    protected String readUriFor( String prefix ) {
+        // Read the store ...
+        try {
+            PathFactory pathFactory = store.getContext().getValueFactories().getPathFactory();
+            Path pathToNamespaceNode = pathFactory.create(parentOfNamespaceNodes, prefix);
+            Property uri = store.getProperty(uriPropertyName).on(pathToNamespaceNode);
+            // Get the URI property value ...
+            ValueFactory<String> stringFactory = store.getContext().getValueFactories().getStringFactory();
+            return stringFactory.create(uri.getFirstValue());
+        } catch (PathNotFoundException e) {
+            // Nothing to read
+            return null;
+        }
+    }
+
+    protected String getPrefixFor( Path path ) {
+        Path.Segment lastSegment = path.getLastSegment();
+        String localName = lastSegment.getName().getLocalName();
+        int index = lastSegment.getIndex();
+        if (index == 1) {
+            if (GENERATED_PREFIX.equals(localName)) return localName + "00" + index;
+            return localName;
+        }
+        if (index < 10) {
+            return localName + "00" + index;
+        }
+        if (index < 100) {
+            return localName + "0" + index;
+        }
+        return localName + index;
+    }
+
+    protected String readPrefixFor( String namespaceUri,
+                                    boolean generateIfMissing ) {
+        // Read the store ...
+        try {
+            Subgraph nsGraph = store.getSubgraphOfDepth(2).at(parentOfNamespaceNodes);
+            ValueFactory<String> stringFactory = store.getContext().getValueFactories().getStringFactory();
+            for (Location nsLocation : nsGraph.getRoot().getChildren()) {
+                Node ns = nsGraph.getNode(nsLocation);
+                String prefix = getPrefixFor(nsLocation.getPath());
+                String uri = stringFactory.create(ns.getProperty(uriPropertyName).getFirstValue());
+                if (prefix != null && uri != null) {
+                    if (uri.equals(namespaceUri)) return prefix;
+                }
+            }
+            if (generateIfMissing) {
+                // Generated prefixes are simply "ns" followed by the SNS index ...
+                PathFactory pathFactory = store.getContext().getValueFactories().getPathFactory();
+                Path pathToNamespaceNode = pathFactory.create(parentOfNamespaceNodes, GENERATED_PREFIX);
+                Location actualLocation = store.createAt(pathToNamespaceNode)
+                                               .with(namespaceProperties)
+                                               .and(uriPropertyName, namespaceUri)
+                                               .getLocation();
+
+                return getPrefixFor(actualLocation.getPath());
+            }
+
+        } catch (PathNotFoundException e) {
+            // Nothing to read
+        }
+        return null;
+    }
+
+    protected String doRegister( String prefix,
+                                 String uri ) {
+        assert prefix != null;
+        assert uri != null;
+        prefix = prefix.trim();
+        uri = uri.trim();
+
+        // Read the store ...
+        String previousUri = null;
+        ValueFactory<String> stringFactory = store.getContext().getValueFactories().getStringFactory();
+        PathFactory pathFactory = store.getContext().getValueFactories().getPathFactory();
+        Path pathToNamespaceNode = pathFactory.create(parentOfNamespaceNodes, prefix);
+        try {
+            Subgraph nsGraph = store.getSubgraphOfDepth(2).at(parentOfNamespaceNodes);
+            // Iterate over the existing mappings, looking for one that uses the URI ...
+            Location nsNodeWithPrefix = null;
+            boolean updateNode = true;
+            Set<Location> locationsToRemove = new HashSet<Location>();
+            for (Location nsLocation : nsGraph.getRoot().getChildren()) {
+                Node ns = nsGraph.getNode(nsLocation);
+                String actualPrefix = getPrefixFor(nsLocation.getPath());
+                String actualUri = stringFactory.create(ns.getProperty(uriPropertyName).getFirstValue());
+                if (actualPrefix != null && actualUri != null) {
+                    if (actualPrefix.equals(prefix)) {
+                        nsNodeWithPrefix = nsLocation;
+                        if (actualUri.equals(uri)) {
+                            updateNode = false;
+                            break;
+                        }
+                        previousUri = actualUri;
+                    }
+                    if (actualUri.equals(uri)) {
+                        locationsToRemove.add(ns.getLocation());
+                    }
+                }
+            }
+            Graph.Batch batch = store.batch();
+            // Remove any other nodes that have the same URI ...
+            for (Location namespaceToRemove : locationsToRemove) {
+                batch.delete(namespaceToRemove).and();
+            }
+            // Now update/create the namespace mapping ...
+            if (nsNodeWithPrefix == null) {
+                // We didn't find an existing node, so we have to create it ...
+                batch.create(pathToNamespaceNode).with(namespaceProperties).and(uriPropertyName, uri).and();
+            } else {
+                if (updateNode) {
+                    // There was already an existing node, so update it ...
+                    batch.set(uriPropertyName).to(uri).on(pathToNamespaceNode).and();
+                }
+            }
+            // Execute all these changes ...
+            batch.execute();
+        } catch (PathNotFoundException e) {
+            // Nothing stored yet ...
+            store.createAt(pathToNamespaceNode).with(namespaceProperties).and(uriPropertyName, uri).getLocation();
+        }
+        return previousUri;
+    }
+
+    protected boolean doUnregister( String uri ) {
+        // Read the store ...
+        ValueFactory<String> stringFactory = store.getContext().getValueFactories().getStringFactory();
+        boolean result = false;
+        try {
+            Subgraph nsGraph = store.getSubgraphOfDepth(2).at(parentOfNamespaceNodes);
+            // Iterate over the existing mappings, looking for one that uses the prefix and uri ...
+            Set<Location> locationsToRemove = new HashSet<Location>();
+            for (Location nsLocation : nsGraph.getRoot().getChildren()) {
+                Node ns = nsGraph.getNode(nsLocation);
+                String actualUri = stringFactory.create(ns.getProperty(uriPropertyName).getFirstValue());
+                if (actualUri.equals(uri)) {
+                    locationsToRemove.add(ns.getLocation());
+                    result = true;
+                }
+            }
+            // Remove any other nodes that have the same URI ...
+            Graph.Batch batch = store.batch();
+            for (Location namespaceToRemove : locationsToRemove) {
+                batch.delete(namespaceToRemove).and();
+            }
+            // Execute all these changes ...
+            batch.execute();
+        } catch (PathNotFoundException e) {
+            // Nothing stored yet, so do nothing ...
+        }
+        return result;
+    }
+
+}


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

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/LocalNamespaceRegistry.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/LocalNamespaceRegistry.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/LocalNamespaceRegistry.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -36,7 +36,7 @@
  * @author Randall Hauch
  */
 @ThreadSafe
-public class LocalNamespaceRegistry extends BasicNamespaceRegistry {
+public class LocalNamespaceRegistry extends SimpleNamespaceRegistry {
 
     private final NamespaceRegistry delegate;
 
@@ -65,7 +65,7 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.property.basic.BasicNamespaceRegistry#getDefaultNamespaceUri()
+     * @see org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry#getDefaultNamespaceUri()
      */
     @Override
     public String getDefaultNamespaceUri() {
@@ -77,7 +77,7 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.property.basic.BasicNamespaceRegistry#getNamespaceForPrefix(java.lang.String)
+     * @see org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry#getNamespaceForPrefix(java.lang.String)
      */
     @Override
     public String getNamespaceForPrefix( String prefix ) {
@@ -89,7 +89,7 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.property.basic.BasicNamespaceRegistry#getNamespaces()
+     * @see org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry#getNamespaces()
      */
     @Override
     public Set<Namespace> getNamespaces() {
@@ -116,7 +116,7 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.property.basic.BasicNamespaceRegistry#getPrefixForNamespaceUri(java.lang.String, boolean)
+     * @see org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry#getPrefixForNamespaceUri(java.lang.String, boolean)
      */
     @Override
     public String getPrefixForNamespaceUri( String namespaceUri,
@@ -130,7 +130,7 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.property.basic.BasicNamespaceRegistry#getRegisteredNamespaceUris()
+     * @see org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry#getRegisteredNamespaceUris()
      */
     @Override
     public Set<String> getRegisteredNamespaceUris() {
@@ -142,7 +142,7 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.property.basic.BasicNamespaceRegistry#isRegisteredNamespaceUri(java.lang.String)
+     * @see org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry#isRegisteredNamespaceUri(java.lang.String)
      */
     @Override
     public boolean isRegisteredNamespaceUri( String namespaceUri ) {
@@ -152,7 +152,7 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.property.basic.BasicNamespaceRegistry#register(java.lang.String, java.lang.String)
+     * @see org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry#register(java.lang.String, java.lang.String)
      */
     @Override
     public String register( String prefix,
@@ -167,7 +167,7 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.property.basic.BasicNamespaceRegistry#unregister(java.lang.String)
+     * @see org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry#unregister(java.lang.String)
      */
     @Override
     public boolean unregister( String namespaceUri ) {

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/SimpleNamespaceRegistry.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/SimpleNamespaceRegistry.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/SimpleNamespaceRegistry.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,200 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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.property.basic;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+
+/**
+ * A simple {@link NamespaceRegistry} implementation that is not thread-safe, but that provides all the basic functionality.
+ * 
+ * @author Randall Hauch
+ */
+ at NotThreadSafe
+public class SimpleNamespaceRegistry implements NamespaceRegistry {
+
+    public static final String DEFAULT_NAMESPACE_URI = "";
+    public static final String DEFAULT_PREFIX_TEMPLATE = "ns##000";
+    public static final String DEFAULT_PREFIX_NUMBER_FORMAT = "##000";
+
+    private final Map<String, String> namespacesByPrefix = new HashMap<String, String>();
+    private final Map<String, String> prefixesByNamespace = new HashMap<String, String>();
+    private String generatedPrefixTemplate = DEFAULT_PREFIX_TEMPLATE;
+    private int nextGeneratedPrefixNumber = 1;
+
+    /**
+     * 
+     */
+    public SimpleNamespaceRegistry() {
+        this(DEFAULT_NAMESPACE_URI);
+    }
+
+    /**
+     * @param defaultNamespaceUri the namespace URI to use for the default prefix
+     */
+    public SimpleNamespaceRegistry( final String defaultNamespaceUri ) {
+        register("", defaultNamespaceUri);
+    }
+
+    /**
+     * @return prefixTemplate
+     */
+    public String getGeneratedPrefixTemplate() {
+        return this.generatedPrefixTemplate;
+    }
+
+    /**
+     * @param prefixTemplate Sets prefixTemplate to the specified value.
+     */
+    public void setGeneratedPrefixTemplate( String prefixTemplate ) {
+        if (prefixTemplate == null) prefixTemplate = DEFAULT_PREFIX_TEMPLATE;
+        this.generatedPrefixTemplate = prefixTemplate;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getNamespaceForPrefix( String prefix ) {
+        CheckArg.isNotNull(prefix, "prefix");
+        return this.namespacesByPrefix.get(prefix);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getPrefixForNamespaceUri( String namespaceUri,
+                                            boolean generateIfMissing ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        String prefix = null;
+        prefix = this.prefixesByNamespace.get(namespaceUri);
+        if (prefix == null && generateIfMissing) {
+            // Now we can genereate a prefix and register it ...
+            prefix = this.generatePrefix();
+            this.register(prefix, namespaceUri);
+            return prefix;
+        }
+        return prefix;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRegisteredNamespaceUri( String namespaceUri ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        return this.prefixesByNamespace.containsKey(namespaceUri);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getDefaultNamespaceUri() {
+        return this.namespacesByPrefix.get("");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String register( String prefix,
+                            String namespaceUri ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        String previousNamespaceForPrefix = null;
+        namespaceUri = namespaceUri.trim();
+        if (prefix == null) prefix = generatePrefix();
+        prefix = prefix.trim();
+        prefix = prefix.replaceFirst("^:+", "");
+        prefix = prefix.replaceFirst(":+$", "");
+        previousNamespaceForPrefix = this.namespacesByPrefix.put(prefix, namespaceUri);
+        String previousPrefix = this.prefixesByNamespace.put(namespaceUri, prefix);
+        if (previousPrefix != null && !previousPrefix.equals(prefix)) {
+            this.namespacesByPrefix.remove(previousPrefix);
+        }
+        if (previousNamespaceForPrefix != null && !previousNamespaceForPrefix.equals(namespaceUri)) {
+            this.prefixesByNamespace.remove(previousNamespaceForPrefix);
+        }
+        return previousNamespaceForPrefix;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.NamespaceRegistry#unregister(java.lang.String)
+     */
+    public boolean unregister( String namespaceUri ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        namespaceUri = namespaceUri.trim();
+        String prefix = this.prefixesByNamespace.remove(namespaceUri);
+        if (prefix == null) return false;
+        this.namespacesByPrefix.remove(prefix);
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<String> getRegisteredNamespaceUris() {
+        Set<String> result = new HashSet<String>();
+        result.addAll(this.prefixesByNamespace.keySet());
+        return Collections.unmodifiableSet(result);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.NamespaceRegistry#getNamespaces()
+     */
+    public Set<Namespace> getNamespaces() {
+        Set<Namespace> result = new HashSet<Namespace>();
+        for (Map.Entry<String, String> entry : this.namespacesByPrefix.entrySet()) {
+            result.add(new BasicNamespace(entry.getKey(), entry.getValue()));
+        }
+        return Collections.unmodifiableSet(result);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        List<Namespace> namespaces = new ArrayList<Namespace>(getNamespaces());
+        Collections.sort(namespaces);
+        return namespaces.toString();
+    }
+
+    protected String generatePrefix() {
+        DecimalFormat formatter = new DecimalFormat(this.generatedPrefixTemplate);
+        return formatter.format(nextGeneratedPrefixNumber++);
+    }
+
+}


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

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/ThreadSafeNamespaceRegistry.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/ThreadSafeNamespaceRegistry.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/ThreadSafeNamespaceRegistry.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,204 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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.property.basic;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+
+/**
+ * A thread-safe {@link NamespaceRegistry} that may be used as a thread-safe wrapper around another non-thread-safe
+ * implementation.
+ * 
+ * @author Randall Hauch
+ */
+ at ThreadSafe
+public class ThreadSafeNamespaceRegistry implements NamespaceRegistry {
+
+    private final ReadWriteLock registryLock = new ReentrantReadWriteLock();
+    private final NamespaceRegistry delegate;
+
+    /**
+     */
+    public ThreadSafeNamespaceRegistry() {
+        this(new SimpleNamespaceRegistry());
+    }
+
+    /**
+     * @param nonThreadSafeRegistry a {@link NamespaceRegistry} implementation that is not thread safe and to which this instance
+     *        will delegate; may not be null
+     */
+    public ThreadSafeNamespaceRegistry( NamespaceRegistry nonThreadSafeRegistry ) {
+        CheckArg.isNotNull(nonThreadSafeRegistry, "nonThreadSafeRegistry");
+        delegate = nonThreadSafeRegistry;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getNamespaceForPrefix( String prefix ) {
+        CheckArg.isNotNull(prefix, "prefix");
+        Lock lock = this.registryLock.readLock();
+        try {
+            lock.lock();
+            return this.delegate.getNamespaceForPrefix(prefix);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getPrefixForNamespaceUri( String namespaceUri,
+                                            boolean generateIfMissing ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        String prefix = null;
+        Lock lock = this.registryLock.readLock();
+        try {
+            lock.lock();
+            prefix = delegate.getPrefixForNamespaceUri(namespaceUri, false);
+        } finally {
+            lock.unlock();
+        }
+        if (prefix == null && generateIfMissing) {
+            // Get a write lock ...
+            lock = this.registryLock.writeLock();
+            try {
+                lock.lock();
+                prefix = delegate.getPrefixForNamespaceUri(namespaceUri, true);
+                return prefix;
+            } finally {
+                lock.unlock();
+            }
+        }
+        return prefix;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRegisteredNamespaceUri( String namespaceUri ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        Lock lock = this.registryLock.readLock();
+        try {
+            lock.lock();
+            return delegate.isRegisteredNamespaceUri(namespaceUri);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getDefaultNamespaceUri() {
+        Lock lock = this.registryLock.readLock();
+        try {
+            lock.lock();
+            return delegate.getDefaultNamespaceUri();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String register( String prefix,
+                            String namespaceUri ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        Lock lock = this.registryLock.writeLock();
+        try {
+            lock.lock();
+            return delegate.register(prefix, namespaceUri);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.NamespaceRegistry#unregister(java.lang.String)
+     */
+    public boolean unregister( String namespaceUri ) {
+        CheckArg.isNotNull(namespaceUri, "namespaceUri");
+        Lock lock = this.registryLock.writeLock();
+        try {
+            lock.lock();
+            return delegate.unregister(namespaceUri);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<String> getRegisteredNamespaceUris() {
+        Lock lock = this.registryLock.readLock();
+        try {
+            lock.lock();
+            return delegate.getRegisteredNamespaceUris();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.NamespaceRegistry#getNamespaces()
+     */
+    public Set<Namespace> getNamespaces() {
+        Lock lock = this.registryLock.readLock();
+        try {
+            lock.lock();
+            return delegate.getNamespaces();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        List<Namespace> namespaces = new ArrayList<Namespace>(getNamespaces());
+        Collections.sort(namespaces);
+        return namespaces.toString();
+    }
+
+}


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

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -424,6 +424,62 @@
     }
 
     @Test
+    public void shouldCreateNodeAndReturnGraph() {
+        graph.create(validPath).and().getNodeAt(validPath);
+        assertThat(numberOfExecutions, is(2));
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c");
+        assertNextRequestReadNode(Location.create(validPath));
+        assertNoMoreRequests();
+    }
+
+    @Test
+    public void shouldCreateNodeAtPathWithPropertiesAndReturnLocation() {
+        Location actual = graph.createAt(validPath).with(validIdProperty1).getLocation();
+        assertThat(actual, is(notNullValue()));
+        assertThat(numberOfExecutions, is(1));
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1);
+        assertNoMoreRequests();
+
+        actual = graph.createAt(validPath).with(validIdProperty1).and(validIdProperty2).getLocation();
+        assertThat(actual, is(notNullValue()));
+        assertThat(numberOfExecutions, is(1));
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1, validIdProperty2);
+        assertNoMoreRequests();
+    }
+
+    @Test
+    public void shouldCreateNodeAtPathWithPropertiesAndReturnNode() {
+        Node node = graph.createAt(validPath).with(validIdProperty1).getNode();
+        assertThat(node, is(notNullValue()));
+        assertThat(numberOfExecutions, is(2));
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1);
+        assertNextRequestReadNode(Location.create(validPath));
+        assertNoMoreRequests();
+
+        node = graph.createAt(validPath).with(validIdProperty1).and(validIdProperty2).getNode();
+        assertThat(node, is(notNullValue()));
+        assertThat(numberOfExecutions, is(2));
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1, validIdProperty2);
+        assertNextRequestReadNode(Location.create(validPath));
+        assertNoMoreRequests();
+    }
+
+    @Test
+    public void shouldCreateNodeAtPathWithPropertiesAndReturnGraph() {
+        graph.createAt(validPath).with(validIdProperty1).and().getNodeAt(validPath);
+        assertThat(numberOfExecutions, is(2));
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1);
+        assertNextRequestReadNode(Location.create(validPath));
+        assertNoMoreRequests();
+
+        graph.createAt(validPath).with(validIdProperty1).and(validIdProperty2).and().getNodeAt(validPath);
+        assertThat(numberOfExecutions, is(2));
+        assertNextRequestIsCreate(Location.create(validPath.getParent()), "c", validIdProperty1, validIdProperty2);
+        assertNextRequestReadNode(Location.create(validPath));
+        assertNoMoreRequests();
+    }
+
+    @Test
     public void shouldCreateNodesWithBatch() {
         graph.batch().create(validPath, validIdProperty1).and().remove("prop").on(validPathString).execute();
         graph.batch().move(validPath).and(validPath).into(validPathString).and().create(validPath).execute();
@@ -596,8 +652,8 @@
         assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", validPath));
 
         graph.set("propName").on(validPath).to(validPath.getLastSegment().getName());
-        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName",
-                                                                                  validPath.getLastSegment().getName()));
+        assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", validPath.getLastSegment()
+                                                                                                          .getName()));
         Date now = new Date();
         graph.set("propName").on(validPath).to(now);
         assertNextRequestUpdateProperties(Location.create(validPath), createProperty("propName", now));
@@ -720,8 +776,16 @@
         assertNextRequestIsMove(Location.create(validUuid), Location.create(validPath));
         assertNoMoreRequests();
 
-        graph.batch().move(validPath).into(validIdProperty1, validIdProperty2).and().move(validPathString).into(validIdProperty1,
-                                                                                                                validIdProperty2).and().move(validUuid).into(validPath).execute();
+        graph.batch()
+             .move(validPath)
+             .into(validIdProperty1, validIdProperty2)
+             .and()
+             .move(validPathString)
+             .into(validIdProperty1, validIdProperty2)
+             .and()
+             .move(validUuid)
+             .into(validPath)
+             .execute();
         assertThat(numberOfExecutions, is(1));
         extractRequestsFromComposite();
         assertNextRequestIsMove(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
@@ -747,8 +811,16 @@
         assertNextRequestIsCopy(Location.create(validUuid), Location.create(validPath));
         assertNoMoreRequests();
 
-        graph.batch().copy(validPath).into(validIdProperty1, validIdProperty2).and().copy(validPathString).into(validIdProperty1,
-                                                                                                                validIdProperty2).and().copy(validUuid).into(validPath).execute();
+        graph.batch()
+             .copy(validPath)
+             .into(validIdProperty1, validIdProperty2)
+             .and()
+             .copy(validPathString)
+             .into(validIdProperty1, validIdProperty2)
+             .and()
+             .copy(validUuid)
+             .into(validPath)
+             .execute();
         assertThat(numberOfExecutions, is(1));
         extractRequestsFromComposite();
         assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -26,210 +26,230 @@
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsNot.not;
 import static org.junit.Assert.assertThat;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
-
 import org.jboss.dna.common.text.NoOpEncoder;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.PathFactory;
 import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
 import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
 import org.jboss.dna.graph.property.basic.NameValueFactory;
 import org.jboss.dna.graph.property.basic.PathValueFactory;
+import org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry;
 import org.jboss.dna.graph.property.basic.StringValueFactory;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-
 /**
  * Tests <code>Location</code> class and factory constructors.
  */
 public class LocationTest {
 
-	private static final NoOpEncoder NO_OP_ENCODER = new NoOpEncoder();
-	private static final StringValueFactory STRING_VALUE_FACTORY = new StringValueFactory(NO_OP_ENCODER, NO_OP_ENCODER);
-	private static final NameValueFactory NAME_VALUE_FACTORY = new NameValueFactory(new BasicNamespaceRegistry("http://www.jboss.org/dna/1.0"), NO_OP_ENCODER, STRING_VALUE_FACTORY);
-	
-	private PathFactory pathFactory = new PathValueFactory(NO_OP_ENCODER, 
-			STRING_VALUE_FACTORY, NAME_VALUE_FACTORY);
-	
-	private static UUID uuid = UUID.randomUUID();
-	
-	private Path pathA = pathFactory.create("/A");
-	private Path pathABC = pathFactory.create("/A/B/C");
+    private static final NoOpEncoder NO_OP_ENCODER = new NoOpEncoder();
+    private static final StringValueFactory STRING_VALUE_FACTORY = new StringValueFactory(NO_OP_ENCODER, NO_OP_ENCODER);
+    private static final NameValueFactory NAME_VALUE_FACTORY = new NameValueFactory(
+                                                                                    new SimpleNamespaceRegistry(
+                                                                                                                "http://www.jboss.org/dna/1.0"),
+                                                                                    NO_OP_ENCODER, STRING_VALUE_FACTORY);
 
-	private static Property propA = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("A"), "Value A");
-	private static Property propB = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("B"), "Value B");
-	private static Property propU = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-	
-	private static List<Property> propListAB;
-	private static List<Property> propListABU;
-	
-	
+    private PathFactory pathFactory = new PathValueFactory(NO_OP_ENCODER, STRING_VALUE_FACTORY, NAME_VALUE_FACTORY);
+
+    private static UUID uuid = UUID.randomUUID();
+
+    private Path pathA = pathFactory.create("/A");
+    private Path pathABC = pathFactory.create("/A/B/C");
+
+    private static Property propA = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("A"), "Value A");
+    private static Property propB = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("B"), "Value B");
+    private static Property propU = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+
+    private static List<Property> propListAB;
+    private static List<Property> propListABU;
+
     @BeforeClass
-    public static void beforeAny() { 
-    	propListAB = new ArrayList<Property>();
-    	propListAB.add(propA);
-    	propListAB.add(propB);
+    public static void beforeAny() {
+        propListAB = new ArrayList<Property>();
+        propListAB.add(propA);
+        propListAB.add(propB);
 
-    	propListABU = new ArrayList<Property>();
-    	propListABU.add(propA);
-    	propListABU.add(propB);
-    	propListABU.add(propU);
+        propListABU = new ArrayList<Property>();
+        propListABU.add(propA);
+        propListABU.add(propB);
+        propListABU.add(propU);
 
     }
-    
+
     @Test
     public void locationsWithSamePathsAreEqual() {
-    	Location locationA1 = Location.create(pathA);
-    	Location locationA2 = Location.create(pathA);
-    	
-    	assertThat("Locations created with identical paths must be equal", locationA1, is(locationA2));
-    	
-    	Location locationABC1 = Location.create(pathABC);
-    	Location locationABC2 = Location.create(pathABC);
-    	
-    	assertThat("Locations created with identical non-trivial paths must be equal", locationABC1, is(locationABC2));
+        Location locationA1 = Location.create(pathA);
+        Location locationA2 = Location.create(pathA);
+
+        assertThat("Locations created with identical paths must be equal", locationA1, is(locationA2));
+
+        Location locationABC1 = Location.create(pathABC);
+        Location locationABC2 = Location.create(pathABC);
+
+        assertThat("Locations created with identical non-trivial paths must be equal", locationABC1, is(locationABC2));
     }
 
     @Test
     public void locationsWithSamePathsAreSame() {
-    	Location locationA1 = Location.create(pathA);
-    	Location locationA2 = Location.create(pathA);
-    	
-    	assertThat("isSame must return true for locations created with identical paths", locationA1.isSame(locationA2), is(true));
-    	
-    	Location locationABC1 = Location.create(pathABC);
-    	Location locationABC2 = Location.create(pathABC);
-    	
-    	assertThat("isSame must return true for locations created with identical, non-trivial paths", locationABC1.isSame(locationABC2), is(true));
+        Location locationA1 = Location.create(pathA);
+        Location locationA2 = Location.create(pathA);
+
+        assertThat("isSame must return true for locations created with identical paths", locationA1.isSame(locationA2), is(true));
+
+        Location locationABC1 = Location.create(pathABC);
+        Location locationABC2 = Location.create(pathABC);
+
+        assertThat("isSame must return true for locations created with identical, non-trivial paths",
+                   locationABC1.isSame(locationABC2),
+                   is(true));
     }
 
     @Test
     public void locationsWithSamePathsAndSamePropertyAreNotEqual() {
-    	Location locationA1 = Location.create(pathA, propA);
-    	Location locationA2 = Location.create(pathA, propA);
-    	
-    	assertThat("Locations created with identical paths and different property must be equal", locationA1, is(locationA2));
-    }    
+        Location locationA1 = Location.create(pathA, propA);
+        Location locationA2 = Location.create(pathA, propA);
 
+        assertThat("Locations created with identical paths and different property must be equal", locationA1, is(locationA2));
+    }
+
     @Test
     public void locationsWithSamePathsAndSamePropertyAreNotSame() {
-    	Location locationA1 = Location.create(pathA, propA);
-    	Location locationA2 = Location.create(pathA, propA);
-    	
-    	assertThat("isSame must return true for locations created with identical paths and property", locationA1.isSame(locationA2), is(true));
-    }   
-    
+        Location locationA1 = Location.create(pathA, propA);
+        Location locationA2 = Location.create(pathA, propA);
+
+        assertThat("isSame must return true for locations created with identical paths and property",
+                   locationA1.isSame(locationA2),
+                   is(true));
+    }
+
     @Test
     public void locationsWithSamePathsAndDifferentPropertyAreNotEqual() {
-    	Location locationA1 = Location.create(pathA, propA);
-    	Location locationA2 = Location.create(pathA, propB);
-    	
-    	assertThat("Locations created with identical paths and different property must not be equal", locationA1, not(locationA2));
-    }    
+        Location locationA1 = Location.create(pathA, propA);
+        Location locationA2 = Location.create(pathA, propB);
 
+        assertThat("Locations created with identical paths and different property must not be equal", locationA1, not(locationA2));
+    }
+
     @Test
     public void locationsWithSamePathsAndDifferentPropertyAreNotSame() {
-    	Location locationA1 = Location.create(pathA, propA);
-    	Location locationA2 = Location.create(pathA, propB);
-    	
-    	assertThat("isSame must not return true for locations created with identical paths and property", locationA1.isSame(locationA2), is(false));
-    }    
-    
+        Location locationA1 = Location.create(pathA, propA);
+        Location locationA2 = Location.create(pathA, propB);
+
+        assertThat("isSame must not return true for locations created with identical paths and property",
+                   locationA1.isSame(locationA2),
+                   is(false));
+    }
+
     @Test
     public void locationsWithDifferentPathsAndSamePropertyAreNotEqual() {
-    	Location locationA1 = Location.create(pathA, propA);
-    	Location locationA2 = Location.create(pathABC, propA);
-    	
-    	assertThat("Locations created with different paths and the same property must not be equal", locationA1, not(locationA2));
-    }    
+        Location locationA1 = Location.create(pathA, propA);
+        Location locationA2 = Location.create(pathABC, propA);
 
+        assertThat("Locations created with different paths and the same property must not be equal", locationA1, not(locationA2));
+    }
+
     @Test
     public void locationsWithDifferentPathsAndSamePropertyAreNotSame() {
-    	Location locationA1 = Location.create(pathA, propA);
-    	Location locationA2 = Location.create(pathABC, propA);
-    	
-    	assertThat("isSame must not return true for locations created with different paths and the same property", locationA1.isSame(locationA2), is(false));
-    }      
+        Location locationA1 = Location.create(pathA, propA);
+        Location locationA2 = Location.create(pathABC, propA);
 
+        assertThat("isSame must not return true for locations created with different paths and the same property",
+                   locationA1.isSame(locationA2),
+                   is(false));
+    }
+
     @Test
     public void locationsWithSamePathsAndSamePropertiesAreNotEqual() {
-    	Location locationA1 = Location.create(pathA, propListAB);
-    	Location locationA2 = Location.create(pathA, propListAB);
-    	
-    	assertThat("Locations created with identical paths and different properties must be equal", locationA1, is(locationA2));
-    }    
+        Location locationA1 = Location.create(pathA, propListAB);
+        Location locationA2 = Location.create(pathA, propListAB);
 
+        assertThat("Locations created with identical paths and different properties must be equal", locationA1, is(locationA2));
+    }
+
     @Test
     public void locationsWithSamePathsAndSamePropertiesAreNotSame() {
-    	Location locationA1 = Location.create(pathA, propListAB);
-    	Location locationA2 = Location.create(pathA, propListAB);
-    	
-    	assertThat("isSame must return true for locations created with identical paths and properties", locationA1.isSame(locationA2), is(true));
-    }   
-    
+        Location locationA1 = Location.create(pathA, propListAB);
+        Location locationA2 = Location.create(pathA, propListAB);
+
+        assertThat("isSame must return true for locations created with identical paths and properties",
+                   locationA1.isSame(locationA2),
+                   is(true));
+    }
+
     @Test
     public void locationsWithSamePathsAndDifferentPropertiesAreNotEqual() {
-    	Location locationA1 = Location.create(pathA, propListAB);
-    	Location locationA2 = Location.create(pathA, propListABU);
-    	
-    	assertThat("Locations created with identical paths and different properties must not be equal", locationA1, not(locationA2));
-    }    
+        Location locationA1 = Location.create(pathA, propListAB);
+        Location locationA2 = Location.create(pathA, propListABU);
 
+        assertThat("Locations created with identical paths and different properties must not be equal",
+                   locationA1,
+                   not(locationA2));
+    }
+
     @Test
     public void locationsWithSamePathsAndDifferentPropertiesAreNotSame() {
-    	Location locationA1 = Location.create(pathA, propListAB);
-    	Location locationA2 = Location.create(pathA, propListABU);
-    	
-    	assertThat("isSame must not return true for locations created with identical paths and different properties", locationA1.isSame(locationA2), is(false));
-    }    
-    
+        Location locationA1 = Location.create(pathA, propListAB);
+        Location locationA2 = Location.create(pathA, propListABU);
+
+        assertThat("isSame must not return true for locations created with identical paths and different properties",
+                   locationA1.isSame(locationA2),
+                   is(false));
+    }
+
     @Test
     public void locationsWithDifferentPathsAndSamePropertiesAreNotEqual() {
-    	Location locationA1 = Location.create(pathA, propListAB);
-    	Location locationA2 = Location.create(pathABC, propListAB);
-    	
-    	assertThat("Locations created with identical paths and different properties must not be equal", locationA1, not(locationA2));
-    }    
+        Location locationA1 = Location.create(pathA, propListAB);
+        Location locationA2 = Location.create(pathABC, propListAB);
 
+        assertThat("Locations created with identical paths and different properties must not be equal",
+                   locationA1,
+                   not(locationA2));
+    }
+
     @Test
     public void locationsWithDifferentPathsAndSamePropertiesAreNotSame() {
-    	Location locationA1 = Location.create(pathA, propListAB);
-    	Location locationA2 = Location.create(pathABC, propListAB);
-    	
-    	assertThat("isSame must not return true for locations created with different paths and the same properties", locationA1.isSame(locationA2), is(false));
-    }    
-    
+        Location locationA1 = Location.create(pathA, propListAB);
+        Location locationA2 = Location.create(pathABC, propListAB);
+
+        assertThat("isSame must not return true for locations created with different paths and the same properties",
+                   locationA1.isSame(locationA2),
+                   is(false));
+    }
+
     @Test
     public void testTransitivityOfWithOperationForPathAndUUID() {
-    	Location locationA1 = Location.create(pathA);
-    	locationA1 = locationA1.with(uuid);
-    	
-    	Location locationU1 = Location.create(uuid);
-    	locationU1 = locationU1.with(pathA);
-    	
-    	assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true));
-    	assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true));
-    	assertThat("With() operation must be transitive for getString", locationA1.getString().equals(locationU1.getString()), is(true));
-    	assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true));
+        Location locationA1 = Location.create(pathA);
+        locationA1 = locationA1.with(uuid);
+
+        Location locationU1 = Location.create(uuid);
+        locationU1 = locationU1.with(pathA);
+
+        assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true));
+        assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true));
+        assertThat("With() operation must be transitive for getString",
+                   locationA1.getString().equals(locationU1.getString()),
+                   is(true));
+        assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true));
     }
-        
+
     @Test
     public void testTransitivityOfWithOperationForPathAndProperty() {
-    	Location locationA1 = Location.create(pathA);
-    	locationA1 = locationA1.with(propB);
-    	
-    	Location locationU1 = Location.create(propB);
-    	locationU1 = locationU1.with(pathA);
-    	
-    	assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true));
-    	assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true));
-    	assertThat("With() operation must be transitive for getString", locationA1.getString().equals(locationU1.getString()), is(true));
-    	assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true));
-    } 
+        Location locationA1 = Location.create(pathA);
+        locationA1 = locationA1.with(propB);
 
+        Location locationU1 = Location.create(propB);
+        locationU1 = locationU1.with(pathA);
+
+        assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true));
+        assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true));
+        assertThat("With() operation must be transitive for getString",
+                   locationA1.getString().equals(locationU1.getString()),
+                   is(true));
+        assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true));
+    }
+
 }

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/AbstractValueComparatorsTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/AbstractValueComparatorsTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/AbstractValueComparatorsTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -32,8 +32,7 @@
 import java.util.Comparator;
 import java.util.List;
 import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.property.ValueFactories;
-import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
+import org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry;
 import org.jboss.dna.graph.property.basic.StandardValueFactories;
 import org.junit.Test;
 
@@ -43,13 +42,14 @@
  */
 public abstract class AbstractValueComparatorsTest<T> {
 
-    public static final BasicNamespaceRegistry NAMESPACE_REGISTRY = new BasicNamespaceRegistry();
+    public static final NamespaceRegistry NAMESPACE_REGISTRY = new SimpleNamespaceRegistry();
     public static final ValueFactories VALUE_FACTORIES = new StandardValueFactories(NAMESPACE_REGISTRY);
 
     protected final Comparator<T> comparator;
     protected final T[] validNonNullValues;
 
-    protected AbstractValueComparatorsTest( Comparator<T> comparator, T... validNonNullValues ) {
+    protected AbstractValueComparatorsTest( Comparator<T> comparator,
+                                            T... validNonNullValues ) {
         CheckArg.isNotNull(comparator, "comparator");
         CheckArg.isNotEmpty(validNonNullValues, "validNonNullValues");
         this.comparator = comparator;
@@ -125,7 +125,8 @@
         }
     }
 
-    protected void assertValuesCompareUsing( T value1, T value2 ) {
+    protected void assertValuesCompareUsing( T value1,
+                                             T value2 ) {
         int value1ToValue2 = comparator.compare(value1, value2);
         int value2ToValue1 = comparator.compare(value2, value1);
         if (value1ToValue2 == 0) {

Added: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/AbstractNamespaceRegistryTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/AbstractNamespaceRegistryTest.java	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/AbstractNamespaceRegistryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,170 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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.property.basic;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItem;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.junit.Before;
+import org.junit.Test;
+
+public abstract class AbstractNamespaceRegistryTest<NamespaceRegistryType extends NamespaceRegistry> {
+
+    protected String validNamespaceUri1;
+    protected String validNamespaceUri2;
+    protected String validNamespaceUri3;
+    protected String validPrefix1;
+    protected String validPrefix2;
+    protected NamespaceRegistryType namespaceRegistry;
+
+    @Before
+    public void setUp() {
+        validNamespaceUri1 = "http://example.com/foo";
+        validNamespaceUri2 = "http://acme.com/something";
+        validNamespaceUri3 = "http://www.redhat.com";
+        validPrefix1 = "foo";
+        validPrefix2 = "acme";
+        namespaceRegistry = createNamespaceRegistry();
+    }
+
+    protected abstract NamespaceRegistryType createNamespaceRegistry();
+
+    @Test
+    public void shouldReturnNullForNamespaceUriIfPrefixIsNotRegistered() {
+        assertThat(namespaceRegistry.getNamespaceForPrefix("notfound"), is(nullValue()));
+        // now register some namespaces ...
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        assertThat(namespaceRegistry.getNamespaceForPrefix("notfound"), is(nullValue()));
+    }
+
+    @Test
+    public void shouldReturnNamespaceUriForPrefixThatIsRegistered() {
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
+        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowNullPrefixParameterWhenGettingNamespaceUri() {
+        namespaceRegistry.getNamespaceForPrefix(null);
+    }
+
+    @Test
+    public void shouldReturnNullForPrefixIfNamespaceUriIsNotRegistered() {
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(nullValue()));
+        // now register some namespaces ...
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(nullValue()));
+    }
+
+    @Test
+    public void shouldReturnPrefixForNamespaceUriThatIsRegistered() {
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri1, false), is(validPrefix1));
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, false), is(validPrefix2));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowNullNamespaceUriParameterWhenGettingPrefix() {
+        namespaceRegistry.getPrefixForNamespaceUri(null, false);
+    }
+
+    @Test
+    public void shouldAlwaysHaveDefaultNamespaceRegistered() {
+        assertThat(namespaceRegistry.getDefaultNamespaceUri(), is(notNullValue()));
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        assertThat(namespaceRegistry.getDefaultNamespaceUri(), is(notNullValue()));
+    }
+
+    @Test
+    public void shouldReturnNonNullDefaultNamespaceUriWhenThereAreNamespacesRegisteredIncludineOneWithZeroLengthPrefix() {
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register("", validNamespaceUri2);
+        assertThat(namespaceRegistry.getDefaultNamespaceUri(), is(validNamespaceUri2));
+        assertThat(namespaceRegistry.getNamespaceForPrefix(""), is(validNamespaceUri2));
+        assertThat(namespaceRegistry.getRegisteredNamespaceUris(), hasItem(validNamespaceUri2));
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, false), is(""));
+    }
+
+    @Test
+    public void shouldNotFindRegisteredNamespaceIfNamespaceNotRegistered() {
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(false));
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(false));
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri3), is(false));
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(true));
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(true));
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri3), is(false));
+    }
+
+    @Test
+    public void shouldFindRegisteredNamespace() {
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(true));
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(true));
+    }
+
+    @Test
+    public void shouldBeAbleToCopyNamespacesToAnotherRegistry() {
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        namespaceRegistry.register("", validNamespaceUri3);
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(true));
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(true));
+        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri3), is(true));
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri1, false), is(validPrefix1));
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, false), is(validPrefix2));
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(""));
+        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
+        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
+        assertThat(namespaceRegistry.getNamespaceForPrefix(""), is(validNamespaceUri3));
+
+        NamespaceRegistry newRegistry = new SimpleNamespaceRegistry();
+        for (String uri : this.namespaceRegistry.getRegisteredNamespaceUris()) {
+            String prefix = this.namespaceRegistry.getPrefixForNamespaceUri(uri, false);
+            newRegistry.register(prefix, uri);
+        }
+        assertThat(newRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(true));
+        assertThat(newRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(true));
+        assertThat(newRegistry.isRegisteredNamespaceUri(validNamespaceUri3), is(true));
+        assertThat(newRegistry.getPrefixForNamespaceUri(validNamespaceUri1, false), is(validPrefix1));
+        assertThat(newRegistry.getPrefixForNamespaceUri(validNamespaceUri2, false), is(validPrefix2));
+        assertThat(newRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(""));
+        assertThat(newRegistry.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
+        assertThat(newRegistry.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
+        assertThat(newRegistry.getNamespaceForPrefix(""), is(validNamespaceUri3));
+
+    }
+
+}


Property changes on: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/AbstractNamespaceRegistryTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicNameTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicNameTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicNameTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -30,6 +30,7 @@
 import org.jboss.dna.common.text.TextEncoder;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
 import org.jboss.dna.graph.property.Path;
 import org.junit.Before;
 import org.junit.Test;
@@ -40,7 +41,7 @@
  */
 public class BasicNameTest {
 
-    private BasicNamespaceRegistry namespaceRegistry;
+    private NamespaceRegistry namespaceRegistry;
     private Name name;
     private String validNamespaceUri;
     private String validLocalName;
@@ -55,7 +56,7 @@
         this.validLocalName = "localPart";
         this.name = new BasicName(validNamespaceUri, validLocalName);
         this.encoder = Path.URL_ENCODER;
-        this.namespaceRegistry = new BasicNamespaceRegistry();
+        this.namespaceRegistry = new SimpleNamespaceRegistry();
         this.namespaceRegistry.register(validNamespacePrefix, validNamespaceUri);
         this.delimiterEncoder = new TextEncoder() {
             public String encode( String text ) {

Deleted: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicNamespaceRegistryTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicNamespaceRegistryTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicNamespaceRegistryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -1,186 +0,0 @@
-/*
- * 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. 
- *
- * JBoss DNA is free software. 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.property.basic;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.junit.Assert.assertThat;
-import static org.junit.matchers.JUnitMatchers.hasItem;
-import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author Randall Hauch
- */
-public class BasicNamespaceRegistryTest {
-
-    private String validNamespaceUri1;
-    private String validNamespaceUri2;
-    private String validNamespaceUri3;
-    private String validPrefix1;
-    private String validPrefix2;
-    private BasicNamespaceRegistry namespaceRegistry;
-
-    @Before
-    public void setUp() {
-        namespaceRegistry = new BasicNamespaceRegistry();
-        validNamespaceUri1 = "http://www.jboss.org/dna/2";
-        validNamespaceUri2 = "http://acme.com/something";
-        validNamespaceUri3 = "http://www.redhat.com";
-        validPrefix1 = "dna";
-        validPrefix2 = "acme";
-    }
-
-    @Test
-    public void shouldReturnNullForNamespaceUriIfPrefixIsNotRegistered() {
-        assertThat(namespaceRegistry.getNamespaceForPrefix("notfound"), is(nullValue()));
-        // now register some namespaces ...
-        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
-        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
-        assertThat(namespaceRegistry.getNamespaceForPrefix("notfound"), is(nullValue()));
-    }
-
-    @Test
-    public void shouldReturnNamespaceUriForPrefixThatIsRegistered() {
-        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
-        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
-        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
-        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
-    }
-
-    @Test( expected = IllegalArgumentException.class )
-    public void shouldNotAllowNullPrefixParameterWhenGettingNamespaceUri() {
-        namespaceRegistry.getNamespaceForPrefix(null);
-    }
-
-    @Test
-    public void shouldReturnNullForPrefixIfNamespaceUriIsNotRegistered() {
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(nullValue()));
-        // now register some namespaces ...
-        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
-        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(nullValue()));
-    }
-
-    @Test
-    public void shouldGeneratePrefixIfNamespaceUriIsNotRegistered() {
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(nullValue()));
-        // Now get the generated prefix ...
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, true), is("ns001"));
-        // Change the template ...
-        namespaceRegistry.setGeneratedPrefixTemplate("xyz0000abc");
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, true), is("xyz0002abc"));
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, true), is("xyz0002abc"));
-        // Change the template again ...
-        namespaceRegistry.setGeneratedPrefixTemplate("xyz####abc");
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri1, true), is("xyz3abc"));
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri1, true), is("xyz3abc"));
-    }
-
-    @Test
-    public void shouldReturnPrefixForNamespaceUriThatIsRegistered() {
-        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
-        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri1, false), is(validPrefix1));
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, false), is(validPrefix2));
-    }
-
-    @Test( expected = IllegalArgumentException.class )
-    public void shouldNotAllowNullNamespaceUriParameterWhenGettingPrefix() {
-        namespaceRegistry.getPrefixForNamespaceUri(null, false);
-    }
-
-    @Test
-    public void shouldAlwaysHaveDefaultNamespaceRegistered() {
-        assertThat(namespaceRegistry.getDefaultNamespaceUri(), is(notNullValue()));
-        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
-        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
-        assertThat(namespaceRegistry.getDefaultNamespaceUri(), is(notNullValue()));
-    }
-
-    @Test
-    public void shouldReturnNonNullDefaultNamespaceUriWhenThereAreNamespacesRegisteredIncludineOneWithZeroLengthPrefix() {
-        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
-        namespaceRegistry.register("", validNamespaceUri2);
-        assertThat(namespaceRegistry.getDefaultNamespaceUri(), is(validNamespaceUri2));
-        assertThat(namespaceRegistry.getNamespaceForPrefix(""), is(validNamespaceUri2));
-        assertThat(namespaceRegistry.getRegisteredNamespaceUris(), hasItem(validNamespaceUri2));
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, false), is(""));
-    }
-
-    @Test
-    public void shouldNotFindRegisteredNamespaceIfNamespaceNotRegistered() {
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(false));
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(false));
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri3), is(false));
-        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
-        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(true));
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(true));
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri3), is(false));
-    }
-
-    @Test
-    public void shouldFindRegisteredNamespace() {
-        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
-        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(true));
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(true));
-    }
-
-    @Test
-    public void shouldBeAbleToCopyNamespacesToAnotherRegistry() {
-        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
-        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
-        namespaceRegistry.register("", validNamespaceUri3);
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(true));
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(true));
-        assertThat(namespaceRegistry.isRegisteredNamespaceUri(validNamespaceUri3), is(true));
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri1, false), is(validPrefix1));
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, false), is(validPrefix2));
-        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(""));
-        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
-        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
-        assertThat(namespaceRegistry.getNamespaceForPrefix(""), is(validNamespaceUri3));
-
-        BasicNamespaceRegistry newRegistry = new BasicNamespaceRegistry();
-        for (String uri : this.namespaceRegistry.getRegisteredNamespaceUris()) {
-            String prefix = this.namespaceRegistry.getPrefixForNamespaceUri(uri, false);
-            newRegistry.register(prefix, uri);
-        }
-        assertThat(newRegistry.isRegisteredNamespaceUri(validNamespaceUri1), is(true));
-        assertThat(newRegistry.isRegisteredNamespaceUri(validNamespaceUri2), is(true));
-        assertThat(newRegistry.isRegisteredNamespaceUri(validNamespaceUri3), is(true));
-        assertThat(newRegistry.getPrefixForNamespaceUri(validNamespaceUri1, false), is(validPrefix1));
-        assertThat(newRegistry.getPrefixForNamespaceUri(validNamespaceUri2, false), is(validPrefix2));
-        assertThat(newRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(""));
-        assertThat(newRegistry.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
-        assertThat(newRegistry.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
-        assertThat(newRegistry.getNamespaceForPrefix(""), is(validNamespaceUri3));
-
-    }
-
-}

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathOldTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathOldTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathOldTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -38,6 +38,7 @@
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.property.InvalidPathException;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.ValueFormatException;
 import org.junit.Before;
@@ -52,7 +53,7 @@
     public static final TextEncoder NO_OP_ENCODER = Path.NO_OP_ENCODER;
     public static final Path ROOT = RootPath.INSTANCE;
 
-    private BasicNamespaceRegistry namespaceRegistry;
+    private NamespaceRegistry namespaceRegistry;
     private String validNamespaceUri;
     private Path path;
     private Path path2;
@@ -75,7 +76,7 @@
             validSegmentsList.add(segment);
         }
         path = new BasicPath(validSegmentsList, true);
-        namespaceRegistry = new BasicNamespaceRegistry();
+        namespaceRegistry = new SimpleNamespaceRegistry();
         namespaceRegistry.register(validNamespacePrefix, validNamespaceUri);
         StringValueFactory stringValueFactory = new StringValueFactory(Path.DEFAULT_DECODER, Path.DEFAULT_ENCODER);
         NameValueFactory nameValueFactory = new NameValueFactory(namespaceRegistry, Path.DEFAULT_DECODER, stringValueFactory);

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathSegmentTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathSegmentTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathSegmentTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -30,14 +30,9 @@
 import org.jboss.dna.common.text.TextEncoder;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.ValueFactory;
-import org.jboss.dna.graph.property.basic.BasicName;
-import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
-import org.jboss.dna.graph.property.basic.BasicPathSegment;
-import org.jboss.dna.graph.property.basic.NameValueFactory;
-import org.jboss.dna.graph.property.basic.PathValueFactory;
-import org.jboss.dna.graph.property.basic.StringValueFactory;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -48,7 +43,7 @@
 
     public static final TextEncoder NO_OP_ENCODER = Path.NO_OP_ENCODER;
 
-    private BasicNamespaceRegistry registry;
+    private NamespaceRegistry registry;
     private ValueFactory<String> stringValueFactory;
     private NameValueFactory nameFactory;
     private PathValueFactory factory;
@@ -58,7 +53,7 @@
 
     @Before
     public void beforeEach() {
-        this.registry = new BasicNamespaceRegistry();
+        this.registry = new SimpleNamespaceRegistry();
         this.registry.register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
         this.stringValueFactory = new StringValueFactory(Path.DEFAULT_DECODER, Path.DEFAULT_ENCODER);
         this.nameFactory = new NameValueFactory(registry, Path.DEFAULT_DECODER, stringValueFactory);

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicPathTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -37,6 +37,7 @@
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.property.InvalidPathException;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.ValueFormatException;
 import org.junit.Before;
@@ -51,7 +52,7 @@
     public static final TextEncoder NO_OP_ENCODER = Path.NO_OP_ENCODER;
     public static final Path ROOT = RootPath.INSTANCE;
 
-    private BasicNamespaceRegistry namespaceRegistry;
+    private NamespaceRegistry namespaceRegistry;
     private String validNamespaceUri;
     private Path path2;
     private Path.Segment[] validSegments;
@@ -74,7 +75,7 @@
             validSegmentsList.add(segment);
         }
         super.path = new BasicPath(validSegmentsList, true);
-        namespaceRegistry = new BasicNamespaceRegistry();
+        namespaceRegistry = new SimpleNamespaceRegistry();
         namespaceRegistry.register(validNamespacePrefix, validNamespaceUri);
         StringValueFactory stringValueFactory = new StringValueFactory(Path.DEFAULT_DECODER, Path.DEFAULT_ENCODER);
         NameValueFactory nameValueFactory = new NameValueFactory(namespaceRegistry, Path.DEFAULT_DECODER, stringValueFactory);

Added: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/GraphNamespaceRegistryTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/GraphNamespaceRegistryTest.java	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/GraphNamespaceRegistryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,141 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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.property.basic;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import java.util.Set;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyFactory;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class GraphNamespaceRegistryTest extends AbstractNamespaceRegistryTest<GraphNamespaceRegistry> {
+
+    protected ExecutionContext context;
+    protected InMemoryRepositorySource source;
+    protected Graph graph;
+    private Path pathToParentOfNamespaceNodes;
+    private Name uriPropertyName;
+    private Property[] additionalNamespaceProperties;
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.basic.AbstractNamespaceRegistryTest#setUp()
+     */
+    @Override
+    public void setUp() {
+        super.setUp();
+
+        // Set up the context and register any namespaces that we'll be using to manage the namespaces ...
+        context = new ExecutionContext();
+        NameFactory nameFactory = context.getValueFactories().getNameFactory();
+        PropertyFactory propertyFactory = context.getPropertyFactory();
+        context.getNamespaceRegistry().register("nsx", "http://www.example.com/namespaces");
+        context.getNamespaceRegistry().register("other", "http://www.example.com/other");
+        uriPropertyName = context.getValueFactories().getNameFactory().create("nsx:uri");
+        additionalNamespaceProperties = new Property[] {
+            propertyFactory.create(nameFactory.create("nsx:something"), "Some value"),
+            propertyFactory.create(nameFactory.create("nsx:something2"), "Some value2"),
+            propertyFactory.create(nameFactory.create("other:something2"), "Some other value2")};
+
+        // Set up the repository that we'll be using ...
+        source = new InMemoryRepositorySource();
+        source.setName("namespace repository");
+        graph = Graph.create(source, context);
+
+        // Create the path to the where the namespaces will be managed ...
+        pathToParentOfNamespaceNodes = graph.create("/a").and().create("/a/b").and().createAt("/a/b/c").getLocation().getPath();
+
+        // Now set up the graph-based namespace registry ...
+        namespaceRegistry = new GraphNamespaceRegistry(graph, pathToParentOfNamespaceNodes, uriPropertyName,
+                                                       additionalNamespaceProperties);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.basic.AbstractNamespaceRegistryTest#createNamespaceRegistry()
+     */
+    @Override
+    protected GraphNamespaceRegistry createNamespaceRegistry() {
+        return null;
+    }
+
+    @Test
+    public void shouldInitializeFromPersistedContent() {
+        // Add some namespaces ...
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
+        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
+
+        // Now set up the graph-based namespace registry ...
+        GraphNamespaceRegistry registry2 = new GraphNamespaceRegistry(graph, pathToParentOfNamespaceNodes, uriPropertyName,
+                                                                      additionalNamespaceProperties);
+        // All namespaces should match ...
+        Set<NamespaceRegistry.Namespace> all = namespaceRegistry.getNamespaces();
+        Set<NamespaceRegistry.Namespace> all2 = registry2.getNamespaces();
+        assertThat(all, is(all2));
+        assertThat(registry2.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
+        assertThat(registry2.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
+
+        registry2.refresh();
+        all2 = registry2.getNamespaces();
+        assertThat(all, is(all2));
+        assertThat(registry2.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
+        assertThat(registry2.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
+    }
+
+    @Test
+    public void shouldRefreshFromPersistedContent() {
+        // Add some namespaces ...
+        namespaceRegistry.register(validPrefix1, validNamespaceUri1);
+        namespaceRegistry.register(validPrefix2, validNamespaceUri2);
+        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix1), is(validNamespaceUri1));
+        assertThat(namespaceRegistry.getNamespaceForPrefix(validPrefix2), is(validNamespaceUri2));
+
+        // Get the namespaces, refresh, then get all the namespaces again
+        Set<NamespaceRegistry.Namespace> allBefore = namespaceRegistry.getNamespaces();
+        namespaceRegistry.refresh();
+        Set<NamespaceRegistry.Namespace> allAfter = namespaceRegistry.getNamespaces();
+
+        assertThat(allBefore, is(allAfter));
+        for (NamespaceRegistry.Namespace namespace : allBefore) {
+            assertThat(namespaceRegistry.getNamespaceForPrefix(namespace.getPrefix()), is(namespace.getNamespaceUri()));
+            assertThat(namespaceRegistry.getPrefixForNamespaceUri(namespace.getNamespaceUri(), false), is(namespace.getPrefix()));
+        }
+    }
+
+}


Property changes on: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/GraphNamespaceRegistryTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/InMemoryBinaryValueFactoryTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/InMemoryBinaryValueFactoryTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/InMemoryBinaryValueFactoryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -23,8 +23,8 @@
  */
 package org.jboss.dna.graph.property.basic;
 
-import static org.jboss.dna.graph.property.basic.BinaryContains.hasContent;
 import static org.hamcrest.core.Is.is;
+import static org.jboss.dna.graph.property.basic.BinaryContains.hasContent;
 import static org.junit.Assert.assertThat;
 import java.io.ByteArrayInputStream;
 import java.io.StringReader;
@@ -40,15 +40,9 @@
 import org.jboss.dna.common.text.TextEncoder;
 import org.jboss.dna.graph.property.Binary;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.Reference;
-import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
-import org.jboss.dna.graph.property.basic.InMemoryBinaryValueFactory;
-import org.jboss.dna.graph.property.basic.JodaDateTime;
-import org.jboss.dna.graph.property.basic.NameValueFactory;
-import org.jboss.dna.graph.property.basic.PathValueFactory;
-import org.jboss.dna.graph.property.basic.StringValueFactory;
-import org.jboss.dna.graph.property.basic.UuidReference;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -60,7 +54,7 @@
     private InMemoryBinaryValueFactory factory;
     private StringValueFactory stringFactory;
     private NameValueFactory nameFactory;
-    private BasicNamespaceRegistry namespaceRegistry;
+    private NamespaceRegistry namespaceRegistry;
     private PathValueFactory pathFactory;
     private TextEncoder encoder;
 
@@ -72,7 +66,7 @@
         encoder = Path.URL_ENCODER;
         stringFactory = new StringValueFactory(Path.URL_DECODER, encoder);
         factory = new InMemoryBinaryValueFactory(Path.URL_DECODER, stringFactory);
-        namespaceRegistry = new BasicNamespaceRegistry();
+        namespaceRegistry = new SimpleNamespaceRegistry();
         namespaceRegistry.register("jboss", "http://www.jboss.org");
         namespaceRegistry.register("dna", "http://www.jboss.org/dna");
         nameFactory = new NameValueFactory(namespaceRegistry, Path.URL_DECODER, stringFactory);

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/LocalNamespaceRegistryTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/LocalNamespaceRegistryTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/LocalNamespaceRegistryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -28,8 +28,6 @@
 import java.util.HashMap;
 import java.util.Map;
 import org.jboss.dna.graph.property.NamespaceRegistry;
-import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
-import org.jboss.dna.graph.property.basic.LocalNamespaceRegistry;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -44,7 +42,7 @@
 
     @Before
     public void beforeEach() {
-        delegate = new BasicNamespaceRegistry();
+        delegate = new SimpleNamespaceRegistry();
         local = new LocalNamespaceRegistry(delegate);
         uri = "http://www.example.com";
     }

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/NameValueFactoryTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/NameValueFactoryTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/NameValueFactoryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -34,9 +34,6 @@
 import org.jboss.dna.graph.property.NamespaceRegistry;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.ValueFactory;
-import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
-import org.jboss.dna.graph.property.basic.NameValueFactory;
-import org.jboss.dna.graph.property.basic.StringValueFactory;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -57,7 +54,7 @@
 
     @Before
     public void beforeEach() {
-        this.registry = new BasicNamespaceRegistry();
+        this.registry = new SimpleNamespaceRegistry();
         this.registry.register("dna", "http://www.jboss.org/dna/namespace");
         this.encoder = Path.DEFAULT_ENCODER;
         this.decoder = Path.DEFAULT_DECODER;

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/PathValueFactoryTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/PathValueFactoryTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/PathValueFactoryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -23,8 +23,8 @@
  */
 package org.jboss.dna.graph.property.basic;
 
-import static org.jboss.dna.graph.property.basic.IsPathContaining.hasSegments;
 import static org.hamcrest.core.Is.is;
+import static org.jboss.dna.graph.property.basic.IsPathContaining.hasSegments;
 import static org.junit.Assert.assertThat;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -33,11 +33,6 @@
 import org.jboss.dna.graph.property.Name;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.ValueFactory;
-import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
-import org.jboss.dna.graph.property.basic.BasicPathSegment;
-import org.jboss.dna.graph.property.basic.NameValueFactory;
-import org.jboss.dna.graph.property.basic.PathValueFactory;
-import org.jboss.dna.graph.property.basic.StringValueFactory;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -48,7 +43,7 @@
 
     public static final TextEncoder NO_OP_ENCODER = Path.NO_OP_ENCODER;
 
-    private BasicNamespaceRegistry registry;
+    private SimpleNamespaceRegistry registry;
     private ValueFactory<String> stringValueFactory;
     private NameValueFactory nameFactory;
     private PathValueFactory factory;
@@ -57,7 +52,7 @@
 
     @Before
     public void beforeEach() {
-        this.registry = new BasicNamespaceRegistry();
+        this.registry = new SimpleNamespaceRegistry();
         this.registry.register("dna", "http://www.jboss.org/dna/namespace");
         this.stringValueFactory = new StringValueFactory(Path.DEFAULT_DECODER, Path.DEFAULT_ENCODER);
         this.nameFactory = new NameValueFactory(registry, Path.DEFAULT_DECODER, stringValueFactory);

Copied: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/SimpleNamespaceRegistryTest.java (from rev 723, trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/BasicNamespaceRegistryTest.java)
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/SimpleNamespaceRegistryTest.java	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/SimpleNamespaceRegistryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,61 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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.property.basic;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class SimpleNamespaceRegistryTest extends AbstractNamespaceRegistryTest<SimpleNamespaceRegistry> {
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.basic.AbstractNamespaceRegistryTest#createNamespaceRegistry()
+     */
+    @Override
+    protected SimpleNamespaceRegistry createNamespaceRegistry() {
+        return new SimpleNamespaceRegistry();
+    }
+
+    @Test
+    public void shouldGeneratePrefixIfNamespaceUriIsNotRegistered() {
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, false), is(nullValue()));
+        // Now get the generated prefix ...
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri3, true), is("ns001"));
+        // Change the template ...
+        namespaceRegistry.setGeneratedPrefixTemplate("xyz0000abc");
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, true), is("xyz0002abc"));
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri2, true), is("xyz0002abc"));
+        // Change the template again ...
+        namespaceRegistry.setGeneratedPrefixTemplate("xyz####abc");
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri1, true), is("xyz3abc"));
+        assertThat(namespaceRegistry.getPrefixForNamespaceUri(validNamespaceUri1, true), is("xyz3abc"));
+    }
+
+}


Property changes on: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/SimpleNamespaceRegistryTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/ThreadSafeNamespaceRegistryTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/ThreadSafeNamespaceRegistryTest.java	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/ThreadSafeNamespaceRegistryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,42 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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.property.basic;
+
+
+/**
+ * @author Randall Hauch
+ */
+public class ThreadSafeNamespaceRegistryTest extends AbstractNamespaceRegistryTest<ThreadSafeNamespaceRegistry> {
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.property.basic.AbstractNamespaceRegistryTest#createNamespaceRegistry()
+     */
+    @Override
+    protected ThreadSafeNamespaceRegistry createNamespaceRegistry() {
+        return new ThreadSafeNamespaceRegistry(new SimpleNamespaceRegistry());
+    }
+
+}


Property changes on: trunk/dna-graph/src/test/java/org/jboss/dna/graph/property/basic/ThreadSafeNamespaceRegistryTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java	                        (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,37 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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 org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.basic.BasicName;
+
+/**
+ * @author Randall Hauch
+ */
+public class DnaLexicon extends org.jboss.dna.graph.DnaLexicon {
+
+    public static final Name NAMESPACES = new BasicName(Namespace.URI, "namespaces");
+    public static final Name NAMESPACE = new BasicName(Namespace.URI, "namespace");
+
+}


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

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-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -1,57 +1,78 @@
-/*
- * 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.
- *
- * JBoss DNA is free software. 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 org.jboss.dna.common.i18n.I18n;
-
-/**
- * @author John Verhaeg
- * @author Randall Hauch
- */
-public final class JcrI18n {
-
-    public static I18n cannotConvertValue;
-    public static I18n credentialsMustProvideJaasMethod;
-    public static I18n credentialsMustReturnAccessControlContext;
-    public static I18n credentialsMustReturnLoginContext;
-    public static I18n defaultWorkspaceName;
-    public static I18n inputStreamConsumed;
-    public static I18n nonInputStreamConsumed;
-    public static I18n pathNotFound;
-    public static I18n permissionDenied;
-    public static I18n repositoryMustBeConfigured;
-    public static I18n sourceInUse;
-
-    public static I18n REP_NAME_DESC;
-    public static I18n REP_VENDOR_DESC;
-    public static I18n SPEC_NAME_DESC;
-
-    static {
-        try {
-            I18n.initialize(JcrI18n.class);
-        } catch (final Exception err) {
-            System.err.println(err);
-        }
-    }
-}
+/*
+ * 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.
+ *
+ * JBoss DNA is free software. 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 org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author John Verhaeg
+ * @author Randall Hauch
+ */
+public final class JcrI18n {
+
+    public static I18n cannotConvertValue;
+    public static I18n credentialsMustProvideJaasMethod;
+    public static I18n credentialsMustReturnAccessControlContext;
+    public static I18n credentialsMustReturnLoginContext;
+    public static I18n defaultWorkspaceName;
+    public static I18n inputStreamConsumed;
+    public static I18n nonInputStreamConsumed;
+    public static I18n pathNotFound;
+    public static I18n permissionDenied;
+    public static I18n repositoryMustBeConfigured;
+    public static I18n sourceInUse;
+
+    public static I18n noNamespaceWithPrefix;
+    public static I18n noNamespaceWithUri;
+    public static I18n unableToChangeTheDefaultNamespace;
+    public static I18n unableToRegisterReservedNamespacePrefix;
+    public static I18n unableToRegisterReservedNamespaceUri;
+    public static I18n unableToRegisterNamespaceUsingXmlPrefix;
+    public static I18n unableToRegisterNamespaceWithInvalidPrefix;
+    public static I18n errorRegisteringPersistentNamespace;
+    public static I18n unableToUnregisterReservedNamespacePrefix;
+    public static I18n unableToUnregisterReservedNamespaceUri;
+    public static I18n unableToUnregisterPrefixForNamespaceThatIsNotRegistered;
+
+    public static I18n errorWhileInitializingTheNamespaceRegistry;
+    public static I18n invalidPathParameter;
+
+    public static I18n REP_NAME_DESC;
+    public static I18n REP_VENDOR_DESC;
+    public static I18n SPEC_NAME_DESC;
+
+    // New implementation
+    public static I18n errorObtainingWorkspaceNames;
+    public static I18n errorObtainingDefaultWorkspaceName;
+    public static I18n workspaceNameIsInvalid;
+    public static I18n errorVerifyingWorkspaceName;
+
+    static {
+        try {
+            I18n.initialize(JcrI18n.class);
+        } catch (final Exception err) {
+            System.err.println(err);
+        }
+    }
+}

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -23,10 +23,14 @@
  */
 package org.jboss.dna.jcr;
 
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.basic.BasicName;
 
 /**
  * @author Randall Hauch
  */
 class JcrLexicon extends org.jboss.dna.graph.JcrLexicon {
 
+    public static final Name SYSTEM = new BasicName(Namespace.URI, "system");
+
 }

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNamespaceRegistry.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNamespaceRegistry.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNamespaceRegistry.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -23,34 +23,99 @@
  */
 package org.jboss.dna.jcr;
 
-import java.util.Iterator;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
+import javax.jcr.AccessDeniedException;
 import javax.jcr.NamespaceException;
-import javax.jcr.NamespaceRegistry;
 import javax.jcr.RepositoryException;
-import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.xml.XMLConstants;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.xml.XmlCharacters;
+import org.jboss.dna.graph.JcrLexicon;
+import org.jboss.dna.graph.JcrMixLexicon;
+import org.jboss.dna.graph.JcrNtLexicon;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.NamespaceRegistry.Namespace;
+import org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry;
+import org.jboss.dna.graph.property.basic.ThreadSafeNamespaceRegistry;
 
 /**
- * @author John Verhaeg
- * @author Randall Hauch
+ * A thread-safe JCR {@link javax.jcr.NamespaceRegistry} implementation that has the standard JCR namespaces pre-registered and
+ * enforces the JCR semantics for {@link #registerNamespace(String, String) registering} and {@link #unregisterNamespace(String)
+ * unregistering} namespaces.
  */
-final class JcrNamespaceRegistry implements NamespaceRegistry {
+ at ThreadSafe
+class JcrNamespaceRegistry implements javax.jcr.NamespaceRegistry {
 
-    private org.jboss.dna.graph.property.NamespaceRegistry dnaNamespaceRegistry;
+    static final String DEFAULT_NAMESPACE_PREFIX = "";
+    static final String DEFAULT_NAMESPACE_URI = "";
 
-    JcrNamespaceRegistry( org.jboss.dna.graph.property.NamespaceRegistry dnaNamespaceRegistry ) {
-        this.dnaNamespaceRegistry = dnaNamespaceRegistry;
+    static final String XML_NAMESPACE_PREFIX = XMLConstants.XML_NS_PREFIX;
+    static final String XML_NAMESPACE_URI = XMLConstants.XML_NS_URI;
+    static final String XMLNS_NAMESPACE_PREFIX = XMLConstants.XMLNS_ATTRIBUTE;
+    static final String XMLNS_NAMESPACE_URI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
+
+    static final Set<String> STANDARD_BUILT_IN_PREFIXES;
+    static final Set<String> STANDARD_BUILT_IN_URIS;
+    static final Map<String, String> STANDARD_BUILT_IN_NAMESPACES_BY_PREFIX;
+    static final Map<String, String> STANDARD_BUILT_IN_PREFIXES_BY_NAMESPACE;
+
+    static {
+        // Set up the standard namespaces ...
+        Map<String, String> namespaces = new HashMap<String, String>();
+        namespaces.put(DEFAULT_NAMESPACE_PREFIX, DEFAULT_NAMESPACE_URI);
+        namespaces.put(JcrLexicon.Namespace.PREFIX, JcrLexicon.Namespace.URI);
+        namespaces.put(JcrNtLexicon.Namespace.PREFIX, JcrNtLexicon.Namespace.URI);
+        namespaces.put(JcrMixLexicon.Namespace.PREFIX, JcrMixLexicon.Namespace.URI);
+        namespaces.put(JcrSvLexicon.Namespace.PREFIX, JcrSvLexicon.Namespace.URI);
+        namespaces.put(XML_NAMESPACE_PREFIX, XML_NAMESPACE_URI);
+        namespaces.put(XMLNS_NAMESPACE_PREFIX, XMLNS_NAMESPACE_URI);
+        namespaces.put(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
+        // Set up the reverse map for the standard namespaces ...
+        Map<String, String> prefixes = new HashMap<String, String>();
+        for (Map.Entry<String, String> entry : namespaces.entrySet()) {
+            String uri = entry.getValue();
+            String prefix = entry.getKey();
+            prefixes.put(uri, prefix);
+        }
+        // Now set up the unmodifiable static collections ...
+        STANDARD_BUILT_IN_NAMESPACES_BY_PREFIX = Collections.unmodifiableMap(namespaces);
+        STANDARD_BUILT_IN_PREFIXES_BY_NAMESPACE = Collections.unmodifiableMap(prefixes);
+        STANDARD_BUILT_IN_PREFIXES = Collections.unmodifiableSet(namespaces.keySet());
+        STANDARD_BUILT_IN_URIS = Collections.unmodifiableSet(new HashSet<String>(namespaces.values()));
     }
 
+    private final NamespaceRegistry registry;
+
+    JcrNamespaceRegistry() {
+        this(new ThreadSafeNamespaceRegistry(new SimpleNamespaceRegistry())); // thread-safe implementation
+    }
+
+    JcrNamespaceRegistry( NamespaceRegistry dnaRegistry ) {
+        this.registry = dnaRegistry;
+        // Add the built-ins, ensuring we overwrite any badly-initialized values ...
+        for (Map.Entry<String, String> builtIn : STANDARD_BUILT_IN_NAMESPACES_BY_PREFIX.entrySet()) {
+            this.registry.register(builtIn.getKey(), builtIn.getValue());
+        }
+    }
+
     /**
      * {@inheritDoc}
      * 
      * @see javax.jcr.NamespaceRegistry#getPrefix(java.lang.String)
      */
     public String getPrefix( String uri ) throws NamespaceException, RepositoryException {
-        String prefix = dnaNamespaceRegistry.getPrefixForNamespaceUri(uri, false);
+        // Check the standard ones first, ensuring that invalid changes to the persistent storage don't matter ...
+        String prefix = STANDARD_BUILT_IN_PREFIXES_BY_NAMESPACE.get(uri);
+        if (prefix != null) return prefix;
+        // Now check the underlying registry ...
+        prefix = registry.getPrefixForNamespaceUri(uri, false);
         if (prefix == null) {
-            throw new NamespaceException();
+            throw new NamespaceException(JcrI18n.noNamespaceWithUri.text(uri));
         }
         return prefix;
     }
@@ -61,11 +126,11 @@
      * @see javax.jcr.NamespaceRegistry#getPrefixes()
      */
     public String[] getPrefixes() {
-        Set<String> uris = dnaNamespaceRegistry.getRegisteredNamespaceUris();
-        String[] prefixes = new String[uris.size()];
-        Iterator<String> iter = uris.iterator();
-        for (int ndx = 0; iter.hasNext(); ndx++) {
-            prefixes[ndx] = dnaNamespaceRegistry.getPrefixForNamespaceUri(iter.next(), false);
+        Set<Namespace> namespaces = registry.getNamespaces();
+        String[] prefixes = new String[namespaces.size()];
+        int i = 0;
+        for (Namespace namespace : namespaces) {
+            prefixes[i++] = namespace.getPrefix();
         }
         return prefixes;
     }
@@ -75,10 +140,14 @@
      * 
      * @see javax.jcr.NamespaceRegistry#getURI(java.lang.String)
      */
-    public String getURI( String prefix ) throws NamespaceException {
-        String uri = dnaNamespaceRegistry.getNamespaceForPrefix(prefix);
+    public String getURI( String prefix ) throws NamespaceException, RepositoryException {
+        // Check the standard ones first, ensuring that invalid changes to the persistent storage don't matter ...
+        String uri = STANDARD_BUILT_IN_NAMESPACES_BY_PREFIX.get(prefix);
+        if (uri != null) return uri;
+        // Now check the underlying registry ...
+        uri = registry.getNamespaceForPrefix(prefix);
         if (uri == null) {
-            throw new NamespaceException();
+            throw new NamespaceException(JcrI18n.noNamespaceWithPrefix.text(prefix));
         }
         return uri;
     }
@@ -89,22 +158,90 @@
      * @see javax.jcr.NamespaceRegistry#getURIs()
      */
     public String[] getURIs() {
-        Set<String> uris = dnaNamespaceRegistry.getRegisteredNamespaceUris();
-        return uris.toArray(new String[uris.size()]);
+        Set<Namespace> namespaces = registry.getNamespaces();
+        String[] uris = new String[namespaces.size()];
+        int i = 0;
+        for (Namespace namespace : namespaces) {
+            uris[i++] = namespace.getNamespaceUri();
+        }
+        return uris;
     }
 
     /**
      * {@inheritDoc}
+     * 
+     * @see javax.jcr.NamespaceRegistry#registerNamespace(java.lang.String, java.lang.String)
      */
-    public void registerNamespace( String prefix,
-                                   String uri ) throws UnsupportedRepositoryOperationException {
-        throw new UnsupportedRepositoryOperationException();
+    public synchronized void registerNamespace( String prefix,
+                                                String uri ) throws NamespaceException, RepositoryException {
+        CheckArg.isNotNull(prefix, "prefix");
+        CheckArg.isNotNull(uri, "uri");
+        // Check the zero-length prefix and zero-length URI ...
+        if (DEFAULT_NAMESPACE_PREFIX.equals(prefix) || DEFAULT_NAMESPACE_URI.equals(uri)) {
+            throw new NamespaceException(JcrI18n.unableToChangeTheDefaultNamespace.text());
+        }
+        // Check whether the prefix or URI are reserved (case-sensitive) ...
+        if (STANDARD_BUILT_IN_PREFIXES.contains(prefix)) {
+            throw new NamespaceException(JcrI18n.unableToRegisterReservedNamespacePrefix.text(prefix, uri));
+        }
+        if (STANDARD_BUILT_IN_URIS.contains(uri)) {
+            throw new NamespaceException(JcrI18n.unableToRegisterReservedNamespaceUri.text(prefix, uri));
+        }
+        // Check whether the prefix begins with 'xml' (in any case) ...
+        if (prefix.toLowerCase().startsWith(XML_NAMESPACE_PREFIX)) {
+            throw new NamespaceException(JcrI18n.unableToRegisterNamespaceUsingXmlPrefix.text(prefix, uri));
+        }
+
+        // The prefix must be a valid XML Namespace prefix (i.e., a valid NCName) ...
+        if (!XmlCharacters.isValidName(prefix)) {
+            throw new NamespaceException(JcrI18n.unableToRegisterNamespaceWithInvalidPrefix.text(prefix, uri));
+        }
+
+        // Now we're sure the prefix and URI are valid and okay for a custom mapping ...
+        try {
+            registry.register(prefix, uri);
+        } catch (RuntimeException e) {
+            throw new RepositoryException(e.getMessage(), e.getCause());
+        }
     }
 
     /**
      * {@inheritDoc}
+     * 
+     * @see javax.jcr.NamespaceRegistry#unregisterNamespace(java.lang.String)
      */
-    public void unregisterNamespace( String prefix ) throws UnsupportedRepositoryOperationException {
-        throw new UnsupportedRepositoryOperationException();
+    public synchronized void unregisterNamespace( String prefix )
+        throws NamespaceException, AccessDeniedException, RepositoryException {
+        CheckArg.isNotNull(prefix, "prefix");
+        // Look to see whether the prefix is registered ...
+        String uri = registry.getNamespaceForPrefix(prefix);
+        // It is an error to unregister a namespace that is not registered ...
+        if (uri == null) {
+            throw new NamespaceException(JcrI18n.unableToUnregisterPrefixForNamespaceThatIsNotRegistered.text(prefix));
+        }
+        // Unregistering a built-in prefix or URI is invalid ...
+        if (STANDARD_BUILT_IN_PREFIXES.contains(prefix)) {
+            throw new NamespaceException(JcrI18n.unableToUnregisterReservedNamespacePrefix.text(prefix, uri));
+        }
+        if (STANDARD_BUILT_IN_URIS.contains(uri)) {
+            throw new NamespaceException(JcrI18n.unableToUnregisterReservedNamespaceUri.text(prefix, uri));
+        }
+
+        // Now we're sure the prefix is valid and is actually used in a mapping ...
+        try {
+            registry.unregister(uri);
+        } catch (RuntimeException e) {
+            throw new RepositoryException(e.getMessage(), e.getCause());
+        }
     }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return registry.toString();
+    }
 }

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -28,10 +28,9 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.UUID;
+import java.util.Set;
 import javax.jcr.Credentials;
-import javax.jcr.LoginException;
-import javax.jcr.Node;
+import javax.jcr.NoSuchWorkspaceException;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -42,8 +41,8 @@
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.Graph;
 import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
-import com.google.common.base.ReferenceType;
-import com.google.common.collect.ReferenceMap;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.request.InvalidWorkspaceException;
 
 /**
  * Creates JCR {@link Session sessions} to an underlying repository (which may be a federated repository).
@@ -72,6 +71,7 @@
 @ThreadSafe
 public class JcrRepository implements Repository {
 
+    private final String sourceName;
     private final Map<String, String> descriptors;
     private final ExecutionContext executionContext;
     private final RepositoryConnectionFactory connectionFactory;
@@ -82,12 +82,14 @@
      * 
      * @param executionContext An execution context.
      * @param connectionFactory A repository connection factory.
+     * @param repositorySourceName the name of the repository source (in the connection factory) that should be used
      * @throws IllegalArgumentException If <code>executionContextFactory</code> or <code>connectionFactory</code> is
      *         <code>null</code>.
      */
     public JcrRepository( ExecutionContext executionContext,
-                          RepositoryConnectionFactory connectionFactory ) {
-        this(null, executionContext, connectionFactory);
+                          RepositoryConnectionFactory connectionFactory,
+                          String repositorySourceName ) {
+        this(null, executionContext, connectionFactory, repositorySourceName);
     }
 
     /**
@@ -95,18 +97,22 @@
      * establish {@link Session sessions} to the underlying repository source upon {@link #login() login}.
      * 
      * @param descriptors The {@link #getDescriptorKeys() descriptors} for this repository; may be <code>null</code>.
-     * @param executionContext An execution context.
-     * @param connectionFactory A repository connection factory.
+     * @param executionContext the execution context in which this repository is to operate
+     * @param connectionFactory the factory for repository connections
+     * @param repositorySourceName the name of the repository source (in the connection factory) that should be used
      * @throws IllegalArgumentException If <code>executionContextFactory</code> or <code>connectionFactory</code> is
      *         <code>null</code>.
      */
     public JcrRepository( Map<String, String> descriptors,
                           ExecutionContext executionContext,
-                          RepositoryConnectionFactory connectionFactory ) {
+                          RepositoryConnectionFactory connectionFactory,
+                          String repositorySourceName ) {
         CheckArg.isNotNull(executionContext, "executionContext");
         CheckArg.isNotNull(connectionFactory, "connectionFactory");
+        CheckArg.isNotNull(repositorySourceName, "repositorySourceName");
         this.executionContext = executionContext;
         this.connectionFactory = connectionFactory;
+        this.sourceName = repositorySourceName;
         Map<String, String> modifiableDescriptors;
         if (descriptors == null) {
             modifiableDescriptors = new HashMap<String, String>();
@@ -134,7 +140,7 @@
             modifiableDescriptors.put(Repository.REP_VENDOR_URL_DESC, "http://www.jboss.org/dna");
         }
         if (!modifiableDescriptors.containsKey(Repository.REP_VERSION_DESC)) {
-            modifiableDescriptors.put(Repository.REP_VERSION_DESC, "0.2");
+            modifiableDescriptors.put(Repository.REP_VERSION_DESC, "0.4");
         }
         modifiableDescriptors.put(Repository.SPEC_NAME_DESC, JcrI18n.SPEC_NAME_DESC.text());
         modifiableDescriptors.put(Repository.SPEC_VERSION_DESC, "1.0");
@@ -142,6 +148,25 @@
     }
 
     /**
+     * Get the name of the repository source that this repository is using.
+     * 
+     * @return the name of the RepositorySource
+     * @see #getConnectionFactory()
+     */
+    String getRepositorySourceName() {
+        return sourceName;
+    }
+
+    /**
+     * Get the connection factory that this repository is using.
+     * 
+     * @return the connection factory; never null
+     */
+    RepositoryConnectionFactory getConnectionFactory() {
+        return this.connectionFactory;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @throws IllegalArgumentException if <code>key</code> is <code>null</code>.
@@ -206,6 +231,7 @@
     public synchronized Session login( Credentials credentials,
                                        String workspaceName ) throws RepositoryException {
         // Ensure credentials are either null or provide a JAAS method
+        Map<String, Object> sessionAttributes = new HashMap<String, Object>();
         ExecutionContext execContext;
         if (credentials == null) {
             execContext = executionContext;
@@ -246,21 +272,44 @@
             } catch (Exception error) {
                 throw new RepositoryException(error);
             }
+            if (credentials instanceof SimpleCredentials) {
+                SimpleCredentials simple = (SimpleCredentials)credentials;
+                for (String attributeName : simple.getAttributeNames()) {
+                    Object attributeValue = simple.getAttribute(attributeName);
+                    sessionAttributes.put(attributeName, attributeValue);
+                }
+            }
         }
-        // Authenticate if possible
-        assert execContext != null;
-        LoginContext loginContext = execContext.getLoginContext();
-        if (loginContext != null) {
+
+        // Ensure valid workspace name
+        Graph graph = Graph.create(sourceName, connectionFactory, executionContext);
+        if (workspaceName == null) {
             try {
-                loginContext.login();
-            } catch (javax.security.auth.login.LoginException error) {
-                throw new LoginException(error);
+                // Get the correct workspace name given the desired workspace name (which may be null) ...
+                workspaceName = graph.getCurrentWorkspace().getName();
+            } catch (RepositorySourceException e) {
+                throw new RepositoryException(JcrI18n.errorObtainingDefaultWorkspaceName.text(sourceName, e.getMessage()), e);
             }
+        } else {
+            try {
+                // Verify that the workspace exists (or can be created) ...
+                Set<String> workspaces = graph.getWorkspaces();
+                if (!workspaces.contains(workspaceName)) {
+                    // Try to create it ...
+                    graph.createWorkspace().namedSomethingLike(workspaceName).getName();
+                }
+                workspaceName = graph.getCurrentWorkspace().getName();
+            } catch (InvalidWorkspaceException e) {
+                throw new NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(sourceName, workspaceName), e);
+            } catch (RepositorySourceException e) {
+                String msg = JcrI18n.errorVerifyingWorkspaceName.text(sourceName, workspaceName, e.getMessage());
+                throw new NoSuchWorkspaceException(msg, e);
+            }
         }
-        // Ensure valid workspace name
-        if (workspaceName == null) workspaceName = JcrI18n.defaultWorkspaceName.text();
-        // Create session
-        Graph graph = Graph.create(workspaceName, connectionFactory, execContext);
-        return new JcrSession(this, workspaceName, graph, new ReferenceMap<UUID, Node>(ReferenceType.STRONG, ReferenceType.SOFT));
+
+        // Create the workspace, which will create its own session ...
+        sessionAttributes = Collections.unmodifiableMap(sessionAttributes);
+        JcrWorkspace workspace = new JcrWorkspace(this, workspaceName, execContext, sessionAttributes);
+        return workspace.getSession();
     }
 }

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-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -28,11 +28,14 @@
 import java.security.AccessControlException;
 import java.security.Principal;
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import javax.jcr.Credentials;
 import javax.jcr.Item;
+import javax.jcr.NamespaceException;
 import javax.jcr.Node;
 import javax.jcr.PathNotFoundException;
 import javax.jcr.Property;
@@ -40,6 +43,7 @@
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
 import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.jcr.Workspace;
@@ -48,14 +52,15 @@
 import javax.security.auth.login.LoginException;
 import net.jcip.annotations.NotThreadSafe;
 import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.common.util.StringUtil;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.Graph;
 import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.UuidFactory;
 import org.jboss.dna.graph.property.ValueFactories;
+import org.jboss.dna.graph.property.basic.LocalNamespaceRegistry;
 import org.xml.sax.ContentHandler;
 import com.google.common.base.ReferenceType;
 import com.google.common.collect.ReferenceMap;
@@ -67,32 +72,76 @@
 @NotThreadSafe
 class JcrSession implements Session {
 
-    private final Repository repository;
+    private static final String[] NO_ATTRIBUTES_NAMES = new String[] {};
+
+    /**
+     * The repository that created this session.
+     */
+    private final JcrRepository repository;
+
+    /**
+     * The workspace that corresponds to this session.
+     */
+    private final JcrWorkspace workspace;
+
+    /**
+     * A JCR namespace registry that is specific to this session, with any locally-defined namespaces defined in this session.
+     * This is backed by the workspace's namespace registry.
+     */
+    private final JcrNamespaceRegistry sessionRegistry;
+
+    /**
+     * The execution context for this session, which uses the {@link #sessionRegistry session's namespace registry}
+     */
+    private final ExecutionContext executionContext;
+
+    /**
+     * The graph representing this session, which uses the {@link #graph session's graph}.
+     */
     private final Graph graph;
-    private final ExecutionContext executionContext;
+
+    /**
+     * The session-specific attributes that came from the {@link SimpleCredentials}' {@link SimpleCredentials#getAttributeNames()}
+     */
+    private final Map<String, Object> sessionAttributes;
+
     private final ReferenceMap<UUID, Node> nodesByUuid;
     private final ReferenceMap<String, Node> nodesByJcrUuid;
     private boolean isLive;
-    private Workspace workspace;
     private JcrRootNode rootNode;
 
-    JcrSession( Repository repository,
-                String workspaceName,
-                Graph graph,
-                ReferenceMap<UUID, Node> nodesByUuid ) throws RepositoryException {
+    JcrSession( JcrRepository repository,
+                JcrWorkspace workspace,
+                ExecutionContext workspaceContext,
+                Map<String, Object> sessionAttributes ) {
         assert repository != null;
-        assert graph != null;
-        assert workspaceName != null;
-        assert nodesByUuid != null;
+        assert workspace != null;
+        assert sessionAttributes != null;
+        assert workspaceContext != null;
         this.repository = repository;
-        this.graph = graph;
-        this.executionContext = graph.getContext();
-        assert this.executionContext != null;
-        this.nodesByUuid = nodesByUuid;
+        this.sessionAttributes = sessionAttributes;
+        this.workspace = workspace;
+
+        // Create an execution context for this session, which should use the local namespace registry ...
+        NamespaceRegistry local = new LocalNamespaceRegistry(workspaceContext.getNamespaceRegistry());
+        this.executionContext = workspaceContext.with(local);
+        this.sessionRegistry = new JcrNamespaceRegistry(local);
+
+        // Set up the graph to use for this session (which uses the session's namespace registry and context) ...
+        this.graph = Graph.create(this.repository.getRepositorySourceName(),
+                                  this.repository.getConnectionFactory(),
+                                  this.executionContext);
+
+        this.nodesByUuid = new ReferenceMap<UUID, Node>(ReferenceType.STRONG, ReferenceType.SOFT);
         this.nodesByJcrUuid = new ReferenceMap<String, Node>(ReferenceType.STRONG, ReferenceType.SOFT);
         this.isLive = true;
-        // Following must be initialized after session's state is initialized
-        this.workspace = new JcrWorkspace(this, workspaceName);
+
+        assert this.repository != null;
+        assert this.sessionAttributes != null;
+        assert this.workspace != null;
+        assert this.executionContext != null;
+        assert this.sessionRegistry != null;
+        assert this.graph != null;
     }
 
     ExecutionContext getExecutionContext() {
@@ -100,8 +149,94 @@
     }
 
     /**
+     * Return an unmodifiable map of nodes given then UUID.
+     * 
+     * @return nodesByUuid
+     */
+    Map<UUID, Node> getNodesByUuid() {
+        return Collections.unmodifiableMap(nodesByUuid);
+    }
+
+    /**
      * {@inheritDoc}
      * 
+     * @see javax.jcr.Session#getWorkspace()
+     */
+    public Workspace getWorkspace() {
+        return this.workspace;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.Session#getRepository()
+     */
+    public Repository getRepository() {
+        return this.repository;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @return <code>null</code>
+     * @see javax.jcr.Session#getAttribute(java.lang.String)
+     */
+    public Object getAttribute( String name ) {
+        return sessionAttributes.get(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @return An empty array
+     * @see javax.jcr.Session#getAttributeNames()
+     */
+    public String[] getAttributeNames() {
+        Set<String> names = sessionAttributes.keySet();
+        if (names.isEmpty()) return NO_ATTRIBUTES_NAMES;
+        return names.toArray(new String[names.size()]);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.Session#getNamespacePrefix(java.lang.String)
+     */
+    public String getNamespacePrefix( String uri ) throws RepositoryException {
+        return sessionRegistry.getPrefix(uri);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.Session#getNamespacePrefixes()
+     */
+    public String[] getNamespacePrefixes() {
+        return sessionRegistry.getPrefixes();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.Session#getNamespaceURI(java.lang.String)
+     */
+    public String getNamespaceURI( String prefix ) throws RepositoryException {
+        return sessionRegistry.getURI(prefix);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see javax.jcr.Session#setNamespacePrefix(java.lang.String, java.lang.String)
+     */
+    public void setNamespacePrefix( String newPrefix,
+                                    String existingUri ) throws NamespaceException, RepositoryException {
+        sessionRegistry.registerNamespace(newPrefix, existingUri);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#addLockToken(java.lang.String)
      */
@@ -179,26 +314,6 @@
     /**
      * {@inheritDoc}
      * 
-     * @return <code>null</code>
-     * @see javax.jcr.Session#getAttribute(java.lang.String)
-     */
-    public Object getAttribute( String name ) {
-        return null;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @return An empty array
-     * @see javax.jcr.Session#getAttributeNames()
-     */
-    public String[] getAttributeNames() {
-        return StringUtil.EMPTY_STRING_ARRAY;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
      * @throws UnsupportedOperationException always
      * @see javax.jcr.Session#getImportContentHandler(java.lang.String, int)
      */
@@ -255,33 +370,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /**
-     * {@inheritDoc}
-     * 
-     * @see javax.jcr.Session#getNamespacePrefix(java.lang.String)
-     */
-    public String getNamespacePrefix( String uri ) throws RepositoryException {
-        return workspace.getNamespaceRegistry().getPrefix(uri);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see javax.jcr.Session#getNamespacePrefixes()
-     */
-    public String[] getNamespacePrefixes() throws RepositoryException {
-        return workspace.getNamespaceRegistry().getPrefixes();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see javax.jcr.Session#getNamespaceURI(java.lang.String)
-     */
-    public String getNamespaceURI( String prefix ) throws RepositoryException {
-        return workspace.getNamespaceRegistry().getURI(prefix);
-    }
-
     private Node getNode( Path path ) throws RepositoryException {
         // Get node from source
         org.jboss.dna.graph.Node graphNode = graph.getNodeAt(path);
@@ -322,15 +410,6 @@
     /**
      * {@inheritDoc}
      * 
-     * @see javax.jcr.Session#getRepository()
-     */
-    public Repository getRepository() {
-        return this.repository;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
      * @see javax.jcr.Session#getRootNode()
      */
     public Node getRootNode() {
@@ -407,15 +486,6 @@
     /**
      * {@inheritDoc}
      * 
-     * @see javax.jcr.Session#getWorkspace()
-     */
-    public Workspace getWorkspace() {
-        return this.workspace;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
      * @return false
      * @see javax.jcr.Session#hasPendingChanges()
      */
@@ -428,8 +498,11 @@
      * 
      * @see javax.jcr.Session#impersonate(javax.jcr.Credentials)
      */
+    @SuppressWarnings( "unused" )
     public Session impersonate( Credentials credentials ) throws RepositoryException {
-        return repository.login(credentials);
+        // this is not right:
+        // return repository.login(credentials);
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -521,7 +594,8 @@
                 if (uuid == null && DnaLexicon.UUID.equals(name)) uuid = uuidFactory.create(dnaProp.getValues()).next();
                 else if (jcrUuidName.equals(name)) dnaUuidProp = dnaProp;
                 else if (jcrMixinTypesName.equals(name)) {
-                    org.jboss.dna.graph.property.ValueFactory<String> stringFactory = executionContext.getValueFactories().getStringFactory();
+                    org.jboss.dna.graph.property.ValueFactory<String> stringFactory = executionContext.getValueFactories()
+                                                                                                      .getStringFactory();
                     for (String mixin : stringFactory.create(dnaProp)) {
                         if ("mix:referenceable".equals(mixin)) referenceable = true;
                     }
@@ -573,15 +647,4 @@
     public void save() {
         throw new UnsupportedOperationException();
     }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @throws UnsupportedOperationException always
-     * @see javax.jcr.Session#setNamespacePrefix(java.lang.String, java.lang.String)
-     */
-    public void setNamespacePrefix( String newPrefix,
-                                    String existingUri ) {
-        throw new UnsupportedOperationException();
-    }
 }

Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java	                        (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,37 @@
+/*
+ * 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. 
+ *
+ * JBoss DNA is free software. 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;
+
+
+/**
+ * @author Randall Hauch
+ */
+public class JcrSvLexicon {
+
+    public static class Namespace {
+        public static final String URI = "http://www.jcp.org/jcr/sv/1.0";
+        public static final String PREFIX = "sv";
+    }
+
+}


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

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-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -23,15 +23,41 @@
  */
 package org.jboss.dna.jcr;
 
+import java.io.IOException;
 import java.io.InputStream;
+import java.util.Map;
+import java.util.Set;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.InvalidSerializedDataException;
+import javax.jcr.ItemExistsException;
 import javax.jcr.NamespaceRegistry;
+import javax.jcr.PathNotFoundException;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.Workspace;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.observation.ObservationManager;
 import javax.jcr.query.QueryManager;
 import javax.jcr.version.Version;
+import javax.jcr.version.VersionException;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.GraphImporter;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyFactory;
+import org.jboss.dna.graph.property.ValueFormatException;
+import org.jboss.dna.graph.property.basic.GraphNamespaceRegistry;
+import org.jboss.dna.graph.property.basic.ThreadSafeNamespaceRegistry;
 import org.xml.sax.ContentHandler;
 
 /**
@@ -40,158 +66,261 @@
  */
 final class JcrWorkspace implements Workspace {
 
+    /**
+     * The name of this workspace. This name is used as the name of the source when
+     * {@link RepositoryConnectionFactory#createConnection(String) creating connections} to the underlying
+     * {@link RepositorySource} that stores the content for this workspace.
+     */
     private final String name;
-    private final JcrSession session;
-    private final NamespaceRegistry namespaceRegistry;
 
     /**
-     * @param session the session that owns this workspace; may not be null
-     * @param name the name of the workspace; may not be null
-     * @throws RepositoryException
+     * The context in which this workspace is executing/operating. This context already has been authenticated.
      */
-    JcrWorkspace( JcrSession session,
-                  String name ) throws RepositoryException {
-        assert session != null;
-        assert name != null;
-        this.session = session;
-        this.name = name;
-        this.namespaceRegistry = new JcrNamespaceRegistry(session.getExecutionContext().getNamespaceRegistry());
-        // Ensure workspace with supplied name is accessible
-        // if (name == null) name = session.getDnaRepository().getSource(session.getSubject()).getName();
-        // String matchedName = null;
-        // for (String accessibleName : getAccessibleWorkspaceNames()) {
-        // if (name.equalsIgnoreCase(accessibleName)) {
-        // matchedName = name;
-        // break;
-        // }
-        // }
-        // if (matchedName == null) {
-        // throw new LoginException();
-        // }
+    private final ExecutionContext context;
+
+    /**
+     * The reference to the {@link JcrRepository} instance that owns this {@link Workspace} instance. Very few methods on this
+     * repository object are used; mainly {@link JcrRepository#getConnectionFactory()} and
+     * {@link JcrRepository#getRepositorySourceName()}.
+     */
+    private final JcrRepository repository;
+
+    /**
+     * The graph used by this workspace to access persistent content. This graph is not thread-safe, but since this workspace is
+     * not thread-safe, it is okay for any method in this workspace to use the same graph. It is also okay for other objects that
+     * have the same thread context as this workspace (e.g., the session, namespace registry, etc.) to also reuse this same graph
+     * instance (though it's not very expensive at all for each to have their own instance, too).
+     */
+    private final Graph graph;
+
+    /**
+     * Reference to the namespace registry for this workspace. Per the JCR specification, this registry instance is persistent
+     * (unlike the namespace-related methods in the {@link Session}, like {@link Session#getNamespacePrefix(String)},
+     * {@link Session#setNamespacePrefix(String, String)}, etc.).
+     */
+    private final JcrNamespaceRegistry workspaceRegistry;
+
+    /**
+     * The {@link Session} instance that this corresponds with this workspace.
+     */
+    private final JcrSession session;
+
+    JcrWorkspace( JcrRepository repository,
+                  String workspaceName,
+                  ExecutionContext context,
+                  Map<String, Object> sessionAttributes ) {
+        assert workspaceName != null;
+        assert context != null;
+        assert repository != null;
+        this.name = workspaceName;
+        this.repository = repository;
+
+        // Set up the execution context for this workspace, which should use the namespace registry that persists
+        // the namespaces in the graph ...
+        Graph namespaceGraph = Graph.create(this.repository.getRepositorySourceName(),
+                                            this.repository.getConnectionFactory(),
+                                            context);
+        Name uriProperty = DnaLexicon.NAMESPACE_URI;
+        PathFactory pathFactory = context.getValueFactories().getPathFactory();
+        Path root = pathFactory.createRootPath();
+        Path namespacesPath = context.getValueFactories().getPathFactory().create(root, JcrLexicon.SYSTEM, DnaLexicon.NAMESPACES);
+        PropertyFactory propertyFactory = context.getPropertyFactory();
+        Property namespaceType = propertyFactory.create(JcrLexicon.PRIMARY_TYPE, DnaLexicon.NAMESPACE);
+        org.jboss.dna.graph.property.NamespaceRegistry persistentRegistry = new GraphNamespaceRegistry(namespaceGraph,
+                                                                                                       namespacesPath,
+                                                                                                       uriProperty, namespaceType);
+        persistentRegistry = new ThreadSafeNamespaceRegistry(persistentRegistry);
+        this.context = context.with(persistentRegistry);
+
+        // Set up and initialize the persistent (and thread-safe) JCR namespace registry ...
+        this.workspaceRegistry = new JcrNamespaceRegistry(persistentRegistry);
+
+        // Now create a graph with this new execution context ...
+        this.graph = Graph.create(this.repository.getRepositorySourceName(), this.repository.getConnectionFactory(), this.context);
+        this.graph.useWorkspace(workspaceName);
+
+        // Set up the session for this workspace ...
+        this.session = new JcrSession(this.repository, this, this.context, sessionAttributes);
     }
 
+    String getSourceName() {
+        return this.repository.getRepositorySourceName();
+    }
+
     /**
      * {@inheritDoc}
-     * 
-     * @see javax.jcr.Workspace#clone(java.lang.String, java.lang.String, java.lang.String, boolean)
      */
-    public void clone( String srcWorkspace,
-                       String srcAbsPath,
-                       String destAbsPath,
-                       boolean removeExisting ) {
-        throw new UnsupportedOperationException();
+    public String getName() {
+        return name;
     }
 
     /**
      * {@inheritDoc}
      */
-    public void copy( String srcAbsPath,
-                      String destAbsPath ) {
-        throw new UnsupportedOperationException();
+    public Session getSession() {
+        return this.session;
     }
 
     /**
      * {@inheritDoc}
+     * 
+     * @see javax.jcr.Workspace#getNamespaceRegistry()
      */
-    public void copy( String srcWorkspace,
-                      String srcAbsPath,
-                      String destAbsPath ) {
-        throw new UnsupportedOperationException();
+    public NamespaceRegistry getNamespaceRegistry() {
+        return workspaceRegistry;
     }
 
     /**
      * {@inheritDoc}
      */
-    public String[] getAccessibleWorkspaceNames() {
-        // try {
-        // Node node = session.getRootNode().getNode("dna:jcr");
-        // if (node != null) {
-        // Property property = node.getProperty("dna:workspaceNames");
-        // if (property != null) {
-        // Value[] values = property.getValues();
-        // if (values.length > 0) {
-        // String[] names = new String[values.length];
-        // for (int ndx = values.length; --ndx >= 0;) {
-        // names[ndx] = values[ndx].getString();
-        // }
-        // return names;
-        // }
-        // }
-        // }
-        // } catch (PathNotFoundException meansOnlyDefaultWorkspaceNameAvailable) {
-        // // TODO: Check permissions and, if writable, create node & property and, if allowed, set to include this source's name
-        // }
-        // // Repository is read-only, so just return this source's name
-        // return new String[] {session.getDnaRepository().getSource(session.getSubject()).getName()};
-        throw new UnsupportedOperationException();
+    public String[] getAccessibleWorkspaceNames() throws RepositoryException {
+        try {
+            Set<String> workspaces = graph.getWorkspaces();
+            return workspaces.toArray(new String[workspaces.size()]);
+        } catch (RepositorySourceException e) {
+            throw new RepositoryException(JcrI18n.errorObtainingWorkspaceNames.text(getSourceName(), e.getMessage()), e);
+        }
     }
 
     /**
      * {@inheritDoc}
      */
-    public ContentHandler getImportContentHandler( String parentAbsPath,
-                                                   int uuidBehavior ) {
+    public NodeTypeManager getNodeTypeManager() {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
      */
-    public String getName() {
-        return name;
+    public ObservationManager getObservationManager() {
+        throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
-     * 
-     * @see javax.jcr.Workspace#getNamespaceRegistry()
      */
-    public NamespaceRegistry getNamespaceRegistry() {
-        return namespaceRegistry;
+    public QueryManager getQueryManager() {
+        throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
+     * 
+     * @see javax.jcr.Workspace#clone(java.lang.String, java.lang.String, java.lang.String, boolean)
      */
-    public NodeTypeManager getNodeTypeManager() {
+    public void clone( String srcWorkspace,
+                       String srcAbsPath,
+                       String destAbsPath,
+                       boolean removeExisting ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
+     * 
+     * @see javax.jcr.Workspace#copy(java.lang.String, java.lang.String)
      */
-    public ObservationManager getObservationManager() {
-        throw new UnsupportedOperationException();
+    public void copy( String srcAbsPath,
+                      String destAbsPath )
+        throws ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException,
+        LockException, RepositoryException {
+        CheckArg.isNotEmpty(srcAbsPath, "srcAbsPath");
+        CheckArg.isNotEmpty(destAbsPath, "destAbsPath");
+
+        // Create the paths ...
+        PathFactory factory = context.getValueFactories().getPathFactory();
+        Path srcPath = null;
+        Path destPath = null;
+        try {
+            srcPath = factory.create(srcAbsPath);
+        } catch (ValueFormatException e) {
+            throw new RepositoryException(JcrI18n.invalidPathParameter.text(srcAbsPath, "srcAbsPath"), e);
+        }
+        try {
+            destPath = factory.create(destAbsPath);
+        } catch (ValueFormatException e) {
+            throw new RepositoryException(JcrI18n.invalidPathParameter.text(destAbsPath, "destAbsPath"), e);
+        }
+
+        // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
+        graph.copy(srcPath).to(destPath);
     }
 
     /**
      * {@inheritDoc}
      */
-    public QueryManager getQueryManager() {
+    public void copy( String srcWorkspace,
+                      String srcAbsPath,
+                      String destAbsPath ) {
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
+     * 
+     * @see javax.jcr.Workspace#getImportContentHandler(java.lang.String, int)
      */
-    public Session getSession() {
-        return this.session;
+    @SuppressWarnings( "unused" )
+    public ContentHandler getImportContentHandler( String parentAbsPath,
+                                                   int uuidBehavior )
+        throws PathNotFoundException, ConstraintViolationException, VersionException, LockException, AccessDeniedException,
+        RepositoryException {
+        CheckArg.isNotEmpty(parentAbsPath, "parentAbsPath");
+        // Create a graph importer, which can return the content handler that can be used by the caller
+        // to call the handler's event methods to create content...
+        GraphImporter importer = new GraphImporter(graph);
+        Path parentPath = context.getValueFactories().getPathFactory().create(parentAbsPath);
+        return importer.getHandlerForImportingXml(Location.create(parentPath), false);
     }
 
     /**
      * {@inheritDoc}
+     * 
+     * @see javax.jcr.Workspace#importXML(java.lang.String, java.io.InputStream, int)
      */
+    @SuppressWarnings( "unused" )
     public void importXML( String parentAbsPath,
                            InputStream in,
-                           int uuidBehavior ) {
+                           int uuidBehavior )
+        throws IOException, PathNotFoundException, ItemExistsException, ConstraintViolationException,
+        InvalidSerializedDataException, LockException, AccessDeniedException, RepositoryException {
+        // try {
+        // graph.importXmlFrom(in).into(parentAbsPath);
+        // } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+        // throw new PathNotFoundException(e.getMessage(), e);
+        // } catch (SAXException err) {
+        // }
         throw new UnsupportedOperationException();
     }
 
     /**
      * {@inheritDoc}
+     * 
+     * @see javax.jcr.Workspace#move(java.lang.String, java.lang.String)
      */
+    @SuppressWarnings( "unused" )
     public void move( String srcAbsPath,
-                      String destAbsPath ) {
+                      String destAbsPath ) throws PathNotFoundException, RepositoryException {
+        CheckArg.isNotEmpty(srcAbsPath, "srcAbsPath");
+        CheckArg.isNotEmpty(destAbsPath, "destAbsPath");
+
+        // Create the paths ...
+        PathFactory factory = context.getValueFactories().getPathFactory();
+        Path srcPath = null;
+        Path destPath = null;
+        try {
+            srcPath = factory.create(srcAbsPath);
+        } catch (ValueFormatException e) {
+            throw new RepositoryException(JcrI18n.invalidPathParameter.text(srcAbsPath, "srcAbsPath"), e);
+        }
+        try {
+            destPath = factory.create(destAbsPath);
+        } catch (ValueFormatException e) {
+            throw new RepositoryException(JcrI18n.invalidPathParameter.text(destAbsPath, "destAbsPath"), e);
+        }
+
+        // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
+        // graph.move(srcPath).to(destPath);
         throw new UnsupportedOperationException();
     }
 

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-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties	2009-02-27 22:21:50 UTC (rev 738)
@@ -33,6 +33,26 @@
 repositoryMustBeConfigured = DNA repositories must be configured with either a repository source factory or a repository source.
 sourceInUse = All sessions must end before a new repository source can be set.
 
+noNamespaceWithPrefix = There is no namespace with prefix "{0}"
+noNamespaceWithUri = There is no namespace with URI "{0}"
+unableToChangeTheDefaultNamespace = The default namespace is reserved and cannot be changed
+unableToRegisterReservedNamespacePrefix = Unable to register the namespace "{1}" with prefix "{0}" because this prefix is reserved
+unableToRegisterReservedNamespaceUri = Unable to register the namespace "{1}" with prefix "{0}" because this URI is reserved
+unableToRegisterNamespaceUsingXmlPrefix = Unable to register the namespace "{1}" with prefix "{0}" because prefixes starting with 'xml' (in any case) are reserved
+unableToRegisterNamespaceWithInvalidPrefix = Unable to register the namespace "{1}" with prefix "{0}" because the prefix must be a valid XML NCName
+errorRegisteringPersistentNamespace = Error registering the persisted namespace "{1}" with prefix "{0}"
+unableToUnregisterReservedNamespacePrefix = Unable to unregister the namespace "{1}" with prefix "{0}" because this prefix is reserved
+unableToUnregisterReservedNamespaceUri = Unable to unregister the namespace "{1}" with prefix "{0}" because this URI is reserved
+unableToUnregisterPrefixForNamespaceThatIsNotRegistered = The namespace with prefix "{0}" is not registered and cannot be unregistered
+
+errorWhileInitializingTheNamespaceRegistry = Error while initializing the namespace registry for workspace "{0}"
+invalidPathParameter = The "{1}" parameter value "{0}" was not a valid path
+
 REP_NAME_DESC = DNA Repository
 REP_VENDOR_DESC = JBoss - A division of Red Hat Middleware LLC
-SPEC_NAME_DESC = Content Repository for Java Technology API
\ No newline at end of file
+SPEC_NAME_DESC = Content Repository for Java Technology API
+
+errorObtainingWorkspaceNames = Error while obtaining the workspace names for the "{0}" repository: {1}
+errorObtainingDefaultWorkspaceName = Error while obtaining the default workspace names for the "{0}" repository: {1}
+workspaceNameIsInvalid = "{1}" is not a valid workspace name for the "{0}" repository
+errorVerifyingWorkspaceName = Error validating the workspace name "{1}" for the "{0}" repository: {2}
\ No newline at end of file

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JackrabbitJcrTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JackrabbitJcrTckTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JackrabbitJcrTckTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -161,8 +161,12 @@
             // Wrap a connection to the in-memory (DNA) repository in a (JCR) repository
             connection = source.getConnection();
             repository = new JcrRepository(Collections.<String, String>emptyMap(), executionContext.create(accessControlContext),
-                                           connectionFactory);
+                                           connectionFactory, source.getName());
 
+            // Make sure the path to the namespaces exists ...
+            Graph graph = Graph.create(source.getName(), connectionFactory, executionContext);
+            graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces");
+
             // Set up some sample nodes in the graph to match the expected test configuration
             try {
 
@@ -173,7 +177,6 @@
                 executionContext.getNamespaceRegistry().register("sv", "http://www.jcp.org/jcr/sv/1.0");
 
                 Path destinationPath = executionContext.getValueFactories().getPathFactory().create("/");
-                Graph graph = Graph.create(source.getName(), connectionFactory, executionContext);
                 GraphImporter importer = new GraphImporter(graph);
 
                 URI xmlContent = new File("src/test/resources/repositoryJackrabbitTck.xml").toURI();

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNamespaceRegistryTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNamespaceRegistryTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNamespaceRegistryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -23,15 +23,13 @@
  */
 package org.jboss.dna.jcr;
 
-import static org.hamcrest.collection.IsArrayContaining.hasItemInArray;
 import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNot.not;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
 import javax.jcr.NamespaceException;
-import javax.jcr.UnsupportedRepositoryOperationException;
 import org.jboss.dna.graph.ExecutionContext;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
 /**
@@ -39,83 +37,276 @@
  */
 public class JcrNamespaceRegistryTest {
 
-    static ExecutionContext executionContext;
+    private ExecutionContext executionContext;
     private JcrNamespaceRegistry registry;
 
-    @BeforeClass
-    public static void beforeClass() throws Exception {
-        executionContext = TestUtil.getExecutionContext();
-    }
-
     @Before
     public void before() {
+        executionContext = new ExecutionContext();
         registry = new JcrNamespaceRegistry(executionContext.getNamespaceRegistry());
     }
 
+    protected void assertThatNamespaceIsRegistered( String prefix,
+                                                    String uri ) throws Exception {
+        assertThat(registry.getURI(prefix), is(uri));
+        assertThat(registry.getPrefix(uri), is(prefix));
+
+        boolean foundPrefix = false;
+        for (String existingPrefix : registry.getPrefixes()) {
+            if (existingPrefix.equals(prefix)) foundPrefix = true;
+        }
+        assertThat(foundPrefix, is(true));
+
+        boolean foundUri = false;
+        for (String existingUri : registry.getURIs()) {
+            if (existingUri.equals(uri)) foundUri = true;
+        }
+        assertThat(foundUri, is(true));
+    }
+
+    protected void assertThatNamespacePrefixIsNotRegistered( String prefix ) throws Exception {
+        try {
+            registry.getURI(prefix);
+            fail("Should not have found namespace mapping with prefix \"" + prefix + "\"");
+        } catch (NamespaceException e) {
+            // good
+        }
+        for (String existingPrefix : registry.getPrefixes()) {
+            assertThat(existingPrefix, is(not(prefix)));
+        }
+    }
+
+    protected void assertThatNamespaceUriIsNotRegistered( String uri ) throws Exception {
+        try {
+            registry.getPrefix(uri);
+            fail("Should not have found namespace mapping with URI \"" + uri + "\"");
+        } catch (NamespaceException e) {
+            // good
+        }
+        for (String existingUri : registry.getURIs()) {
+            assertThat(existingUri, is(not(uri)));
+        }
+    }
+
     @Test
-    public void shouldProvidePrefixes() {
-        String[] prefixes = registry.getPrefixes();
-        assertThat(prefixes, notNullValue());
-        assertThat(prefixes, hasItemInArray(""));
-        assertThat(prefixes, hasItemInArray("dna"));
-        assertThat(prefixes, hasItemInArray("jcr"));
-        assertThat(prefixes, hasItemInArray("mix"));
-        assertThat(prefixes, hasItemInArray("nt"));
-        // assertThat(prefixes, hasItemInArray("xml"));
+    public void shouldBeInitializedWithNamespacesDefinedByTheJcrSpecification() throws Exception {
+        // Don't use the constants, since this needs to check that the actual values are correct
+        assertThatNamespaceIsRegistered("jcr", "http://www.jcp.org/jcr/1.0");
+        assertThatNamespaceIsRegistered("nt", "http://www.jcp.org/jcr/nt/1.0");
+        assertThatNamespaceIsRegistered("mix", "http://www.jcp.org/jcr/mix/1.0");
+        assertThatNamespaceIsRegistered("xml", "http://www.w3.org/XML/1998/namespace");
+        assertThatNamespaceIsRegistered("", "");
     }
 
     @Test
-    public void shouldProvideUris() {
-        String[] uris = registry.getURIs();
-        assertThat(uris, notNullValue());
-        assertThat(uris, hasItemInArray(""));
-        assertThat(uris, hasItemInArray("http://www.jboss.org/dna/1.0"));
-        assertThat(uris, hasItemInArray("http://www.jcp.org/jcr/1.0"));
-        assertThat(uris, hasItemInArray("http://www.jcp.org/jcr/mix/1.0"));
-        assertThat(uris, hasItemInArray("http://www.jcp.org/jcr/nt/1.0"));
-        // assertThat(uris, hasItemInArray("http://www.w3.org/XML/1998/namespace"));
+    public void shouldBeInitializedWithNamespacesDefinedByTheJcrApiJavaDoc() throws Exception {
+        // Don't use the constants, since this needs to check that the actual values are correct
+        assertThatNamespaceIsRegistered("sv", "http://www.jcp.org/jcr/sv/1.0");
+        assertThatNamespaceIsRegistered("xmlns", "http://www.w3.org/2000/xmlns/");
     }
 
-    @Test( expected = UnsupportedRepositoryOperationException.class )
-    public void shouldNotAllowRegisterNamespace() throws Exception {
-        registry.registerNamespace(null, null);
+    @Test
+    public void shouldBeInitializedWithNamespacesSpecificToDna() throws Exception {
+        // Don't use the constants, since this needs to check that the actual values are correct
+        assertThatNamespaceIsRegistered("dna", "http://www.jboss.org/dna/1.0");
     }
 
-    @Test( expected = UnsupportedRepositoryOperationException.class )
-    public void shouldNotAllowUnregisterNamespace() throws Exception {
-        registry.unregisterNamespace(null);
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowRegisteringNullPrefix() throws Exception {
+        registry.registerNamespace("foo", null);
     }
 
     @Test( expected = IllegalArgumentException.class )
-    public void shouldNotAllowNullPrefix() throws Exception {
-        registry.getURI(null);
+    public void shouldNotAllowRegisteringNullUri() throws Exception {
+        registry.registerNamespace(null, "http://example.com");
     }
 
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringPrefixThatStartsWithLowercaseXml() throws Exception {
+        registry.registerNamespace("xmlw", "http://example.com");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringPrefixThatStartsWithUppercaseXml() throws Exception {
+        registry.registerNamespace("XMLw", "http://example.com");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringPrefixThatStartsWithMixedcaseXml() throws Exception {
+        registry.registerNamespace("XmLw", "http://example.com");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringEmptyPrefix() throws Exception {
+        registry.registerNamespace("", "http://www.jcp.org/jcr/1.0");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringEmptyUri() throws Exception {
+        registry.registerNamespace("foo", "");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingJcrPrefix() throws Exception {
+        registry.registerNamespace("jcr", "http://example.com");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingNtPrefix() throws Exception {
+        registry.registerNamespace("nt", "http://example.com");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingMixPrefix() throws Exception {
+        registry.registerNamespace("mix", "http://example.com");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingSvPrefix() throws Exception {
+        registry.registerNamespace("sv", "http://example.com");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingXmlPrefix() throws Exception {
+        registry.registerNamespace("xml", "http://example.com");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingDnaPrefix() throws Exception {
+        registry.registerNamespace("dna", "http://example.com");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingJcrUri() throws Exception {
+        registry.registerNamespace("foo", "http://www.jcp.org/jcr/1.0");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingNtUri() throws Exception {
+        registry.registerNamespace("foo", "http://www.jcp.org/jcr/nt/1.0");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingMixUri() throws Exception {
+        registry.registerNamespace("foo", "http://www.jcp.org/jcr/mix/1.0");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingSvUri() throws Exception {
+        registry.registerNamespace("foo", "http://www.jcp.org/jcr/sv/1.0");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingXmlUri() throws Exception {
+        registry.registerNamespace("foo", "http://www.w3.org/XML/1998/namespace");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingXmlnsUri() throws Exception {
+        registry.registerNamespace("foo", "http://www.w3.org/2000/xmlns/");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringUsingDnaUri() throws Exception {
+        registry.registerNamespace("foo", "http://www.jboss.org/dna/1.0");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowRegisteringPrefixThatIsNotValidXmlNCName() throws Exception {
+        registry.registerNamespace("1foot&in<door", "http://example.com");
+    }
+
     @Test( expected = IllegalArgumentException.class )
-    public void shouldNotAllowNullUri() throws Exception {
-        registry.getPrefix(null);
+    public void shouldNotAllowUnregisteringNullPrefix() throws Exception {
+        registry.unregisterNamespace(null);
     }
 
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowUnregisteringBlankPrefix() throws Exception {
+        registry.unregisterNamespace("");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowUnregisteringJcrPrefix() throws Exception {
+        registry.unregisterNamespace("jcr");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowUnregisteringNtPrefix() throws Exception {
+        registry.unregisterNamespace("nt");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowUnregisteringMixPrefix() throws Exception {
+        registry.unregisterNamespace("mix");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowUnregisteringSvPrefix() throws Exception {
+        registry.unregisterNamespace("sv");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowUnregisteringXmlPrefix() throws Exception {
+        registry.unregisterNamespace("xml");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowUnregisteringDnaPrefix() throws Exception {
+        registry.unregisterNamespace("dna");
+    }
+
+    @Test( expected = NamespaceException.class )
+    public void shouldNotAllowUnregisteringPrefixThatIsNotUsed() throws Exception {
+        String prefix = "bar";
+        assertThatNamespacePrefixIsNotRegistered(prefix);
+        registry.unregisterNamespace(prefix);
+    }
+
     @Test
-    public void shouldProvideUriForRegisteredPrefix() throws Exception {
-        assertThat(registry.getPrefix(""), is(""));
-        assertThat(registry.getPrefix("http://www.jboss.org/dna/1.0"), is("dna"));
-        assertThat(registry.getPrefix("http://www.jcp.org/jcr/1.0"), is("jcr"));
-        assertThat(registry.getPrefix("http://www.jcp.org/jcr/mix/1.0"), is("mix"));
-        assertThat(registry.getPrefix("http://www.jcp.org/jcr/nt/1.0"), is("nt"));
-        // assertThat(registry.getPrefix("http://www.w3.org/XML/1998/namespace"), is("xml"));
+    public void shouldRegisterNewPrefixWithNewUri() throws Exception {
+        String prefix = "foo";
+        String uri = "http://example.com";
+        assertThatNamespacePrefixIsNotRegistered(prefix);
+        assertThatNamespaceUriIsNotRegistered(uri);
+        registry.registerNamespace(prefix, uri);
+        assertThatNamespaceIsRegistered(prefix, uri);
     }
 
     @Test
-    public void shouldProvidePrefixForRegisteredUri() throws Exception {
-        assertThat(registry.getURI(""), is(""));
-        assertThat(registry.getURI("dna"), is("http://www.jboss.org/dna/1.0"));
-        assertThat(registry.getURI("jcr"), is("http://www.jcp.org/jcr/1.0"));
-        assertThat(registry.getURI("mix"), is("http://www.jcp.org/jcr/mix/1.0"));
-        assertThat(registry.getURI("nt"), is("http://www.jcp.org/jcr/nt/1.0"));
-        // assertThat(registry.getURI("xml"), is("http://www.w3.org/XML/1998/namespace"));
+    public void shouldRegisterRemoveExistingMappingWhenUsingNewPrefixWithPreviouslyUsedUri() throws Exception {
+        String prefix1 = "foo1";
+        String prefix2 = "foo2";
+        String uri = "http://example.com";
+        assertThatNamespacePrefixIsNotRegistered(prefix1);
+        assertThatNamespacePrefixIsNotRegistered(prefix2);
+        assertThatNamespaceUriIsNotRegistered(uri);
+        // Register the URI with the first prefix.
+        registry.registerNamespace(prefix1, uri);
+        assertThatNamespaceIsRegistered(prefix1, uri);
+        // Register the same URI with a different prefix. This should remove the mapping with 'prefix1'
+        registry.registerNamespace(prefix2, uri);
+        assertThatNamespaceIsRegistered(prefix2, uri);
+        assertThatNamespacePrefixIsNotRegistered(prefix1);
     }
 
+    @Test
+    public void shouldRegisterOverwriteExistingMappingWhenUsingPreviouslyUsedPrefixWithNewUri() throws Exception {
+        String prefix = "foo1";
+        String uri1 = "http://example.com";
+        String uri2 = "http://acme.com";
+        assertThatNamespacePrefixIsNotRegistered(prefix);
+        assertThatNamespaceUriIsNotRegistered(uri1);
+        assertThatNamespaceUriIsNotRegistered(uri2);
+        // Register the first URI with the prefix.
+        registry.registerNamespace(prefix, uri1);
+        assertThatNamespaceIsRegistered(prefix, uri1);
+        // Register the second URI with the same prefix. 'uri1' should no longer be used
+        registry.registerNamespace(prefix, uri2);
+        assertThatNamespaceIsRegistered(prefix, uri2);
+        assertThatNamespaceUriIsNotRegistered(uri1);
+    }
+
     @Test( expected = NamespaceException.class )
     public void shouldNotAllowUnregisteredPrefix() throws Exception {
         registry.getURI("bogus");

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -27,7 +27,6 @@
 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.stub;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.util.HashMap;
@@ -38,8 +37,11 @@
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
 import org.jboss.dna.graph.connector.RepositoryConnection;
 import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
@@ -51,18 +53,15 @@
  */
 public class JcrRepositoryTest {
 
-    private Repository repository;
-    @Mock
+    private String sourceName;
+    private ExecutionContext context;
+    private JcrRepository repository;
+    private InMemoryRepositorySource source;
     private Map<String, String> descriptors;
-    @Mock
     private RepositoryConnectionFactory connectionFactory;
+    protected AccessControlContext accessControlContext = AccessController.getContext();
     @Mock
-    private ExecutionContext executionContext;
-    @Mock
     LoginContext loginContext;
-    @Mock
-    private RepositoryConnection connection;
-    AccessControlContext accessControlContext = AccessController.getContext();
     private Credentials credentials = new Credentials() {
 
         private static final long serialVersionUID = 1L;
@@ -76,27 +75,58 @@
     @Before
     public void before() throws Exception {
         MockitoAnnotations.initMocks(this);
-        stub(executionContext.create(accessControlContext)).toReturn(executionContext);
-        stub(connectionFactory.createConnection(JcrI18n.defaultWorkspaceName.text())).toReturn(connection);
-        repository = new JcrRepository(descriptors, executionContext, connectionFactory);
+        sourceName = "repository";
+
+        // Set up the source ...
+        source = new InMemoryRepositorySource();
+        source.setName(sourceName);
+
+        // Set up the execution context ...
+        context = new ExecutionContext();
+
+        // Stub out the connection factory ...
+        connectionFactory = new RepositoryConnectionFactory() {
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.jboss.dna.graph.connector.RepositoryConnectionFactory#createConnection(java.lang.String)
+             */
+            @SuppressWarnings( "synthetic-access" )
+            public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+                return sourceName.equals(sourceName) ? source.getConnection() : null;
+            }
+        };
+
+        // Make sure the path to the namespaces exists ...
+        Graph graph = Graph.create(source, context);
+        graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces");
+
+        // Set up the repository ...
+        descriptors = new HashMap<String, String>();
+        repository = new JcrRepository(descriptors, context, connectionFactory, sourceName);
     }
 
     @Test
-    public void shouldAllowNoDescriptors() {
-        new JcrRepository(descriptors, executionContext, connectionFactory);
+    public void shouldAllowNullDescriptors() {
+        new JcrRepository(null, context, connectionFactory, sourceName);
     }
 
     @Test( expected = IllegalArgumentException.class )
-    public void shouldNotAllowNoExecutionContextFactory() throws Exception {
-        new JcrRepository(null, connectionFactory);
+    public void shouldNotAllowNullExecutionContext() throws Exception {
+        new JcrRepository(descriptors, null, connectionFactory, sourceName);
     }
 
     @Test( expected = IllegalArgumentException.class )
-    public void shouldNotAllowNoConnectionFactories() throws Exception {
-        new JcrRepository(executionContext, null);
+    public void shouldNotAllowNullConnectionFactories() throws Exception {
+        new JcrRepository(descriptors, context, null, sourceName);
     }
 
     @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowNullSourceName() throws Exception {
+        new JcrRepository(descriptors, context, connectionFactory, null);
+    }
+
+    @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowNoDescriptorKey() {
         repository.getDescriptor(null);
     }
@@ -118,7 +148,7 @@
 
     @Test
     public void shouldProvideBuiltInDescriptorsWhenNotSuppliedDescriptors() {
-        Repository repository = new JcrRepository(descriptors, executionContext, connectionFactory);
+        Repository repository = new JcrRepository(descriptors, context, connectionFactory, sourceName);
         testDescriptorKeys(repository);
         testDescriptorValues(repository);
     }
@@ -127,7 +157,7 @@
     public void shouldProvideUserSuppliedDescriptors() {
         Map<String, String> descriptors = new HashMap<String, String>();
         descriptors.put("property", "value");
-        Repository repository = new JcrRepository(descriptors, executionContext, connectionFactory);
+        Repository repository = new JcrRepository(descriptors, context, connectionFactory, sourceName);
         testDescriptorKeys(repository);
         testDescriptorValues(repository);
         assertThat(repository.getDescriptor("property"), is("value"));
@@ -148,7 +178,6 @@
     @Test
     public void shouldAllowLoginWithProperCredentials() throws Exception {
         repository.login(credentials);
-        stub(executionContext.create(loginContext)).toReturn(executionContext);
         repository.login(new Credentials() {
 
             private static final long serialVersionUID = 1L;
@@ -235,7 +264,7 @@
         assertThat(repository.getDescriptor(Repository.REP_NAME_DESC), is(JcrI18n.REP_NAME_DESC.text()));
         assertThat(repository.getDescriptor(Repository.REP_VENDOR_DESC), is(JcrI18n.REP_VENDOR_DESC.text()));
         assertThat(repository.getDescriptor(Repository.REP_VENDOR_URL_DESC), is("http://www.jboss.org/dna"));
-        assertThat(repository.getDescriptor(Repository.REP_VERSION_DESC), is("0.2"));
+        assertThat(repository.getDescriptor(Repository.REP_VERSION_DESC), is("0.4"));
         assertThat(repository.getDescriptor(Repository.SPEC_NAME_DESC), is(JcrI18n.SPEC_NAME_DESC.text()));
         assertThat(repository.getDescriptor(Repository.SPEC_VERSION_DESC), is("1.0"));
     }

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -29,12 +29,15 @@
 import static org.hamcrest.core.IsNull.notNullValue;
 import static org.hamcrest.core.IsNull.nullValue;
 import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.stub;
 import java.io.InputStream;
 import java.security.AccessControlException;
 import java.security.Principal;
 import java.util.Calendar;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.UUID;
 import javax.jcr.Item;
 import javax.jcr.NamespaceException;
@@ -48,57 +51,82 @@
 import javax.security.auth.login.LoginContext;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositoryConnection;
 import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySourceException;
 import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
 import org.junit.After;
-import org.junit.AfterClass;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import com.google.common.base.ReferenceType;
-import com.google.common.collect.ReferenceMap;
+import org.mockito.MockitoAnnotations.Mock;
 
 /**
  * @author jverhaeg
  */
 public class JcrSessionTest {
 
-    static final String REPOSITORY_NAME = "Test repository";
-    static final String WORKSPACE_NAME = JcrI18n.defaultWorkspaceName.text();
+    private String workspaceName;
+    private ExecutionContext context;
+    private InMemoryRepositorySource source;
+    private JcrWorkspace workspace;
+    private JcrSession session;
+    private Graph graph;
+    private RepositoryConnectionFactory connectionFactory;
+    private Map<String, Object> sessionAttributes;
+    @Mock
+    private JcrRepository repository;
 
-    static ExecutionContext executionContext;
-    static InMemoryRepositorySource repositorySource;
-    static Graph graph;
-    static RepositoryConnectionFactory connectionFactory;
-    static Repository repository;
+    @Before
+    public void beforeEach() throws Exception {
+        workspaceName = "workspace1";
+        final String repositorySourceName = "repository";
 
-    @BeforeClass
-    public static void beforeClass() throws Exception {
-        executionContext = TestUtil.getExecutionContext();
-        repositorySource = new InMemoryRepositorySource();
-        repositorySource.setName(REPOSITORY_NAME);
-        graph = Graph.create(repositorySource, executionContext);
+        // Set up the source ...
+        source = new InMemoryRepositorySource();
+        source.setName(workspaceName);
+        source.setDefaultWorkspaceName(workspaceName);
+
+        // Set up the execution context ...
+        context = new ExecutionContext();
+
+        // Set up the initial content ...
+        graph = Graph.create(source, context);
         graph.create("/a").and().create("/a/b").and().create("/a/b/c");
         graph.set("booleanProperty").on("/a/b").to(true);
         graph.set("stringProperty").on("/a/b/c").to("value");
-        connectionFactory = TestUtil.createJackRabbitConnectionFactory(repositorySource, executionContext);
-        repository = new JcrRepository(executionContext, connectionFactory);
-    }
 
-    @AfterClass
-    public static void afterClass() {
-    }
+        // Make sure the path to the namespaces exists ...
+        graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces");
 
-    private Session session;
-    private ReferenceMap<UUID, Node> nodesByUuid;
+        // Stub out the connection factory ...
+        connectionFactory = new RepositoryConnectionFactory() {
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.jboss.dna.graph.connector.RepositoryConnectionFactory#createConnection(java.lang.String)
+             */
+            @SuppressWarnings( "synthetic-access" )
+            public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+                return repositorySourceName.equals(sourceName) ? source.getConnection() : null;
+            }
+        };
 
-    @Before
-    public void before() throws Exception {
+        // Stub out the repository, since we only need a few methods ...
         MockitoAnnotations.initMocks(this);
-        nodesByUuid = new ReferenceMap<UUID, Node>(ReferenceType.STRONG, ReferenceType.SOFT);
-        session = repository.login();
+        stub(repository.getRepositorySourceName()).toReturn(repositorySourceName);
+        stub(repository.getConnectionFactory()).toReturn(connectionFactory);
+
+        // Set up the session attributes ...
+        sessionAttributes = new HashMap<String, Object>();
+        sessionAttributes.put("attribute1", "value1");
+
+        // Now create the workspace ...
+        workspace = new JcrWorkspace(repository, workspaceName, context, sessionAttributes);
+
+        // Create the session and log in ...
+        session = (JcrSession)workspace.getSession();
     }
 
     @After
@@ -109,26 +137,23 @@
     }
 
     @Test( expected = AssertionError.class )
-    public void shouldNotAllowNoRepository() throws Exception {
-        Graph graph = Graph.create(WORKSPACE_NAME, connectionFactory, executionContext);
-        new JcrSession(null, WORKSPACE_NAME, graph, nodesByUuid);
+    public void shouldNotAllowNullRepository() throws Exception {
+        new JcrSession(null, workspace, context, sessionAttributes);
     }
 
     @Test( expected = AssertionError.class )
-    public void shouldNotAllowNoWorkspaceName() throws Exception {
-        Graph graph = Graph.create(WORKSPACE_NAME, connectionFactory, executionContext);
-        new JcrSession(repository, null, graph, nodesByUuid);
+    public void shouldNotAllowNullWorkspace() throws Exception {
+        new JcrSession(repository, null, context, sessionAttributes);
     }
 
     @Test( expected = AssertionError.class )
-    public void shouldNotAllowNoGraph() throws Exception {
-        new JcrSession(repository, WORKSPACE_NAME, null, nodesByUuid);
+    public void shouldNotAllowNullExecutionContext() throws Exception {
+        new JcrSession(repository, workspace, null, sessionAttributes);
     }
 
     @Test( expected = AssertionError.class )
-    public void shouldNotAllowNoUuid2NodeMap() throws Exception {
-        Graph graph = Graph.create(WORKSPACE_NAME, connectionFactory, executionContext);
-        new JcrSession(repository, WORKSPACE_NAME, graph, null);
+    public void shouldNotAllowNullSessionAttributesMap() throws Exception {
+        new JcrSession(repository, workspace, context, null);
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -167,12 +192,46 @@
     }
 
     @Test
-    public void shouldProvideNoAttributes() throws Exception {
+    public void shouldReturnNullValueForNullAttributeName() throws Exception {
         assertThat(session.getAttribute(null), nullValue());
     }
 
     @Test
+    public void shouldReturnNullValueForEmptyOrBlankAttributeName() throws Exception {
+        assertThat(session.getAttribute(""), nullValue());
+        assertThat(session.getAttribute("  "), nullValue());
+    }
+
+    @Test
+    public void shouldReturnNullValueForNonExistantAttributeName() throws Exception {
+        assertThat(session.getAttribute("something else entirely"), nullValue());
+    }
+
+    @Test
+    public void shouldReturnPropertyAttributeValueGivenNameOfExistingAttribute() throws Exception {
+        assertThat(session.getAttribute("attribute1"), is((Object)"value1"));
+    }
+
+    @Test
+    public void shouldProvideAttributeNames() throws Exception {
+        String[] names = session.getAttributeNames();
+        assertThat(names, notNullValue());
+        assertThat(names.length, is(1));
+        assertThat(names[0], is("attribute1"));
+    }
+
+    @Test
     public void shouldProvideEmptyAttributeNames() throws Exception {
+        // Set up the session attributes ...
+        sessionAttributes = new HashMap<String, Object>();
+
+        // Now create the workspace ...
+        workspace = new JcrWorkspace(repository, workspaceName, context, sessionAttributes);
+
+        // Create the session and log in ...
+        session = (JcrSession)workspace.getSession();
+
+        // Get get the attribute names (there should be none) ...
         String[] names = session.getAttributeNames();
         assertThat(names, notNullValue());
         assertThat(names.length, is(0));
@@ -180,7 +239,7 @@
 
     @Test
     public void shouldProvideAccessToRepository() throws Exception {
-        assertThat(session.getRepository(), is(repository));
+        assertThat(session.getRepository(), is((Repository)repository));
     }
 
     @Test
@@ -210,12 +269,9 @@
         Principal principal = Mockito.mock(Principal.class);
         stub(principal.getName()).toReturn("name");
         Subject subject = new Subject(false, Collections.singleton(principal), Collections.EMPTY_SET, Collections.EMPTY_SET);
-        ExecutionContext executionContext = Mockito.mock(ExecutionContext.class);
-        stub(executionContext.getSubject()).toReturn(subject);
-        stub(executionContext.getLoginContext()).toReturn(Mockito.mock(LoginContext.class));
-        Graph graph = Mockito.mock(Graph.class);
-        stub(graph.getContext()).toReturn(executionContext);
-        Session session = new JcrSession(repository, WORKSPACE_NAME, graph, nodesByUuid);
+        LoginContext loginContext = mock(LoginContext.class);
+        stub(loginContext.getSubject()).toReturn(subject);
+        Session session = new JcrSession(repository, workspace, context.create(loginContext), sessionAttributes);
         try {
             assertThat(session.getUserID(), is("name"));
         } finally {
@@ -225,9 +281,7 @@
 
     @Test
     public void shouldProvideRootNode() throws Exception {
-        ReferenceMap<UUID, Node> nodesByUuid = new ReferenceMap<UUID, Node>(ReferenceType.STRONG, ReferenceType.SOFT);
-        Graph graph = Graph.create(WORKSPACE_NAME, connectionFactory, executionContext);
-        Session session = new JcrSession(repository, WORKSPACE_NAME, graph, nodesByUuid);
+        Map<UUID, Node> nodesByUuid = session.getNodesByUuid();
         assertThat(nodesByUuid.isEmpty(), is(true));
         Node root = session.getRootNode();
         assertThat(root, notNullValue());
@@ -267,7 +321,7 @@
         assertThat(session.hasPendingChanges(), is(false));
     }
 
-    @Test
+    @Test( expected = UnsupportedOperationException.class )
     public void shouldAllowImpersonation() throws Exception {
         assertThat(session.impersonate(null), notNullValue());
     }

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -26,61 +26,79 @@
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsNull.notNullValue;
 import static org.junit.Assert.assertThat;
-import javax.jcr.Session;
-import javax.jcr.Workspace;
+import static org.mockito.Mockito.stub;
+import java.util.HashMap;
+import java.util.Map;
+import javax.jcr.NamespaceRegistry;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.JcrLexicon;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySourceException;
 import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
-import org.junit.After;
-import org.junit.AfterClass;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
 
 /**
  * @author jverhaeg
  */
 public class JcrWorkspaceTest {
 
-    @BeforeClass
-    public static void beforeClass() throws Exception {
-        JcrSessionTest.executionContext = TestUtil.getExecutionContext();
-        InMemoryRepositorySource source = new InMemoryRepositorySource();
-        source.setName(JcrSessionTest.REPOSITORY_NAME);
-        JcrSessionTest.repositorySource = source;
-        JcrSessionTest.connectionFactory = TestUtil.createJackRabbitConnectionFactory(JcrSessionTest.repositorySource,
-                                                                                      JcrSessionTest.executionContext);
-        JcrSessionTest.repository = new JcrRepository(JcrSessionTest.executionContext, JcrSessionTest.connectionFactory);
-    }
+    private String workspaceName;
+    private ExecutionContext context;
+    private InMemoryRepositorySource source;
+    private JcrWorkspace workspace;
+    private RepositoryConnectionFactory connectionFactory;
+    private Map<String, Object> sessionAttributes;
+    @Mock
+    private JcrRepository repository;
 
-    @AfterClass
-    public static void afterClass() {
-    }
+    @Before
+    public void beforeEach() throws Exception {
+        final String repositorySourceName = "repository";
+        workspaceName = "workspace1";
 
-    private Session session;
-    private Workspace workspace;
+        // Set up the source ...
+        source = new InMemoryRepositorySource();
+        source.setName(repositorySourceName);
+        source.setDefaultWorkspaceName(workspaceName);
 
-    @Before
-    public void before() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        session = JcrSessionTest.repository.login();
-        workspace = session.getWorkspace();
-    }
+        // Set up the execution context ...
+        context = new ExecutionContext();
 
-    @After
-    public void after() throws Exception {
-        if (session.isLive()) {
-            session.logout();
-        }
-    }
+        // Set up the initial content ...
+        Graph graph = Graph.create(source, context);
+        graph.create("/a").and().create("/a/b").and().create("/a/b/c").and().create("/b");
+        graph.set("booleanProperty").on("/a/b").to(true);
+        graph.set("stringProperty").on("/a/b/c").to("value");
 
-    @Test( expected = AssertionError.class )
-    public void shouldNotAllowNoSession() throws Exception {
-        new JcrWorkspace(null, JcrSessionTest.WORKSPACE_NAME);
-    }
+        // Make sure the path to the namespaces exists ...
+        graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces");
 
-    @Test( expected = AssertionError.class )
-    public void shouldNotAllowNoWorkspaceName() throws Exception {
-        new JcrWorkspace((JcrSession)session, null);
+        // Stub out the connection factory ...
+        connectionFactory = new RepositoryConnectionFactory() {
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.jboss.dna.graph.connector.RepositoryConnectionFactory#createConnection(java.lang.String)
+             */
+            @SuppressWarnings( "synthetic-access" )
+            public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+                return repositorySourceName.equals(sourceName) ? source.getConnection() : null;
+            }
+        };
+
+        // Stub out the repository, since we only need a few methods ...
+        MockitoAnnotations.initMocks(this);
+        stub(repository.getRepositorySourceName()).toReturn(repositorySourceName);
+        stub(repository.getConnectionFactory()).toReturn(connectionFactory);
+
+        // Now create the workspace ...
+        sessionAttributes = new HashMap<String, Object>();
+        workspace = new JcrWorkspace(repository, workspaceName, context, sessionAttributes);
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -88,34 +106,48 @@
         workspace.clone(null, null, null, false);
     }
 
-    @Test( expected = UnsupportedOperationException.class )
-    public void shouldNotAllowCopy() throws Exception {
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowCopyFromNullPathToNullPath() throws Exception {
         workspace.copy(null, null);
     }
 
+    @Test
+    public void shouldCopyFromPathToAnotherPathInSameWorkspace() throws Exception {
+        workspace.copy("/a/b", "/b/b-copy");
+    }
+
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotAllowCopyFromOtherWorkspace() throws Exception {
         workspace.copy(null, null, null);
     }
 
-    @Test( expected = UnsupportedOperationException.class )
+    @Test
     public void shouldNotAllowGetAccessibleWorkspaceNames() throws Exception {
-        workspace.getAccessibleWorkspaceNames();
+        String[] names = workspace.getAccessibleWorkspaceNames();
+        assertThat(names.length, is(1));
+        assertThat(names[0], is(workspaceName));
     }
 
-    @Test( expected = UnsupportedOperationException.class )
-    public void shouldNotAllowImportContentHandler() throws Exception {
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowImportContentHandlerWithNullPath() throws Exception {
         workspace.getImportContentHandler(null, 0);
     }
 
     @Test
+    public void shouldGetImportContentHandlerWithValidPath() throws Exception {
+        assertThat(workspace.getImportContentHandler("/b", 0), is(notNullValue()));
+    }
+
+    @Test
     public void shouldProvideName() throws Exception {
-        assertThat(workspace.getName(), is(JcrSessionTest.WORKSPACE_NAME));
+        assertThat(workspace.getName(), is(workspaceName));
     }
 
     @Test
     public void shouldProvideNamespaceRegistry() throws Exception {
-        assertThat(workspace.getNamespaceRegistry(), notNullValue());
+        NamespaceRegistry registry = workspace.getNamespaceRegistry();
+        assertThat(registry, is(notNullValue()));
+        assertThat(registry.getURI(JcrLexicon.Namespace.PREFIX), is(JcrLexicon.Namespace.URI));
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -135,7 +167,7 @@
 
     @Test
     public void shouldProvideSession() throws Exception {
-        assertThat(workspace.getSession(), is(session));
+        assertThat(workspace.getSession(), is(notNullValue()));
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -143,12 +175,17 @@
         workspace.importXML(null, null, 0);
     }
 
-    @Test( expected = UnsupportedOperationException.class )
-    public void shouldNotAllowMove() throws Exception {
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowMoveFromNullPath() throws Exception {
         workspace.move(null, null);
     }
 
     @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotAllowMoveFromPathToAnotherPathInSameWorkspace() throws Exception {
+        workspace.move("/a/b", "/b/b-copy");
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
     public void shouldNotAllowRestore() throws Exception {
         workspace.restore(null, false);
     }

Added: trunk/dna-jcr/src/test/resources/cars.xml
===================================================================
--- trunk/dna-jcr/src/test/resources/cars.xml	                        (rev 0)
+++ trunk/dna-jcr/src/test/resources/cars.xml	2009-02-27 22:21:50 UTC (rev 738)
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ 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.
+  ~
+  ~ JBoss DNA is free software. 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 distribution; if not, write to:
+  ~ Free Software Foundation, Inc.
+  ~ 51 Franklin Street, Fifth Floor
+  ~ Boston, MA  02110-1301  USA
+  -->
+<Cars xmlns:jcr="http://www.jcp.org/jcr/1.0">
+    <Hybrid>
+        <car jcr:name="Toyota Prius" maker="Toyota" model="Prius" year="2008" msrp="$21,500" userRating="4.2" valueRating="5" mpgCity="48" mpgHighway="45"/>
+        <car jcr:name="Toyota Highlander" maker="Toyota" model="Highlander" year="2008" msrp="$34,200" userRating="4" valueRating="5" mpgCity="27" mpgHighway="25"/>
+        <car jcr:name="Nissan Altima" maker="Nissan" model="Altima" year="2008" msrp="$18,260" mpgCity="23" mpgHighway="32"/>
+    </Hybrid>
+    <Sports>
+        <car jcr:name="Aston Martin DB9" maker="Aston Martin" model="DB9" year="2008" msrp="$171,600" userRating="5" mpgCity="12" mpgHighway="19" lengthInInches="185.5" wheelbaseInInches="108.0" engine="5,935 cc 5.9 liters V 12"/>
+        <car jcr:name="Infiniti G37" maker="Infiniti" model="G37" year="2008" msrp="$34,900" userRating="3.5" valueRating="4" mpgCity="18" mpgHighway="24" />
+    </Sports>
+    <Luxury>
+        <car jcr:name="Cadillac DTS" maker="Cadillac" model="DTS" year="2008" engine="3.6-liter V6" userRating="0"/>
+        <car jcr:name="Bentley Continental" maker="Bentley" model="Continental" year="2008" msrp="$170,990" mpgCity="10" mpgHighway="17" />
+        <car jcr:name="Lexus IS350" maker="Lexus" model="IS350" year="2008" msrp="$36,305" mpgCity="18" mpgHighway="25" userRating="4" valueRating="5" />
+    </Luxury>
+    <Utility>
+        <car jcr:name="Land Rover LR2" maker="Land Rover" model="LR2" year="2008" msrp="$33,985" userRating="4.5" valueRating="5" mpgCity="16" mpgHighway="23" />
+        <car jcr:name="Land Rover LR3" maker="Land Rover" model="LR3" year="2008" msrp="$48,525" userRating="5" valueRating="2" mpgCity="12" mpgHighway="17" />
+        <car jcr:name="Hummer H3" maker="Hummer" model="H3" year="2008" msrp="$30,595" userRating="3.5" valueRating="4" mpgCity="13" mpgHighway="16" />
+        <car jcr:name="Ford F-150" maker="Ford" model="F-150" year="2008" msrp="$23,910" userRating="4" valueRating="1" mpgCity="14" mpgHighway="20" />
+    </Utility>
+</Cars>\ No newline at end of file


Property changes on: trunk/dna-jcr/src/test/resources/cars.xml
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java	2009-02-24 14:40:05 UTC (rev 737)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java	2009-02-27 22:21:50 UTC (rev 738)
@@ -245,7 +245,7 @@
         LoginContext loginContext = getLoginContext(); // will ask user to authenticate if needed
         switch (api) {
             case JCR: {
-                JcrRepository jcrRepository = new JcrRepository(context, sources);
+                JcrRepository jcrRepository = new JcrRepository(context, sources, sourceName);
                 Session session = null;
                 if (loginContext != null) {
                     Credentials credentials = new JaasCredentials(loginContext);



