[dna-commits] DNA SVN: r531 - in trunk: docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository and 6 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Wed Sep 17 18:56:29 EDT 2008


Author: rhauch
Date: 2008-09-17 18:56:29 -0400 (Wed, 17 Sep 2008)
New Revision: 531

Added:
   trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientUsingJcrTest.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PlaceholderContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/MergeStrategy.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java
Removed:
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergeStrategy.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategy.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategy.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategyTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategyTest.java
Modified:
   trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
   trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
Log:
DNA-222 - Create Getting Started example application for repositories
http://jira.jboss.com/jira/browse/DNA-222

More testing with several fixes.  DNA-225 is still an issue.

Modified: trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java	2008-09-17 22:56:21 UTC (rev 530)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -32,6 +32,7 @@
 import javax.jcr.NodeIterator;
 import javax.jcr.PropertyIterator;
 import javax.jcr.Session;
+import javax.jcr.Value;
 import javax.naming.NamingException;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
@@ -258,13 +259,26 @@
                     pathToNode = pathToNode.replaceAll("^/+", "");
                     // Get the node by path ...
                     Node root = session.getRootNode();
-                    Node node = root.getNode(pathToNode);
+                    Node node = root;
+                    if (pathToNode.length() != 0) {
+                        if (!pathToNode.endsWith("]")) pathToNode = pathToNode + "[1]";
+                        node = pathToNode.equals("") ? root : root.getNode(pathToNode);
+                    }
 
                     // Now populate the properties and children ...
                     if (properties != null) {
                         for (PropertyIterator iter = node.getProperties(); iter.hasNext();) {
                             javax.jcr.Property property = iter.nextProperty();
-                            Object[] values = property.getDefinition().isMultiple() ? property.getValues() : new Object[] {property.getValue()};
+                            Object[] values = null;
+                            if (property.getDefinition().isMultiple()) {
+                                Value[] jcrValues = property.getValues();
+                                values = new String[jcrValues.length];
+                                for (int i = 0; i < jcrValues.length; i++) {
+                                    values[i] = jcrValues[i].getString();
+                                }
+                            } else {
+                                values = new Object[] {property.getValue().getString()};
+                            }
                             properties.put(property.getName(), values);
                         }
                     }

Modified: trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java	2008-09-17 22:56:21 UTC (rev 530)
+++ trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -32,7 +32,6 @@
 import java.util.Map;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.MockitoAnnotations;
 import org.mockito.MockitoAnnotations.Mock;
@@ -44,6 +43,7 @@
 
     private RepositoryClient client;
     private Map<String, Object[]> properties;
+    private Map<String, Object> uuids;
     private List<String> children;
     @Mock
     private UserInterface userInterface;
@@ -51,6 +51,7 @@
     @Before
     public void beforeEach() {
         MockitoAnnotations.initMocks(this);
+        uuids = new HashMap<String, Object>();
         properties = new HashMap<String, Object[]>();
         children = new ArrayList<String>();
         client = new RepositoryClient();
@@ -74,6 +75,22 @@
         assertThat(actualValues, is(values));
     }
 
+    protected void getNodeInfo( String source,
+                                String path ) throws Throwable {
+        properties.clear();
+        children.clear();
+        assertThat(client.getNodeInfo(source, path, properties, children), is(true));
+        // Record the UUID of the node ...
+        final Object uuid = properties.get("dna:uuid");
+        final String key = source + "\n" + path;
+        final Object existingUuid = uuids.get(key);
+        if (existingUuid != null) {
+            assertThat(uuid, is(existingUuid));
+        } else {
+            uuids.put(key, uuid);
+        }
+    }
+
     @Test
     public void shouldStartupWithoutError() throws Exception {
         client.startRepositories();
@@ -89,23 +106,20 @@
     @Test
     public void shouldHaveContentFromConfigurationRepository() throws Throwable {
         client.startRepositories();
-        assertThat(client.getNodeInfo("Configuration", "/dna:system", properties, children), is(true));
+
+        getNodeInfo("Configuration", "/dna:system");
         assertThat(children, hasItems("dna:sources", "dna:federatedRepositories"));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(2));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Configuration", "/dna:system/dna:sources", properties, children), is(true));
+        getNodeInfo("Configuration", "/dna:system/dna:sources");
         assertThat(children, hasItems("SourceA", "SourceB", "SourceC", "SourceD"));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(2));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Configuration", "/dna:system/dna:sources/SourceA", properties, children), is(true));
+        getNodeInfo("Configuration", "/dna:system/dna:sources/SourceA");
         assertThat(children.size(), is(0));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
@@ -116,25 +130,22 @@
     }
 
     @Test
-    public void shouldLoadCarsRepository() throws Throwable {
+    public void shouldHaveContentFromCarsRepository() throws Throwable {
         client.startRepositories();
-        assertThat(client.getNodeInfo("Cars", "/Cars", properties, children), is(true));
+
+        getNodeInfo("Cars", "/Cars");
         assertThat(children, hasItems("Hybrid", "Sports", "Luxury", "Utility"));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(2));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Cars", "/Cars/Hybrid", properties, children), is(true));
+        getNodeInfo("Cars", "/Cars/Hybrid");
         assertThat(children, hasItems("Toyota Prius", "Toyota Highlander", "Nissan Altima"));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(2));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Cars", "/Cars/Sports/Aston Martin DB9", properties, children), is(true));
+        getNodeInfo("Cars", "/Cars/Sports/Aston Martin DB9");
         assertThat(children.size(), is(0));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
@@ -153,17 +164,16 @@
     }
 
     @Test
-    public void shouldLoadAircraftRepository() throws Throwable {
+    public void shouldHaveContentFromAircraftRepository() throws Throwable {
         client.startRepositories();
-        assertThat(client.getNodeInfo("Aircraft", "/Aircraft", properties, children), is(true));
+
+        getNodeInfo("Aircraft", "/Aircraft");
         assertThat(children, hasItems("Business", "Commercial", "Vintage", "Homebuilt"));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(2));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Aircraft", "/Aircraft/Commercial", properties, children), is(true));
+        getNodeInfo("Aircraft", "/Aircraft/Commercial");
         assertThat(children, hasItems("Boeing 777",
                                       "Boeing 767",
                                       "Boeing 787",
@@ -176,9 +186,7 @@
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(2));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Aircraft", "/Aircraft/Vintage/Wright Flyer", properties, children), is(true));
+        getNodeInfo("Aircraft", "/Aircraft/Vintage/Wright Flyer");
         assertThat(children.size(), is(0));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
@@ -191,41 +199,32 @@
         assertThat(properties.size(), is(8));
     }
 
-    @Ignore
     @Test
-    public void shouldLoadVehiclesRepository() throws Throwable {
+    public void shouldHaveContentFromVehiclesRepository() throws Throwable {
         client.startRepositories();
-        assertThat(client.getNodeInfo("Vehicles", "/", properties, children), is(true));
+
+        getNodeInfo("Vehicles", "/");
         assertThat(children, hasItems("Vehicles"));
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(1));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Vehicles", "/Vehicles", properties, children), is(true));
+        getNodeInfo("Vehicles", "/Vehicles");
         assertThat(children, hasItems("Cars", "Aircraft"));
-        assertThat(properties.containsKey("jcr:primaryType"), is(false));
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(1));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Vehicles", "/", properties, children), is(true));
+        getNodeInfo("Vehicles", "/");
         assertThat(children, hasItems("Vehicles"));
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(1));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Vehicles", "/Vehicles/Cars/Hybrid", properties, children), is(true));
+        getNodeInfo("Vehicles", "/Vehicles/Cars/Hybrid");
         assertThat(children, hasItems("Toyota Prius", "Toyota Highlander", "Nissan Altima"));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
         assertThat(properties.size(), is(2));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Vehicles", "/Vehicles/Cars/Sports/Aston Martin DB9", properties, children), is(true));
+        getNodeInfo("Vehicles", "/Vehicles/Cars/Sports/Aston Martin DB9");
         assertThat(children.size(), is(0));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
@@ -242,9 +241,7 @@
         assertProperty("engine", "5,935 cc 5.9 liters V 12");
         assertThat(properties.size(), is(12));
 
-        properties.clear();
-        children.clear();
-        assertThat(client.getNodeInfo("Vehicles", "/Vehicles/Aircraft/Vintage/Wright Flyer", properties, children), is(true));
+        getNodeInfo("Vehicles", "/Vehicles/Aircraft/Vintage/Wright Flyer");
         assertThat(children.size(), is(0));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
@@ -262,4 +259,14 @@
         client.startRepositories();
         assertThat(client.getNodeInfo("Cars", "/Cars/Sports/Non Existant Car", properties, children), is(false));
     }
+
+    @Test
+    public void shouldBeAbleToExecuteTestsRepeatedly() throws Throwable {
+        for (int i = 0; i != 10; ++i) {
+            shouldHaveContentFromConfigurationRepository();
+            shouldHaveContentFromCarsRepository();
+            shouldHaveContentFromAircraftRepository();
+            // shouldHaveContentFromVehiclesRepository();
+        }
+    }
 }

Added: trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientUsingJcrTest.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientUsingJcrTest.java	                        (rev 0)
+++ trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientUsingJcrTest.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -0,0 +1,40 @@
+/*
+ * 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.example.dna.repository;
+
+import org.jboss.example.dna.repository.RepositoryClient.Api;
+
+/**
+ * @author Randall Hauch
+ */
+public class RepositoryClientUsingJcrTest extends RepositoryClientTest {
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.example.dna.repository.RepositoryClientTest#getApi()
+     */
+    @Override
+    protected Api getApi() {
+        return RepositoryClient.Api.JCR;
+    }
+}


Property changes on: trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientUsingJcrTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java	2008-09-17 22:56:21 UTC (rev 530)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -23,6 +23,7 @@
 
 import java.io.Serializable;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
