Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 518   Methods: 28
NCLOC: 241   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Fqn.java 94.4% 95.5% 100% 96.1%
coverage coverage
 1    /*
 2    * JBoss, the OpenSource J2EE webOS
 3    *
 4    * Distributable under LGPL license.
 5    * See terms of license at gnu.org.
 6    */
 7    package org.jboss.cache;
 8   
 9   
 10    import net.jcip.annotations.Immutable;
 11    import org.apache.commons.logging.Log;
 12    import org.apache.commons.logging.LogFactory;
 13   
 14    import java.io.Externalizable;
 15    import java.io.IOException;
 16    import java.io.ObjectInput;
 17    import java.io.ObjectOutput;
 18    import java.util.ArrayList;
 19    import java.util.Arrays;
 20    import java.util.Collections;
 21    import java.util.List;
 22    import java.util.StringTokenizer;
 23   
 24    /**
 25    * A Fully Qualified Name (Fqn) is a list of names (typically Strings but can be any Object),
 26    * which represent a path to a particular {@link Node} or sometimes a {@link Region} in a {@link Cache}.
 27    * <p/>
 28    * This name can be absolute (i.e., relative from the root node - {@link #ROOT}), or relative to any node in the cache. Reading the
 29    * documentation on each API call that makes use of {@link org.jboss.cache.Fqn}s will tell you whether the API expects a
 30    * relative or absolute Fqn.
 31    * <p/>
 32    * For instance, using this class to fetch a particular node might look like
 33    * this. (Here data on "Joe" is kept under the "Smith" surname node, under
 34    * the "people" tree.)
 35    * <pre>
 36    * Fqn<String> abc = Fqn.fromString("/people/Smith/Joe/");
 37    * Node joesmith = Cache.getRoot().getChild(abc);
 38    * </pre>
 39    * Alternatively, the same Fqn could be constructed using an array:
 40    * <pre>
 41    * Fqn<String> abc = new Fqn<String>(new String[] { "people", "Smith", "Joe" });
 42    * </pre>
 43    * This is a bit more efficient to construct.
 44    * <p/>
 45    * <p/>
 46    * Note that<br>
 47    * <p/>
 48    * <code>Fqn<String> f = new Fqn<String>("/a/b/c");</code>
 49    * <p/>
 50    * is <b>not</b> the same as
 51    * <p/>
 52    * <code>Fqn<String> f = Fqn.fromString("/a/b/c");</code>
 53    * <p/>
 54    * The former will result in a single Fqn, called "/a/b/c" which hangs directly under Fqn.ROOT.
 55    * <p/>
 56    * The latter will result in 3 Fqns, called "a", "b" and "c", where "c" is a child of "b", "b" is a child of "a", and "a" hangs off Fqn.ROOT.
 57    * <p/>
 58    * Another way to look at it is that the "/" separarator is only parsed when it forms
 59    * part of a String passed in to Fqn.fromString() and not otherwise.
 60    *
 61    * @version $Revision: 1.54 $
 62    */
 63    @Immutable
 64    public class Fqn<E> implements Cloneable, Externalizable, Comparable<Fqn>
 65    {
 66   
 67    /**
 68    * Separator between FQN elements.
 69    */
 70    public static final String SEPARATOR = "/";
 71    private static final long serialVersionUID = -5351930616956603651L;
 72    private List<E> elements;
 73    private transient int hash_code = 0;
 74   
 75    /**
 76    * Immutable root FQN.
 77    */
 78    public static final Fqn ROOT = new Fqn();
 79    private static Log log = LogFactory.getLog(Fqn.class);
 80    // a cached string representation of this Fqn, used by toString to it isn't calculated again every time.
 81    private String cachedStringRep;
 82   
 83    /**
 84    * Constructs a root Fqn
 85    */
 86  25816 public Fqn()
 87    {
 88  25816 elements = Collections.emptyList();
 89    }
 90   
 91    /**
 92    * Constructs a FQN from a list of names.
 93    *
 94    * @param names List of names
 95    */
 96  7827474 public Fqn(List<E> names)
 97    {
 98    // the list is unsafe - may be referenced externally
 99  7828769 this(names, false);
 100    }
 101   
 102    /**
 103    * If safe is false, Collections.unmodifiableList() is used to wrap the list passed in. This is an optimisation so
 104    * Fqn.fromString(), probably the most frequently used factory method, doesn't end up needing to use the unmodifiableList()
 105    * since it creates the list internally.
 106    *
 107    * @param names List of names
 108    * @param safe whether this list is referenced externally (safe = false) or not (safe = true).
 109    */
 110  9066444 protected Fqn(List<E> names, boolean safe)
 111    {
 112  9066445 if (names != null)
 113    {
 114    // if not safe make a defensive copy
 115  9066445 elements = safe ? names : new ArrayList<E>(names);
 116    }
 117    else
 118    {
 119  0 elements = Collections.emptyList();
 120    }
 121    }
 122   
 123   
 124    /**
 125    * Constructs a Fqn from an array of names.
 126    *
 127    * @param names Names that comprose this Fqn
 128    */
 129  168414 public Fqn(E... names)
 130    {
 131    // safe - the list is created here.
 132  168414 this(Arrays.asList(names), true);
 133    }
 134   
 135    /**
 136    * Constructs a Fqn from a base and relative Fqn.
 137    *
 138    * @param base parent Fqn
 139    * @param relative Sub-Fqn relative to the parent
 140    */
 141  57214 public Fqn(Fqn<E> base, Fqn<E> relative)
 142    {
 143  57214 this(base, relative.elements);
 144    }
 145   
 146    /**
 147    * Constructs a Fqn from a base and a list of relative names.
 148    *
 149    * @param base parent Fqn
 150    * @param relative List of elements that identify the child Fqn, relative to the parent
 151    */
 152  57222 public Fqn(Fqn<E> base, List<E> relative)
 153    {
 154  57222 List<E> elements = new ArrayList<E>(base.elements.size() + relative.size());
 155  57222 elements.addAll(base.elements);
 156  57222 elements.addAll(relative);
 157  57222 this.elements = elements;
 158    }
 159   
 160    /**
 161    * Constructs a Fqn from a base and two relative names.
 162    *
 163    * @param base parent Fqn
 164    * @param childNames elements that denote the path to the Fqn, under the parent
 165    */
 166  1389605 public Fqn(Fqn<E> base, E... childNames)
 167    {
 168  1389605 List<E> elements = new ArrayList<E>(base.elements.size() + childNames.length);
 169  1389605 elements.addAll(base.elements);
 170  1389605 elements.addAll(Arrays.asList(childNames));
 171  1389605 this.elements = elements;
 172    }
 173   
 174    /**
 175    * Returns a new Fqn from a string, where the elements are deliminated by
 176    * one or more separator ({@link #SEPARATOR}) characters.<br><br>
 177    * Example use:<br>
 178    * <pre>
 179    * Fqn.fromString("/a/b/c/");
 180    * </pre><br>
 181    * is equivalent to:<br>
 182    * <pre>
 183    * new Fqn("a", "b", "c");
 184    * </pre><br>
 185    * but not<br>
 186    * <pre>
 187    * new Fqn("/a/b/c");
 188    * </pre>
 189    *
 190    * @param stringRepresentation String representation of the Fqn
 191    * @return an Fqn<String> constructed from the string representation passed in
 192    * @see #Fqn(Object[])
 193    */
 194  1069263 public static Fqn<String> fromString(String stringRepresentation)
 195    {
 196  1069263 if (stringRepresentation == null)
 197    {
 198  1 return Fqn.ROOT;
 199    }
 200  1069262 List<String> list = new ArrayList<String>();
 201  1069262 StringTokenizer tok = new StringTokenizer(stringRepresentation, SEPARATOR);
 202  2615110 while (tok.hasMoreTokens()) list.add(tok.nextToken());
 203  1069262 return new Fqn<String>(list, true);
 204    }
 205   
 206    /**
 207    * Obtains an ancestor of the current Fqn. Literally performs <code>elements.subList(0, generation)</code>
 208    * such that if
 209    * <code>
 210    * generation == Fqn.size()
 211    * </code>
 212    * then the return value is the Fqn itself (current generation), and if
 213    * <code>
 214    * generation == Fqn.size() - 1
 215    * </code>
 216    * then the return value is the same as
 217    * <code>
 218    * Fqn.getParent()
 219    * </code>
 220    * i.e., just one generation behind the current generation.
 221    * <code>
 222    * generation == 0
 223    * </code>
 224    * would return Fqn.ROOT.
 225    *
 226    * @param generation the generation of the ancestor to retrieve
 227    * @return an ancestor of the current Fqn
 228    */
 229  7224 public Fqn<E> getAncestor(int generation)
 230    {
 231  420 if (generation == 0) return Fqn.ROOT;
 232  6804 return getSubFqn(0, generation);
 233    }
 234   
 235    /**
 236    * Obtains a sub-Fqn from the given Fqn. Literally performs <code>elements.subList(startIndex, endIndex)</code>
 237    */
 238  6977 public Fqn<E> getSubFqn(int startIndex, int endIndex)
 239    {
 240  6977 return new Fqn<E>(elements.subList(startIndex, endIndex));
 241    }
 242   
 243    /**
 244    * @return the number of elements in the Fqn. The root node contains zero.
 245    */
 246  12417794 public int size()
 247    {
 248  12417776 return elements.size();
 249    }
 250   
 251    /**
 252    * @param n index of the element to return
 253    * @return Returns the nth element in the Fqn.
 254    */
 255  26968136 public E get(int n)
 256    {
 257  26968132 return elements.get(n);
 258    }
 259   
 260    /**
 261    * @return the last element in the Fqn.
 262    * @see #getLastElementAsString
 263    */
 264  1901480 public E getLastElement()
 265    {
 266  1428095 if (isRoot()) return null;
 267  473385 return elements.get(elements.size() - 1);
 268    }
 269   
 270    /**
 271    * @param element element to find
 272    * @return true if the Fqn contains this element, false otherwise.
 273    */
 274  228792 public boolean hasElement(E element)
 275    {
 276  228789 return elements.lastIndexOf(element) != -1;
 277    }
 278   
 279    /**
 280    * Clones the Fqn.
 281    */
 282  4 public Fqn<E> clone() throws CloneNotSupportedException
 283    {
 284  4 try
 285    {
 286  4 return (Fqn<E>) super.clone();
 287    }
 288    catch (CloneNotSupportedException e)
 289    {
 290  0 log.error("Unable to clone Fqn " + this, e);
 291  0 return null;
 292    }
 293    }
 294   
 295    /**
 296    * Returns true if obj is a Fqn with the same elements.
 297    */
 298  25413298 public boolean equals(Object obj)
 299    {
 300  25413298 if (this == obj)
 301    {
 302  5077813 return true;
 303    }
 304  20335485 if (!(obj instanceof Fqn))
 305    {
 306  436 return false;
 307    }
 308  20335049 Fqn other = (Fqn) obj;
 309  20335049 return elements.equals(other.elements);
 310    }
 311   
 312    /**
 313    * Returns a hash code with Fqn elements.
 314    */
 315  23642915 public int hashCode()
 316    {
 317  23642915 if (hash_code == 0)
 318    {
 319  8996738 hash_code = _hashCode();
 320    }
 321  23642905 return hash_code;
 322    }
 323   
 324    /**
 325    * Returns this Fqn as a string, prefixing the first element with a {@link Fqn#SEPARATOR} and
 326    * joining each subsequent element with a {@link Fqn#SEPARATOR}.
 327    * If this is the root Fqn, returns {@link Fqn#SEPARATOR}.
 328    * Example:
 329    * <pre>
 330    * new Fqn(new Object[] { "a", "b", "c" }).toString(); // "/a/b/c"
 331    * Fqn.ROOT.toString(); // "/"
 332    * </pre>
 333    */
 334  1484746 public String toString()
 335    {
 336  1484748 if (cachedStringRep == null)
 337    {
 338  842460 if (isRoot())
 339    {
 340  306 cachedStringRep = SEPARATOR;
 341    }
 342    else
 343    {
 344  842154 StringBuffer sb = new StringBuffer();
 345  842154 for (E element : elements)
 346    {
 347  4710803 sb.append(SEPARATOR).append(element);
 348    }
 349  842154 cachedStringRep = sb.toString();
 350    }
 351    }
 352  1484748 return cachedStringRep;
 353    }
 354   
 355  58200 public void writeExternal(ObjectOutput out) throws IOException
 356    {
 357  58200 out.writeShort(elements.size());
 358  58200 for (E element : elements)
 359    {
 360  207550 out.writeObject(element);
 361    }
 362    }
 363   
 364  25445 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
 365    {
 366  25445 short length = in.readShort();
 367  25445 this.elements = new ArrayList<E>(length);
 368  25445 for (int i = 0; i < length; i++)
 369    {
 370  70897 elements.add((E) in.readObject());
 371    }
 372    }
 373   
 374   
 375    /**
 376    * Returns true if this Fqn is child of parentFqn.
 377    * Example usage:
 378    * <pre>
 379    * Fqn<String> f1 = Fqn.fromString("/a/b");
 380    * Fqn<String> f2 = Fqn.fromString("/a/b/c");
 381    * assertTrue(f1.isChildOf(f2));
 382    * assertFalse(f1.isChildOf(f1));
 383    * assertFalse(f2.isChildOf(f1));
 384    * </pre>
 385    *
 386    * @param parentFqn candidate parent to test against
 387    * @return true if the target is a child of parentFqn
 388    */
 389  4455 public boolean isChildOf(Fqn<E> parentFqn)
 390    {
 391  4455 return parentFqn.elements.size() != elements.size() && isChildOrEquals(parentFqn);
 392    }
 393   
 394    /**
 395    * Returns true if this Fqn is equals or the child of parentFqn.
 396    * Example usage:
 397    * <pre>
 398    * Fqn<String> f1 = Fqn.fromString("/a/b");
 399    * Fqn<String> f2 = Fqn.fromString("/a/b/c");
 400    * assertTrue(f1.isChildOrEquals(f2));
 401    * assertTrue(f1.isChildOrEquals(f1));
 402    * assertFalse(f2.isChildOrEquals(f1));
 403    * </pre>
 404    *
 405    * @param parentFqn candidate parent to test against
 406    * @return true if this Fqn is equals or the child of parentFqn.
 407    */
 408  30395 public boolean isChildOrEquals(Fqn<E> parentFqn)
 409    {
 410  30395 List<E> parentList = parentFqn.elements;
 411  30395 if (parentList.size() > elements.size())
 412    {
 413  1964 return false;
 414    }
 415  28431 for (int i = parentList.size() - 1; i >= 0; i--)
 416    {
 417  34097 if (!parentList.get(i).equals(elements.get(i)))
 418    {
 419  5054 return false;
 420    }
 421    }
 422  23377 return true;
 423    }
 424   
 425    /**
 426    * Calculates a hash code by summing the hash code of all elements.
 427    *
 428    * @return a cached hashcode
 429    */
 430  8996738 private int _hashCode()
 431    {
 432  8996738 int hashCode = 0;
 433  8996738 int count = 1;
 434  8996738 Object o;
 435  8996738 for (E element : elements)
 436    {
 437  35721465 o = element;
 438  35721545 hashCode += (o == null) ? 0 : o.hashCode() * count++;
 439    }
 440  8996738 if (hashCode == 0)// fix degenerate case
 441    {
 442  542 hashCode = 0xFEED;
 443    }
 444  8996738 return hashCode;
 445    }
 446   
 447    /**
 448    * Returns the parent of this Fqn.
 449    * The parent of the root node is {@link #ROOT}.
 450    * Examples:
 451    * <pre>
 452    * Fqn<String> f1 = Fqn.fromString("/a");
 453    * Fqn<String> f2 = Fqn.fromString("/a/b");
 454    * assertEquals(f1, f2.getParent());
 455    * assertEquals(Fqn.ROOT, f1.getParent().getParent());
 456    * assertEquals(Fqn.ROOT, Fqn.ROOT.getParent());
 457    * </pre>
 458    *
 459    * @return the parent Fqn
 460    */
 461  8314895 public Fqn<E> getParent()
 462    {
 463  8314895 switch (elements.size())
 464    {
 465  4495 case 0:
 466  798707 case 1:
 467  803202 return ROOT;
 468  7511693 default:
 469  7511693 return new Fqn<E>(elements.subList(0, elements.size() - 1));
 470    }
 471    }
 472   
 473    /**
 474    * Returns true if this is a root Fqn.
 475    *
 476    * @return true if the Fqn is Fqn.ROOT.
 477    */
 478  11474061 public boolean isRoot()
 479    {
 480  11474061 return elements.isEmpty();
 481    }
 482   
 483    /**
 484    * If this is the root, returns {@link Fqn#SEPARATOR}.
 485    *
 486    * @return a String representation of the last element that makes up this Fqn.
 487    */
 488  47 public String getLastElementAsString()
 489    {
 490  47 if (isRoot())
 491    {
 492  0 return SEPARATOR;
 493    }
 494    else
 495    {
 496  47 return String.valueOf(getLastElement());
 497    }
 498    }
 499   
 500    /**
 501    * Peeks into the elements that build up this Fqn. The list returned is
 502    * read-only, to maintain the immutable nature of Fqn.
 503    *
 504    * @return an unmodifiable list
 505    */
 506  3205 public List<E> peekElements()
 507    {
 508  3205 return elements;
 509    }
 510   
 511    /**
 512    * Compares this Fqn to another using {@link FqnComparator}.
 513    */
 514  1363 public int compareTo(Fqn Fqn)
 515    {
 516  1363 return FqnComparator.INSTANCE.compare(this, Fqn);
 517    }
 518    }