Index: deploy/jbossas/modeshape-jbossas-service/src/kit/modeshape-config.xml =================================================================== --- deploy/jbossas/modeshape-jbossas-service/src/kit/modeshape-config.xml (revision 2538) +++ deploy/jbossas/modeshape-jbossas-service/src/kit/modeshape-config.xml (working copy) @@ -56,6 +56,8 @@ /org/modeshape/sequencer/ddl/dialect/oracle/OracleDdl.cnd /org/modeshape/sequencer/ddl/dialect/postgres/PostgresDdl.cnd + + Index: deploy/jbossas/modeshape-jbossas-service/src/kit/modeshape-initial-content.xml new file mode 100644 =================================================================== --- /dev/null (revision 2538) +++ deploy/jbossas/modeshape-jbossas-service/src/kit/modeshape-initial-content.xml (working copy) @@ -0,0 +1,28 @@ + + + + Index: modeshape-graph/src/main/java/org/modeshape/graph/GraphMerger.java =================================================================== --- modeshape-graph/src/main/java/org/modeshape/graph/GraphMerger.java (revision 2538) +++ modeshape-graph/src/main/java/org/modeshape/graph/GraphMerger.java (working copy) @@ -24,10 +24,13 @@ package org.modeshape.graph; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; import net.jcip.annotations.NotThreadSafe; -import org.modeshape.common.collection.Collections; import org.modeshape.common.util.CheckArg; import org.modeshape.graph.Graph.Batch; import org.modeshape.graph.property.Name; @@ -42,8 +45,21 @@ import org.modeshape.graph.property.ValueComparators; @NotThreadSafe class GraphMerger { + private static final PropertyMerger SKIP_MERGER = new SkipMerger(); + private static final PropertyMerger UNION_MERGER = new UnionPropertyMerger(); + private static final PropertyMerger DEFAULT_MERGER = new DefaultPropertyMerger(); + + private static final Map MERGERS; + static { + Map mergers = new HashMap(); + mergers.put(JcrLexicon.NAME, SKIP_MERGER); + mergers.put(JcrLexicon.UUID, SKIP_MERGER); + mergers.put(ModeShapeLexicon.UUID, SKIP_MERGER); + mergers.put(JcrLexicon.MIXIN_TYPES, UNION_MERGER); + MERGERS = Collections.unmodifiableMap(mergers); + } + private final Graph initialContent; - private final Set ignoredProperties = Collections.unmodifiableSet(JcrLexicon.UUID, ModeShapeLexicon.UUID); protected GraphMerger( Graph initialContent ) { CheckArg.isNotNull(initialContent, "initialContent"); @@ -89,29 +105,14 @@ class GraphMerger { Collection desiredProperties = desiredNode.getProperties(); if (desiredProperties.isEmpty()) return; for (Property desiredProperty : desiredProperties) { - Property actual = actualNode.getProperty(desiredProperty.getName()); - boolean performSet = false; + Name propertyName = desiredProperty.getName(); + Property actual = actualNode.getProperty(propertyName); if (actual == null) { - performSet = true; - } else { - if (ignoredProperties.contains(actual.getName())) continue; - // the actual property already exists ... - Iterator actualValues = actual.getValues(); - Iterator desiredValues = desiredProperty.getValues(); - while (actualValues.hasNext() && desiredValues.hasNext()) { - Object actualValue = actualValues.next(); - Object desiredValue = desiredValues.next(); - if (ValueComparators.OBJECT_COMPARATOR.compare(actualValue, desiredValue) != 0) { - performSet = true; - break; - } - } - if (!performSet && (actualValues.hasNext() || desiredValues.hasNext())) { - performSet = true; - } - } - if (performSet) { batch.set(desiredProperty).on(actualLocation); + } else { + PropertyMerger merger = MERGERS.get(propertyName); + if (merger == null) merger = DEFAULT_MERGER; + merger.mergeProperty(batch, actualLocation.getPath(), actual, desiredProperty); } } } @@ -161,4 +162,98 @@ class GraphMerger { } } + protected static interface PropertyMerger { + public void mergeProperty( Batch batch, + Path path, + Property actual, + Property desired ); + } + + protected static class SkipMerger implements PropertyMerger { + /** + * {@inheritDoc} + * + * @see org.modeshape.graph.GraphMerger.PropertyMerger#mergeProperty(org.modeshape.graph.Graph.Batch, + * org.modeshape.graph.property.Path, org.modeshape.graph.property.Property, org.modeshape.graph.property.Property) + */ + public void mergeProperty( Batch batch, + Path path, + Property actual, + Property desired ) { + // do nothing ... + } + } + + protected static class UnionPropertyMerger implements PropertyMerger { + /** + * {@inheritDoc} + * + * @see org.modeshape.graph.GraphMerger.PropertyMerger#mergeProperty(org.modeshape.graph.Graph.Batch, + * org.modeshape.graph.property.Path, org.modeshape.graph.property.Property, org.modeshape.graph.property.Property) + */ + public void mergeProperty( Batch batch, + Path path, + Property actual, + Property desired ) { + // the actual property already exists ... + if (desired.size() == 0) { + // nothing in the desired property ... + return; + } + + Set unionedValues = new HashSet(); + Iterator actualValues = actual.getValues(); + while (actualValues.hasNext()) { + Object value = actualValues.next(); + if (value == null) continue; + unionedValues.add(value); + } + int actualSize = unionedValues.size(); + Iterator desiredValues = desired.getValues(); + while (desiredValues.hasNext()) { + Object value = desiredValues.next(); + if (value == null) continue; + unionedValues.add(value); + } + if (actualSize == unionedValues.size()) { + // The desired property adds nothing ... + return; + } + + batch.set(actual.getName()).on(path).to(unionedValues).and(); + } + } + + protected static class DefaultPropertyMerger implements PropertyMerger { + + /** + * {@inheritDoc} + * + * @see org.modeshape.graph.GraphMerger.PropertyMerger#mergeProperty(Batch, Path, Property, Property) + */ + public void mergeProperty( Batch batch, + Path path, + Property actual, + Property desired ) { + // the actual property already exists ... + Iterator actualValues = actual.getValues(); + Iterator desiredValues = desired.getValues(); + boolean performSet = false; + while (actualValues.hasNext() && desiredValues.hasNext()) { + Object actualValue = actualValues.next(); + Object desiredValue = desiredValues.next(); + if (ValueComparators.OBJECT_COMPARATOR.compare(actualValue, desiredValue) != 0) { + performSet = true; + break; + } + } + if (!performSet && (actualValues.hasNext() || desiredValues.hasNext())) { + performSet = true; + } + if (performSet) { + batch.set(desired).on(path); + } + } + } + } Index: modeshape-graph/src/test/java/org/modeshape/graph/GraphInitializerTest.java deleted file mode 100644 =================================================================== --- modeshape-graph/src/test/java/org/modeshape/graph/GraphInitializerTest.java (revision 2538) +++ /dev/null (working copy) @@ -1,128 +0,0 @@ -/* - * ModeShape (http://www.modeshape.org) - * See the COPYRIGHT.txt file distributed with this work for information - * regarding copyright ownership. Some portions may be licensed - * to Red Hat, Inc. under one or more contributor license agreements. - * See the AUTHORS.txt file in the distribution for a full listing of - * individual contributors. - * - * ModeShape is free software. Unless otherwise indicated, all code in ModeShape - * is licensed to you under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * ModeShape 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.modeshape.graph; - -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsNull.notNullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import java.net.URL; -import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource; -import org.modeshape.graph.connector.xmlfile.XmlFileRepositorySource; -import org.modeshape.graph.property.PathNotFoundException; - -/** - * - */ -public class GraphInitializerTest { - - private ExecutionContext context; - private InMemoryRepositorySource graphSource; - private XmlFileRepositorySource initialContentSource; - private Graph graph; - private Graph initialContent; - private boolean print = false; - - @Before - public void beforeEaach() { - context = new ExecutionContext(); - - graphSource = new InMemoryRepositorySource(); - graphSource.setName("Graph source"); - - initialContentSource = new XmlFileRepositorySource(); - initialContentSource.setName("Initial content source"); - initialContentSource.setContentLocation(resourceUrl("aircraft.xml")); - - graph = Graph.create(graphSource, context); - initialContent = Graph.create(initialContentSource, context); - } - - @Test - public void shouldHaveNonEmptyInitialContent() { - assertNodeExists(initialContent, "Aircraft"); - } - - @Test - public void shouldInitializeEmptySource() { - assertNoChildren(graph, "/"); - graph.merge(initialContent); - // print = true; - printSubgraph(graph, "/"); - assertNodeExists(initialContent, "Aircraft"); - assertNodeDoesNotExist(initialContent, "Aircraft[2]"); - } - - @Test - public void shouldInitializeSourceWithOnlySomeNodes() { - assertNoChildren(graph, "/"); - graph.create("/Aircraft").and(); - graph.merge(initialContent); - // print = true; - printSubgraph(graph, "/"); - assertNodeExists(initialContent, "Aircraft"); - assertNodeDoesNotExist(initialContent, "Aircraft[2]"); - } - - protected void assertNoChildren( Graph graph, - String path ) { - assertNodeExists(graph, path); - List children = graph.getChildren().of(path); - assertThat(children.isEmpty(), is(true)); - } - - protected Node assertNodeExists( Graph graph, - String path ) { - Node node = graph.getNodeAt(path); - assertThat(node, is(notNullValue())); - return node; - } - - protected void assertNodeDoesNotExist( Graph graph, - String path ) { - try { - graph.getNodeAt(path); - fail("Node does exist at \"" + path + "\""); - } catch (PathNotFoundException e) { - // expected ... - } - } - - protected void printSubgraph( Graph graph, - String path ) { - if (print) { - Subgraph subgraph = graph.getSubgraphOfDepth(Integer.MAX_VALUE).at(path); - System.out.println(subgraph); - } - } - - protected String resourceUrl( String path ) { - URL url = this.getClass().getClassLoader().getResource(path); - return url != null ? url.toExternalForm() : path; - } - -} Index: modeshape-graph/src/test/java/org/modeshape/graph/GraphMergerTest.java new file mode 100644 =================================================================== --- /dev/null (revision 2538) +++ modeshape-graph/src/test/java/org/modeshape/graph/GraphMergerTest.java (working copy) @@ -0,0 +1,128 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape 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.modeshape.graph; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import java.net.URL; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource; +import org.modeshape.graph.connector.xmlfile.XmlFileRepositorySource; +import org.modeshape.graph.property.PathNotFoundException; + +/** + * + */ +public class GraphMergerTest { + + private ExecutionContext context; + private InMemoryRepositorySource graphSource; + private XmlFileRepositorySource initialContentSource; + private Graph graph; + private Graph initialContent; + private boolean print = false; + + @Before + public void beforeEaach() { + context = new ExecutionContext(); + + graphSource = new InMemoryRepositorySource(); + graphSource.setName("Graph source"); + + initialContentSource = new XmlFileRepositorySource(); + initialContentSource.setName("Initial content source"); + initialContentSource.setContentLocation(resourceUrl("aircraft.xml")); + + graph = Graph.create(graphSource, context); + initialContent = Graph.create(initialContentSource, context); + } + + @Test + public void shouldHaveNonEmptyInitialContent() { + assertNodeExists(initialContent, "Aircraft"); + } + + @Test + public void shouldInitializeEmptySource() { + assertNoChildren(graph, "/"); + graph.merge(initialContent); + // print = true; + printSubgraph(graph, "/"); + assertNodeExists(initialContent, "Aircraft"); + assertNodeDoesNotExist(initialContent, "Aircraft[2]"); + } + + @Test + public void shouldInitializeSourceWithOnlySomeNodes() { + assertNoChildren(graph, "/"); + graph.create("/Aircraft").and(); + graph.merge(initialContent); + // print = true; + printSubgraph(graph, "/"); + assertNodeExists(initialContent, "Aircraft"); + assertNodeDoesNotExist(initialContent, "Aircraft[2]"); + } + + protected void assertNoChildren( Graph graph, + String path ) { + assertNodeExists(graph, path); + List children = graph.getChildren().of(path); + assertThat(children.isEmpty(), is(true)); + } + + protected Node assertNodeExists( Graph graph, + String path ) { + Node node = graph.getNodeAt(path); + assertThat(node, is(notNullValue())); + return node; + } + + protected void assertNodeDoesNotExist( Graph graph, + String path ) { + try { + graph.getNodeAt(path); + fail("Node does exist at \"" + path + "\""); + } catch (PathNotFoundException e) { + // expected ... + } + } + + protected void printSubgraph( Graph graph, + String path ) { + if (print) { + Subgraph subgraph = graph.getSubgraphOfDepth(Integer.MAX_VALUE).at(path); + System.out.println(subgraph); + } + } + + protected String resourceUrl( String path ) { + URL url = this.getClass().getClassLoader().getResource(path); + return url != null ? url.toExternalForm() : path; + } + +}