[dna-commits] DNA SVN: r647 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/properties and 13 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Mon Nov 24 10:13:59 EST 2008


Author: rhauch
Date: 2008-11-24 10:13:59 -0500 (Mon, 24 Nov 2008)
New Revision: 647

Added:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/InvalidRequestException.java
Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Property.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicEmptyProperty.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicMultiValueProperty.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicSingleValueProperty.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CreateNodeRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/MoveBranchRequest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.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/executor/FederatingCommandExecutor.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnection.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/Model.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModel.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicRequestProcessor.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/ChildEntity.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/LargeValueEntity.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/PropertiesEntity.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/NodeId.java
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/Serializer.java
   trunk/extensions/dna-connector-store-jpa/src/main/resources/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.properties
   trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionTest.java
   trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/ModelTest.java
   trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModelTest.java
   trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/SerializerTest.java
Log:
DNA-40 Persistant storage for information not stored in other repository sources

More progress on the relational database storage connector.

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	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -493,7 +493,7 @@
         Path at = createPath(atPath);
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child, 0));
+        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child));
         return nextGraph;
     }
 
@@ -514,7 +514,7 @@
         Path at = createPath(atPath);
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child, 0, properties));
+        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child, properties));
         return nextGraph;
     }
 
@@ -533,7 +533,7 @@
         CheckArg.isNotNull(at, "at");
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child, 0));
+        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child));
         return nextGraph;
     }
 
@@ -554,7 +554,7 @@
         CheckArg.isNotNull(at, "at");
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child, 0, properties));
+        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child, properties));
         return nextGraph;
     }
 
@@ -575,7 +575,7 @@
         CheckArg.isNotNull(at, "at");
         Path parent = at.getParent();
         Name child = at.getLastSegment().getName();
-        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child, 0, properties));
+        this.requestQueue.submit(new CreateNodeRequest(new Location(parent), child, properties));
         return nextGraph;
     }
 
@@ -594,45 +594,27 @@
         final NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
         CheckArg.isNotNull(parent, "parent");
         return new CreateNode<Conjunction<Graph>>() {
-            public Conjunction<Graph> node( String name,
-                                            Property... properties ) {
-                return node(name, -1, properties);
-            }
-
-            public Conjunction<Graph> node( String name,
-                                            Iterator<Property> properties ) {
-                return node(name, -1, properties);
-            }
-
-            public Conjunction<Graph> node( String name,
-                                            Iterable<Property> properties ) {
-                return node(name, -1, properties);
-            }
-
             @SuppressWarnings( "synthetic-access" )
             public Conjunction<Graph> node( String name,
-                                            int desiredIndexInParent,
                                             Property... properties ) {
                 Name child = nameFactory.create(name);
-                requestQueue.submit(new CreateNodeRequest(parent, child, desiredIndexInParent, properties));
+                requestQueue.submit(new CreateNodeRequest(parent, child, properties));
                 return nextGraph;
             }
 
             @SuppressWarnings( "synthetic-access" )
             public Conjunction<Graph> node( String name,
-                                            int desiredIndexInParent,
                                             Iterator<Property> properties ) {
                 Name child = nameFactory.create(name);
-                requestQueue.submit(new CreateNodeRequest(parent, child, desiredIndexInParent, properties));
+                requestQueue.submit(new CreateNodeRequest(parent, child, properties));
                 return nextGraph;
             }
 
             @SuppressWarnings( "synthetic-access" )
             public Conjunction<Graph> node( String name,
-                                            int desiredIndexInParent,
                                             Iterable<Property> properties ) {
                 Name child = nameFactory.create(name);
-                requestQueue.submit(new CreateNodeRequest(parent, child, desiredIndexInParent, properties));
+                requestQueue.submit(new CreateNodeRequest(parent, child, properties));
                 return nextGraph;
             }
         };
@@ -1617,7 +1599,7 @@
             Path at = createPath(atPath);
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name, 0);
+            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name);
         }
 
         /**
@@ -1638,7 +1620,7 @@
             Path at = createPath(atPath);
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name, 0).with(property);
+            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name).with(property);
         }
 
         /**
@@ -1661,7 +1643,7 @@
             Path at = createPath(atPath);
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name, 0).with(firstProperty,
+            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name).with(firstProperty,
                                                                                                                       additionalProperties);
         }
 
@@ -1681,7 +1663,7 @@
             CheckArg.isNotNull(at, "at");
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name, 0);
+            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name);
         }
 
         /**
@@ -1703,7 +1685,7 @@
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
             CreateAction<BatchConjunction> action = new CreateAction<BatchConjunction>(nextRequests, requestQueue,
-                                                                                       new Location(parent), name, 0);
+                                                                                       new Location(parent), name);
             for (Property property : properties) {
                 action.and(property);
             }
@@ -1728,7 +1710,7 @@
             CheckArg.isNotNull(at, "at");
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name, 0).with(property);
+            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name).with(property);
         }
 
         /**
@@ -1751,7 +1733,7 @@
             CheckArg.isNotNull(at, "at");
             Path parent = at.getParent();
             Name name = at.getLastSegment().getName();
-            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name, 0).with(firstProperty,
+            return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(parent), name).with(firstProperty,
                                                                                                                       additionalProperties);
         }
 
@@ -2649,42 +2631,6 @@
          */
         Next node( String nodeName,
                    Iterable<Property> properties );
-
-        /**
-         * Specify the name of the node that is to be created.
-         * 
-         * @param nodeName the name of the new node
-         * @param sameNameSiblingIndex the desired same-name-sibling index
-         * @param properties the properties for the new node
-         * @return the next component for making additional requests.
-         */
-        Next node( String nodeName,
-                   int sameNameSiblingIndex,
-                   Property... properties );
-
-        /**
-         * Specify the name of the node that is to be created.
-         * 
-         * @param nodeName the name of the new node
-         * @param sameNameSiblingIndex the desired same-name-sibling index
-         * @param properties the properties for the new node
-         * @return the next component for making additional requests.
-         */
-        Next node( String nodeName,
-                   int sameNameSiblingIndex,
-                   Iterator<Property> properties );
-
-        /**
-         * Specify the name of the node that is to be created.
-         * 
-         * @param nodeName the name of the new node
-         * @param sameNameSiblingIndex the desired same-name-sibling index
-         * @param properties the properties for the new node
-         * @return the next component for making additional requests.
-         */
-        Next node( String nodeName,
-                   int sameNameSiblingIndex,
-                   Iterable<Property> properties );
     }
 
     /**
@@ -2701,16 +2647,6 @@
          * @return the interface used to complete the request
          */
         CreateAction<Next> nodeNamed( String nodeName );
-
-        /**
-         * Specify the name of the node that is to be created.
-         * 
-         * @param nodeName the name of the new node
-         * @param sameNameSiblingIndex the desired same-name-sibling index
-         * @return the interface used to complete the request
-         */
-        CreateAction<Next> nodeNamed( String nodeName,
-                                      int sameNameSiblingIndex );
     }
 
     /**
@@ -3557,18 +3493,15 @@
     static class CreateAction<T> extends AbstractAction<T> implements Create<T> {
         private final Location parent;
         private final Name childName;
-        private final int desiredIndex;
         private final List<Property> properties = new LinkedList<Property>();
 
         /*package*/CreateAction( T afterConjunction,
                                   RequestQueue queue,
                                   Location parent,
-                                  Name childName,
-                                  int desiredIndex ) {
+                                  Name childName ) {
             super(afterConjunction, queue);
             this.parent = parent;
             this.childName = childName;
-            this.desiredIndex = desiredIndex;
         }
 
         public Create<T> and( UUID uuid ) {
@@ -3633,7 +3566,7 @@
 
         @Override
         public T and() {
-            this.queue().submit(new CreateNodeRequest(parent, childName, desiredIndex, this.properties));
+            this.queue().submit(new CreateNodeRequest(parent, childName, this.properties));
             return super.and();
         }
 
@@ -3658,16 +3591,7 @@
             ExecutionContext context = queue().getGraph().getContext();
             NameFactory factory = context.getValueFactories().getNameFactory();
             Name nameObj = factory.create(name);
-            return new CreateAction<T>(afterConjunction(), queue(), parent, nameObj, 0);
+            return new CreateAction<T>(afterConjunction(), queue(), parent, nameObj);
         }
-
-        public CreateAction<T> nodeNamed( String name,
-                                          int desiredIndex ) {
-            ExecutionContext context = queue().getGraph().getContext();
-            NameFactory factory = context.getValueFactories().getNameFactory();
-            Name nameObj = factory.create(name);
-            if (desiredIndex < 0) desiredIndex = 0;
-            return new CreateAction<T>(afterConjunction(), queue(), parent, nameObj, desiredIndex);
-        }
     }
 }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Property.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Property.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Property.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -107,6 +107,18 @@
     boolean isEmpty();
 
     /**
+     * Obtain the property's first value in its natural form. This is equivalent to calling
+     * <code>isEmpty() ? null : iterator().next()</code>
+     * 
+     * @return the first value, or null if the property is {@link #isEmpty() empty}
+     * @see Iterable#iterator()
+     * @see #getValues()
+     * @see #getValuesAsArray()
+     * @see #isEmpty()
+     */
+    Object getFirstValue();
+
+    /**
      * Obtain the property's values in their natural form. This is equivalent to calling {@link Iterable#iterator() iterator()}.
      * <p>
      * A valid iterator is returned if the property has {@link #isSingle() single valued} or {@link #isMultiple() multi-valued}.
@@ -116,6 +128,7 @@
      * </p>
      * 
      * @return an iterator over the values; never null
+     * @see #getFirstValue()
      * @see Iterable#iterator()
      * @see #getValuesAsArray()
      * @see ValueFactory#create(Iterator)
@@ -133,6 +146,7 @@
      * </p>
      * 
      * @return the array of values
+     * @see #getFirstValue()
      * @see Iterable#iterator()
      * @see #getValues()
      * @see ValueFactory#create(Object[])

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicEmptyProperty.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicEmptyProperty.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicEmptyProperty.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -76,7 +76,16 @@
 
     /**
      * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.properties.Property#getFirstValue()
      */
+    public Object getFirstValue() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public Iterator<Object> iterator() {
         return SHARED_ITERATOR;
     }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicMultiValueProperty.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicMultiValueProperty.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicMultiValueProperty.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -100,7 +100,16 @@
 
     /**
      * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.properties.Property#getFirstValue()
      */
