Index: dna-graph/src/main/java/org/jboss/dna/graph/Location.java =================================================================== --- dna-graph/src/main/java/org/jboss/dna/graph/Location.java (revision 731) +++ dna-graph/src/main/java/org/jboss/dna/graph/Location.java (working copy) @@ -24,12 +24,13 @@ package org.jboss.dna.graph; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.UUID; + import net.jcip.annotations.Immutable; + import org.jboss.dna.common.text.TextEncoder; import org.jboss.dna.common.util.CheckArg; import org.jboss.dna.common.util.HashCode; @@ -45,12 +46,12 @@ * @author Randall Hauch */ @Immutable -public class Location implements Iterable { +public abstract class Location implements Iterable { /** * Simple shared iterator instance that is used when there are no properties. */ - private static final Iterator NO_ID_PROPERTIES_ITERATOR = new Iterator() { + protected static final Iterator NO_ID_PROPERTIES_ITERATOR = new Iterator() { public boolean hasNext() { return false; } @@ -74,7 +75,7 @@ public static Location create( Path path ) { CheckArg.isNotNull(path, "path"); - return new Location(path, null); + return new PathLocation(path); } /** @@ -88,7 +89,7 @@ public static Location create( UUID uuid ) { CheckArg.isNotNull(uuid, "uuid"); Property idProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid); - return new Location(null, Collections.singletonList(idProperty)); + return new PathPropertyLocation(null, idProperty); } /** @@ -103,13 +104,7 @@ public static Location create( Path path, UUID uuid ) { CheckArg.isNotNull(uuid, "uuid"); - List idProperties = null; - if (uuid != null) { - Property idProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid); - idProperties = Collections.singletonList(idProperty); - } - - return new Location(path, idProperties); + return new PathPropertyLocation(path, new BasicSingleValueProperty(DnaLexicon.UUID, uuid)); } /** @@ -124,7 +119,7 @@ Property idProperty ) { CheckArg.isNotNull(path, "path"); CheckArg.isNotNull(idProperty, "idProperty"); - return new Location(path, idProperty != null ? Collections.singletonList(idProperty) : null); + return new PathPropertyLocation(path, idProperty); } /** @@ -147,7 +142,7 @@ for (Property property : remainingIdProperties) { idProperties.add(property); } - return new Location(path, Collections.unmodifiableList(idProperties)); + return new PathPropertiesLocation(path, idProperties); } /** @@ -166,7 +161,7 @@ for (Property property : idProperties) { idPropertiesList.add(property); } - return new Location(path, Collections.unmodifiableList(idPropertiesList)); + return new PathPropertiesLocation(path, idPropertiesList); } /** @@ -178,7 +173,7 @@ */ public static Location create( Property idProperty ) { CheckArg.isNotNull(idProperty, "idProperty"); - return new Location(null, Collections.singletonList(idProperty)); + return new PathPropertyLocation(null, idProperty); } /** @@ -198,7 +193,7 @@ for (Property property : remainingIdProperties) { idProperties.add(property); } - return new Location(null, Collections.unmodifiableList(idProperties)); + return new PathPropertiesLocation(null, idProperties); } /** @@ -214,7 +209,7 @@ for (Property property : idProperties) { idPropertiesList.add(property); } - return new Location(null, Collections.unmodifiableList(idPropertiesList)); + return new PathPropertiesLocation(null, idPropertiesList); } /** @@ -226,89 +221,15 @@ */ public static Location create( List idProperties ) { CheckArg.isNotEmpty(idProperties, "idProperties"); - return new Location(null, idProperties); + return new PathPropertiesLocation(null, idProperties); } /** - * Create a location defined by a path and multiple identification properties. - * - * @param path the path - * @param idProperties the identification properties - * @return a new Location with the given path and identification properties - * @throws IllegalArgumentException if path is null, or if idProperties is empty - */ - protected static Location create( Path path, - List idProperties ) { - CheckArg.isNotNull(path, "path"); - CheckArg.isNotEmpty(idProperties, "idProperties"); - return new Location(path, idProperties); - } - - private final Path path; - private final List idProperties; - - /** - * Create a new location with a given path and set of identification properties. - * - * @param path the path - * @param idProperties the identification properties - */ - protected Location( Path path, - List idProperties ) { - this.path = path; - this.idProperties = idProperties; - } - - /** - * Create a location from another but adding the supplied identification property. The new identification property will - * replace any existing identification property with the same name on the original. - * - * @param original the original location - * @param newIdProperty the new identification property - * @throws IllegalArgumentException if original is null - */ - protected Location( Location original, - Property newIdProperty ) { - this.path = original.getPath(); - if (original.hasIdProperties()) { - List originalIdProperties = original.getIdProperties(); - if (newIdProperty == null) { - this.idProperties = original.idProperties; - } else { - List idProperties = new ArrayList(originalIdProperties.size() + 1); - for (Property property : originalIdProperties) { - if (!newIdProperty.getName().equals(property.getName())) idProperties.add(property); - } - idProperties.add(newIdProperty); - this.idProperties = Collections.unmodifiableList(idProperties); - } - } else { - this.idProperties = Collections.singletonList(newIdProperty); - } - } - - /** - * Create a location from another but adding the supplied identification property. The new identification property will - * replace any existing identification property with the same name on the original. - * - * @param original the original location - * @param newPath the new path for the location - * @throws IllegalArgumentException if original is null - */ - protected Location( Location original, - Path newPath ) { - this.path = newPath != null ? newPath : original.getPath(); - this.idProperties = original.idProperties; - } - - /** * Get the path that (at least in part) defines this location. * * @return the path, or null if this location is not defined with a path */ - public Path getPath() { - return path; - } + public abstract Path getPath(); /** * Return whether this location is defined (at least in part) by a path. @@ -316,7 +237,7 @@ * @return true if a {@link #getPath() path} helps define this location */ public boolean hasPath() { - return path != null; + return getPath() != null; } /** @@ -324,9 +245,7 @@ * * @return the identification properties, or null if this location is not defined with identification properties */ - public List getIdProperties() { - return idProperties; - } + public abstract List getIdProperties(); /** * Return whether this location is defined (at least in part) with identification properties. @@ -334,7 +253,7 @@ * @return true if a {@link #getIdProperties() identification properties} help define this location */ public boolean hasIdProperties() { - return idProperties != null && idProperties.size() != 0; + return getIdProperties() != null && getIdProperties().size() != 0; } /** @@ -346,8 +265,8 @@ */ public Property getIdProperty( Name name ) { CheckArg.isNotNull(name, "name"); - if (idProperties != null) { - for (Property property : idProperties) { + if (getIdProperties() != null) { + for (Property property : getIdProperties()) { if (property.getName().equals(name)) return property; } } @@ -449,7 +368,7 @@ * @see java.lang.Iterable#iterator() */ public Iterator iterator() { - return idProperties != null ? idProperties.iterator() : NO_ID_PROPERTIES_ITERATOR; + return getIdProperties() != null ? getIdProperties().iterator() : NO_ID_PROPERTIES_ITERATOR; } /** @@ -459,7 +378,7 @@ */ @Override public int hashCode() { - return HashCode.compute(path, idProperties); + return HashCode.compute(getPath(), getIdProperties()); } /** @@ -624,22 +543,14 @@ * @param newIdProperty the new identification property, which may be null * @return the new location, or this location if the new identification property is null or empty */ - public Location with( Property newIdProperty ) { - if (newIdProperty == null || newIdProperty.isEmpty()) return this; - return new Location(this, newIdProperty); - } - + public abstract Location with( Property newIdProperty ); /** * Create a copy of this location that uses the supplied path. * * @param newPath the new path for the location * @return the new location, or this location if the path is equal to this location's path */ - public Location with( Path newPath ) { - if (newPath == null) return this; - if (!this.path.equals(newPath)) return new Location(this, newPath); - return this; - } + public abstract Location with( Path newPath ); /** * Create a copy of this location that adds the supplied UUID as an identification property. The new identification property @@ -648,14 +559,6 @@ * @param uuid the new UUID, which may be null * @return the new location, or this location if the new identification property is null or empty */ - public Location with( UUID uuid ) { - if (uuid == null) return this; - Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid); - if (this.hasIdProperties()) { - Property existing = this.getIdProperty(DnaLexicon.UUID); - if (existing != null && existing.equals(newProperty)) return this; - } - return new Location(this, newProperty); - } + public abstract Location with( UUID uuid ); } Index: dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java =================================================================== --- dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java (revision 0) +++ dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java (revision 0) @@ -0,0 +1,178 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.graph; + +import java.util.List; +import java.util.UUID; + +import net.jcip.annotations.Immutable; + +import org.jboss.dna.common.text.TextEncoder; +import org.jboss.dna.common.util.CheckArg; +import org.jboss.dna.common.util.HashCode; +import org.jboss.dna.graph.property.NamespaceRegistry; +import org.jboss.dna.graph.property.Path; +import org.jboss.dna.graph.property.Property; +import org.jboss.dna.graph.property.basic.BasicSingleValueProperty; + +/** + * Special location type optimized for use when only a path is specified. + * This class should never be directly instantiated by users of the DNA framework. + * Instead, use @{link Location#create} to create the correct location. + * + * @see Location + */ +@Immutable +class PathLocation extends Location { + + private final Path path; + private final int hashCode; + + PathLocation(Path path) { + CheckArg.isNotNull(path, "path"); + + this.path = path; + + // Paths are immutable, so PathLocations are immutable... + // ... so we can cache the hash code. + hashCode = HashCode.compute(path); + } + + /** + * {@inheritDoc} + * + * @see Location#getPath() + */ + @Override + public final Path getPath() { + return path; + } + + + /** + * {@inheritDoc} + * + * @see Location#hasPath() + */ + @Override + public final boolean hasPath() { + return true; + } + + /** + * {@inheritDoc} + * + * @see Location#getIdProperties() + */ + @Override + public final List getIdProperties() { + return null; + } + + /** + * {@inheritDoc} + * + * @see Location#hasIdProperties() + */ + @Override + public final boolean hasIdProperties() { + return false; + } + + + /** + * {@inheritDoc} + * + * @see Location#getUuid() + */ + @Override + public final UUID getUuid() { + return null; + } + + /** + * {@inheritDoc} + * + * @see Location#hashCode() + */ + @Override + public int hashCode() { + return hashCode; + } + + /** + * {@inheritDoc} + * + * @see Location#getString(NamespaceRegistry, TextEncoder, TextEncoder) + */ + @Override + public String getString(NamespaceRegistry namespaceRegistry, TextEncoder encoder, TextEncoder delimiterEncoder) { + StringBuilder sb = new StringBuilder(); + sb.append("{ "); + sb.append(path.getString(namespaceRegistry, encoder, delimiterEncoder)); + sb.append(" }"); + return sb.toString(); + } + + + /** + * {@inheritDoc} + * + * @see Location#with(Property) + */ + @Override + public Location with( Property newIdProperty ) { + if (newIdProperty == null || newIdProperty.isEmpty()) return this; + return Location.create(path, newIdProperty); + } + + /** + * {@inheritDoc} + * + * @see Location#with(Path) + */ + @Override + public Location with( Path newPath ) { + if (newPath == null) return this; + if (!this.getPath().equals(newPath)) return Location.create(newPath); + return this; + } + + + /** + * {@inheritDoc} + * + * @see Location#with(UUID) + */ + @Override + public Location with( UUID uuid ) { + if (uuid == null) return this; + Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid); + if (this.hasIdProperties()) { + Property existing = this.getIdProperty(DnaLexicon.UUID); + if (existing != null && existing.equals(newProperty)) return this; + } + return Location.create(path, uuid); + } +} Index: dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java =================================================================== --- dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java (revision 0) +++ dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java (revision 0) @@ -0,0 +1,173 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.graph; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import net.jcip.annotations.Immutable; + +import org.jboss.dna.common.util.CheckArg; +import org.jboss.dna.common.util.HashCode; +import org.jboss.dna.graph.property.Path; +import org.jboss.dna.graph.property.Property; +import org.jboss.dna.graph.property.basic.BasicSingleValueProperty; + +/** + * General purpose location type that supports a path and zero or more properties. + * This class should never be directly instantiated by users of the DNA framework. + * Instead, use @{link Location#create} to create the correct location. + * + * @see Location + */ +@Immutable +class PathPropertiesLocation extends Location { + + private final Path path; + private final List idProperties; + + private final int hashCode; + + /** + * Create a new location with a given path and set of identification properties. + * + * @param path the path + * @param idProperties the identification properties + */ + PathPropertiesLocation( Path path, List idProperties ) { + // The path could be null + // CheckArg.isNotNull(path, "path"); + // If the properties are a null, a PathLocation should be used instead. + CheckArg.isNotNull(idProperties, "idProperties"); + + this.path = path; + this.idProperties = Collections.unmodifiableList(idProperties); + + // Paths are immutable, Properties are immutable, the idProperties list + // is wrapped in an unmodifiableList by the Location factory methods... + // ... so we can cache the hash code. + + hashCode = HashCode.compute(path, idProperties); + } + + /** + * {@inheritDoc} + * + * @see Location#getPath() + */ + @Override + public final Path getPath() { + return path; + } + + /** + * {@inheritDoc} + * + * @see Location#getIdProperties() + */ + @Override + public final List getIdProperties() { + return idProperties; + } + + /** + * {@inheritDoc} + * + * @see Location#hasIdProperties() + */ + @Override + public final boolean hasIdProperties() { + return idProperties.size() > 0; + } + + /** + * {@inheritDoc} + * + * @see Location#hashCode() + */ + @Override + public int hashCode() { + return hashCode; + } + + /** + * {@inheritDoc} + * + * @see Location#with(Property) + */ + @Override + public Location with( Property newIdProperty ) { + if (newIdProperty == null || newIdProperty.isEmpty()) return this; + + List newIdProperties; + + if (hasIdProperties()) { + newIdProperties = new ArrayList(idProperties.size() + 1); + for (Property property : idProperties) { + if (!newIdProperty.getName().equals(property.getName())) newIdProperties.add(property); + } + newIdProperties.add(newIdProperty); + newIdProperties = Collections.unmodifiableList(newIdProperties); + } else { + return Location.create(path, newIdProperty); + } + + return new PathPropertiesLocation(path, newIdProperties); + } + + /** + * {@inheritDoc} + * + * @see Location#with(Path) + */ + @Override + public Location with( Path newPath ) { + if (newPath == null) return this; + if (!this.getPath().equals(newPath)) return Location.create(newPath, idProperties); + return this; + } + + /** + * {@inheritDoc} + * + * @see Location#with(UUID) + */ + @Override + public Location with( UUID uuid ) { + if (uuid == null) return this; + Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid); + if (this.hasIdProperties()) { + Property existing = this.getIdProperty(DnaLexicon.UUID); + if (existing != null && existing.equals(newProperty)) return this; + } + + List newIdProperties = new ArrayList(idProperties.size() + 1); + newIdProperties.addAll(idProperties); + newIdProperties.add(newProperty); + + return Location.create(path, newIdProperties); + } +} Index: dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java =================================================================== --- dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java (revision 0) +++ dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java (revision 0) @@ -0,0 +1,197 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.graph; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import net.jcip.annotations.Immutable; + +import org.jboss.dna.common.util.CheckArg; +import org.jboss.dna.common.util.HashCode; +import org.jboss.dna.graph.property.Name; +import org.jboss.dna.graph.property.Path; +import org.jboss.dna.graph.property.Property; +import org.jboss.dna.graph.property.basic.BasicSingleValueProperty; + +/** + * General purpose location type that supports a path and a property. + * This class should never be directly instantiated by users of the DNA framework. + * Instead, use @{link Location#create} to create the correct location. + * + * @see Location + */ +@Immutable +class PathPropertyLocation extends Location { + + private final Path path; + private final Property idProperty; + private final List idProperties; + + private final int hashCode; + + /** + * Create a new location with a given path and identification property. + * + * @param path the path + * @param idProperty the identification property + */ + PathPropertyLocation( Path path, Property idProperty ) { + // The path could be null + // CheckArg.isNotNull(path, "path"); + // If the properties are a null, a PathLocation should be used instead. + CheckArg.isNotNull(idProperty, "idProperty"); + + this.path = path; + this.idProperty = idProperty; + this.idProperties = Collections.singletonList(idProperty); + + // Paths are immutable, Properties are immutable, the idProperties list + // is wrapped in an unmodifiableList by the Location factory methods... + // ... so we can cache the hash code. + + hashCode = HashCode.compute(path, idProperties); + } + + /** + * {@inheritDoc} + * + * @see Location#getPath() + */ + @Override + public final Path getPath() { + return path; + } + + /** + * {@inheritDoc} + * + * @see Location#getIdProperties() + */ + @Override + public final List getIdProperties() { + return idProperties; + } + + /** + * {@inheritDoc} + * + * @see Location#hasIdProperties() + */ + @Override + public final boolean hasIdProperties() { + return true; + } + + /** + * {@inheritDoc} + * + * @see Location#getIdProperty(Name) + */ + @Override + public final Property getIdProperty( Name name ) { + CheckArg.isNotNull(name, "name"); + if (idProperty.getName().equals(name)) return idProperty; + + return null; + } + + /** + * {@inheritDoc} + * + * @see Location#getUuid() + */ + @Override + public UUID getUuid() { + if (DnaLexicon.UUID.equals(idProperty.getName())) { + Object value = idProperty.getFirstValue(); + if (value instanceof UUID) return (UUID)value; + } + return null; + } + + + /** + * {@inheritDoc} + * + * @see Location#hashCode() + */ + @Override + public int hashCode() { + return hashCode; + } + + /** + * {@inheritDoc} + * + * @see Location#with(Property) + */ + @Override + public Location with( Property newIdProperty ) { + if (newIdProperty == null || newIdProperty.isEmpty()) return this; + + // A new property with same name overrides the old property with the same name + if (newIdProperty.getName().equals(idProperty.getName())) return Location.create(path, newIdProperty); + + List newIdProperties = new ArrayList(2); + newIdProperties.add(idProperty); + newIdProperties.add(newIdProperty); + + return Location.create(path, newIdProperties); + } + + /** + * {@inheritDoc} + * + * @see Location#with(Path) + */ + @Override + public Location with( Path newPath ) { + if (newPath == null && path == null) return this; + if (path != null && (path.equals(newPath))) return this; + + return Location.create(newPath, idProperty); + } + + /** + * {@inheritDoc} + * + * @see Location#with(UUID) + */ + @Override + public Location with( UUID uuid ) { + if (uuid == null) return this; + + // A new property with same name overrides the old property with the same name + if (idProperty.getName().equals(DnaLexicon.UUID)) return Location.create(path, uuid); + + List newIdProperties = new ArrayList(2); + newIdProperties.add(idProperty); + newIdProperties.add(new BasicSingleValueProperty(DnaLexicon.UUID, uuid)); + + return Location.create(path, newIdProperties); + } +} Index: dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java =================================================================== --- dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java (revision 0) +++ dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java (revision 0) @@ -0,0 +1,235 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.graph; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.jboss.dna.common.text.NoOpEncoder; +import org.jboss.dna.graph.property.Path; +import org.jboss.dna.graph.property.PathFactory; +import org.jboss.dna.graph.property.Property; +import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry; +import org.jboss.dna.graph.property.basic.BasicSingleValueProperty; +import org.jboss.dna.graph.property.basic.NameValueFactory; +import org.jboss.dna.graph.property.basic.PathValueFactory; +import org.jboss.dna.graph.property.basic.StringValueFactory; +import org.junit.BeforeClass; +import org.junit.Test; + + +/** + * Tests Location class and factory constructors. + */ +public class LocationTest { + + private static final NoOpEncoder NO_OP_ENCODER = new NoOpEncoder(); + private static final StringValueFactory STRING_VALUE_FACTORY = new StringValueFactory(NO_OP_ENCODER, NO_OP_ENCODER); + private static final NameValueFactory NAME_VALUE_FACTORY = new NameValueFactory(new BasicNamespaceRegistry("http://www.jboss.org/dna/1.0"), NO_OP_ENCODER, STRING_VALUE_FACTORY); + + private PathFactory pathFactory = new PathValueFactory(NO_OP_ENCODER, + STRING_VALUE_FACTORY, NAME_VALUE_FACTORY); + + private static UUID uuid = UUID.randomUUID(); + + private Path pathA = pathFactory.create("/A"); + private Path pathABC = pathFactory.create("/A/B/C"); + + private static Property propA = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("A"), "Value A"); + private static Property propB = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("B"), "Value B"); + private static Property propU = new BasicSingleValueProperty(DnaLexicon.UUID, uuid); + + private static List propListAB; + private static List propListABU; + + + @BeforeClass + public static void beforeAny() { + propListAB = new ArrayList(); + propListAB.add(propA); + propListAB.add(propB); + + propListABU = new ArrayList(); + propListABU.add(propA); + propListABU.add(propB); + propListABU.add(propU); + + } + + @Test + public void locationsWithSamePathsAreEqual() { + Location locationA1 = Location.create(pathA); + Location locationA2 = Location.create(pathA); + + assertThat("Locations created with identical paths must be equal", locationA1, is(locationA2)); + + Location locationABC1 = Location.create(pathABC); + Location locationABC2 = Location.create(pathABC); + + assertThat("Locations created with identical non-trivial paths must be equal", locationABC1, is(locationABC2)); + } + + @Test + public void locationsWithSamePathsAreSame() { + Location locationA1 = Location.create(pathA); + Location locationA2 = Location.create(pathA); + + assertThat("isSame must return true for locations created with identical paths", locationA1.isSame(locationA2), is(true)); + + Location locationABC1 = Location.create(pathABC); + Location locationABC2 = Location.create(pathABC); + + assertThat("isSame must return true for locations created with identical, non-trivial paths", locationABC1.isSame(locationABC2), is(true)); + } + + @Test + public void locationsWithSamePathsAndSamePropertyAreNotEqual() { + Location locationA1 = Location.create(pathA, propA); + Location locationA2 = Location.create(pathA, propA); + + assertThat("Locations created with identical paths and different property must be equal", locationA1, is(locationA2)); + } + + @Test + public void locationsWithSamePathsAndSamePropertyAreNotSame() { + Location locationA1 = Location.create(pathA, propA); + Location locationA2 = Location.create(pathA, propA); + + assertThat("isSame must return true for locations created with identical paths and property", locationA1.isSame(locationA2), is(true)); + } + + @Test + public void locationsWithSamePathsAndDifferentPropertyAreNotEqual() { + Location locationA1 = Location.create(pathA, propA); + Location locationA2 = Location.create(pathA, propB); + + assertThat("Locations created with identical paths and different property must not be equal", locationA1, not(locationA2)); + } + + @Test + public void locationsWithSamePathsAndDifferentPropertyAreNotSame() { + Location locationA1 = Location.create(pathA, propA); + Location locationA2 = Location.create(pathA, propB); + + assertThat("isSame must not return true for locations created with identical paths and property", locationA1.isSame(locationA2), is(false)); + } + + @Test + public void locationsWithDifferentPathsAndSamePropertyAreNotEqual() { + Location locationA1 = Location.create(pathA, propA); + Location locationA2 = Location.create(pathABC, propA); + + assertThat("Locations created with different paths and the same property must not be equal", locationA1, not(locationA2)); + } + + @Test + public void locationsWithDifferentPathsAndSamePropertyAreNotSame() { + Location locationA1 = Location.create(pathA, propA); + Location locationA2 = Location.create(pathABC, propA); + + assertThat("isSame must not return true for locations created with different paths and the same property", locationA1.isSame(locationA2), is(false)); + } + + @Test + public void locationsWithSamePathsAndSamePropertiesAreNotEqual() { + Location locationA1 = Location.create(pathA, propListAB); + Location locationA2 = Location.create(pathA, propListAB); + + assertThat("Locations created with identical paths and different properties must be equal", locationA1, is(locationA2)); + } + + @Test + public void locationsWithSamePathsAndSamePropertiesAreNotSame() { + Location locationA1 = Location.create(pathA, propListAB); + Location locationA2 = Location.create(pathA, propListAB); + + assertThat("isSame must return true for locations created with identical paths and properties", locationA1.isSame(locationA2), is(true)); + } + + @Test + public void locationsWithSamePathsAndDifferentPropertiesAreNotEqual() { + Location locationA1 = Location.create(pathA, propListAB); + Location locationA2 = Location.create(pathA, propListABU); + + assertThat("Locations created with identical paths and different properties must not be equal", locationA1, not(locationA2)); + } + + @Test + public void locationsWithSamePathsAndDifferentPropertiesAreNotSame() { + Location locationA1 = Location.create(pathA, propListAB); + Location locationA2 = Location.create(pathA, propListABU); + + assertThat("isSame must not return true for locations created with identical paths and different properties", locationA1.isSame(locationA2), is(false)); + } + + @Test + public void locationsWithDifferentPathsAndSamePropertiesAreNotEqual() { + Location locationA1 = Location.create(pathA, propListAB); + Location locationA2 = Location.create(pathABC, propListAB); + + assertThat("Locations created with identical paths and different properties must not be equal", locationA1, not(locationA2)); + } + + @Test + public void locationsWithDifferentPathsAndSamePropertiesAreNotSame() { + Location locationA1 = Location.create(pathA, propListAB); + Location locationA2 = Location.create(pathABC, propListAB); + + assertThat("isSame must not return true for locations created with different paths and the same properties", locationA1.isSame(locationA2), is(false)); + } + + @Test + public void testTransitivityOfWithOperationForPathAndUUID() { + Location locationA1 = Location.create(pathA); + locationA1 = locationA1.with(uuid); + + Location locationU1 = Location.create(uuid); + locationU1 = locationU1.with(pathA); + + assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true)); + assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true)); + assertThat("With() operation must be transitive for getString", locationA1.getString().equals(locationU1.getString()), is(true)); + assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true)); + } + + @Test + public void testTransitivityOfWithOperationForPathAndProperty() { + Location locationA1 = Location.create(pathA); + locationA1 = locationA1.with(propB); + + Location locationU1 = Location.create(propB); + locationU1 = locationU1.with(pathA); + + assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true)); + assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true)); + assertThat("With() operation must be transitive for getString", locationA1.getString().equals(locationU1.getString()), is(true)); + assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true)); + } + +}