@@ -179,6 +180,46 @@
     }
 
     /**
+     * Create a placeholder contribution of a single child from the named source.
+     * 
+     * @param sourceName the name of the source, which may not be null or blank
+     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
+     * @param child the child from the source; may not be null or empty
+     * @return the contribution
+     */
+    public static Contribution createPlaceholder( String sourceName,
+                                                  Path pathInSource,
+                                                  DateTime expirationTime,
+                                                  Segment child ) {
+        if (child == null) {
+            return new EmptyContribution(sourceName, expirationTime);
+        }
+        return new PlaceholderContribution(sourceName, pathInSource, expirationTime, Collections.singletonList(child));
+    }
+
+    /**
+     * Create a placeholder contribution of the supplied properties and children from the named source.
+     * 
+     * @param sourceName the name of the source, which may not be null or blank
+     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
+     * @param children the children from the source; may not be null or empty
+     * @return the contribution
+     */
+    public static Contribution createPlaceholder( String sourceName,
+                                                  Path pathInSource,
+                                                  DateTime expirationTime,
+                                                  List<Segment> children ) {
+        if (children == null || children.isEmpty()) {
+            return new EmptyContribution(sourceName, expirationTime);
+        }
+        return new PlaceholderContribution(sourceName, pathInSource, expirationTime, children);
+    }
+
+    /**
      * This is the first version of this class. See the documentation of BasicMergePlan.serialVersionUID.
      */
     private static final long serialVersionUID = 1L;
@@ -299,6 +340,16 @@
     }
 
     /**
+     * Determine whether this contribution is considered a placeholder necessary solely because the same source has contributions
+     * at or below the children.
+     * 
+     * @return true if a placeholder contribution, or false otherwise
+     */
+    public boolean isPlaceholder() {
+        return false;
+    }
+
+    /**
      * {@inheritDoc}
      * <p>
      * This implementation returns the hash code of the {@link #getSourceName() source name}, and is compatible with the

Added: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PlaceholderContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PlaceholderContribution.java	                        (rev 0)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PlaceholderContribution.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -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.connector.federation.contribution;
+
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Path.Segment;
+
+/**
+ * A placeholder contribution needed because of a source's contribution below the specified children.
+ * 
+ * @author Randall Hauch
+ */
+ at Immutable
+public class PlaceholderContribution extends MultiChildContribution {
+
+    /**
+     * This is the first version of this class. See the documentation of MergePlan.serialVersionUID.
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Create a contribution of children from the source with the supplied name.
+     * 
+     * @param sourceName the name of the source, which may not be null or blank
+     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
+     * @param children the children from the source; may not be null or empty
+     */
+    public PlaceholderContribution( String sourceName,
+                                    Path pathInSource,
+                                    DateTime expirationTime,
+                                    Iterable<Segment> children ) {
+        super(sourceName, pathInSource, expirationTime, children);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.connector.federation.contribution.Contribution#isPlaceholder()
+     */
+    @Override
+    public boolean isPlaceholder() {
+        return true;
+    }
+}


Property changes on: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PlaceholderContribution.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

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-09-17 22:56:21 UTC (rev 530)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -40,9 +40,9 @@
 import org.jboss.dna.connector.federation.contribution.Contribution;
 import org.jboss.dna.connector.federation.merge.FederatedNode;
 import org.jboss.dna.connector.federation.merge.MergePlan;
-import org.jboss.dna.connector.federation.merge.MergeStrategy;
-import org.jboss.dna.connector.federation.merge.OneContributionMergeStrategy;
-import org.jboss.dna.connector.federation.merge.SimpleMergeStrategy;
+import org.jboss.dna.connector.federation.merge.strategy.MergeStrategy;
+import org.jboss.dna.connector.federation.merge.strategy.OneContributionMergeStrategy;
+import org.jboss.dna.connector.federation.merge.strategy.SimpleMergeStrategy;
 import org.jboss.dna.spi.DnaLexicon;
 import org.jboss.dna.spi.ExecutionContext;
 import org.jboss.dna.spi.cache.CachePolicy;
@@ -315,7 +315,7 @@
                 Path pathToLoad = path.getParent();
                 while (!pathToLoad.equals(lowestExistingAncestor)) {
                     loadContributionsFromSources(pathToLoad, null, contributions); // sourceNames may be null or empty
-                    FederatedNode mergedNode = createFederatedNode(pathToLoad, contributions, true);
+                    FederatedNode mergedNode = createFederatedNode(null, pathToLoad, contributions, true);
                     if (mergedNode == null) {
                         // No source had a contribution ...
                         I18n msg = FederationI18n.nodeDoesNotExistAtPath;
@@ -361,7 +361,7 @@
 
         // Get the contributions from the sources given their names ...
         loadContributionsFromSources(path, sourceNames, contributions); // sourceNames may be null or empty
-        FederatedNode mergedNode = createFederatedNode(path, contributions, true);
+        FederatedNode mergedNode = createFederatedNode(fromCache, path, contributions, true);
         if (mergedNode == null) {
             // No source had a contribution ...
             Path ancestor = path.getParent();
@@ -372,7 +372,8 @@
         return mergedNode;
     }
 
-    protected FederatedNode createFederatedNode( Path path,
+    protected FederatedNode createFederatedNode( BasicGetNodeCommand fromCache,
+                                                 Path path,
                                                  List<Contribution> contributions,
                                                  boolean updateCache ) throws RepositorySourceException {
 
@@ -394,11 +395,21 @@
             }
         }
 
-        // Merge the results into a single set of results ...
-        FederatedNode mergedNode = new FederatedNode(path, UUID.randomUUID());
+        // Create the node, and use the existing UUID if one is found in the cache ...
         ExecutionContext context = getExecutionContext();
-        assert contributions.size() > 0;
         assert context != null;
+        UUID uuid = null;
+        if (fromCache != null) {
+            Property uuidProperty = fromCache.getPropertiesByName().get(DnaLexicon.UUID);
+            if (uuidProperty != null && !uuidProperty.isEmpty()) {
+                uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getValues().next());
+            }
+        }
+        if (uuid == null) uuid = UUID.randomUUID();
+        FederatedNode mergedNode = new FederatedNode(path, uuid);
+
+        // Merge the results into a single set of results ...
+        assert contributions.size() > 0;
         mergingStrategy.merge(mergedNode, contributions, context);
         if (mergedNode.getCachePolicy() == null) {
             mergedNode.setCachePolicy(defaultCachePolicy);
@@ -455,7 +466,7 @@
                         if (path.isAncestorOf(topLevelPath)) {
                             assert topLevelPath.size() > path.size();
                             Path.Segment child = topLevelPath.getSegment(path.size());
-                            contribution = Contribution.create(source, path, expirationTime, null, child);
+                            contribution = Contribution.createPlaceholder(source, path, expirationTime, child);
                         }
                         break;
                     }
@@ -470,7 +481,7 @@
                             }
                         }
                         if (children.size() > 0) {
-                            contribution = Contribution.create(source, path, expirationTime, null, children);
+                            contribution = Contribution.createPlaceholder(source, path, expirationTime, children);
                         }
                     }
                 }
@@ -549,37 +560,4 @@
         }
         cacheConnection.execute(context, intoCache);
     }