+    public Object getFirstValue() {
+        return values.get(0);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public Iterator<Object> iterator() {
         return new ReadOnlyIterator(values.iterator());
     }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -147,9 +147,9 @@
      */
     public int compareTo( Name that ) {
         if (that == this) return 0;
-        int diff = this.getNamespaceUri().compareTo(that.getNamespaceUri());
+        int diff = this.getLocalName().compareTo(that.getLocalName());
         if (diff != 0) return diff;
-        diff = this.getLocalName().compareTo(that.getLocalName());
+        diff = this.getNamespaceUri().compareTo(that.getNamespaceUri());
         return diff;
     }
 
@@ -169,8 +169,9 @@
         if (obj == this) return true;
         if (obj instanceof Name) {
             Name that = (Name)obj;
+            if (!this.getLocalName().equals(that.getLocalName())) return false;
             if (!this.getNamespaceUri().equals(that.getNamespaceUri())) return false;
-            return this.getLocalName().equals(that.getLocalName());
+            return true;
         }
         return false;
     }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicSingleValueProperty.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicSingleValueProperty.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicSingleValueProperty.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -79,7 +79,16 @@
 
     /**
      * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.properties.Property#getFirstValue()
      */
+    public Object getFirstValue() {
+        return value;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public Iterator<Object> iterator() {
         return new ValueIterator();
     }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CreateNodeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CreateNodeRequest.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CreateNodeRequest.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -47,7 +47,6 @@
 
     private final Location under;
     private final Name childName;
-    private final Integer desiredIndex;
     private final List<Property> properties;
     private final NodeConflictBehavior conflictBehavior;
     private Location actualLocation;
@@ -57,17 +56,14 @@
      * 
      * @param parentLocation the location of the existing parent node, under which the new child should be created
      * @param childName the name of the new child to create under the existing parent
-     * @param desiredIndexInParent the desired index in the parent under which the new child should be created, or 0 if the child
-     *        is to be appended under the end of the existing children
      * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
      *        properties} for the new node
      * @throws IllegalArgumentException if the location or the child name is null
      */
     public CreateNodeRequest( Location parentLocation,
                               Name childName,
-                              int desiredIndexInParent,
                               Property... properties ) {
-        this(parentLocation, childName, desiredIndexInParent, DEFAULT_CONFLICT_BEHAVIOR, properties);
+        this(parentLocation, childName, DEFAULT_CONFLICT_BEHAVIOR, properties);
     }
 
     /**
@@ -75,17 +71,14 @@
      * 
      * @param parentLocation the location of the existing parent node, under which the new child should be created
      * @param childName the name of the new child to create under the existing parent
-     * @param desiredIndexInParent the desired index in the parent under which the new child should be created, or 0 if the child
-     *        is to be appended under the end of the existing children
      * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
      *        properties} for the new node
      * @throws IllegalArgumentException if the location or the child name is null
      */
     public CreateNodeRequest( Location parentLocation,
                               Name childName,
-                              int desiredIndexInParent,
                               Iterable<Property> properties ) {
-        this(parentLocation, childName, desiredIndexInParent, DEFAULT_CONFLICT_BEHAVIOR, properties);
+        this(parentLocation, childName, DEFAULT_CONFLICT_BEHAVIOR, properties);
     }
 
     /**
@@ -93,17 +86,14 @@
      * 
      * @param parentLocation the location of the existing parent node, under which the new child should be created
      * @param childName the name of the new child to create under the existing parent
-     * @param desiredIndexInParent the desired index in the parent under which the new child should be created, or 0 if the child
-     *        is to be appended under the end of the existing children
      * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
      *        properties} for the new node
      * @throws IllegalArgumentException if the location or the child name is null
      */
     public CreateNodeRequest( Location parentLocation,
                               Name childName,
-                              int desiredIndexInParent,
                               Iterator<Property> properties ) {
-        this(parentLocation, childName, desiredIndexInParent, DEFAULT_CONFLICT_BEHAVIOR, properties);
+        this(parentLocation, childName, DEFAULT_CONFLICT_BEHAVIOR, properties);
     }
 
     /**
@@ -111,8 +101,6 @@
      * 
      * @param parentLocation the location of the existing parent node, under which the new child should be created
      * @param childName the name of the new child to create under the existing parent
-     * @param desiredIndexInParent the desired index in the parent under which the new child should be created, or 0 if the child
-     *        is to be appended under the end of the existing children
      * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
      *        properties} for the new node
      * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code>
@@ -121,7 +109,6 @@
      */
     public CreateNodeRequest( Location parentLocation,
                               Name childName,
-                              int desiredIndexInParent,
                               NodeConflictBehavior conflictBehavior,
                               Property... properties ) {
         CheckArg.isNotNull(parentLocation, "parentLocation");
@@ -129,7 +116,6 @@
         CheckArg.isNotNull(childName, "childName");
         this.under = parentLocation;
         this.childName = childName;
-        this.desiredIndex = desiredIndexInParent < 1 ? null : new Integer(desiredIndexInParent);
         this.conflictBehavior = conflictBehavior;
         int number = properties.length + (under.hasIdProperties() ? under.getIdProperties().size() : 0);
         List<Property> props = new ArrayList<Property>(number);
@@ -144,8 +130,6 @@
      * 
      * @param parentLocation the location of the existing parent node, under which the new child should be created
      * @param childName the name of the new child to create under the existing parent
-     * @param desiredIndexInParent the desired index in the parent under which the new child should be created, or 0 if the child
-     *        is to be appended under the end of the existing children
      * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
      *        properties} for the new node
      * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code>
