[dna-commits] DNA SVN: r733 - in trunk/dna-graph/src: test/java/org/jboss/dna/graph and 1 other directory.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Mon Feb 23 10:55:51 EST 2009


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

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

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

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

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathLocation.java	2009-02-23 15:55:50 UTC (rev 733)
@@ -0,0 +1,178 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph;
+
+import java.util.List;
+import java.util.UUID;
+
+import net.jcip.annotations.Immutable;
+
+import org.jboss.dna.common.text.TextEncoder;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+
+/**
+ * Special location type optimized for use when only a path is specified.
+ * This class should never be directly instantiated by users of the DNA framework.
+ * Instead, use @{link Location#create} to create the correct location.
+ *
+ * @see Location
+ */
+ at Immutable
+class PathLocation extends Location {
+
+	private final Path path;
+	private final int hashCode;
+
+	PathLocation(Path path) {
+		CheckArg.isNotNull(path, "path");
+
+		this.path = path;
+		
+		// Paths are immutable, so PathLocations are immutable...
+		// ... so we can cache the hash code.
+		hashCode = HashCode.compute(path);
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getPath()
+     */
+	@Override
+	public final Path getPath() {
+		return path;
+	}
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasPath()
+     */	
+	@Override
+	public final boolean hasPath() {
+		return true;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperties()
+     */	
+	@Override
+	public final List<Property> getIdProperties() {
+		return null;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */	
+	@Override
+	public final boolean hasIdProperties() {
+		return false;
+	}
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getUuid()
+     */	
+	@Override
+	public final UUID getUuid() {
+		return null;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hashCode()
+     */	
+	@Override
+	public int hashCode() {
+		return hashCode;
+	}
+		
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getString(NamespaceRegistry, TextEncoder, TextEncoder)
+     */	
+	@Override
+	public String getString(NamespaceRegistry namespaceRegistry, TextEncoder encoder, TextEncoder delimiterEncoder) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("{ ");
+		sb.append(path.getString(namespaceRegistry, encoder, delimiterEncoder));
+		sb.append(" }");
+		return sb.toString();
+	}
+
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Property)
+     */	
+	@Override
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+        return Location.create(path, newIdProperty);
+    }
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Path)
+     */	
+	@Override
+    public Location with( Path newPath ) {
+        if (newPath == null) return this;
+        if (!this.getPath().equals(newPath)) return Location.create(newPath);
+        return this;
+    }	
+	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(UUID)
+     */
+	@Override
+    public Location with( UUID uuid ) {
+        if (uuid == null) return this;
+        Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+        if (this.hasIdProperties()) {
+            Property existing = this.getIdProperty(DnaLexicon.UUID);
+            if (existing != null && existing.equals(newProperty)) return this;
+        }
+        return Location.create(path, uuid);
+    }	
+}


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

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertiesLocation.java	2009-02-23 15:55:50 UTC (rev 733)
@@ -0,0 +1,173 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import net.jcip.annotations.Immutable;
+
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+
+/**
+ * General purpose location type that supports a path and zero or more properties.
+ * This class should never be directly instantiated by users of the DNA framework.
+ * Instead, use @{link Location#create} to create the correct location.
+ *
+ * @see Location
+ */
+ at Immutable
+class PathPropertiesLocation extends Location {
+
+    private final Path path;
+    private final List<Property> idProperties;
+
+    private final int hashCode;
+    
+    /**
+     * Create a new location with a given path and set of identification properties.
+     * 
+     * @param path the path
+     * @param idProperties the identification properties
+     */
+	PathPropertiesLocation( Path path, List<Property> idProperties ) {
+		// The path could be null
+		// CheckArg.isNotNull(path, "path");
+		// If the properties are a null, a PathLocation should be used instead.
+		CheckArg.isNotNull(idProperties, "idProperties");
+		
+	    this.path = path;
+	    this.idProperties = Collections.unmodifiableList(idProperties);
+	    
+	    // Paths are immutable, Properties are immutable, the idProperties list 
+	    // is wrapped in an unmodifiableList by the Location factory methods...
+	    // ... so we can cache the hash code.
+	    
+	    hashCode = HashCode.compute(path, idProperties);
+	}
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getPath()
+     */
+	@Override
+	public final Path getPath() {
+		return path;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperties()
+     */	
+	@Override
+	public final List<Property> getIdProperties() {
+		return idProperties;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */	
+	@Override
+	public final boolean hasIdProperties() {
+		return idProperties.size() > 0;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hashCode()
+     */	
+	@Override
+	public int hashCode() {
+		return hashCode;
+	}	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Property)
+     */	
+	@Override
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+
+	    List<Property> newIdProperties;
+	    
+	    if (hasIdProperties()) {
+        	newIdProperties = new ArrayList<Property>(idProperties.size() + 1);
+            for (Property property : idProperties) {
+                if (!newIdProperty.getName().equals(property.getName())) newIdProperties.add(property);
+            }
+            newIdProperties.add(newIdProperty);
+            newIdProperties = Collections.unmodifiableList(newIdProperties);
+	    } else {
+	    	return Location.create(path, newIdProperty);
+	    }
+	    
+	    return new PathPropertiesLocation(path, newIdProperties);        
+    }    
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Path)
+     */	
+	@Override
+    public Location with( Path newPath ) {
+        if (newPath == null) return this;
+        if (!this.getPath().equals(newPath)) return Location.create(newPath, idProperties);
+        return this;
+    }	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(UUID)
+     */
+	@Override
+    public Location with( UUID uuid ) {
+        if (uuid == null) return this;
+        Property newProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+        if (this.hasIdProperties()) {
+            Property existing = this.getIdProperty(DnaLexicon.UUID);
+            if (existing != null && existing.equals(newProperty)) return this;
+        }
+        
+        List<Property> newIdProperties = new ArrayList<Property>(idProperties.size() + 1);
+        newIdProperties.addAll(idProperties);
+        newIdProperties.add(newProperty);
+        
+        return Location.create(path, newIdProperties);
+    }	
+}


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

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/PathPropertyLocation.java	2009-02-23 15:55:50 UTC (rev 733)
@@ -0,0 +1,197 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import net.jcip.annotations.Immutable;
+
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+
+/**
+ * General purpose location type that supports a path and a property.
+ * This class should never be directly instantiated by users of the DNA framework.
+ * Instead, use @{link Location#create} to create the correct location.
+ *
+ * @see Location
+ */
+ at Immutable
+class PathPropertyLocation extends Location {
+
+    private final Path path;
+    private final Property idProperty;
+    private final List<Property> idProperties;
+
+    private final int hashCode;
+    
+    /**
+     * Create a new location with a given path and identification property.
+     * 
+     * @param path the path
+     * @param idProperty the identification property
+     */
+    PathPropertyLocation( Path path, Property idProperty ) {
+		// The path could be null
+		// CheckArg.isNotNull(path, "path");
+		// If the properties are a null, a PathLocation should be used instead.
+		CheckArg.isNotNull(idProperty, "idProperty");
+		
+	    this.path = path;
+	    this.idProperty = idProperty;
+	    this.idProperties = Collections.singletonList(idProperty);
+	    
+	    // Paths are immutable, Properties are immutable, the idProperties list 
+	    // is wrapped in an unmodifiableList by the Location factory methods...
+	    // ... so we can cache the hash code.
+	    
+	    hashCode = HashCode.compute(path, idProperties);
+	}
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getPath()
+     */
+	@Override
+	public final Path getPath() {
+		return path;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperties()
+     */	
+	@Override
+	public final List<Property> getIdProperties() {
+		return idProperties;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hasIdProperties()
+     */	
+	@Override
+	public final boolean hasIdProperties() {
+		return true;
+	}
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getIdProperty(Name)
+     */	
+	@Override
+    public final Property getIdProperty( Name name ) {
+        CheckArg.isNotNull(name, "name");
+	    if (idProperty.getName().equals(name)) return idProperty;
+
+	    return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#getUuid()
+     */	
+	@Override
+    public UUID getUuid() {
+		if (DnaLexicon.UUID.equals(idProperty.getName())) {
+            Object value = idProperty.getFirstValue();
+            if (value instanceof UUID) return (UUID)value;
+        }
+        return null;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#hashCode()
+     */	
+	@Override
+	public int hashCode() {
+		return hashCode;
+	}	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Property)
+     */	
+	@Override
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+        
+        // A new property with same name overrides the old property with the same name
+        if (newIdProperty.getName().equals(idProperty.getName())) return Location.create(path, newIdProperty);
+        
+        List<Property> newIdProperties = new ArrayList<Property>(2);
+        newIdProperties.add(idProperty);
+        newIdProperties.add(newIdProperty);
+                
+        return Location.create(path, newIdProperties);
+    }    
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(Path)
+     */	
+	@Override
+    public Location with( Path newPath ) {
+        if (newPath == null && path == null) return this;
+        if (path != null && (path.equals(newPath))) return this;
+        
+        return Location.create(newPath, idProperty);
+    }	
+	
+    /**
+     * {@inheritDoc}
+     * 
+     * @see Location#with(UUID)
+     */
+	@Override
+    public Location with( UUID uuid ) {
+        if (uuid == null) return this;
+        
+        // A new property with same name overrides the old property with the same name
+        if (idProperty.getName().equals(DnaLexicon.UUID)) return Location.create(path, uuid);
+        
+        List<Property> newIdProperties = new ArrayList<Property>(2);
+        newIdProperties.add(idProperty);
+        newIdProperties.add(new BasicSingleValueProperty(DnaLexicon.UUID, uuid));
+        
+        return Location.create(path, newIdProperties);
+    }	
+}


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

Added: trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/LocationTest.java	2009-02-23 15:55:50 UTC (rev 733)
@@ -0,0 +1,235 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.jboss.dna.common.text.NoOpEncoder;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
+import org.jboss.dna.graph.property.basic.BasicSingleValueProperty;
+import org.jboss.dna.graph.property.basic.NameValueFactory;
+import org.jboss.dna.graph.property.basic.PathValueFactory;
+import org.jboss.dna.graph.property.basic.StringValueFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+/**
+ * Tests <code>Location</code> class and factory constructors.
+ */
+public class LocationTest {
+
+	private static final NoOpEncoder NO_OP_ENCODER = new NoOpEncoder();
+	private static final StringValueFactory STRING_VALUE_FACTORY = new StringValueFactory(NO_OP_ENCODER, NO_OP_ENCODER);
+	private static final NameValueFactory NAME_VALUE_FACTORY = new NameValueFactory(new BasicNamespaceRegistry("http://www.jboss.org/dna/1.0"), NO_OP_ENCODER, STRING_VALUE_FACTORY);
+	
+	private PathFactory pathFactory = new PathValueFactory(NO_OP_ENCODER, 
+			STRING_VALUE_FACTORY, NAME_VALUE_FACTORY);
+	
+	private static UUID uuid = UUID.randomUUID();
+	
+	private Path pathA = pathFactory.create("/A");
+	private Path pathABC = pathFactory.create("/A/B/C");
+
+	private static Property propA = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("A"), "Value A");
+	private static Property propB = new BasicSingleValueProperty(NAME_VALUE_FACTORY.create("B"), "Value B");
+	private static Property propU = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+	
+	private static List<Property> propListAB;
+	private static List<Property> propListABU;
+	
+	
+    @BeforeClass
+    public static void beforeAny() { 
+    	propListAB = new ArrayList<Property>();
+    	propListAB.add(propA);
+    	propListAB.add(propB);
+
+    	propListABU = new ArrayList<Property>();
+    	propListABU.add(propA);
+    	propListABU.add(propB);
+    	propListABU.add(propU);
+
+    }
+    
+    @Test
+    public void locationsWithSamePathsAreEqual() {
+    	Location locationA1 = Location.create(pathA);
+    	Location locationA2 = Location.create(pathA);
+    	
+    	assertThat("Locations created with identical paths must be equal", locationA1, is(locationA2));
+    	
+    	Location locationABC1 = Location.create(pathABC);
+    	Location locationABC2 = Location.create(pathABC);
+    	
+    	assertThat("Locations created with identical non-trivial paths must be equal", locationABC1, is(locationABC2));
+    }
+
+    @Test
+    public void locationsWithSamePathsAreSame() {
+    	Location locationA1 = Location.create(pathA);
+    	Location locationA2 = Location.create(pathA);
+    	
+    	assertThat("isSame must return true for locations created with identical paths", locationA1.isSame(locationA2), is(true));
+    	
+    	Location locationABC1 = Location.create(pathABC);
+    	Location locationABC2 = Location.create(pathABC);
+    	
+    	assertThat("isSame must return true for locations created with identical, non-trivial paths", locationABC1.isSame(locationABC2), is(true));
+    }
+
+    @Test
+    public void locationsWithSamePathsAndSamePropertyAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathA, propA);
+    	
+    	assertThat("Locations created with identical paths and different property must be equal", locationA1, is(locationA2));
+    }    
+
+    @Test
+    public void locationsWithSamePathsAndSamePropertyAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathA, propA);
+    	
+    	assertThat("isSame must return true for locations created with identical paths and property", locationA1.isSame(locationA2), is(true));
+    }   
+    
+    @Test
+    public void locationsWithSamePathsAndDifferentPropertyAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathA, propB);
+    	
+    	assertThat("Locations created with identical paths and different property must not be equal", locationA1, not(locationA2));
+    }    
+
+    @Test
+    public void locationsWithSamePathsAndDifferentPropertyAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathA, propB);
+    	
+    	assertThat("isSame must not return true for locations created with identical paths and property", locationA1.isSame(locationA2), is(false));
+    }    
+    
+    @Test
+    public void locationsWithDifferentPathsAndSamePropertyAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathABC, propA);
+    	
+    	assertThat("Locations created with different paths and the same property must not be equal", locationA1, not(locationA2));
+    }    
+
+    @Test
+    public void locationsWithDifferentPathsAndSamePropertyAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propA);
+    	Location locationA2 = Location.create(pathABC, propA);
+    	
+    	assertThat("isSame must not return true for locations created with different paths and the same property", locationA1.isSame(locationA2), is(false));
+    }      
+
+    @Test
+    public void locationsWithSamePathsAndSamePropertiesAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathA, propListAB);
+    	
+    	assertThat("Locations created with identical paths and different properties must be equal", locationA1, is(locationA2));
+    }    
+
+    @Test
+    public void locationsWithSamePathsAndSamePropertiesAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathA, propListAB);
+    	
+    	assertThat("isSame must return true for locations created with identical paths and properties", locationA1.isSame(locationA2), is(true));
+    }   
+    
+    @Test
+    public void locationsWithSamePathsAndDifferentPropertiesAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathA, propListABU);
+    	
+    	assertThat("Locations created with identical paths and different properties must not be equal", locationA1, not(locationA2));
+    }    
+
+    @Test
+    public void locationsWithSamePathsAndDifferentPropertiesAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathA, propListABU);
+    	
+    	assertThat("isSame must not return true for locations created with identical paths and different properties", locationA1.isSame(locationA2), is(false));
+    }    
+    
+    @Test
+    public void locationsWithDifferentPathsAndSamePropertiesAreNotEqual() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathABC, propListAB);
+    	
+    	assertThat("Locations created with identical paths and different properties must not be equal", locationA1, not(locationA2));
+    }    
+
+    @Test
+    public void locationsWithDifferentPathsAndSamePropertiesAreNotSame() {
+    	Location locationA1 = Location.create(pathA, propListAB);
+    	Location locationA2 = Location.create(pathABC, propListAB);
+    	
+    	assertThat("isSame must not return true for locations created with different paths and the same properties", locationA1.isSame(locationA2), is(false));
+    }    
+    
+    @Test
+    public void testTransitivityOfWithOperationForPathAndUUID() {
+    	Location locationA1 = Location.create(pathA);
+    	locationA1 = locationA1.with(uuid);
+    	
+    	Location locationU1 = Location.create(uuid);
+    	locationU1 = locationU1.with(pathA);
+    	
+    	assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true));
+    	assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true));
+    	assertThat("With() operation must be transitive for getString", locationA1.getString().equals(locationU1.getString()), is(true));
+    	assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true));
+    }
+        
+    @Test
+    public void testTransitivityOfWithOperationForPathAndProperty() {
+    	Location locationA1 = Location.create(pathA);
+    	locationA1 = locationA1.with(propB);
+    	
+    	Location locationU1 = Location.create(propB);
+    	locationU1 = locationU1.with(pathA);
+    	
+    	assertThat("With() operation must be transitive for equals", locationA1.equals(locationU1), is(true));
+    	assertThat("With() operation must be transitive for isSame", locationA1.isSame(locationU1), is(true));
+    	assertThat("With() operation must be transitive for getString", locationA1.getString().equals(locationU1.getString()), is(true));
+    	assertThat("With() operation must be transitive for hashCode", locationA1.hashCode() == locationU1.hashCode(), is(true));
+    } 
+
+}


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




More information about the dna-commits mailing list