-
-    /**
-     * Determine if the supplied plan is considered current
-     * 
-     * @param path the path of the node at which (or below which) the merge plan applies
-     * @param plan the merge plan
-     * @return true if the merge plan is current, or false if it needs to be (at least partially) rebuilt
-     */
-    protected boolean isCurrent( Path path,
-                                 MergePlan plan ) {
-        // First check the time ...
-        DateTime now = getCurrentTimeInUtc();
-        if (plan.isExpired(now)) return false;
-
-        // Does the plan have any contributions from sources that don't exist ?
-        for (Contribution contribution : plan) {
-            if (!sourceNames.contains(contribution.getSourceName())) return false;
-        }
-        //
-        // // Determine if any new source projections exists that aren't part of the plan ...
-        // for (String sourceName : sourceNames) {
-        // if (plan.isSource(sourceName)) continue;
-        // // The source is new ... see whether there are any regions that apply ...
-        // // for (FederatedRegion region : this.regionsBySourceName.get(sourceName)) {
-        // // // If the region's path is not at/above the path, the region doesn't matter
-        // // if (!region.appliesTo(path)) continue;
-        // // // The region applies to the path ...
-        // // return false;
-        // // }
-        // }
-        return true;
-    }
-
 }

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergeStrategy.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergeStrategy.java	2008-09-17 22:56:21 UTC (rev 530)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergeStrategy.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -1,44 +0,0 @@
-/*
- * 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.connector.federation.merge;
-
-import java.util.List;
-import org.jboss.dna.connector.federation.contribution.Contribution;
-import org.jboss.dna.spi.ExecutionContext;
-
-/**
- * @author Randall Hauch
- */
-public interface MergeStrategy {
-
-    /**
-     * Merge the contributions into a single
-     * 
-     * @param federatedNode the federated node into which the contributions are to be merged; never null
-     * @param contributions the contributions to the node; never null, never empty, and never containing nulls
-     * @param context the context in which this operation is to be performed; never null
-     */
-    public void merge( FederatedNode federatedNode,
-                       List<Contribution> contributions,
-                       ExecutionContext context );
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategy.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategy.java	2008-09-17 22:56:21 UTC (rev 530)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategy.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -1,118 +0,0 @@
-/*
- * 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.connector.federation.merge;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.connector.federation.contribution.Contribution;
-import org.jboss.dna.spi.ExecutionContext;
-import org.jboss.dna.spi.graph.Name;
-import org.jboss.dna.spi.graph.Property;
-import org.jboss.dna.spi.graph.UuidFactory;
-import org.jboss.dna.spi.graph.ValueFormatException;
-import org.jboss.dna.spi.graph.Path.Segment;
-
-/**
- * A merge strategy that is optimized for merging when there is a single contribution.
- * 
- * @author Randall Hauch
- */
- at ThreadSafe
-public class OneContributionMergeStrategy implements MergeStrategy {
-
-    public static final boolean DEFAULT_REUSE_UUID_FROM_CONTRIBUTION = true;
-
-    private boolean useUuidFromContribution = DEFAULT_REUSE_UUID_FROM_CONTRIBUTION;
-
-    /**
-     * @return reuseUuidFromContribution
-     */
-    public boolean isContributionUuidUsedForFederatedNode() {
-        return useUuidFromContribution;
-    }
-
-    /**
-     * @param useUuidFromContribution Sets useUuidFromContribution to the specified value.
-     */
-    public void setContributionUuidUsedForFederatedNode( boolean useUuidFromContribution ) {
-        this.useUuidFromContribution = useUuidFromContribution;
-    }
-
-    /**
-     * {@inheritDoc}
-     * <p>
-     * This method only uses the one and only one non-null {@link Contribution} in the <code>contributions</code>.
-     * </p>
-     * 
-     * @see org.jboss.dna.connector.federation.merge.MergeStrategy#merge(org.jboss.dna.connector.federation.merge.FederatedNode,
-     *      java.util.List, org.jboss.dna.spi.ExecutionContext)
-     */
-    public void merge( FederatedNode federatedNode,
-                       List<Contribution> contributions,
-                       ExecutionContext context ) {
-        assert federatedNode != null;
-        assert context != null;
-        assert contributions != null;
-        assert contributions.size() > 0;
-        Contribution contribution = contributions.get(0);
-        assert contribution != null;
-        final boolean findUuid = isContributionUuidUsedForFederatedNode();
-        // Copy the children ...
-        List<Segment> children = federatedNode.getChildren();
-        children.clear();
-        Iterator<Segment> childIterator = contribution.getChildren();
-        while (childIterator.hasNext()) {
-            Segment child = childIterator.next();
-            children.add(child);
-        }
-        // Copy the properties ...
-        Map<Name, Property> properties = federatedNode.getPropertiesByName();
-        properties.clear();
-        UUID uuid = null;
-        UuidFactory uuidFactory = null;
-        Iterator<Property> propertyIterator = contribution.getProperties();
-        while (propertyIterator.hasNext()) {
-            Property property = propertyIterator.next();
-            properties.put(property.getName(), property);
-            if (findUuid && uuid == null && property.getName().getLocalName().equals("uuid") && property.isSingle()) {
-                if (uuidFactory == null) uuidFactory = context.getValueFactories().getUuidFactory();
-                try {
-                    uuid = uuidFactory.create(property.getValues().next());
-                } catch (ValueFormatException e) {
-                    // Ignore conversion exceptions
-                }
-            }
-        }
-        // If we found a single "uuid" property whose value is a valid UUID ..
-        if (uuid != null) {
-            // then set the UUID on the federated node ...
-            federatedNode.setUuid(uuid);
-        }
-        // Assign the merge plan ...
-        MergePlan mergePlan = MergePlan.create(contributions);
-        federatedNode.setMergePlan(mergePlan);
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategy.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategy.java	2008-09-17 22:56:21 UTC (rev 530)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategy.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -1,275 +0,0 @@
-/*
- * 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.connector.federation.merge;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.UUID;
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.connector.federation.contribution.Contribution;
-import org.jboss.dna.spi.ExecutionContext;
-import org.jboss.dna.spi.graph.IoException;
-import org.jboss.dna.spi.graph.Name;
-import org.jboss.dna.spi.graph.Path;
-import org.jboss.dna.spi.graph.PathFactory;
-import org.jboss.dna.spi.graph.Property;
-import org.jboss.dna.spi.graph.PropertyFactory;
-import org.jboss.dna.spi.graph.UuidFactory;
-import org.jboss.dna.spi.graph.ValueComparators;
-import org.jboss.dna.spi.graph.Path.Segment;
-
-/**
- * This merge strategy simply merges all of the contributions' properties and combines the children according to the order of the
- * contributions. No children are merged, and all properties are used (except if they are deemed to be duplicates of the property
- * in other contributions).
- * 
- * @author Randall Hauch
- */
- at ThreadSafe
-public class SimpleMergeStrategy implements MergeStrategy {
-
-    private boolean removeDuplicateProperties = true;
-
-    /**
-     * @return removeDuplicateProperties
-     */
-    public boolean isRemoveDuplicateProperties() {
-        return removeDuplicateProperties;
-    }
-
-    /**
-     * @param removeDuplicateProperties Sets removeDuplicateProperties to the specified value.
-     */
-    public void setRemoveDuplicateProperties( boolean removeDuplicateProperties ) {
-        this.removeDuplicateProperties = removeDuplicateProperties;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.connector.federation.merge.MergeStrategy#merge(org.jboss.dna.connector.federation.merge.FederatedNode,
-     *      java.util.List, org.jboss.dna.spi.ExecutionContext)
-     */
-    public void merge( FederatedNode federatedNode,
-                       List<Contribution> contributions,
-                       ExecutionContext context ) {
-        assert federatedNode != null;
-        assert context != null;
-        assert contributions != null;
-        assert contributions.size() > 0;
-        PathFactory pathFactory = context.getValueFactories().getPathFactory();
-        // Prepare the federated node ...
-        List<Segment> children = federatedNode.getChildren();
-        children.clear();
-        Map<Name, Integer> childNames = new HashMap<Name, Integer>();
-        Map<Name, Property> properties = federatedNode.getPropertiesByName();
-        properties.clear();
-        UUID uuid = null;
-        UuidFactory uuidFactory = null;
-        final boolean removeDuplicateProperties = isRemoveDuplicateProperties();
-        // Iterate over the set of contributions (in order) ...
-        for (Contribution contribution : contributions) {
-            // Copy the children ...
-            int childListIndex = 0;
-            Iterator<Segment> childIterator = contribution.getChildren();
-            while (childIterator.hasNext()) {
-                Segment child = childIterator.next();
-                int index = Path.NO_INDEX;
-                Integer previous = childNames.put(child.getName(), 1);
-                if (previous != null) {
-                    int previousValue = previous.intValue();
-                    if (previousValue == 1) {
-                        // If the previous value was 1, then go back and look for the child that has no index but that should ...
-                        // Walk backwards, just in case the previous same-name-sibling is closer to the end
-                        for (int i = children.size() - 1; i >= 0; --i) {
-                            Path.Segment childSegment = children.get(i);
-                            if (childSegment.getName().equals(child.getName())) {
-                                children.set(i, pathFactory.createSegment(child.getName(), 1));
-                                break;
-                            }
-                        }
-                    }
-                    // Add the previous value back in ...
-                    childNames.put(child.getName(), ++previousValue);
-                    index = previousValue;
-                }
-                children.add(pathFactory.createSegment(child.getName(), index));
-                ++childListIndex;
-            }
-
-            // Copy the properties ...
-            Iterator<Property> propertyIterator = contribution.getProperties();
-            while (propertyIterator.hasNext()) {
-                Property property = propertyIterator.next();
-                Property existing = properties.put(property.getName(), property);
-                if (existing != null) {
-                    // There's already an existing property, so we need to merge them ...
-                    Property merged = merge(existing, property, context.getPropertyFactory(), removeDuplicateProperties);
-                    properties.put(property.getName(), merged);
-                }
-
-                if (uuid == null && property.getName().getLocalName().equals("uuid") && property.isSingle()) {
-                    if (uuidFactory == null) uuidFactory = context.getValueFactories().getUuidFactory();
-                    try {
-                        uuid = uuidFactory.create(property.getValues().next());
-                    } catch (IoException e) {
-                        // Ignore conversion exceptions
-                        assert uuid == null;
-                    }
-                }
-            }
-        }
-        // If we found a single "uuid" property whose value is a valid UUID ..
-        if (uuid != null) {
-            // then set the UUID on the federated node ...
-            federatedNode.setUuid(uuid);
-        }
-        // Assign the merge plan ...
-        MergePlan mergePlan = MergePlan.create(contributions);
-        federatedNode.setMergePlan(mergePlan);
-    }
-
-    /**
-     * Merge the values from the two properties with the same name, returning a new property with the newly merged values.
-     * <p>
-     * The current algorithm merges the values by concatenating the values from <code>property1</code> and <code>property2</code>,
-     * and if <code>removeDuplicates</code> is true any values in <code>property2</code> that are identical to values found in
-     * <code>property1</code> are skipped.
-     * </p>
-     * 
-     * @param property1 the first property; may not be null, and must have the same {@link Property#getName() name} as
-     *        <code>property2</code>
-     * @param property2 the second property; may not be null, and must have the same {@link Property#getName() name} as
-     *        <code>property1</code>
-     * @param factory the property factory, used to create the result
-     * @param removeDuplicates true if this method removes any values in the second property that duplicate values found in the
-     *        first property.
-     * @return the property that contains the same {@link Property#getName() name} as the input properties, but with values that
-     *         are merged from both of the input properties
-     */
-    protected Property merge( Property property1,
-                              Property property2,
-                              PropertyFactory factory,
-                              boolean removeDuplicates ) {
-        assert property1 != null;
-        assert property2 != null;
-        assert property1.getName().equals(property2.getName());
-        if (property1.isEmpty()) return property2;
-        if (property2.isEmpty()) return property1;
-
-        // If they are both single-valued, then we can use a more efficient algorithm ...
-        if (property1.isSingle() && property2.isSingle()) {
-            Object value1 = property1.getValues().next();
-            Object value2 = property2.getValues().next();
-            if (removeDuplicates && ValueComparators.OBJECT_COMPARATOR.compare(value1, value2) == 0) return property1;
-            return factory.create(property1.getName(), new Object[] {value1, value2});
-        }
-
-        // One or both properties are multi-valued, so use an algorithm that works with in all cases ...
-        if (!removeDuplicates) {
-            Iterator<?> valueIterator = new DualIterator(property1.getValues(), property2.getValues());
-            return factory.create(property1.getName(), valueIterator);
-        }
-
-        // First copy all the values from property 1 ...
-        Object[] values = new Object[property1.size() + property2.size()];
-        int index = 0;
-        for (Object property1Value : property1) {
-            values[index++] = property1Value;
-        }
-        assert index == property1.size();
-        // Now add any values of property2 that don't match a value in property1 ...
-        for (Object property2Value : property2) {
-            // Brute force, go through the values of property1 and compare ...
-            boolean matched = false;
-            for (Object property1Value : property1) {
-                if (ValueComparators.OBJECT_COMPARATOR.compare(property1Value, property2Value) == 0) {
-                    // The values are the same ...
-                    matched = true;
-                    break;
-                }
-            }
-            if (!matched) values[index++] = property2Value;
-        }
-        if (index != values.length) {
-            Object[] newValues = new Object[index];
-            System.arraycopy(values, 0, newValues, 0, index);
-            values = newValues;
-        }
-        return factory.create(property1.getName(), values);
-    }
-
-    protected static class DualIterator implements Iterator<Object> {
-
-        private final Iterator<?>[] iterators;
-        private Iterator<?> current;
-        private int index = 0;
-
-        protected DualIterator( Iterator<?>... iterators ) {
-            assert iterators != null;
-            assert iterators.length > 0;
-            this.iterators = iterators;
-            this.current = this.iterators[0];
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see java.util.Iterator#hasNext()
-         */
-        public boolean hasNext() {
-            if (this.current != null) return this.current.hasNext();
-            return false;
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see java.util.Iterator#next()
-         */
-        public Object next() {
-            while (this.current != null) {
-                if (this.current.hasNext()) return this.current.next();
-                // Get the next iterator ...
-                if (++this.index < iterators.length) {
-                    this.current = this.iterators[this.index];
-                } else {
-                    this.current = null;
-                }
-            }
-            throw new NoSuchElementException();
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see java.util.Iterator#remove()
-         */
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-}

Copied: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/MergeStrategy.java (from rev 522, trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergeStrategy.java)
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/MergeStrategy.java	                        (rev 0)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/MergeStrategy.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -0,0 +1,45 @@
+/*
+ * 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.connector.federation.merge.strategy;
+
+import java.util.List;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.connector.federation.merge.FederatedNode;
+import org.jboss.dna.spi.ExecutionContext;
+
+/**
+ * @author Randall Hauch
+ */
+public interface MergeStrategy {
+
+    /**
+     * Merge the contributions into a single
+     * 
+     * @param federatedNode the federated node into which the contributions are to be merged; never null
+     * @param contributions the contributions to the node; never null, never empty, and never containing nulls
+     * @param context the context in which this operation is to be performed; never null
+     */
+    public void merge( FederatedNode federatedNode,
+                       List<Contribution> contributions,
+                       ExecutionContext context );
+
+}


Property changes on: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/MergeStrategy.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Copied: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java (from rev 522, trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategy.java)
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java	                        (rev 0)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -0,0 +1,128 @@
+/*
+ * 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.connector.federation.merge.strategy;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.connector.federation.merge.FederatedNode;
+import org.jboss.dna.connector.federation.merge.MergePlan;
+import org.jboss.dna.spi.DnaLexicon;
+import org.jboss.dna.spi.ExecutionContext;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.UuidFactory;
+import org.jboss.dna.spi.graph.ValueFormatException;
+import org.jboss.dna.spi.graph.Path.Segment;
+
+/**
+ * A merge strategy that is optimized for merging when there is a single contribution.
+ * 
+ * @author Randall Hauch
+ */
+ at ThreadSafe
+public class OneContributionMergeStrategy implements MergeStrategy {
+
+    public static final boolean DEFAULT_REUSE_UUID_FROM_CONTRIBUTION = true;
+
+    private boolean useUuidFromContribution = DEFAULT_REUSE_UUID_FROM_CONTRIBUTION;
+
+    /**
+     * @return reuseUuidFromContribution
+     */
+    public boolean isContributionUuidUsedForFederatedNode() {
+        return useUuidFromContribution;
+    }
+
+    /**
+     * @param useUuidFromContribution Sets useUuidFromContribution to the specified value.
+     */
+    public void setContributionUuidUsedForFederatedNode( boolean useUuidFromContribution ) {
+        this.useUuidFromContribution = useUuidFromContribution;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This method only uses the one and only one non-null {@link Contribution} in the <code>contributions</code>.
+     * </p>
+     * 
+     * @see org.jboss.dna.connector.federation.merge.strategy.MergeStrategy#merge(org.jboss.dna.connector.federation.merge.FederatedNode,
+     *      java.util.List, org.jboss.dna.spi.ExecutionContext)
+     */
+    public void merge( FederatedNode federatedNode,
+                       List<Contribution> contributions,
+                       ExecutionContext context ) {
+        assert federatedNode != null;
+        assert context != null;
+        assert contributions != null;
+        assert contributions.size() > 0;
+        Contribution contribution = contributions.get(0);
+        assert contribution != null;
+        final boolean findUuid = isContributionUuidUsedForFederatedNode();
+        // Copy the children ...
+        List<Segment> children = federatedNode.getChildren();
+        children.clear();
+        Iterator<Segment> childIterator = contribution.getChildren();
+        while (childIterator.hasNext()) {
+            Segment child = childIterator.next();
+            children.add(child);
+        }
+        // Copy the properties ...
+        Map<Name, Property> properties = federatedNode.getPropertiesByName();
+        properties.clear();
+        UUID uuid = null;
+        UuidFactory uuidFactory = null;
+        Iterator<Property> propertyIterator = contribution.getProperties();
+        while (propertyIterator.hasNext()) {
+            Property property = propertyIterator.next();
+            if (findUuid && uuid == null && property.getName().getLocalName().equals("uuid")) {
+                if (property.isSingle()) {
+                    if (uuidFactory == null) uuidFactory = context.getValueFactories().getUuidFactory();
+                    try {
+                        uuid = uuidFactory.create(property.getValues().next());
+                    } catch (ValueFormatException e) {
+                        // Ignore conversion exceptions
+                    }
+                }
+            } else {
+                properties.put(property.getName(), property);
+            }
+        }
+        // If we found a single "uuid" property whose value is a valid UUID ..
+        if (uuid != null) {
+            // then set the UUID on the federated node ...
+            federatedNode.setUuid(uuid);
+        }
+        // Set the UUID as a property ...
+        Property uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, federatedNode.getUuid());
+        properties.put(uuidProperty.getName(), uuidProperty);
+
+        // Assign the merge plan ...
+        MergePlan mergePlan = MergePlan.create(contributions);
+        federatedNode.setMergePlan(mergePlan);
+    }
+
+}


Property changes on: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Copied: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java (from rev 522, trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategy.java)
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java	                        (rev 0)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -0,0 +1,285 @@
+/*
+ * 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.connector.federation.merge.strategy;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.connector.federation.merge.FederatedNode;
+import org.jboss.dna.connector.federation.merge.MergePlan;
+import org.jboss.dna.spi.DnaLexicon;
+import org.jboss.dna.spi.ExecutionContext;
+import org.jboss.dna.spi.graph.IoException;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.UuidFactory;
+import org.jboss.dna.spi.graph.ValueComparators;
+import org.jboss.dna.spi.graph.Path.Segment;
+
+/**
+ * This merge strategy simply merges all of the contributions' properties and combines the children according to the order of the
+ * contributions. No children are merged, and all properties are used (except if they are deemed to be duplicates of the property
+ * in other contributions).
+ * 
+ * @author Randall Hauch
+ */
+ at ThreadSafe
+public class SimpleMergeStrategy implements MergeStrategy {
+
+    private boolean removeDuplicateProperties = true;
+
+    /**
+     * @return removeDuplicateProperties
+     */
+    public boolean isRemoveDuplicateProperties() {
+        return removeDuplicateProperties;
+    }
+
+    /**
+     * @param removeDuplicateProperties Sets removeDuplicateProperties to the specified value.
+     */
+    public void setRemoveDuplicateProperties( boolean removeDuplicateProperties ) {
+        this.removeDuplicateProperties = removeDuplicateProperties;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.connector.federation.merge.strategy.MergeStrategy#merge(org.jboss.dna.connector.federation.merge.FederatedNode,
+     *      java.util.List, org.jboss.dna.spi.ExecutionContext)
+     */
+    public void merge( FederatedNode federatedNode,
+                       List<Contribution> contributions,
+                       ExecutionContext context ) {
+        assert federatedNode != null;
+        assert context != null;
+        assert contributions != null;
+        assert contributions.size() > 0;
+        PathFactory pathFactory = context.getValueFactories().getPathFactory();
+        // Prepare the federated node ...
+        List<Segment> children = federatedNode.getChildren();
+        children.clear();
+        Map<Name, Integer> childNames = new HashMap<Name, Integer>();
+        Map<Name, Property> properties = federatedNode.getPropertiesByName();
+        properties.clear();
+        UUID uuid = null;
+        UuidFactory uuidFactory = null;
+        final boolean removeDuplicateProperties = isRemoveDuplicateProperties();
+        // Iterate over the set of contributions (in order) ...
+        for (Contribution contribution : contributions) {
+            // If the contribution is a placeholder contribution, then the children should be merged into other children ...
+            if (contribution.isPlaceholder()) {
+                // Iterate over the children and add only if there is not already one ...
+                Iterator<Segment> childIterator = contribution.getChildren();
+                while (childIterator.hasNext()) {
+                    Segment child = childIterator.next();
+                    if (!childNames.containsKey(child)) {
+                        childNames.put(child.getName(), 1);
+                        children.add(pathFactory.createSegment(child.getName()));
+                    }
+                }
+
+            } else {
+                // Copy the children ...
+                Iterator<Segment> childIterator = contribution.getChildren();
+                while (childIterator.hasNext()) {
+                    Segment child = childIterator.next();
+                    int index = Path.NO_INDEX;
+                    Integer previous = childNames.put(child.getName(), 1);
+                    if (previous != null) {
+                        int previousValue = previous.intValue();
+                        // Correct the index in the child name map ...
+                        childNames.put(child.getName(), ++previousValue);
+                        index = previousValue;
+                    }
+                    children.add(pathFactory.createSegment(child.getName(), index));
+                }
+
+                // Copy the properties ...
+                Iterator<Property> propertyIterator = contribution.getProperties();
+                while (propertyIterator.hasNext()) {
+                    Property property = propertyIterator.next();
+                    // Skip the "uuid" property on all root nodes ...
+                    if (federatedNode.getPath().isRoot() && property.getName().getLocalName().equals("uuid")) continue;
+                    Property existing = properties.put(property.getName(), property);
+                    if (existing != null) {
+                        // There's already an existing property, so we need to merge them ...
+                        Property merged = merge(existing, property, context.getPropertyFactory(), removeDuplicateProperties);
+                        properties.put(property.getName(), merged);
+                    }
+
+                    if (uuid == null && property.getName().getLocalName().equals("uuid") && property.isSingle()) {
+                        if (uuidFactory == null) uuidFactory = context.getValueFactories().getUuidFactory();
+                        try {
+                            uuid = uuidFactory.create(property.getValues().next());
+                        } catch (IoException e) {
+                            // Ignore conversion exceptions
+                            assert uuid == null;
+                        }
+                    }
+                }
+            }
+        }
+        // If we found a single "uuid" property whose value is a valid UUID ..
+        if (uuid != null) {
+            // then set the UUID on the federated node ...
+            federatedNode.setUuid(uuid);
+        }
+        // Set the UUID as a property ...
+        Property uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, federatedNode.getUuid());
+        properties.put(uuidProperty.getName(), uuidProperty);
+
+        // Assign the merge plan ...
+        MergePlan mergePlan = MergePlan.create(contributions);
+        federatedNode.setMergePlan(mergePlan);
+    }
+
+    /**
+     * Merge the values from the two properties with the same name, returning a new property with the newly merged values.
+     * <p>
+     * The current algorithm merges the values by concatenating the values from <code>property1</code> and <code>property2</code>,
+     * and if <code>removeDuplicates</code> is true any values in <code>property2</code> that are identical to values found in
+     * <code>property1</code> are skipped.
+     * </p>
+     * 
+     * @param property1 the first property; may not be null, and must have the same {@link Property#getName() name} as
+     *        <code>property2</code>
+     * @param property2 the second property; may not be null, and must have the same {@link Property#getName() name} as
+     *        <code>property1</code>
+     * @param factory the property factory, used to create the result
+     * @param removeDuplicates true if this method removes any values in the second property that duplicate values found in the
+     *        first property.
+     * @return the property that contains the same {@link Property#getName() name} as the input properties, but with values that
+     *         are merged from both of the input properties
+     */
+    protected Property merge( Property property1,
+                              Property property2,
+                              PropertyFactory factory,
+                              boolean removeDuplicates ) {
+        assert property1 != null;
+        assert property2 != null;
+        assert property1.getName().equals(property2.getName());
+        if (property1.isEmpty()) return property2;
+        if (property2.isEmpty()) return property1;
+
+        // If they are both single-valued, then we can use a more efficient algorithm ...
+        if (property1.isSingle() && property2.isSingle()) {
+            Object value1 = property1.getValues().next();
+            Object value2 = property2.getValues().next();
+            if (removeDuplicates && ValueComparators.OBJECT_COMPARATOR.compare(value1, value2) == 0) return property1;
+            return factory.create(property1.getName(), new Object[] {value1, value2});
+        }
+
+        // One or both properties are multi-valued, so use an algorithm that works with in all cases ...
+        if (!removeDuplicates) {
+            Iterator<?> valueIterator = new DualIterator(property1.getValues(), property2.getValues());
+            return factory.create(property1.getName(), valueIterator);
+        }
+
+        // First copy all the values from property 1 ...
+        Object[] values = new Object[property1.size() + property2.size()];
+        int index = 0;
+        for (Object property1Value : property1) {
+            values[index++] = property1Value;
+        }
+        assert index == property1.size();
+        // Now add any values of property2 that don't match a value in property1 ...
+        for (Object property2Value : property2) {
+            // Brute force, go through the values of property1 and compare ...
+            boolean matched = false;
+            for (Object property1Value : property1) {
+                if (ValueComparators.OBJECT_COMPARATOR.compare(property1Value, property2Value) == 0) {
+                    // The values are the same ...
+                    matched = true;
+                    break;
+                }
+            }
+            if (!matched) values[index++] = property2Value;
+        }
+        if (index != values.length) {
+            Object[] newValues = new Object[index];
+            System.arraycopy(values, 0, newValues, 0, index);
+            values = newValues;
+        }
+        return factory.create(property1.getName(), values);
+    }
+
+    protected static class DualIterator implements Iterator<Object> {
+
+        private final Iterator<?>[] iterators;
+        private Iterator<?> current;
+        private int index = 0;
+
+        protected DualIterator( Iterator<?>... iterators ) {
+            assert iterators != null;
+            assert iterators.length > 0;
+            this.iterators = iterators;
+            this.current = this.iterators[0];
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.util.Iterator#hasNext()
+         */
+        public boolean hasNext() {
+            if (this.current != null) return this.current.hasNext();
+            return false;
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.util.Iterator#next()
+         */
+        public Object next() {
+            while (this.current != null) {
+                if (this.current.hasNext()) return this.current.next();
+                // Get the next iterator ...
+                if (++this.index < iterators.length) {
+                    this.current = this.iterators[this.index];
+                } else {
+                    this.current = null;
+                }
+            }
+            throw new NoSuchElementException();
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.util.Iterator#remove()
+         */
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+}


Property changes on: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategyTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategyTest.java	2008-09-17 22:56:21 UTC (rev 530)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategyTest.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -1,205 +0,0 @@
-/*
- * 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.connector.federation.merge;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNot.not;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import org.jboss.dna.connector.federation.contribution.Contribution;
-import org.jboss.dna.spi.ExecutionContext;
-import org.jboss.dna.spi.connector.BasicExecutionContext;
-import org.jboss.dna.spi.graph.Name;
-import org.jboss.dna.spi.graph.Path;
-import org.jboss.dna.spi.graph.Property;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class OneContributionMergeStrategyTest {
-
-    private OneContributionMergeStrategy strategy;
-    private List<Contribution> contributions;
-    private ExecutionContext context;
-    private FederatedNode node;
-    private Map<Name, Property> properties;
-    private List<Path.Segment> children;
-    @Mock
-    private Contribution contribution;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        Path path = mock(Path.class);
-        node = new FederatedNode(path, UUID.randomUUID());
-        strategy = new OneContributionMergeStrategy();
-        contributions = new LinkedList<Contribution>();
-        contributions.add(contribution);
-        context = new BasicExecutionContext();
-        context.getNamespaceRegistry().register("dna", "http://www.jboss.org/dna/something");
-        context.getNamespaceRegistry().register("jcr", "http://www.jcr.org");
-        stub(contribution.getSourceName()).toReturn("source name");
-        children = new LinkedList<Path.Segment>();
-        for (int i = 0; i != 10; ++i) {
-            children.add(context.getValueFactories().getPathFactory().createSegment("a" + i));
-        }
-        properties = new HashMap<Name, Property>();
-        for (int i = 0; i != 10; ++i) {
-            Name propertyName = context.getValueFactories().getNameFactory().create("property" + i);
-            properties.put(propertyName, context.getPropertyFactory().create(propertyName, "value"));
-        }
-    }
-
-    @Test
-    public void shouldMergeTheChildrenFromTheFirstContribution() {
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        strategy.merge(node, contributions, context);
-        assertThat(node.getChildren(), is(children));
-    }
-
-    @Test
-    public void shouldMergeThePropertiesFromTheFirstContribution() {
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        strategy.merge(node, contributions, context);
-        assertThat(node.getPropertiesByName(), is(properties));
-    }
-
-    @Test
-    public void shouldCreateMergePlanInTheFederatedNode() {
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        strategy.merge(node, contributions, context);
-        MergePlan mergePlan = node.getMergePlan();
-        assertThat(mergePlan.getContributionFrom(contribution.getSourceName()), is(sameInstance(contribution)));
-        assertThat(mergePlan.getContributionCount(), is(1));
-    }
-
-    @Test
-    public void shouldSetTheUuidOnTheNodeIfThereIsASingleValuedPropertyNamedUuidWithValueThatConvertsToUuidInstance() {
-        // Test the "dna:uuid" property ...
-        Name uuidName = context.getValueFactories().getNameFactory().create("dna:uuid");
-        UUID uuid = UUID.randomUUID();
-        Property uuidProperty = context.getPropertyFactory().create(uuidName, uuid);
-        properties.put(uuidProperty.getName(), uuidProperty);
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        assertThat(node.getUuid(), is(not(uuid)));
-        strategy.merge(node, contributions, context);
-        assertThat(node.getUuid(), is(uuid));
-        properties.remove(uuidProperty.getName());
-
-        // Test the "jcr:uuid" property ...
-        uuidName = context.getValueFactories().getNameFactory().create("jcr:uuid");
-        uuid = UUID.randomUUID();
-        uuidProperty = context.getPropertyFactory().create(uuidName, uuid);
-        properties.put(uuidProperty.getName(), uuidProperty);
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        assertThat(node.getUuid(), is(not(uuid)));
-        strategy.merge(node, contributions, context);
-        assertThat(node.getUuid(), is(uuid));
-        properties.remove(uuidProperty.getName());
-
-        // Test the "uuid" property ...
-        uuidName = context.getValueFactories().getNameFactory().create("uuid");
-        uuid = UUID.randomUUID();
-        uuidProperty = context.getPropertyFactory().create(uuidName, uuid);
-        properties.put(uuidProperty.getName(), uuidProperty);
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        assertThat(node.getUuid(), is(not(uuid)));
-        strategy.merge(node, contributions, context);
-        assertThat(node.getUuid(), is(uuid));
-        properties.remove(uuidProperty.getName());
-
-        // Test the "uuid" property whose value is a String ...
-        uuidName = context.getValueFactories().getNameFactory().create("uuid");
-        uuid = UUID.randomUUID();
-        uuidProperty = context.getPropertyFactory().create(uuidName, uuid.toString());
-        properties.put(uuidProperty.getName(), uuidProperty);
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        assertThat(node.getUuid(), is(not(uuid)));
-        strategy.merge(node, contributions, context);
-        assertThat(node.getUuid(), is(uuid));
-        properties.remove(uuidProperty.getName());
-    }
-
-    @Test
-    public void shouldNotSetTheUuidOnTheNodeIfThereIsNoPropertyNamedUuid() {
-        // Test the "dna:uuid" property ...
-        Name uuidName = context.getValueFactories().getNameFactory().create("dna:uuid");
-        UUID uuid = UUID.randomUUID();
-        Property uuidProperty = context.getPropertyFactory().create(uuidName, uuid);
-        properties.put(uuidProperty.getName(), uuidProperty);
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        assertThat(node.getUuid(), is(not(uuid)));
-        strategy.merge(node, contributions, context);
-        assertThat(node.getUuid(), is(uuid));
-        properties.remove(uuidProperty.getName());
-    }
-
-    @Test
-    public void shouldNotSetTheUuidOnTheNodeIfThereIsAMultiValuedPropertyNamedUuid() {
-        final UUID originalUuid = node.getUuid();
-        // Test the "dna:uuid" property ...
-        Name uuidName = context.getValueFactories().getNameFactory().create("dna:uuid");
-        Property uuidProperty = context.getPropertyFactory().create(uuidName,
-                                                                    UUID.randomUUID(),
-                                                                    UUID.randomUUID(),
-                                                                    UUID.randomUUID());
-        properties.put(uuidProperty.getName(), uuidProperty);
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        strategy.merge(node, contributions, context);
-        assertThat(node.getUuid(), is(originalUuid));
-    }
-
-    @Test
-    public void shouldNotSetTheUuidOnTheNodeIfThereIsASingleValuedPropertyNamedUuidWithValueThatDoesNotConvertToUuidInstance() {
-        final UUID originalUuid = node.getUuid();
-        // Test the "dna:uuid" property ...
-        Name uuidName = context.getValueFactories().getNameFactory().create("dna:uuid");
-        Property uuidProperty = context.getPropertyFactory().create(uuidName, 3.33d);
-        properties.put(uuidProperty.getName(), uuidProperty);
-        stub(contribution.getChildren()).toReturn(children.iterator());
-        stub(contribution.getProperties()).toReturn(properties.values().iterator());
-        strategy.merge(node, contributions, context);
-        assertThat(node.getUuid(), is(originalUuid));
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategyTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategyTest.java	2008-09-17 22:56:21 UTC (rev 530)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategyTest.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -1,297 +0,0 @@
-/*
- * 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.connector.federation.merge;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import org.hamcrest.Matcher;
-import org.jboss.dna.common.collection.IsIteratorContaining;
-import org.jboss.dna.connector.federation.contribution.Contribution;
-import org.jboss.dna.spi.ExecutionContext;
-import org.jboss.dna.spi.connector.BasicExecutionContext;
-import org.jboss.dna.spi.graph.Name;
-import org.jboss.dna.spi.graph.Path;
-import org.jboss.dna.spi.graph.Property;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-/**
- * @author Randall Hauch
- */
-public class SimpleMergeStrategyTest {
-
-    private SimpleMergeStrategy strategy;
-    private List<Contribution> contributions;
-    private ExecutionContext context;
-    private FederatedNode node;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        Path path = mock(Path.class);
-        node = new FederatedNode(path, UUID.randomUUID());
-        strategy = new SimpleMergeStrategy();
-        contributions = new LinkedList<Contribution>();
-        context = new BasicExecutionContext();
-        context.getNamespaceRegistry().register("dna", "http://www.jboss.org/dna/something");
-        context.getNamespaceRegistry().register("jcr", "http://www.jcr.org");
-    }
-
-    @Test
-    public void shouldAddChildrenFromOneContribution() {
-        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]");
-        strategy.merge(node, contributions, context);
-        assertThat(node.getChildren(), hasSegments("childA", "childB[1]", "childB[2]"));
-    }
-
-    @Test
-    public void shouldCombinePropertiesFromOneContribution() {
-        addContribution("source1").setProperty("p1", "p1 value");
-        strategy.merge(node, contributions, context);
-        assertThat(node.getProperties().size(), is(1));
-        assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
-    }
-
-    @Test
-    public void shouldAddChildrenFromMultipleContributionsInOrderAndShouldNotChangeSameNameSiblingIndexesWhenChildrenDoNotShareNamesWithChildrenFromDifferentContributions() {
-        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]");
-        addContribution("source2").addChildren("childX", "childY[1]", "childY[2]");
-        strategy.merge(node, contributions, context);
-        assertThat(node.getChildren(), hasSegments("childA", "childB[1]", "childB[2]", "childX", "childY[1]", "childY[2]"));
-    }
-
-    @Test
-    public void shouldAddChildrenFromMultipleContributionsInOrderAndShouldChangeSameNameSiblingIndexesWhenChildrenDoShareNamesWithChildrenFromDifferentContributions() {
-        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]");
-        addContribution("source2").addChildren("childX", "childB", "childY");
-        addContribution("source3").addChildren("childX", "childB");
-        strategy.merge(node, contributions, context);
-        assertThat(node.getChildren(), hasSegments("childA",
-                                                   "childB[1]",
-                                                   "childB[2]",
-                                                   "childX[1]",
-                                                   "childB[3]",
-                                                   "childY",
-                                                   "childX[2]",
-                                                   "childB[4]"));
-    }
-
-    @Test
-    public void shouldCombinePropertiesFromMultipleContributionsAndRemoveNoValuesWhenNoContributionsContainSameProperty() {
-        addContribution("source1").setProperty("p1", "p1 value");
-        addContribution("source2").setProperty("p2", "p2 value");
-        strategy.merge(node, contributions, context);
-        assertThat(node.getProperties().size(), is(2));
-        assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
-        assertThat(node.getPropertiesByName().get(name("p2")), is(property("p2", "p2 value")));
-    }
-
-    @Test
-    public void shouldCombinePropertiesFromMultipleContributionsAndRemoveDuplicateValuesWhenContributionsContainSameProperty() {
-        addContribution("source1").setProperty("p1", "p1 value").setProperty("p12", "1", "2", "3");
-        addContribution("source2").setProperty("p2", "p2 value").setProperty("p12", "3", "4");
-        strategy.merge(node, contributions, context);
-        assertThat(node.getProperties().size(), is(3));
-        assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
-        assertThat(node.getPropertiesByName().get(name("p2")), is(property("p2", "p2 value")));
-        assertThat(node.getPropertiesByName().get(name("p12")), is(property("p12", "1", "2", "3", "4")));
-    }
-
-    @Test
-    public void shouldCombinePropertiesFromMultipleContributionsAndMaintainAllValuesForEveryProperty() {
-        addContribution("source1").setProperty("p1", "p1 value").setProperty("p12", "1", "2", "3");
-        addContribution("source2").setProperty("p2", "p2 value").setProperty("p12", "3", "4");
-        strategy.merge(node, contributions, context);
-        assertThat(node.getProperties().size(), is(3));
-        for (Contribution contribution : contributions) {
-            Iterator<Property> iter = contribution.getProperties();
-            while (iter.hasNext()) {
-                Property contributionProperty = iter.next();
-                Property mergedProperty = node.getPropertiesByName().get(contributionProperty.getName());
-                assertThat(mergedProperty, is(notNullValue()));
-                // Make sure that the merged property has each value ...
-                for (Object contributedValue : contributionProperty.getValuesAsArray()) {
-                    boolean foundValue = false;
-                    for (Object mergedValue : mergedProperty.getValuesAsArray()) {
-                        if (mergedValue.equals(contributedValue)) {
-                            foundValue = true;
-                            break;
-                        }
-                    }
-                    assertThat(foundValue, is(true));
-                }
-            }
-        }
-    }
-
-    @Test
-    public void shouldCombinePropertiesFromMultipleContributionsWhenPropertyValuesAreOfDifferentPropertyTypes() {
-        addContribution("source1").setProperty("p1", "p1 value").setProperty("p12", "1", "2", "3");
-        addContribution("source2").setProperty("p2", "p2 value").setProperty("p12", 3, 4);
-        strategy.merge(node, contributions, context);
-        assertThat(node.getProperties().size(), is(3));
-        assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
-        assertThat(node.getPropertiesByName().get(name("p2")), is(property("p2", "p2 value")));
-        assertThat(node.getPropertiesByName().get(name("p12")), is(property("p12", "1", "2", "3", 4)));
-    }
-
-    @Test
-    public void shouldCreateMergePlanWhenMergingContributions() {
-        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]").setProperty("p1", "p1 value");
-        addContribution("source2").addChildren("childX", "childB", "childY").setProperty("p2", "p2 value");
-        strategy.merge(node, contributions, context);
-        assertThat(node.getMergePlan(), is(notNullValue()));
-        assertThat(node.getMergePlan().getContributionCount(), is(2));
-        assertThat(node.getMergePlan().getContributionFrom("source1"), is(sameInstance(contributions.get(0))));
-        assertThat(node.getMergePlan().getContributionFrom("source2"), is(sameInstance(contributions.get(1))));
-    }
-
-    @Test
-    public void shouldCorrectlyBuildMockUsingContributionBuilder() {
-        assertThat(contributions.size(), is(0));
-        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]").setProperty("p1", "p1 value");
-        assertThat(contributions.size(), is(1));
-        assertThat(contributions.get(0).getChildren(), hasSegmentIterator("childA", "childB[1]", "childB[2]"));
-    }
-
-    protected Matcher<List<Path.Segment>> hasSegments( String... segment ) {
-        List<Path.Segment> segments = new ArrayList<Path.Segment>();
-        for (String seg : segment) {
-            segments.add(context.getValueFactories().getPathFactory().createSegment(seg));
-        }
-        return equalTo(segments);
-    }
-
-    protected Matcher<Iterator<Path.Segment>> hasSegmentIterator( String... segment ) {
-        Path.Segment[] segments = new Path.Segment[segment.length];
-        int index = 0;
-        for (String seg : segment) {
-            segments[index++] = context.getValueFactories().getPathFactory().createSegment(seg);
-        }
-        return IsIteratorContaining.hasItems(segments);
-    }
-
-    protected Name name( String name ) {
-        return context.getValueFactories().getNameFactory().create(name);
-    }
-
-    protected Property property( String name,
-                                 Object... values ) {
-        return context.getPropertyFactory().create(name(name), values);
-    }
-
-    protected ContributionBuilder addContribution( String sourceName ) {
-        ContributionBuilder builder = new ContributionBuilder(context, sourceName, contributions);
-        contributions.add(builder.getMock());
-        return builder;
-    }
-
-    protected class ContributionBuilder {
-        protected final Contribution mockContribution;
-        protected final ExecutionContext context;
-        protected final Map<Name, Property> properties = new HashMap<Name, Property>();
-        protected final List<Path.Segment> children = new ArrayList<Path.Segment>();
-
-        protected ContributionBuilder( ExecutionContext context,
-                                       String name,
-                                       List<Contribution> contributions ) {
-            this.context = context;
-            this.mockContribution = Mockito.mock(Contribution.class);
-            stub(mockContribution.getSourceName()).toReturn(name);
-            stub(mockContribution.getChildren()).toAnswer(new Answer<Iterator<Path.Segment>>() {
-                public Iterator<Path.Segment> answer( InvocationOnMock invocation ) throws Throwable {
-                    return ContributionBuilder.this.children.iterator();
-                }
-            });
-            stub(mockContribution.getChildrenCount()).toAnswer(new Answer<Integer>() {
-                public Integer answer( InvocationOnMock invocation ) throws Throwable {
-                    return ContributionBuilder.this.children.size();
-                }
-            });
-            stub(mockContribution.getProperties()).toAnswer(new Answer<Iterator<Property>>() {
-                public Iterator<Property> answer( InvocationOnMock invocation ) throws Throwable {
-                    return ContributionBuilder.this.properties.values().iterator();
-                }
-            });
-            stub(mockContribution.getPropertyCount()).toAnswer(new Answer<Integer>() {
-                public Integer answer( InvocationOnMock invocation ) throws Throwable {
-                    return ContributionBuilder.this.properties.size();
-                }
-            });
-        }
-
-        public Contribution getMock() {
-            return this.mockContribution;
-        }
-
-        public ContributionBuilder addChildren( String... segmentNamesForChildren ) {
-            for (String childSegmentName : segmentNamesForChildren) {
-                children.add(context.getValueFactories().getPathFactory().createSegment(childSegmentName));
-            }
-            return this;
-        }
-
-        public ContributionBuilder addChildren( Name... segmentNamesForChildren ) {
-            for (Name childSegmentName : segmentNamesForChildren) {
-                children.add(context.getValueFactories().getPathFactory().createSegment(childSegmentName));
-            }
-            return this;
-        }
-
-        public ContributionBuilder addChildren( Path.Segment... segmentNamesForChildren ) {
-            for (Path.Segment childSegmentName : segmentNamesForChildren) {
-                children.add(childSegmentName);
-            }
-            return this;
-        }
-
-        public ContributionBuilder setProperty( String name,
-                                                Object... values ) {
-            Name propertyName = context.getValueFactories().getNameFactory().create(name);
-            Property property = context.getPropertyFactory().create(propertyName, values);
-            stub(mockContribution.getProperty(propertyName)).toReturn(property);
-            if (values != null && values.length > 0) {
-                properties.put(propertyName, property);
-            } else {
-                properties.remove(propertyName);
-            }
-            return this;
-        }
-    }
-
-}

Copied: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java (from rev 522, trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergeStrategyTest.java)
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java	                        (rev 0)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -0,0 +1,209 @@
+/*
+ * 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.connector.federation.merge.strategy;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.connector.federation.merge.FederatedNode;
+import org.jboss.dna.connector.federation.merge.MergePlan;
+import org.jboss.dna.spi.DnaLexicon;
+import org.jboss.dna.spi.ExecutionContext;
+import org.jboss.dna.spi.connector.BasicExecutionContext;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class OneContributionMergeStrategyTest {
+
+    private OneContributionMergeStrategy strategy;
+    private List<Contribution> contributions;
+    private ExecutionContext context;
+    private FederatedNode node;
+    private Map<Name, Property> properties;
+    private List<Path.Segment> children;
+    @Mock
+    private Contribution contribution;
+
+    @Before
+    public void beforeEach() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        Path path = mock(Path.class);
+        node = new FederatedNode(path, UUID.randomUUID());
+        strategy = new OneContributionMergeStrategy();
+        contributions = new LinkedList<Contribution>();
+        contributions.add(contribution);
+        context = new BasicExecutionContext();
+        context.getNamespaceRegistry().register("dna", "http://www.jboss.org/dna/something");
+        context.getNamespaceRegistry().register("jcr", "http://www.jcr.org");
+        stub(contribution.getSourceName()).toReturn("source name");
+        children = new LinkedList<Path.Segment>();
+        for (int i = 0; i != 10; ++i) {
+            children.add(context.getValueFactories().getPathFactory().createSegment("a" + i));
+        }
+        properties = new HashMap<Name, Property>();
+        for (int i = 0; i != 10; ++i) {
+            Name propertyName = context.getValueFactories().getNameFactory().create("property" + i);
+            properties.put(propertyName, context.getPropertyFactory().create(propertyName, "value"));
+        }
+    }
+
+    @Test
+    public void shouldMergeTheChildrenFromTheFirstContribution() {
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        strategy.merge(node, contributions, context);
+        assertThat(node.getChildren(), is(children));
+    }
+
+    @Test
+    public void shouldMergeThePropertiesFromTheFirstContribution() {
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        strategy.merge(node, contributions, context);
+        properties.put(DnaLexicon.UUID, node.getPropertiesByName().get(DnaLexicon.UUID));
+        assertThat(node.getPropertiesByName(), is(properties));
+    }
+
+    @Test
+    public void shouldCreateMergePlanInTheFederatedNode() {
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        strategy.merge(node, contributions, context);
+        MergePlan mergePlan = node.getMergePlan();
+        assertThat(mergePlan.getContributionFrom(contribution.getSourceName()), is(sameInstance(contribution)));
+        assertThat(mergePlan.getContributionCount(), is(1));
+    }
+
+    @Test
+    public void shouldSetTheUuidOnTheNodeIfThereIsASingleValuedPropertyNamedUuidWithValueThatConvertsToUuidInstance() {
+        // Test the "dna:uuid" property ...
+        Name uuidName = context.getValueFactories().getNameFactory().create("dna:uuid");
+        UUID uuid = UUID.randomUUID();
+        Property uuidProperty = context.getPropertyFactory().create(uuidName, uuid);
+        properties.put(uuidProperty.getName(), uuidProperty);
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        assertThat(node.getUuid(), is(not(uuid)));
+        strategy.merge(node, contributions, context);
+        assertThat(node.getUuid(), is(uuid));
+        properties.remove(uuidProperty.getName());
+
+        // Test the "jcr:uuid" property ...
+        uuidName = context.getValueFactories().getNameFactory().create("jcr:uuid");
+        uuid = UUID.randomUUID();
+        uuidProperty = context.getPropertyFactory().create(uuidName, uuid);
+        properties.put(uuidProperty.getName(), uuidProperty);
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        assertThat(node.getUuid(), is(not(uuid)));
+        strategy.merge(node, contributions, context);
+        assertThat(node.getUuid(), is(uuid));
+        properties.remove(uuidProperty.getName());
+
+        // Test the "uuid" property ...
+        uuidName = context.getValueFactories().getNameFactory().create("uuid");
+        uuid = UUID.randomUUID();
+        uuidProperty = context.getPropertyFactory().create(uuidName, uuid);
+        properties.put(uuidProperty.getName(), uuidProperty);
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        assertThat(node.getUuid(), is(not(uuid)));
+        strategy.merge(node, contributions, context);
+        assertThat(node.getUuid(), is(uuid));
+        properties.remove(uuidProperty.getName());
+
+        // Test the "uuid" property whose value is a String ...
+        uuidName = context.getValueFactories().getNameFactory().create("uuid");
+        uuid = UUID.randomUUID();
+        uuidProperty = context.getPropertyFactory().create(uuidName, uuid.toString());
+        properties.put(uuidProperty.getName(), uuidProperty);
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        assertThat(node.getUuid(), is(not(uuid)));
+        strategy.merge(node, contributions, context);
+        assertThat(node.getUuid(), is(uuid));
+        properties.remove(uuidProperty.getName());
+    }
+
+    @Test
+    public void shouldNotSetTheUuidOnTheNodeIfThereIsNoPropertyNamedUuid() {
+        // Test the "dna:uuid" property ...
+        Name uuidName = context.getValueFactories().getNameFactory().create("dna:uuid");
+        UUID uuid = UUID.randomUUID();
+        Property uuidProperty = context.getPropertyFactory().create(uuidName, uuid);
+        properties.put(uuidProperty.getName(), uuidProperty);
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        assertThat(node.getUuid(), is(not(uuid)));
+        strategy.merge(node, contributions, context);
+        assertThat(node.getUuid(), is(uuid));
+        properties.remove(uuidProperty.getName());
+    }
+
+    @Test
+    public void shouldNotSetTheUuidOnTheNodeIfThereIsAMultiValuedPropertyNamedUuid() {
+        final UUID originalUuid = node.getUuid();
+        // Test the "dna:uuid" property ...
+        Name uuidName = context.getValueFactories().getNameFactory().create("dna:uuid");
+        Property uuidProperty = context.getPropertyFactory().create(uuidName,
+                                                                    UUID.randomUUID(),
+                                                                    UUID.randomUUID(),
+                                                                    UUID.randomUUID());
+        properties.put(uuidProperty.getName(), uuidProperty);
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        strategy.merge(node, contributions, context);
+        assertThat(node.getUuid(), is(originalUuid));
+    }
+
+    @Test
+    public void shouldNotSetTheUuidOnTheNodeIfThereIsASingleValuedPropertyNamedUuidWithValueThatDoesNotConvertToUuidInstance() {
+        final UUID originalUuid = node.getUuid();
+        // Test the "dna:uuid" property ...
+        Name uuidName = context.getValueFactories().getNameFactory().create("dna:uuid");
+        Property uuidProperty = context.getPropertyFactory().create(uuidName, 3.33d);
+        properties.put(uuidProperty.getName(), uuidProperty);
+        stub(contribution.getChildren()).toReturn(children.iterator());
+        stub(contribution.getProperties()).toReturn(properties.values().iterator());
+        strategy.merge(node, contributions, context);
+        assertThat(node.getUuid(), is(originalUuid));
+    }
+
+}


Property changes on: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Copied: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java (from rev 522, trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/SimpleMergeStrategyTest.java)
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java	                        (rev 0)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java	2008-09-17 22:56:29 UTC (rev 531)
@@ -0,0 +1,304 @@
+/*
+ * 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.connector.federation.merge.strategy;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.hamcrest.Matcher;
+import org.jboss.dna.common.collection.IsIteratorContaining;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.connector.federation.merge.FederatedNode;
+import org.jboss.dna.spi.DnaLexicon;
+import org.jboss.dna.spi.ExecutionContext;
+import org.jboss.dna.spi.connector.BasicExecutionContext;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+/**
+ * @author Randall Hauch
+ */
+public class SimpleMergeStrategyTest {
+
+    private SimpleMergeStrategy strategy;
+    private List<Contribution> contributions;
+    private ExecutionContext context;
+    private FederatedNode node;
+
+    @Before
+    public void beforeEach() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        Path path = mock(Path.class);
+        node = new FederatedNode(path, UUID.randomUUID());
+        strategy = new SimpleMergeStrategy();
+        contributions = new LinkedList<Contribution>();
+        context = new BasicExecutionContext();
+        context.getNamespaceRegistry().register("dna", "http://www.jboss.org/dna/something");
+        context.getNamespaceRegistry().register("jcr", "http://www.jcr.org");
+    }
+
+    @Test
+    public void shouldAddChildrenFromOneContribution() {
+        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]");
+        strategy.merge(node, contributions, context);
+        assertThat(node.getChildren(), hasSegments("childA", "childB[1]", "childB[2]"));
+    }
+
+    @Test
+    public void shouldCombinePropertiesFromOneContribution() {
+        addContribution("source1").setProperty("p1", "p1 value");
+        strategy.merge(node, contributions, context);
+        assertThat(node.getProperties().size(), is(2));
+        assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
+        assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
+    }
+
+    @Test
+    public void shouldAddChildrenFromMultipleContributionsInOrderAndShouldNotChangeSameNameSiblingIndexesWhenChildrenDoNotShareNamesWithChildrenFromDifferentContributions() {
+        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]");
+        addContribution("source2").addChildren("childX", "childY[1]", "childY[2]");
+        strategy.merge(node, contributions, context);
+        assertThat(node.getChildren(), hasSegments("childA", "childB[1]", "childB[2]", "childX", "childY[1]", "childY[2]"));
+    }
+
+    @Test
+    public void shouldAddChildrenFromMultipleContributionsInOrderAndShouldChangeSameNameSiblingIndexesWhenChildrenDoShareNamesWithChildrenFromDifferentContributions() {
+        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]");
+        addContribution("source2").addChildren("childX", "childB", "childY");
+        addContribution("source3").addChildren("childX", "childB");
+        strategy.merge(node, contributions, context);
+        assertThat(node.getChildren(), hasSegments("childA",
+                                                   "childB[1]",
+                                                   "childB[2]",
+                                                   "childX[1]",
+                                                   "childB[3]",
+                                                   "childY",
+                                                   "childX[2]",
+                                                   "childB[4]"));
+    }
+
+    @Test
+    public void shouldCombinePropertiesFromMultipleContributionsAndRemoveNoValuesWhenNoContributionsContainSameProperty() {
+        addContribution("source1").setProperty("p1", "p1 value");
+        addContribution("source2").setProperty("p2", "p2 value");
+        strategy.merge(node, contributions, context);
+        assertThat(node.getProperties().size(), is(3));
+        assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
+        assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
+        assertThat(node.getPropertiesByName().get(name("p2")), is(property("p2", "p2 value")));
+    }
+
+    @Test
+    public void shouldCombinePropertiesFromMultipleContributionsAndRemoveDuplicateValuesWhenContributionsContainSameProperty() {
+        addContribution("source1").setProperty("p1", "p1 value").setProperty("p12", "1", "2", "3");
+        addContribution("source2").setProperty("p2", "p2 value").setProperty("p12", "3", "4");
+        strategy.merge(node, contributions, context);
+        assertThat(node.getProperties().size(), is(4));
+        assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
+        assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
+        assertThat(node.getPropertiesByName().get(name("p2")), is(property("p2", "p2 value")));
+        assertThat(node.getPropertiesByName().get(name("p12")), is(property("p12", "1", "2", "3", "4")));
+    }
+
+    @Test
+    public void shouldCombinePropertiesFromMultipleContributionsAndMaintainAllValuesForEveryProperty() {
+        addContribution("source1").setProperty("p1", "p1 value").setProperty("p12", "1", "2", "3");
+        addContribution("source2").setProperty("p2", "p2 value").setProperty("p12", "3", "4");
+        strategy.merge(node, contributions, context);
+        assertThat(node.getProperties().size(), is(4));
+        assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
+        for (Contribution contribution : contributions) {
+            Iterator<Property> iter = contribution.getProperties();
+            while (iter.hasNext()) {
+                Property contributionProperty = iter.next();
+                Property mergedProperty = node.getPropertiesByName().get(contributionProperty.getName());
+                assertThat(mergedProperty, is(notNullValue()));
+                // Make sure that the merged property has each value ...
+                for (Object contributedValue : contributionProperty.getValuesAsArray()) {
+                    boolean foundValue = false;
+                    for (Object mergedValue : mergedProperty.getValuesAsArray()) {
+                        if (mergedValue.equals(contributedValue)) {
+                            foundValue = true;
+                            break;
+                        }
+                    }
+                    assertThat(foundValue, is(true));
+                }
+            }
+        }
+    }
+
+    @Test
+    public void shouldCombinePropertiesFromMultipleContributionsWhenPropertyValuesAreOfDifferentPropertyTypes() {
+        addContribution("source1").setProperty("p1", "p1 value").setProperty("p12", "1", "2", "3");
+        addContribution("source2").setProperty("p2", "p2 value").setProperty("p12", 3, 4);
+        strategy.merge(node, contributions, context);
+        assertThat(node.getProperties().size(), is(4));
+        assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
+        assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
+        assertThat(node.getPropertiesByName().get(name("p2")), is(property("p2", "p2 value")));
+        assertThat(node.getPropertiesByName().get(name("p12")), is(property("p12", "1", "2", "3", 4)));
+    }
+
+    @Test
+    public void shouldCreateMergePlanWhenMergingContributions() {
+        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]").setProperty("p1", "p1 value");
+        addContribution("source2").addChildren("childX", "childB", "childY").setProperty("p2", "p2 value");
+        strategy.merge(node, contributions, context);
+        assertThat(node.getMergePlan(), is(notNullValue()));
+        assertThat(node.getMergePlan().getContributionCount(), is(2));
+        assertThat(node.getMergePlan().getContributionFrom("source1"), is(sameInstance(contributions.get(0))));
+        assertThat(node.getMergePlan().getContributionFrom("source2"), is(sameInstance(contributions.get(1))));
+    }
+
+    @Test
+    public void shouldCorrectlyBuildMockUsingContributionBuilder() {
+        assertThat(contributions.size(), is(0));
+        addContribution("source1").addChildren("childA", "childB[1]", "childB[2]").setProperty("p1", "p1 value");
+        assertThat(contributions.size(), is(1));
+        assertThat(contributions.get(0).getChildren(), hasSegmentIterator("childA", "childB[1]", "childB[2]"));
+    }
+
+    protected Matcher<List<Path.Segment>> hasSegments( String... segment ) {
+        List<Path.Segment> segments = new ArrayList<Path.Segment>();
+        for (String seg : segment) {
+            segments.add(context.getValueFactories().getPathFactory().createSegment(seg));
+        }
+        return equalTo(segments);
+    }
+
+    protected Matcher<Iterator<Path.Segment>> hasSegmentIterator( String... segment ) {
+        Path.Segment[] segments = new Path.Segment[segment.length];
+        int index = 0;
+        for (String seg : segment) {
+            segments[index++] = context.getValueFactories().getPathFactory().createSegment(seg);
+        }
+        return IsIteratorContaining.hasItems(segments);
+    }
+
+    protected Name name( String name ) {
+        return context.getValueFactories().getNameFactory().create(name);
+    }
+
+    protected Property property( String name,
+                                 Object... values ) {
+        return context.getPropertyFactory().create(name(name), values);
+    }
+
+    protected ContributionBuilder addContribution( String sourceName ) {
+        ContributionBuilder builder = new ContributionBuilder(context, sourceName, contributions);
+        contributions.add(builder.getMock());
+        return builder;
+    }
+
+    protected class ContributionBuilder {
+        protected final Contribution mockContribution;
+        protected final ExecutionContext context;
+        protected final Map<Name, Property> properties = new HashMap<Name, Property>();
+        protected final List<Path.Segment> children = new ArrayList<Path.Segment>();
+
+        protected ContributionBuilder( ExecutionContext context,
+                                       String name,
+                                       List<Contribution> contributions ) {
+            this.context = context;
+            this.mockContribution = Mockito.mock(Contribution.class);
+            stub(mockContribution.getSourceName()).toReturn(name);
+            stub(mockContribution.getChildren()).toAnswer(new Answer<Iterator<Path.Segment>>() {
+                public Iterator<Path.Segment> answer( InvocationOnMock invocation ) throws Throwable {
+                    return ContributionBuilder.this.children.iterator();
+                }
+            });
+            stub(mockContribution.getChildrenCount()).toAnswer(new Answer<Integer>() {
+                public Integer answer( InvocationOnMock invocation ) throws Throwable {
+                    return ContributionBuilder.this.children.size();
+                }
+            });
+            stub(mockContribution.getProperties()).toAnswer(new Answer<Iterator<Property>>() {
+                public Iterator<Property> answer( InvocationOnMock invocation ) throws Throwable {
+                    return ContributionBuilder.this.properties.values().iterator();
+                }
+            });
+            stub(mockContribution.getPropertyCount()).toAnswer(new Answer<Integer>() {
+                public Integer answer( InvocationOnMock invocation ) throws Throwable {
+                    return ContributionBuilder.this.properties.size();
+                }
+            });
+        }
+
+        public Contribution getMock() {
+            return this.mockContribution;
+        }
+
+        public ContributionBuilder addChildren( String... segmentNamesForChildren ) {
+            for (String childSegmentName : segmentNamesForChildren) {
+                children.add(context.getValueFactories().getPathFactory().createSegment(childSegmentName));
+            }
+            return this;
+        }
+
+        public ContributionBuilder addChildren( Name... segmentNamesForChildren ) {
+            for (Name childSegmentName : segmentNamesForChildren) {
+                children.add(context.getValueFactories().getPathFactory().createSegment(childSegmentName));
+            }
+            return this;
+        }
+
+        public ContributionBuilder addChildren( Path.Segment... segmentNamesForChildren ) {
+            for (Path.Segment childSegmentName : segmentNamesForChildren) {
+                children.add(childSegmentName);
+            }
+            return this;
+        }
+
+        public ContributionBuilder setProperty( String name,
+                                                Object... values ) {
+            Name propertyName = context.getValueFactories().getNameFactory().create(name);
+            Property property = context.getPropertyFactory().create(propertyName, values);
+            stub(mockContribution.getProperty(propertyName)).toReturn(property);
+            if (values != null && values.length > 0) {
+                properties.put(propertyName, property);
+            } else {
+                properties.remove(propertyName);
+            }
+            return this;
+        }
+    }
+
+}


Property changes on: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain




More information about the dna-commits mailing list