@@ -154,7 +138,6 @@
      */
     public CreateNodeRequest( Location parentLocation,
                               Name childName,
-                              int desiredIndexInParent,
                               NodeConflictBehavior conflictBehavior,
                               Iterable<Property> properties ) {
         CheckArg.isNotNull(parentLocation, "parentLocation");
@@ -162,7 +145,6 @@
         CheckArg.isNotNull(childName, "childName");
         this.under = parentLocation;
         this.childName = childName;
-        this.desiredIndex = desiredIndexInParent < 1 ? null : new Integer(desiredIndexInParent);
         this.conflictBehavior = conflictBehavior;
         List<Property> props = new LinkedList<Property>();
         for (Property property : properties) {
@@ -182,8 +164,6 @@
      * 
      * @param parentLocation the location of the existing parent node, under which the new child should be created
      * @param childName the name of the new child to create under the existing parent
-     * @param desiredIndexInParent the desired index in the parent under which the new child should be created, or 0 if the child
-     *        is to be appended under the end of the existing children
      * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
      *        properties} for the new node
      * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code>
@@ -192,7 +172,6 @@
      */
     public CreateNodeRequest( Location parentLocation,
                               Name childName,
-                              int desiredIndexInParent,
                               NodeConflictBehavior conflictBehavior,
                               Iterator<Property> properties ) {
         CheckArg.isNotNull(parentLocation, "parentLocation");
@@ -200,7 +179,6 @@
         CheckArg.isNotNull(childName, "childName");
         this.under = parentLocation;
         this.childName = childName;
-        this.desiredIndex = desiredIndexInParent < 1 ? null : new Integer(desiredIndexInParent);
         this.conflictBehavior = conflictBehavior;
         List<Property> props = new LinkedList<Property>();
         while (properties.hasNext()) {
@@ -235,16 +213,6 @@
     }
 
     /**
-     * Get the desired index (always positive) in the parent for the new child, or null if the new child should be appended under
-     * the end of the existing children.
-     * 
-     * @return the desired index, or null if there is no desired index
-     */
-    public Integer desiredIndex() {
-        return desiredIndex;
-    }
-
-    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Iterable#iterator()

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/InvalidRequestException.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/InvalidRequestException.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/InvalidRequestException.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors. 
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * 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.
+ *
+ * This software 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.requests;
+
+/**
+ * Specifies that the request was invalid and could not be completed.
+ * 
+ * @author Randall Hauch
+ */
+public class InvalidRequestException extends RuntimeException {
+
+    /**
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 
+     */
+    public InvalidRequestException() {
+    }
+
+    /**
+     * @param message
+     */
+    public InvalidRequestException( String message ) {
+        super(message);
+
+    }
+
+    /**
+     * @param cause
+     */
+    public InvalidRequestException( Throwable cause ) {
+        super(cause);
+
+    }
+
+    /**
+     * @param message
+     * @param cause
+     */
+    public InvalidRequestException( String message,
+                                    Throwable cause ) {
+        super(message, cause);
+
+    }
+
+}

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/MoveBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/MoveBranchRequest.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/MoveBranchRequest.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -25,6 +25,7 @@
 import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.NodeConflictBehavior;
+import org.jboss.dna.graph.properties.Path;
 
 /**
  * Instruction that a branch be moved from one location into another.
@@ -114,6 +115,30 @@
     }
 
     /**
+     * Determine whether this move request can be determined to have no effect.
+     * <p>
+     * A move is known to have no effect when all of the following conditions are true:
+     * <ul>
+     * <li>the {@link #into() into} location has a {@link Location#hasPath() path} but no {@link Location#hasIdProperties()
+     * identification properties};</li>
+     * <li>the {@link #from() from} location has a {@link Location#getPath() path}; and</li>
+     * <li>the {@link #from() from} location's {@link Path#getParent() parent} is the same as the {@link #into() into} location's
+     * path.</li>
+     * </ul>
+     * If all of these conditions are not true, this method returns false.
+     * </p>
+     * 
+     * @return true if this move request really doesn't change the parent of the node, or false if it cannot be determined
+     */
+    public boolean hasNoEffect() {
+        if (into.hasPath() && into.hasIdProperties() == false && from.hasPath()) {
+            return from.getPath().getParent().equals(into.getPath());
+        }
+        // Can't be determined for certain
+        return false;
+    }
+
+    /**
      * Sets the actual and complete location of the node being renamed and its new location. This method must be called when
      * processing the request, and the actual location must have a {@link Location#getPath() path}.
      * 

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	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -162,10 +162,9 @@
 
     protected void assertNextRequestIsCreate( Location parent,
                                               String child,
-                                              int desiredIndex,
                                               Property... properties ) {
         Name name = context.getValueFactories().getNameFactory().create(child);
-        assertThat(executedRequests.poll(), is((Request)new CreateNodeRequest(parent, name, desiredIndex, properties)));
+        assertThat(executedRequests.poll(), is((Request)new CreateNodeRequest(parent, name, properties)));
     }
 
     protected void assertNextRequestReadProperties( Location at,
@@ -310,32 +309,32 @@
     public void shouldCreateNode() {
         graph.create(validPath);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", 0);
+        assertNextRequestIsCreate(new Location(validPath.getParent()), "c");
         assertNoMoreRequests();
 
         graph.create(validPath, validIdProperty1);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", 0, validIdProperty1);
+        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", validIdProperty1);
         assertNoMoreRequests();
 
         graph.create(validPath, validIdProperty1, validIdProperty2);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", 0, validIdProperty1, validIdProperty2);
+        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", validIdProperty1, validIdProperty2);
         assertNoMoreRequests();
 
         graph.create(validPathString);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", 0);
+        assertNextRequestIsCreate(new Location(validPath.getParent()), "c");
         assertNoMoreRequests();
 
         graph.create(validPathString, validIdProperty1);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", 0, validIdProperty1);
+        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", validIdProperty1);
         assertNoMoreRequests();
 
         graph.create(validPathString, validIdProperty1, validIdProperty2);
         assertThat(numberOfExecutions, is(1));
-        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", 0, validIdProperty1, validIdProperty2);
+        assertNextRequestIsCreate(new Location(validPath.getParent()), "c", validIdProperty1, validIdProperty2);
         assertNoMoreRequests();
     }
 

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	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -439,7 +439,7 @@
             assert path != null;
             Path parent = path.getParent();
             Name child = path.getLastSegment().getName();
-            requests.add(new CreateNodeRequest(new Location(parent), child, 0, properties));
+            requests.add(new CreateNodeRequest(new Location(parent), child, properties));
         }
 
         public void create( final Path path,
@@ -449,10 +449,10 @@
             Name child = path.getLastSegment().getName();
             Location location = new Location(parent);
             if (firstProperty == null) {
-                requests.add(new CreateNodeRequest(location, child, 0));
+                requests.add(new CreateNodeRequest(location, child));
             } else {
                 if (additionalProperties == null || additionalProperties.length == 0) {
-                    requests.add(new CreateNodeRequest(location, child, 0, firstProperty));
+                    requests.add(new CreateNodeRequest(location, child, firstProperty));
                 } else {
                     Iterator<Property> iter = new Iterator<Property>() {
                         private int index = -1;
@@ -473,7 +473,7 @@
                             throw new UnsupportedOperationException();
                         }
                     };
-                    requests.add(new CreateNodeRequest(location, child, 0, iter));
+                    requests.add(new CreateNodeRequest(location, child, iter));
                 }
             }
         }

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -651,14 +651,14 @@
             // This is not the root node, so we need to create the node ...
             final Location parentLocation = new Location(path.getParent());
             childName = path.getLastSegment().getName();
-            requests.add(new CreateNodeRequest(parentLocation, childName, 0, NodeConflictBehavior.REPLACE,
+            requests.add(new CreateNodeRequest(parentLocation, childName, NodeConflictBehavior.REPLACE,
                                                mergedNode.getProperties()));
         }
 
         // Now create all of the children that this federated node knows of ...
         for (Location child : mergedNode.getChildren()) {
             childName = child.getPath().getLastSegment().getName();
-            requests.add(new CreateNodeRequest(location, childName, 0, NodeConflictBehavior.APPEND));
+            requests.add(new CreateNodeRequest(location, childName, NodeConflictBehavior.APPEND));
         }
         cacheConnection.execute(context, CompositeRequest.with(requests));
     }

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -189,9 +189,7 @@
     public void process( CreateNodeRequest request ) {
         Location locationInSource = projectIntoSource(request.under());
         Name child = request.named();
-        Integer desiredIndex = request.desiredIndex();
-        int index = desiredIndex != null ? desiredIndex.intValue() : 0;
-        CreateNodeRequest projected = new CreateNodeRequest(locationInSource, child, index, request.properties());
+        CreateNodeRequest projected = new CreateNodeRequest(locationInSource, child, request.properties());
         getConnection().execute(this.getExecutionContext(), projected);
         if (projected.hasError()) {
             projectError(projected, request.under(), request);

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnection.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnection.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnection.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -46,13 +46,15 @@
     private final Model model;
     private final UUID rootNodeUuid;
     private final long largeValueMinimumSizeInBytes;
+    private final boolean compressData;
 
     /*package*/JpaConnection( String sourceName,
                                CachePolicy cachePolicy,
                                EntityManager entityManager,
                                Model model,
                                UUID rootNodeUuid,
-                               long largeValueMinimumSizeInBytes ) {
+                               long largeValueMinimumSizeInBytes,
+                               boolean compressData ) {
         assert sourceName != null;
         assert entityManager != null;
         assert model != null;
@@ -63,6 +65,7 @@
         this.model = model;
         this.rootNodeUuid = rootNodeUuid;
         this.largeValueMinimumSizeInBytes = largeValueMinimumSizeInBytes;
+        this.compressData = compressData;
     }
 
     /**
@@ -122,7 +125,7 @@
     public void execute( ExecutionContext context,
                          Request request ) throws RepositorySourceException {
         long size = largeValueMinimumSizeInBytes;
-        RequestProcessor proc = model.createRequestProcessor(name, context, entityManager, rootNodeUuid, size);
+        RequestProcessor proc = model.createRequestProcessor(name, context, entityManager, rootNodeUuid, size, compressData);
         try {
             proc.process(request);
         } finally {

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -39,6 +39,8 @@
     public static I18n errorSettingContextClassLoader;
     public static I18n existingStoreSpecifiesUnknownModel;
     public static I18n unableToReadLargeValue;
+    public static I18n unableToMoveRootNode;
+    public static I18n locationShouldHavePathAndOrProperty;
 
     public static I18n basicModelDescription;
 

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -112,6 +112,7 @@
     protected static final String RETRY_LIMIT = "retryLimit";
     protected static final String MODEL_NAME = "modelName";
     protected static final String LARGE_VALUE_SIZE_IN_BYTES = "largeValueSizeInBytes";
+    protected static final String COMPRESS_DATA = "compressData";
 
     /**
      * This source supports events.
@@ -142,6 +143,7 @@
     private static final int DEFAULT_NUMBER_OF_CONNECTIONS_TO_ACQUIRE_AS_NEEDED = 1;
     private static final int DEFAULT_IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS = 60 * 3; // 3 minutes
     private static final int DEFAULT_LARGE_VALUE_SIZE_IN_BYTES = 2 ^ 10; // 1 kilobyte
+    private static final boolean DEFAULT_COMPRESS_DATA = true;
 
     /**
      * The first serialized version of this source.
@@ -166,6 +168,7 @@
     private int retryLimit = DEFAULT_RETRY_LIMIT;
     private int cacheTimeToLiveInMilliseconds = DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS * 1000;
     private long largeValueSizeInBytes = DEFAULT_LARGE_VALUE_SIZE_IN_BYTES;
+    private boolean compressData = DEFAULT_COMPRESS_DATA;
     private final Capabilities capabilities = new Capabilities();
     private transient Model model;
     private String modelName;
@@ -554,6 +557,20 @@
     }
 
     /**
+     * @return compressData
+     */
+    public boolean isCompressData() {
+        return compressData;
+    }
+
+    /**
+     * @param compressData Sets compressData to the specified value.
+     */
+    public void setCompressData( boolean compressData ) {
+        this.compressData = compressData;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see org.jboss.dna.graph.connectors.RepositorySource#initialize(org.jboss.dna.graph.connectors.RepositoryContext)
@@ -610,6 +627,7 @@
                                   Integer.toString(getIdleTimeInSecondsBeforeTestingConnections())));
         ref.add(new StringRefAddr(CACHE_TIME_TO_LIVE_IN_MILLISECONDS, Integer.toString(getCacheTimeToLiveInMilliseconds())));
         ref.add(new StringRefAddr(LARGE_VALUE_SIZE_IN_BYTES, Long.toString(getLargeValueSizeInBytes())));
+        ref.add(new StringRefAddr(COMPRESS_DATA, Boolean.toString(isCompressData())));
         if (getModel() != null) {
             ref.add(new StringRefAddr(MODEL_NAME, getModel()));
         }
@@ -655,6 +673,7 @@
             String modelName = values.get(MODEL_NAME);
             String retryLimit = values.get(RETRY_LIMIT);
             String largeModelSize = values.get(LARGE_VALUE_SIZE_IN_BYTES);
+            String compressData = values.get(COMPRESS_DATA);
 
             // Create the source instance ...
             JpaSource source = new JpaSource();
@@ -677,6 +696,7 @@
             if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
             if (modelName != null) source.setModel(modelName);
             if (largeModelSize != null) source.setLargeValueSizeInBytes(Long.parseLong(largeModelSize));
+            if (compressData != null) source.setCompressData(Boolean.parseBoolean(compressData));
             return source;
         }
         return null;
@@ -781,7 +801,7 @@
         if (entityManager == null) {
             entityManager = entityManagerFactory.createEntityManager();
         }
-        return new JpaConnection(getName(), cachePolicy, entityManager, model, rootUuid, largeValueSizeInBytes);
+        return new JpaConnection(getName(), cachePolicy, entityManager, model, rootUuid, largeValueSizeInBytes, compressData);
     }
 
     /**

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/Model.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/Model.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/Model.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -78,7 +78,8 @@
                                                              ExecutionContext context,
                                                              EntityManager entityManager,
                                                              UUID rootNodeUuid,
-                                                             long largeValueMinimumSizeInBytes );
+                                                             long largeValueMinimumSizeInBytes,
+                                                             boolean comparessData );
 
     /**
      * Configure the entity class that will be used by JPA to store information in the database.

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModel.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModel.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModel.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -47,15 +47,17 @@
      * {@inheritDoc}
      * 
      * @see org.jboss.dna.connector.store.jpa.Model#createRequestProcessor(java.lang.String, org.jboss.dna.graph.ExecutionContext,
-     *      javax.persistence.EntityManager, java.util.UUID, long)
+     *      javax.persistence.EntityManager, java.util.UUID, long, boolean)
      */
     @Override
     public RequestProcessor createRequestProcessor( String sourceName,
                                                     ExecutionContext context,
                                                     EntityManager entityManager,
                                                     UUID rootNodeUuid,
-                                                    long largeValueMinimumSizeInBytes ) {
-        return new BasicRequestProcessor(sourceName, context, entityManager, rootNodeUuid, largeValueMinimumSizeInBytes);
+                                                    long largeValueMinimumSizeInBytes,
+                                                    boolean compressData ) {
+        return new BasicRequestProcessor(sourceName, context, entityManager, rootNodeUuid, largeValueMinimumSizeInBytes,
+                                         compressData);
     }
 
     /**

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicRequestProcessor.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicRequestProcessor.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -22,22 +22,35 @@
 package org.jboss.dna.connector.store.jpa.models.basic;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
 import javax.persistence.EntityManager;
 import javax.persistence.EntityTransaction;
 import javax.persistence.NoResultException;
 import javax.persistence.Query;
+import net.jcip.annotations.Immutable;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.IoUtil;
 import org.jboss.dna.common.util.StringUtil;
 import org.jboss.dna.connector.store.jpa.JpaConnectorI18n;
 import org.jboss.dna.connector.store.jpa.models.common.NamespaceEntity;
+import org.jboss.dna.connector.store.jpa.models.common.NodeId;
 import org.jboss.dna.connector.store.jpa.util.Serializer;
 import org.jboss.dna.connector.store.jpa.util.Serializer.LargeValues;
 import org.jboss.dna.graph.DnaLexicon;
@@ -56,15 +69,18 @@
 import org.jboss.dna.graph.requests.CopyBranchRequest;
 import org.jboss.dna.graph.requests.CreateNodeRequest;
 import org.jboss.dna.graph.requests.DeleteBranchRequest;
+import org.jboss.dna.graph.requests.InvalidRequestException;
 import org.jboss.dna.graph.requests.MoveBranchRequest;
 import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
 import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
+import org.jboss.dna.graph.requests.ReadPropertyRequest;
 import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
 import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * @author Randall Hauch
  */
+ at NotThreadSafe
 public class BasicRequestProcessor extends RequestProcessor implements LargeValues {
 
     private final EntityManager entities;
@@ -75,6 +91,7 @@
     private final UUID rootNodeUuid;
     private final Serializer serializer;
     private final long largeValueMinimumSizeInBytes;
+    private final boolean compressData;
 
     /**
      * @param sourceName
@@ -82,12 +99,14 @@
      * @param entityManager
      * @param rootNodeUuid
      * @param largeValueMinimumSizeInBytes
+     * @param compressData
      */
     public BasicRequestProcessor( String sourceName,
                                   ExecutionContext context,
                                   EntityManager entityManager,
                                   UUID rootNodeUuid,
-                                  long largeValueMinimumSizeInBytes ) {
+                                  long largeValueMinimumSizeInBytes,
+                                  boolean compressData ) {
         super(sourceName, context);
         assert entityManager != null;
         assert rootNodeUuid != null;
@@ -97,8 +116,9 @@
         this.nameFactory = context.getValueFactories().getNameFactory();
         this.namespaces = new Namespaces(entityManager);
         this.rootNodeUuid = rootNodeUuid;
-        this.serializer = new Serializer(context, this);
+        this.serializer = new Serializer(context, this, true);
         this.largeValueMinimumSizeInBytes = largeValueMinimumSizeInBytes;
+        this.compressData = compressData;
         // Start the transaction ...
         this.entities.getTransaction().begin();
     }
@@ -106,57 +126,91 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CopyBranchRequest)
-     */
-    @Override
-    public void process( CopyBranchRequest request ) {
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
      * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CreateNodeRequest)
      */
     @Override
     public void process( CreateNodeRequest request ) {
-        // Location actualLocation = null;
-        // try {
-        // // Create nodes have to be defined via a path ...
-        // Location desiredLocation = request.at();
-        // Path desiredPath = desiredLocation.getPath();
-        // assert desiredPath != null;
-        //
-        // // // Get the parent
-        // // String parentUuidString = getUuidOf(parentLocation);
-        // // Location parentActualLocation = getActualLocation(parentLocation, parentUuidString);
-        // // Path parentPath = parentActualLocation.getPath();
-        // //
-        // // // Now see where the child is to be created ...
-        // // request.
-        //
-        // } catch (Throwable e) { // Includes PathNotFoundException
-        // request.setError(e);
-        // return;
-        // }
-        // if (actualLocation != null) request.setActualLocationOfNode(actualLocation);
-    }
+        Location actualLocation = null;
+        String childUuidString = null;
+        try {
+            // Create nodes have to be defined via a path ...
+            Location parentLocation = request.under();
+            ActualLocation actual = getActualLocation(parentLocation);
+            String parentUuidString = actual.uuid;
+            assert parentUuidString != null;
 
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.DeleteBranchRequest)
-     */
-    @Override
-    public void process( DeleteBranchRequest request ) {
-    }
+            // We need to look for an existing UUID property in the request,
+            // so since we have to iterate through the properties, go ahead an serialize them right away ...
+            Set<String> largeValueHexHashes = new HashSet<String>();
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            OutputStream os = compressData ? new ZipOutputStream(baos) : baos;
+            ObjectOutputStream oos = new ObjectOutputStream(os);
+            int numProperties = 0;
+            try {
+                for (Property property : request.properties()) {
+                    if (property.getName().equals(DnaLexicon.UUID)) {
+                        childUuidString = stringFactory.create(property.getFirstValue());
+                    }
+                    if (serializer.serializeProperty(oos, property, largeValueHexHashes)) ++numProperties;
+                }
+            } finally {
+                oos.close();
+            }
+            String largeValueHexHashesString = createHexValuesString(largeValueHexHashes);
+            if (childUuidString == null) childUuidString = stringFactory.create(UUID.randomUUID());
 
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.MoveBranchRequest)
-     */
-    @Override
-    public void process( MoveBranchRequest request ) {
+            // Create the PropertiesEntity ...
+            NodeId nodeId = new NodeId(childUuidString);
+            PropertiesEntity props = new PropertiesEntity(nodeId);
+            props.setData(baos.toByteArray());
+            props.setCompressed(compressData);
+            props.setPropertyCount(numProperties);
+            props.setLargeValueKeys(largeValueHexHashesString);
+            entities.persist(props);
+
+            // Find or create the namespace for the child ...
+            Name childName = request.named();
+            String childNsUri = childName.getNamespaceUri();
+            Integer nsId = namespaces.getId(childNsUri, true);
+            assert nsId != null;
+
+            // Find the largest SNS index in the existing ChildEntity objects with the same name ...
+            String childLocalName = childName.getLocalName();
+            Query query = entities.createNamedQuery("ChildEntity.findMaximumSnsIndex");
+            query.setParameter("uuid", parentUuidString);
+            query.setParameter("ns", nsId);
+            query.setParameter("childName", childLocalName);
+            int nextSnsIndex = 1;
+            try {
+                nextSnsIndex = (Integer)query.getSingleResult();
+            } catch (NoResultException e) {
+            }
+
+            // Find the largest child index in the existing ChildEntity objects ...
+            query = entities.createNamedQuery("ChildEntity.findMaximumChildIndex");
+            query.setParameter("uuid", parentUuidString);
+            int nextIndexInParent = 1;
+            try {
+                nextIndexInParent = (Integer)query.getSingleResult() + 1;
+            } catch (NoResultException e) {
+            }
+
+            // Create the new ChildEntity ...
+            NamespaceEntity ns = entities.find(NamespaceEntity.class, nsId);
+            assert ns != null;
+            ChildId id = new ChildId(parentUuidString, childUuidString);
+            ChildEntity entity = new ChildEntity(id, nextIndexInParent, ns, childLocalName, nextSnsIndex + 1);
+            entities.persist(entity);
+
+        } catch (Throwable e) { // Includes PathNotFoundException
+            request.setError(e);
+            return;
+        }
+        // Look up the actual path, regardless of the supplied path...
+        assert childUuidString != null;
+        Path path = getPathForUuid(childUuidString);
+        actualLocation = new Location(path, UUID.fromString(childUuidString));
+        request.setActualLocationOfNode(actualLocation);
     }
 
     /**
@@ -170,8 +224,9 @@
         Location actualLocation = null;
         try {
             Location location = request.of();
-            String parentUuidString = getUuidOf(location);
-            actualLocation = getActualLocation(location, parentUuidString);
+            ActualLocation actual = getActualLocation(location);
+            String parentUuidString = actual.uuid;
+            actualLocation = actual.location;
             Path path = actualLocation.getPath();
 
             // Find the children of the supplied node ...
@@ -208,23 +263,33 @@
         Location actualLocation = null;
         try {
             Location location = request.at();
-            String uuidString = getUuidOf(location);
-            actualLocation = getActualLocation(location, uuidString);
+            ActualLocation actual = getActualLocation(location);
+            String uuidString = actual.uuid;
+            actualLocation = actual.location;
 
+            // Record the UUID as a property, since it's not stored in the serialized properties...
+            request.addProperty(actualLocation.getIdProperty(DnaLexicon.UUID));
+
             // Find the properties entity for this node ...
             Query query = entities.createNamedQuery("PropertiesEntity.findByUuid");
             query.setParameter("uuid", uuidString);
             PropertiesEntity entity = (PropertiesEntity)query.getSingleResult();
 
             // Deserialize the properties ...
+            boolean compressed = entity.isCompressed();
             int propertyCount = entity.getPropertyCount();
             Collection<Property> properties = new ArrayList<Property>(propertyCount);
             byte[] data = entity.getData();
             ByteArrayInputStream bais = new ByteArrayInputStream(data);
-            ObjectInputStream ois = new ObjectInputStream(bais);
-            serializer.deserializeProperties(ois, properties);
-            for (Property property : properties) {
-                request.addProperty(property);
+            InputStream is = compressed ? new ZipInputStream(bais) : bais;
+            ObjectInputStream ois = new ObjectInputStream(is);
+            try {
+                serializer.deserializeAllProperties(ois, properties);
+                for (Property property : properties) {
+                    request.addProperty(property);
+                }
+            } finally {
+                ois.close();
             }
         } catch (NoResultException e) {
             // there are no properties (probably not expected, but still okay) ...
@@ -238,15 +303,234 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadPropertyRequest)
+     */
+    @Override
+    public void process( ReadPropertyRequest request ) {
+        // Small optimization ...
+        final Name propertyName = request.named();
+        if (DnaLexicon.UUID.equals(propertyName)) {
+            try {
+                // Just get the UUID ...
+                Location location = request.on();
+                ActualLocation actualLocation = getActualLocation(location);
+                request.setActualLocationOfNode(actualLocation.location);
+            } catch (Throwable e) { // Includes PathNotFoundException
+                request.setError(e);
+            }
+            return;
+        }
+        // Process the one property that's requested ...
+        Location actualLocation = null;
+        try {
+            Location location = request.on();
+            ActualLocation actual = getActualLocation(location);
+            String uuidString = actual.uuid;
+            actualLocation = actual.location;
+
+            // Find the properties entity for this node ...
+            Query query = entities.createNamedQuery("PropertiesEntity.findByUuid");
+            query.setParameter("uuid", uuidString);
+            PropertiesEntity entity = (PropertiesEntity)query.getSingleResult();
+
+            // Deserialize the stream of properties, but only materialize the one property ...
+            boolean compressed = entity.isCompressed();
+            int propertyCount = entity.getPropertyCount();
+            Collection<Property> properties = new ArrayList<Property>(propertyCount);
+            byte[] data = entity.getData();
+            ByteArrayInputStream bais = new ByteArrayInputStream(data);
+            InputStream is = compressed ? new ZipInputStream(bais) : bais;
+            ObjectInputStream ois = new ObjectInputStream(is);
+            try {
+                serializer.deserializeSomeProperties(ois, properties, propertyName);
+                for (Property property : properties) {
+                    request.setProperty(property); // should be only one property
+                }
+            } finally {
+                ois.close();
+            }
+        } catch (NoResultException e) {
+            // there are no properties (probably not expected, but still okay) ...
+        } catch (Throwable e) { // Includes PathNotFoundException
+            request.setError(e);
+            return;
+        }
+        if (actualLocation != null) request.setActualLocationOfNode(actualLocation);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.UpdatePropertiesRequest)
      */
     @Override
     public void process( UpdatePropertiesRequest request ) {
+        Location actualLocation = null;
+        try {
+            Location location = request.on();
+            ActualLocation actual = getActualLocation(location);
+            actualLocation = actual.location;
+
+            // Find the properties entity for this node ...
+            Query query = entities.createNamedQuery("PropertiesEntity.findByUuid");
+            query.setParameter("uuid", actual.uuid);
+            PropertiesEntity entity = (PropertiesEntity)query.getSingleResult();
+
+            // Determine which large values are referenced ...
+            String largeValueHexKeys = entity.getLargeValueKeys();
+            Collection<String> hexKeys = null;
+            if (largeValueHexKeys != null) {
+                hexKeys = createHexValues(largeValueHexKeys);
+            }
+
+            // Now serialize the properties and save them ...
+            Collection<String> newHexKeys = new HashSet<String>();
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            OutputStream os = compressData ? new ZipOutputStream(baos) : baos;
+            ObjectOutputStream oos = new ObjectOutputStream(os);
+            int numProperties = 0;
+            try {
+                for (Property property : request.properties()) {
+                    if (serializer.serializeProperty(oos, property, newHexKeys)) ++numProperties;
+                }
+            } finally {
+                oos.close();
+            }
+            largeValueHexKeys = createHexValuesString(newHexKeys);
+            entity.setPropertyCount(numProperties);
+            entity.setData(baos.toByteArray());
+            entity.setCompressed(compressData);
+            entity.setLargeValueKeys(largeValueHexKeys);
+
+            // Update the large values that used to be reference but no longer are ...
+            if (hexKeys != null) {
+                hexKeys.removeAll(newHexKeys);
+                for (String oldHexKey : hexKeys) {
+                    LargeValueEntity largeValue = entities.find(LargeValueEntity.class, oldHexKey);
+                    if (largeValue != null) {
+                        if (largeValue.decrementUsageCount() == 0) {
+                            entities.remove(entity);
+                        }
+                    }
+                }
+            }
+
+        } catch (NoResultException e) {
+            // there are no properties (probably not expected, but still okay) ...
+        } catch (Throwable e) { // Includes PathNotFoundException
+            request.setError(e);
+            return;
+        }
+        if (actualLocation != null) request.setActualLocationOfNode(actualLocation);
     }
 
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CopyBranchRequest)
+     */
+    @Override
+    public void process( CopyBranchRequest request ) {
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.DeleteBranchRequest)
+     */
+    @Override
+    public void process( DeleteBranchRequest request ) {
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.MoveBranchRequest)
+     */
+    @Override
+    public void process( MoveBranchRequest request ) {
+        Location actualOldLocation = null;
+        Location actualNewLocation = null;
+        try {
+            Location fromLocation = request.from();
+            ActualLocation actualLocation = getActualLocation(fromLocation);
+            String fromUuidString = actualLocation.uuid;
+            actualOldLocation = actualLocation.location;
+
+            // It's not possible to move the root node
+            if (actualOldLocation.getPath().isRoot()) {
+                String msg = JpaConnectorI18n.unableToMoveRootNode.text(getSourceName());
+                throw new InvalidRequestException(msg);
+            }
+
+            // Find the ChildEntity of the existing 'from' node ...
+            ChildEntity fromEntity = actualLocation.childEntity;
+            final String oldParentUuid = fromEntity.getId().getParentUuidString();
+
+            // Find the actual new location ...
+            Location toLocation = request.into();
+            String toUuidString = null;
+            if (request.hasNoEffect()) {
+                actualNewLocation = actualOldLocation;
+            } else {
+                // We have to proceed as normal ...
+                ActualLocation actualIntoLocation = getActualLocation(toLocation);
+                toUuidString = actualIntoLocation.uuid;
+                if (!toUuidString.equals(oldParentUuid)) {
+                    // Now we know that the new parent is not the existing parent ...
+                    final int oldSnsIndex = fromEntity.getSameNameSiblingIndex();
+                    final int oldIndex = fromEntity.getIndexInParent();
+
+                    // Find the largest SNS index in the existing ChildEntity objects with the same name ...
+                    String childLocalName = fromEntity.getChildName();
+                    NamespaceEntity ns = fromEntity.getChildNamespace();
+                    Query query = entities.createNamedQuery("ChildEntity.findMaximumSnsIndex");
+                    query.setParameter("uuid", toUuidString);
+                    query.setParameter("ns", ns.getId());
+                    query.setParameter("childName", childLocalName);
+                    int nextSnsIndex = 1;
+                    try {
+                        nextSnsIndex = (Integer)query.getSingleResult();
+                    } catch (NoResultException e) {
+                    }
+
+                    // Find the largest child index in the existing ChildEntity objects ...
+                    query = entities.createNamedQuery("ChildEntity.findMaximumChildIndex");
+                    query.setParameter("uuid", toUuidString);
+                    int nextIndexInParent = 1;
+                    try {
+                        nextIndexInParent = (Integer)query.getSingleResult() + 1;
+                    } catch (NoResultException e) {
+                    }
+
+                    // Move the child entity to be under the new parent ...
+                    fromEntity.setId(new ChildId(toUuidString, fromUuidString));
+                    fromEntity.setIndexInParent(nextIndexInParent);
+                    fromEntity.setSameNameSiblingIndex(nextSnsIndex);
+
+                    // And adjust the SNS index and indexes ...
+                    adjustSnsIndexesAndIndexesAfterRemoving(oldParentUuid, childLocalName, ns.getId(), oldIndex, oldSnsIndex);
+                }
+            }
+
+        } catch (Throwable e) { // Includes PathNotFoundException
+            request.setError(e);
+            return;
+        }
+        request.setActualLocations(actualOldLocation, actualNewLocation);
+    }
+
+    protected void adjustSnsIndexesAndIndexesAfterRemoving( String uuidParent,
+                                                            String childName,
+                                                            int childNamespaceIndex,
+                                                            int childIndex,
+                                                            int childSnsIndex ) {
+
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see org.jboss.dna.graph.requests.processor.RequestProcessor#close()
      */
     @Override
@@ -256,58 +540,100 @@
         super.close();
     }
 
-    protected Location getActualLocation( Location original,
-                                          String uuidString ) {
-        // If the original has a path and a UUID, it is complete already ...
+    /**
+     * Utility method to look up the actual information given a supplied location. This method verifies that the location actually
+     * represents an existing node, or it throws a {@link PathNotFoundException}. In all cases, the resulting information contains
+     * the correct path and the correct UUID.
+     * <p>
+     * Note that this method sometimes performs "unnecessary" work when the location contains both a path to a node and the node's
+     * corresponding UUID. Strictly speaking, this method would need to do very little. However, in such cases, this method does
+     * verify that the information is still correct (ensuring that calls to use the {@link ChildEntity} will be correct). So,
+     * while this work <i>may</i> be unnecessary, it does ensure that the location is consistent and correct (something that is
+     * not unnecessary).
+     * </p>
+     * <p>
+     * There are cases when a request containing a Path and a UUID are no longer correct. The node may have been just moved by
+     * another request (perhaps from a different client), or there may be an error in the component making the request. In these
+     * cases, this method assumes that the path is incorrect (since paths may change) and finds the <i>correct path</i> given the
+     * UUID.
+     * </p>
+     * <p>
+     * This method will also find the path when the location contains just the UUID.
+     * </p>
+     * 
+     * @param original the original location; may not be null
+     * @return the actual location, which includes the verified location and additional information needed by this method that may
+     *         be usable after this method is called
+     * @throws PathNotFoundException if the location does not represent a location that could be found
+     */
+    protected ActualLocation getActualLocation( Location original ) throws PathNotFoundException {
+        assert original != null;
+
+        // Look for the UUID in the original ...
+        Property uuidProperty = original.getIdProperty(DnaLexicon.UUID);
+        String uuidString = uuidProperty.isEmpty() ? null : stringFactory.create(uuidProperty.getFirstValue());
+
+        // If the original location has a UUID, then use that to find the child entity that represents the location ...
+        if (uuidString != null) {
+            // The original has a UUID, so use that to find the child entity.
+            // Then walk up the ancestors and build the path.
+            LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
+            ChildEntity entity = null;
+            ChildEntity childEntity = null;
+            do {
+                String childUuid = uuidString;
+                Query query = entities.createNamedQuery("ChildEntity.findByChildUuid");
+                query.setParameter("childUuidString", childUuid);
+                try {
+                    // Find the parent of the UUID ...
+                    entity = (ChildEntity)query.getSingleResult();
+                    if (childEntity == null) childEntity = entity;
+                    String localName = entity.getChildName();
+                    String uri = entity.getChildNamespace().getUri();
+                    Integer sns = entity.getSameNameSiblingIndex();
+                    Name name = nameFactory.create(uri, localName);
+                    if (sns != null) {
+                        segments.addFirst(pathFactory.createSegment(name, sns));
+                    } else {
+                        segments.addFirst(pathFactory.createSegment(name));
+                    }
+                } catch (NoResultException e) {
+                    entity = null;
+                }
+            } while (entity != null);
+            Path fullPath = pathFactory.createAbsolutePath(segments);
+            return new ActualLocation(new Location(fullPath, uuidProperty), uuidString, childEntity);
+        }
+
+        // There is no UUID, so look for a path ...
         Path path = original.getPath();
-        if (path != null) {
-            if (original.getIdProperty(DnaLexicon.UUID) != null) return original;
-            return original.with(UUID.fromString(uuidString));
+        if (path == null) {
+            String propName = DnaLexicon.UUID.getString(getExecutionContext().getNamespaceRegistry());
+            String msg = JpaConnectorI18n.locationShouldHavePathAndOrProperty.text(getSourceName(), propName);
+            throw new PathNotFoundException(original, pathFactory.createRootPath(), msg);
         }
-        // There is no path, so find it by UUID ...
-        path = getPathForUuid(uuidString);
-        return new Location(path, UUID.fromString(uuidString));
-    }
 
-    protected String getUuidOf( Location location ) throws PathNotFoundException {
-        String uuidString = null;
-        if (location.hasIdProperties()) {
-            // Look for the UUID ...
-            Property uuidProperty = location.getIdProperty(DnaLexicon.UUID);
-            if (uuidProperty != null && !uuidProperty.isEmpty()) {
-                uuidString = stringFactory.create(uuidProperty.iterator().next());
-            }
+        // Walk the child entities, starting at the root, down the to the path ...
+        if (path.isRoot()) {
+            return new ActualLocation(original.with(rootNodeUuid), rootNodeUuid.toString(), null);
         }
-        if (uuidString == null) {
-            // Look up the node by using the path to walk down the children, starting at the root ...
-            Path path = location.getPath();
-            if (path == null) {
-                // Location does not have path or DnaLexicon.UUID id property
-            }
-            assert path != null;
-            if (path.isRoot()) {
-                uuidString = rootNodeUuid.toString();
-            } else {
-                String parentUuid = this.rootNodeUuid.toString();
-                ChildEntity child = null;
-                for (Path.Segment segment : path) {
-                    child = findByPathSegment(parentUuid, segment);
-                    if (child == null) {
-                        // Determine the lowest path that exists ...
-                        Path lowest = path;
-                        while (lowest.getLastSegment() != segment) {
-                            lowest = lowest.getParent();
-                        }
-                        lowest = lowest.getParent();
-                        throw new PathNotFoundException(location, lowest);
-                    }
+        String parentUuid = this.rootNodeUuid.toString();
+        ChildEntity child = null;
+        for (Path.Segment segment : path) {
+            child = findByPathSegment(parentUuid, segment);
+            if (child == null) {
+                // Unable to complete the path, so prepare the exception by determining the lowest path that exists ...
+                Path lowest = path;
+                while (lowest.getLastSegment() != segment) {
+                    lowest = lowest.getParent();
                 }
-                assert child != null;
-                uuidString = child.getId().getChildUuidString();
+                lowest = lowest.getParent();
+                throw new PathNotFoundException(original, lowest);
             }
         }
-        assert uuidString != null;
-        return uuidString;
+        assert child != null;
+        uuidString = child.getId().getChildUuidString();
+        return new ActualLocation(original.with(UUID.fromString(uuidString)), uuidString, child);
     }
 
     /**
@@ -351,7 +677,7 @@
      * Build up the path for the node with the supplied UUID.
      * 
      * @param uuidString the UUID of the node
-     * @return the path to the node
+     * @return the path to the node; never null
      */
     protected Path getPathForUuid( String uuidString ) {
         ChildEntity entity = null;
@@ -359,7 +685,7 @@
         LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
         do {
             // Find the parent of the UUID ...
-            Query query = entities.createNamedQuery("ChildEntity.findParentByUuid");
+            Query query = entities.createNamedQuery("ChildEntity.findByChildUuid");
             query.setParameter("childUuidString", childUuid);
             try {
                 entity = (ChildEntity)query.getSingleResult();
@@ -379,6 +705,25 @@
         return pathFactory.createAbsolutePath(segments);
     }
 
+    protected String createHexValuesString( Collection<String> hexValues ) {
+        if (hexValues == null || hexValues.isEmpty()) return null;
+        StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        for (String hexValue : hexValues) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(',');
+            }
+            sb.append(hexValue);
+        }
+        return sb.toString();
+    }
+
+    protected Collection<String> createHexValues( String hexValuesString ) {
+        return Arrays.asList(hexValuesString.split(","));
+    }
+
     /**
      * {@inheritDoc}
      * 
@@ -426,21 +771,38 @@
             entity.setLength(length);
             entity.setType(type);
             ValueFactories factories = getExecutionContext().getValueFactories();
+            byte[] bytes = null;
             switch (type) {
                 case BINARY:
                     Binary binary = factories.getBinaryFactory().create(value);
+                    InputStream stream = null;
                     try {
                         binary.acquire();
-                        entity.setData(binary.getBytes());
+                        stream = binary.getStream();
+                        if (compressData) stream = new ZipInputStream(stream);
+                        bytes = IoUtil.readBytes(stream);
                     } finally {
-                        binary.release();
+                        try {
+                            if (stream != null) stream.close();
+                        } finally {
+                            binary.release();
+                        }
                     }
                     break;
                 default:
                     String str = factories.getStringFactory().create(value);
-                    entity.setData(str.getBytes());
+                    bytes = str.getBytes();
+                    if (compressData) {
+                        InputStream strStream = new ZipInputStream(new ByteArrayInputStream(bytes));
+                        try {
+                            bytes = IoUtil.readBytes(strStream);
+                        } finally {
+                            strStream.close();
+                        }
+                    }
                     break;
             }
+            entity.setData(bytes);
             entities.persist(entity);
         } else {
             // There is already an existing value, so we'll reuse it and increment the usage count ...
@@ -448,6 +810,26 @@
         }
     }
 
+    @Immutable
+    protected static class ActualLocation {
+        /** The actual location */
+        protected final Location location;
+        /** The string-form of the UUID, supplied as a convenience. */
+        protected final String uuid;
+        /** The ChildEntity that represents the location, which may be null if the location represents the root node */
+        protected final ChildEntity childEntity;
+
+        protected ActualLocation( Location location,
+                                  String uuid,
+                                  ChildEntity childEntity ) {
+            assert location != null;
+            assert uuid != null;
+            this.location = location;
+            this.uuid = uuid;
+            this.childEntity = childEntity;
+        }
+    }
+
     protected static class Namespaces {
 
         private final EntityManager entityManager;

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/ChildEntity.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/ChildEntity.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/ChildEntity.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -46,7 +46,10 @@
 @Table( appliesTo = "DNA_BASIC_CHILDREN", indexes = @Index( name = "CHILDINDEX_INX", columnNames = {"PARENT_UUID", "CHILD_INDEX"} ) )
 @NamedQueries( {
     @NamedQuery( name = "ChildEntity.findByPathSegment", query = "select child from ChildEntity as child where child.id.parentUuidString = :parentUuid AND child.childNamespace.id = :ns AND child.childName = :childName AND child.sameNameSiblingIndex = :sns" ),
-    @NamedQuery( name = "ChildEntity.findAllUnderParent", query = "select child from ChildEntity as child where child.id.parentUuidString = :parentUuid" )} )
+    @NamedQuery( name = "ChildEntity.findAllUnderParent", query = "select child from ChildEntity as child where child.id.parentUuidString = :parentUuid" ),
+    @NamedQuery( name = "ChildEntity.findByChildUuid", query = "select child from ChildEntity as child where child.id.childUuidString = :childUuidString" ),
+    @NamedQuery( name = "ChildEntity.findMaximumSnsIndex", query = "select max(child.sameNameSiblingIndex) from ChildEntity as child where child.id.parentUuidString = :parentUuid AND child.childNamespace.id = :ns AND child.childName = :childName" ),
+    @NamedQuery( name = "ChildEntity.findMaximumChildIndex", query = "select max(child.indexInParent) from ChildEntity as child where child.id.parentUuidString = :parentUuid" )} )
 public class ChildEntity {
 
     @Id

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/LargeValueEntity.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/LargeValueEntity.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/LargeValueEntity.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -153,6 +153,11 @@
         this.usageCount++;
     }
 
+    public int decrementUsageCount() {
+        if (this.usageCount == 0) return 0;
+        return --this.usageCount;
+    }
+
     /**
      * @return compressed
      */

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/PropertiesEntity.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/PropertiesEntity.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/PropertiesEntity.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -59,6 +59,9 @@
     @Column( name = "COMPRESSED", nullable = true )
     private Boolean compressed;
 
+    @Column( name = "LRG_VL_KEYS", nullable = true )
+    private String largeValueKeys;
+
     public PropertiesEntity() {
     }
 
@@ -131,6 +134,20 @@
     }
 
     /**
+     * @return largeValueKeys
+     */
+    public String getLargeValueKeys() {
+        return largeValueKeys;
+    }
+
+    /**
+     * @param largeValueKeys Sets largeValueKeys to the specified value.
+     */
+    public void setLargeValueKeys( String largeValueKeys ) {
+        this.largeValueKeys = largeValueKeys;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#hashCode()

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/NodeId.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/NodeId.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/NodeId.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -49,6 +49,10 @@
     public NodeId() {
     }
 
+    public NodeId( String uuidString ) {
+        this.uuidString = uuidString;
+    }
+
     public NodeId( UUID uuid ) {
         setUuid(uuid);
     }

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/Serializer.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/Serializer.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/Serializer.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -29,10 +29,14 @@
 import java.net.URI;
 import java.security.NoSuchAlgorithmException;
 import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.UUID;
 import org.jboss.dna.common.SystemFailureException;
 import org.jboss.dna.common.util.SecureHash;
+import org.jboss.dna.common.util.StringUtil;
 import org.jboss.dna.connector.store.jpa.models.basic.LargeValueEntity;
+import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.properties.Binary;
 import org.jboss.dna.graph.properties.DateTime;
@@ -52,12 +56,15 @@
     private final PropertyFactory propertyFactory;
     private final ValueFactories valueFactories;
     private final LargeValues largeValues;
+    private final boolean excludeUuidProperty;
 
     public Serializer( ExecutionContext context,
-                       LargeValues largeValues ) {
+                       LargeValues largeValues,
+                       boolean excludeUuidProperty ) {
         this.propertyFactory = context.getPropertyFactory();
         this.valueFactories = context.getValueFactories();
         this.largeValues = largeValues;
+        this.excludeUuidProperty = excludeUuidProperty;
     }
 
     /**
@@ -102,19 +109,21 @@
      * @param stream the stream where the properties' values are to be serialized; may not be null
      * @param number the number of properties exposed by the supplied <code>properties</code> iterator; must be 0 or positive
      * @param properties the iterator over the properties that are to be serialized; may not be null
+     * @param largeValueHexHashes the collection into which any large value hashes should be recordeed
      * @throws IOException if there is an error writing to the <code>stream</code> or <code>largeValues</code>
-     * @see #deserializeProperties(ObjectInputStream, Collection)
-     * @see #serializeProperty(ObjectOutputStream, Property)
+     * @see #deserializeAllProperties(ObjectInputStream, Collection)
+     * @see #serializeProperty(ObjectOutputStream, Property, Collection)
      */
     public void serializeProperties( ObjectOutputStream stream,
                                      int number,
-                                     Iterable<Property> properties ) throws IOException {
+                                     Iterable<Property> properties,
+                                     Collection<String> largeValueHexHashes ) throws IOException {
         assert number >= 0;
         assert properties != null;
         stream.writeInt(number);
         for (Property property : properties) {
             if (property == null) continue;
-            serializeProperty(stream, property);
+            serializeProperty(stream, property, largeValueHexHashes);
         }
     }
 
@@ -135,16 +144,21 @@
      * 
      * @param stream the stream where the property's values are to be serialized; may not be null
      * @param property the property to be serialized; may not be null
+     * @param largeValueHexHashes the collection into which any large value hashes should be recordeed
+     * @return true if the property was serialized, or false if it was not
      * @throws IOException if there is an error writing to the <code>stream</code> or <code>largeValues</code>
-     * @see #serializeProperties(ObjectOutputStream, int, Iterable)
-     * @see #deserializeProperty(ObjectInputStream)
+     * @see #serializeProperties(ObjectOutputStream, int, Iterable, Collection)
+     * @see #deserializePropertyValues(ObjectInputStream, Name, boolean)
      */
-    public void serializeProperty( ObjectOutputStream stream,
-                                   Property property ) throws IOException {
+    public boolean serializeProperty( ObjectOutputStream stream,
+                                      Property property,
+                                      Collection<String> largeValueHexHashes ) throws IOException {
         assert stream != null;
         assert property != null;
+        final Name name = property.getName();
+        if (this.excludeUuidProperty && DnaLexicon.UUID.equals(name)) return false;
         // Write the name ...
-        stream.writeObject(property.getName().getString());
+        stream.writeObject(name.getString());
         // Write the number of values ...
         stream.writeInt(property.size());
         for (Object value : property) {
@@ -158,6 +172,7 @@
                     stream.write(hash);
                     stream.writeLong(stringValue.length());
                     // Now write to the large objects ...
+                    largeValueHexHashes.add(StringUtil.getHexString(hash));
                     largeValues.write(computeHash(stringValue), stringValue.length(), PropertyType.STRING, stringValue);
                 } else {
                     stream.writeChar('S');
@@ -243,6 +258,7 @@
                 }
                 // If this is a large value and the binary has been released, write it to the large objects ...
                 if (largeValues != null && hash != null) {
+                    largeValueHexHashes.add(StringUtil.getHexString(hash));
                     largeValues.write(hash, length, PropertyType.BINARY, value);
                 }
             } else {
@@ -252,6 +268,7 @@
             }
         }
         stream.flush();
+        return true;
     }
 
     /**
@@ -261,11 +278,11 @@
      * @param properties the collection into which each deserialized property is to be placed; may not be null
      * @throws IOException if there is an error writing to the <code>stream</code> or <code>largeValues</code>
      * @throws ClassNotFoundException if the class for the value's object could not be found
-     * @see #deserializeProperty(ObjectInputStream)
-     * @see #serializeProperties(ObjectOutputStream, int, Iterable)
+     * @see #deserializePropertyValues(ObjectInputStream, Name, boolean)
+     * @see #serializeProperties(ObjectOutputStream, int, Iterable, Collection)
      */
-    public void deserializeProperties( ObjectInputStream stream,
-                                       Collection<Property> properties ) throws IOException, ClassNotFoundException {
+    public void deserializeAllProperties( ObjectInputStream stream,
+                                          Collection<Property> properties ) throws IOException, ClassNotFoundException {
         assert propertyFactory != null;
         assert valueFactories != null;
         assert stream != null;
@@ -281,105 +298,177 @@
     }
 
     /**
+     * Deserialize the serialized properties on the supplied object stream.
+     * 
+     * @param stream the stream that contains the serialized properties; may not be null
+     * @param properties the collection into which each deserialized property is to be placed; may not be null
+     * @param names the names of the properties that should be deserialized; should not be null or empty
+     * @throws IOException if there is an error writing to the <code>stream</code> or <code>largeValues</code>
+     * @throws ClassNotFoundException if the class for the value's object could not be found
+     * @see #deserializePropertyValues(ObjectInputStream, Name, boolean)
+     * @see #serializeProperties(ObjectOutputStream, int, Iterable, Collection)
+     */
+    public void deserializeSomeProperties( ObjectInputStream stream,
+                                           Collection<Property> properties,
+                                           Name... names ) throws IOException, ClassNotFoundException {
+        assert stream != null;
+        assert properties != null;
+        assert names != null;
+        assert names.length > 0;
+        Name nameToRead = null;
+        Set<Name> namesToRead = null;
+        if (names.length == 1) {
+            nameToRead = names[0];
+        } else {
+            namesToRead = new HashSet<Name>();
+            for (Name name : names) {
+                if (name != null) namesToRead.add(name);
+            }
+        }
+
+        // Read the number of properties ...
+        boolean read = false;
+        int count = stream.readInt();
+
+        // Now, read the properties (or skip the ones that we're not supposed to read) ...
+        for (int i = 0; i != count; ++i) {
+            // Read the name ...
+            String nameStr = (String)stream.readObject();
+            Name name = valueFactories.getNameFactory().create(nameStr);
+            assert name != null;
+            read = name.equals(nameToRead) || (namesToRead != null && namesToRead.contains(namesToRead));
+            // Now read the property values ...
+            Object[] values = deserializePropertyValues(stream, name, !read);
+            // Add the property to the collection ...
+            Property property = propertyFactory.create(name, values);
+            assert property != null;
+            properties.add(property);
+        }
+    }
+
+    /**
      * Deserialize the serialized property on the supplied object stream.
      * 
      * @param stream the stream that contains the serialized properties; may not be null
-     * @return the deserialized property; never null
+     * @return the deserialized property values, or an empty list if there are no values
      * @throws IOException if there is an error writing to the <code>stream</code> or <code>largeValues</code>
      * @throws ClassNotFoundException if the class for the value's object could not be found
-     * @see #deserializeProperties(ObjectInputStream, Collection)
-     * @see #serializeProperty(ObjectOutputStream, Property)
+     * @see #deserializeAllProperties(ObjectInputStream, Collection)
+     * @see #serializeProperty(ObjectOutputStream, Property, Collection)
      */
     public Property deserializeProperty( ObjectInputStream stream ) throws IOException, ClassNotFoundException {
-        assert propertyFactory != null;
-        assert valueFactories != null;
-        assert stream != null;
-        assert largeValues != null;
         // Read the name ...
         String nameStr = (String)stream.readObject();
         Name name = valueFactories.getNameFactory().create(nameStr);
         assert name != null;
+        // Now read the property values ...
+        Object[] values = deserializePropertyValues(stream, name, false);
+        // Add the property to the collection ...
+        return propertyFactory.create(name, values);
+    }
+
+    /**
+     * Deserialize the serialized property on the supplied object stream.
+     * 
+     * @param stream the stream that contains the serialized properties; may not be null
+     * @param propertyName the name of the property being deserialized
+     * @param skip true if the values don't need to be read, or false if they are to be read
+     * @return the deserialized property values, or an empty list if there are no values
+     * @throws IOException if there is an error writing to the <code>stream</code> or <code>largeValues</code>
+     * @throws ClassNotFoundException if the class for the value's object could not be found
+     * @see #deserializeAllProperties(ObjectInputStream, Collection)
+     * @see #serializeProperty(ObjectOutputStream, Property, Collection)
+     */
+    public Object[] deserializePropertyValues( ObjectInputStream stream,
+                                               Name propertyName,
+                                               boolean skip ) throws IOException, ClassNotFoundException {
+        assert stream != null;
+        assert propertyName != null;
         // Read the number of values ...
         int size = stream.readInt();
-        Object[] values = new Object[size];
+        Object[] values = skip ? null : new Object[size];
         for (int i = 0; i != size; ++i) {
             Object value = null;
             // Read the type of value ...
             char type = stream.readChar();
             switch (type) {
                 case 'S':
-                    // String
-                    value = valueFactories.getStringFactory().create((String)stream.readObject());
+                    String stringValue = (String)stream.readObject();
+                    if (!skip) value = valueFactories.getStringFactory().create(stringValue);
                     break;
                 case 'b':
-                    // boolean
-                    value = valueFactories.getBooleanFactory().create(stream.readBoolean());
+                    boolean booleanValue = stream.readBoolean();
+                    if (!skip) value = valueFactories.getBooleanFactory().create(booleanValue);
                     break;
                 case 'i':
-                    // integer
-                    value = valueFactories.getLongFactory().create(stream.readInt());
+                    int intValue = stream.readInt();
+                    if (!skip) value = valueFactories.getLongFactory().create(intValue);
                     break;
                 case 'l':
-                    // long
-                    value = valueFactories.getLongFactory().create(stream.readLong());
+                    long longValue = stream.readLong();
+                    if (!skip) value = valueFactories.getLongFactory().create(longValue);
                     break;
                 case 's':
-                    // short
-                    value = valueFactories.getLongFactory().create(stream.readShort());
+                    short shortValue = stream.readShort();
+                    if (!skip) value = valueFactories.getLongFactory().create(shortValue);
                     break;
                 case 'f':
-                    // float
-                    value = valueFactories.getDoubleFactory().create(stream.readFloat());
+                    float floatValue = stream.readFloat();
+                    if (!skip) value = valueFactories.getDoubleFactory().create(floatValue);
                     break;
                 case 'd':
-                    // double
-                    value = valueFactories.getDoubleFactory().create(stream.readDouble());
+                    double doubleValue = stream.readDouble();
+                    if (!skip) value = valueFactories.getDoubleFactory().create(doubleValue);
                     break;
                 case 'c':
-                    // double
-                    value = valueFactories.getStringFactory().create("" + stream.readChar());
+                    // char
+                    String charValue = "" + stream.readChar();
+                    if (!skip) value = valueFactories.getStringFactory().create(charValue);
                     break;
                 case 'U':
                     // UUID
                     long msb = stream.readLong();
                     long lsb = stream.readLong();
-                    UUID uuid = new UUID(msb, lsb);
-                    value = valueFactories.getUuidFactory().create(uuid);
+                    if (!skip) {
+                        UUID uuid = new UUID(msb, lsb);
+                        value = valueFactories.getUuidFactory().create(uuid);
+                    }
                     break;
                 case 'I':
                     // URI
                     String uriStr = (String)stream.readObject();
-                    value = valueFactories.getUriFactory().create(uriStr);
+                    if (!skip) value = valueFactories.getUriFactory().create(uriStr);
                     break;
                 case 'N':
                     // Name
                     String nameValueStr = (String)stream.readObject();
-                    value = valueFactories.getNameFactory().create(nameValueStr);
+                    if (!skip) value = valueFactories.getNameFactory().create(nameValueStr);
                     break;
                 case 'P':
                     // Path
                     String pathStr = (String)stream.readObject();
-                    value = valueFactories.getPathFactory().create(pathStr);
+                    if (!skip) value = valueFactories.getPathFactory().create(pathStr);
                     break;
                 case 'T':
                     // DateTime
                     String dateTimeStr = (String)stream.readObject();
-                    value = valueFactories.getDateFactory().create(dateTimeStr);
+                    if (!skip) value = valueFactories.getDateFactory().create(dateTimeStr);
                     break;
                 case 'D':
                     // BigDecimal
                     Object bigDecimal = stream.readObject();
-                    value = valueFactories.getDecimalFactory().create(bigDecimal);
+                    if (!skip) value = valueFactories.getDecimalFactory().create(bigDecimal);
                     break;
                 case 'R':
                     // Reference
-                    value = valueFactories.getReferenceFactory().create((String)stream.readObject());
+                    String refValue = (String)stream.readObject();
+                    if (!skip) value = valueFactories.getReferenceFactory().create(refValue);
                     break;
                 case 'B':
                     // Binary
                     // Read the length of the content ...
                     long binaryLength = stream.readLong();
-                    value = valueFactories.getBinaryFactory().create(stream, binaryLength);
+                    if (!skip) value = valueFactories.getBinaryFactory().create(stream, binaryLength);
                     break;
                 case 'L':
                     // Large object ...
@@ -389,19 +478,17 @@
                     stream.read(hash);
                     // Read the length of the content ...
                     long length = stream.readLong();
-                    value = largeValues.read(valueFactories, hash, length);
+                    if (!skip) value = largeValues.read(valueFactories, hash, length);
                     break;
                 default:
                     // All other objects ...
                     Object object = stream.readObject();
-                    value = valueFactories.getObjectFactory().create(object);
+                    if (!skip) value = valueFactories.getObjectFactory().create(object);
                     break;
             }
-            assert value != null;
-            values[i] = value;
+            if (value != null) values[i] = value;
         }
-        // Add the property to the collection ...
-        return propertyFactory.create(name, values);
+        return values;
     }
 
     public byte[] computeHash( String value ) {

Modified: trunk/extensions/dna-connector-store-jpa/src/main/resources/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.properties
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/resources/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.properties	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/main/resources/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.properties	2008-11-24 15:13:59 UTC (rev 647)
@@ -29,5 +29,8 @@
 errorSettingContextClassLoader = Error while setting the current context class loader for JAP repository source {0} to classloader name {1}
 existingStoreSpecifiesUnknownModel = The JPA repository source {0} uses a model that is not known: {1} 
 unableToReadLargeValue = Unable to read from {0} the large property with hash = {1}
+unableToMoveRootNode = Unable to move the root node to another location in {0}
+locationShouldHavePathAndOrProperty = The source {0} is unable to find a node without a path or a {1} property
 
+
 basicModelDescription = Database model that stores node properties as opaque records and children as transparent records. Large property values are stored separately.

Modified: trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionTest.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionTest.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionTest.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -47,6 +47,7 @@
     private CachePolicy cachePolicy;
     private UUID rootNodeUuid;
     private long largeValueSize;
+    private boolean compressData;
 
     @Before
     public void beforeEach() throws Exception {
@@ -54,6 +55,7 @@
         model = new BasicModel();
         rootNodeUuid = UUID.randomUUID();
         largeValueSize = 2 ^ 10; // 1 kilobyte
+        compressData = false;
 
         // Connect to the database ...
         Ejb3Configuration configurator = new Ejb3Configuration();
@@ -72,7 +74,7 @@
 
         // Create the connection ...
         cachePolicy = mock(CachePolicy.class);
-        connection = new JpaConnection("source", cachePolicy, manager, model, rootNodeUuid, largeValueSize);
+        connection = new JpaConnection("source", cachePolicy, manager, model, rootNodeUuid, largeValueSize, compressData);
     }
 
     @After

Modified: trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/ModelTest.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/ModelTest.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/ModelTest.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -107,7 +107,8 @@
                                                         ExecutionContext context,
                                                         EntityManager entityManager,
                                                         UUID rootNodeUuid,
-                                                        long largeValueMinimumSizeInBytes ) {
+                                                        long largeValueMinimumSizeInBytes,
+                                                        boolean compressData ) {
             return requestProcessor;
         }
     }

Modified: trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModelTest.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModelTest.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModelTest.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -127,7 +127,7 @@
         EntityManager manager = mock(EntityManager.class);
         EntityTransaction txn = mock(EntityTransaction.class);
         stub(manager.getTransaction()).toReturn(txn);
-        RequestProcessor proc = model.createRequestProcessor("test source", context, manager, UUID.randomUUID(), 100);
+        RequestProcessor proc = model.createRequestProcessor("test source", context, manager, UUID.randomUUID(), 100, false);
         assertThat(proc, is(notNullValue()));
     }
 

Modified: trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/SerializerTest.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/SerializerTest.java	2008-11-23 09:57:49 UTC (rev 646)
+++ trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/SerializerTest.java	2008-11-24 15:13:59 UTC (rev 647)
@@ -34,8 +34,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.SecureHash;
@@ -60,6 +62,7 @@
     private LargeValuesHolder largeValues;
     private PropertyFactory propertyFactory;
     private ValueFactories valueFactories;
+    private Set<String> largeValueHexHashes;
 
     @Before
     public void beforeEach() {
@@ -67,7 +70,8 @@
         propertyFactory = context.getPropertyFactory();
         valueFactories = context.getValueFactories();
         largeValues = new LargeValuesHolder();
-        serializer = new Serializer(context, largeValues);
+        largeValueHexHashes = new HashSet<String>();
+        serializer = new Serializer(context, largeValues, false);
     }
 
     @Test
@@ -75,6 +79,7 @@
         Property prop = createProperty("p1", new Long(1));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -82,6 +87,7 @@
         Property prop = createProperty("p1", new Integer(1));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -89,6 +95,7 @@
         Property prop = createProperty("p1", new Short((short)1));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -96,6 +103,7 @@
         Property prop = createProperty("p1", new Float(1.0f));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -103,6 +111,7 @@
         Property prop = createProperty("p1", new Double(1.0d));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -110,6 +119,7 @@
         Property prop = createProperty("p1", new Boolean(true));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -117,6 +127,7 @@
         Property prop = createProperty("p1", valueFactories.getNameFactory().create("something"));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -124,6 +135,7 @@
         Property prop = createProperty("p1", valueFactories.getPathFactory().create("/a/b/c/something"));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -131,10 +143,12 @@
         Property prop = createProperty("p1", valueFactories.getDateFactory().createUtc());
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
 
         prop = createProperty("p1", valueFactories.getDateFactory().create());
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -142,6 +156,7 @@
         Property prop = createProperty("p1", UUID.randomUUID());
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -149,6 +164,7 @@
         Property prop = createProperty("p1", new URI("http://example.com"));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -157,6 +173,7 @@
         Property prop = createProperty("p1", valueFactories.getReferenceFactory().create(uuid.toString()));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -164,6 +181,7 @@
         Property prop = createProperty("p1", valueFactories.getDecimalFactory().create("1.0123455243284347375478525485466895512"));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -172,6 +190,7 @@
         Property prop = createProperty("p1", valueFactories.getBinaryFactory().create(value));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -180,6 +199,7 @@
         Property prop = createProperty("p1", valueFactories.getBinaryFactory().create(value));
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(1));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -187,6 +207,7 @@
         Property prop = createProperty("p1", "v1");
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(0));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -196,6 +217,7 @@
         assertSerializableAndDeserializable(serializer, prop);
         assertThat(largeValues.getCount(), is(1));
         assertThat(largeValues.get(value).value, is((Object)value));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -208,6 +230,7 @@
 
         assertSerializableAndDeserializable(serializer, prop1, prop2, prop3, prop4);
         assertThat(largeValues.getCount(), is(1));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     @Test
@@ -223,6 +246,7 @@
 
         assertSerializableAndDeserializable(serializer, prop1, prop2, prop3, prop4, prop5, prop6);
         assertThat(largeValues.getCount(), is(2));
+        assertThat(largeValueHexHashes.size(), is(largeValues.getCount()));
     }
 
     protected Property createProperty( String name,
@@ -237,7 +261,7 @@
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos);
             try {
-                serializer.serializeProperty(oos, property);
+                serializer.serializeProperty(oos, property, largeValueHexHashes);
             } finally {
                 oos.close();
             }
@@ -264,7 +288,7 @@
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         ObjectOutputStream oos = new ObjectOutputStream(baos);
         try {
-            serializer.serializeProperties(oos, propertyList.size(), propertyList);
+            serializer.serializeProperties(oos, propertyList.size(), propertyList, largeValueHexHashes);
         } finally {
             oos.close();
         }
@@ -274,7 +298,7 @@
         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
         ObjectInputStream ois = new ObjectInputStream(bais);
         try {
-            serializer.deserializeProperties(ois, outputProperties);
+            serializer.deserializeAllProperties(ois, outputProperties);
         } finally {
             ois.close();
         }




More information about the dna-commits mailing list