1 /*
   2  * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.naming;
  27 
  28 import java.util.Enumeration;
  29 import java.util.Properties;
  30 
  31 /**
  32  * This class represents a composite name -- a sequence of
  33  * component names spanning multiple namespaces.
  34  * Each component is a string name from the namespace of a
  35  * naming system. If the component comes from a hierarchical
  36  * namespace, that component can be further parsed into
  37  * its atomic parts by using the CompoundName class.
  38  *<p>
  39  * The components of a composite name are numbered.  The indexes of a
  40  * composite name with N components range from 0 up to, but not including, N.
  41  * This range may be written as [0,N).
  42  * The most significant component is at index 0.
  43  * An empty composite name has no components.
  44  *
  45  * <h1>JNDI Composite Name Syntax</h1>
  46  * JNDI defines a standard string representation for composite names. This
  47  * representation is the concatenation of the components of a composite name
  48  * from left to right using the component separator (a forward
  49  * slash character (/)) to separate each component.
  50  * The JNDI syntax defines the following meta characters:
  51  * <ul>
  52  * <li>escape (backward slash \),
  53  * <li>quote characters  (single (') and double quotes (")), and
  54  * <li>component separator (forward slash character (/)).
  55  * </ul>
  56  * Any occurrence of a leading quote, an escape preceding any meta character,
  57  * an escape at the end of a component, or a component separator character
  58  * in an unquoted component must be preceded by an escape character when
  59  * that component is being composed into a composite name string.
  60  * Alternatively, to avoid adding escape characters as described,
  61  * the entire component can be quoted using matching single quotes
  62  * or matching double quotes. A single quote occurring within a double-quoted
  63  * component is not considered a meta character (and need not be escaped),
  64  * and vice versa.
  65  *<p>
  66  * When two composite names are compared, the case of the characters
  67  * is significant.
  68  *<p>
  69  * A leading component separator (the composite name string begins with
  70  * a separator) denotes a leading empty component (a component consisting
  71  * of an empty string).
  72  * A trailing component separator (the composite name string ends with
  73  * a separator) denotes a trailing empty component.
  74  * Adjacent component separators denote an empty component.
  75  *
  76  *<h1>Composite Name Examples</h1>
  77  *This table shows examples of some composite names. Each row shows
  78  *the string form of a composite name and its corresponding structural form
  79  *(<tt>CompositeName</tt>).
  80  *
  81 <table border="1" cellpadding=3 summary="examples showing string form of composite name and its corresponding structural form (CompositeName)">
  82 
  83 <tr>
  84 <th>String Name</th>
  85 <th>CompositeName</th>
  86 </tr>
  87 
  88 <tr>
  89 <td>
  90 ""
  91 </td>
  92 <td>{} (the empty name == new CompositeName("") == new CompositeName())
  93 </td>
  94 </tr>
  95 
  96 <tr>
  97 <td>
  98 "x"
  99 </td>
 100 <td>{"x"}
 101 </td>
 102 </tr>
 103 
 104 <tr>
 105 <td>
 106 "x/y"
 107 </td>
 108 <td>{"x", "y"}</td>
 109 </tr>
 110 
 111 <tr>
 112 <td>"x/"</td>
 113 <td>{"x", ""}</td>
 114 </tr>
 115 
 116 <tr>
 117 <td>"/x"</td>
 118 <td>{"", "x"}</td>
 119 </tr>
 120 
 121 <tr>
 122 <td>"/"</td>
 123 <td>{""}</td>
 124 </tr>
 125 
 126 <tr>
 127 <td>"//"</td>
 128 <td>{"", ""}</td>
 129 </tr>
 130 
 131 <tr><td>"/x/"</td>
 132 <td>{"", "x", ""}</td>
 133 </tr>
 134 
 135 <tr><td>"x//y"</td>
 136 <td>{"x", "", "y"}</td>
 137 </tr>
 138 </table>
 139  *
 140  *<h1>Composition Examples</h1>
 141  * Here are some composition examples.  The right column shows composing
 142  * string composite names while the left column shows composing the
 143  * corresponding <tt>CompositeName</tt>s.  Notice that composing the
 144  * string forms of two composite names simply involves concatenating
 145  * their string forms together.
 146 
 147 <table border="1" cellpadding=3 summary="composition examples showing string names and composite names">
 148 
 149 <tr>
 150 <th>String Names</th>
 151 <th>CompositeNames</th>
 152 </tr>
 153 
 154 <tr>
 155 <td>
 156 "x/y"           + "/"   = x/y/
 157 </td>
 158 <td>
 159 {"x", "y"}      + {""}  = {"x", "y", ""}
 160 </td>
 161 </tr>
 162 
 163 <tr>
 164 <td>
 165 ""              + "x"   = "x"
 166 </td>
 167 <td>
 168 {}              + {"x"} = {"x"}
 169 </td>
 170 </tr>
 171 
 172 <tr>
 173 <td>
 174 "/"             + "x"   = "/x"
 175 </td>
 176 <td>
 177 {""}            + {"x"} = {"", "x"}
 178 </td>
 179 </tr>
 180 
 181 <tr>
 182 <td>
 183 "x"   + ""      + ""    = "x"
 184 </td>
 185 <td>
 186 {"x"} + {}      + {}    = {"x"}
 187 </td>
 188 </tr>
 189 
 190 </table>
 191  *
 192  *<h1>Multithreaded Access</h1>
 193  * A <tt>CompositeName</tt> instance is not synchronized against concurrent
 194  * multithreaded access. Multiple threads trying to access and modify a
 195  * <tt>CompositeName</tt> should lock the object.
 196  *
 197  * @author Rosanna Lee
 198  * @author Scott Seligman
 199  * @since 1.3
 200  */
 201 
 202 
 203 public class CompositeName implements Name {
 204 
 205     private transient NameImpl impl;
 206     /**
 207       * Constructs a new composite name instance using the components
 208       * specified by 'comps'. This protected method is intended to be
 209       * to be used by subclasses of CompositeName when they override
 210       * methods such as clone(), getPrefix(), getSuffix().
 211       *
 212       * @param comps A non-null enumeration containing the components for the new
 213       *              composite name. Each element is of class String.
 214       *               The enumeration will be consumed to extract its
 215       *               elements.
 216       */
 217     protected CompositeName(Enumeration<String> comps) {
 218         impl = new NameImpl(null, comps); // null means use default syntax
 219     }
 220 
 221     /**
 222       * Constructs a new composite name instance by parsing the string n
 223       * using the composite name syntax (left-to-right, slash separated).
 224       * The composite name syntax is described in detail in the class
 225       * description.
 226       *
 227       * @param  n       The non-null string to parse.
 228       * @exception InvalidNameException If n has invalid composite name syntax.
 229       */
 230     public CompositeName(String n) throws InvalidNameException {
 231         impl = new NameImpl(null, n);  // null means use default syntax
 232     }
 233 
 234     /**
 235       * Constructs a new empty composite name. Such a name returns true
 236       * when <code>isEmpty()</code> is invoked on it.
 237       */
 238     public CompositeName() {
 239         impl = new NameImpl(null);  // null means use default syntax
 240     }
 241 
 242     /**
 243       * Generates the string representation of this composite name.
 244       * The string representation consists of enumerating in order
 245       * each component of the composite name and separating
 246       * each component by a forward slash character. Quoting and
 247       * escape characters are applied where necessary according to
 248       * the JNDI syntax, which is described in the class description.
 249       * An empty component is represented by an empty string.
 250       *
 251       * The string representation thus generated can be passed to
 252       * the CompositeName constructor to create a new equivalent
 253       * composite name.
 254       *
 255       * @return A non-null string representation of this composite name.
 256       */
 257     public String toString() {
 258         return impl.toString();
 259     }
 260 
 261     /**
 262       * Determines whether two composite names are equal.
 263       * If obj is null or not a composite name, false is returned.
 264       * Two composite names are equal if each component in one is equal
 265       * to the corresponding component in the other. This implies
 266       * both have the same number of components, and each component's
 267       * equals() test against the corresponding component in the other name
 268       * returns true.
 269       *
 270       * @param  obj     The possibly null object to compare against.
 271       * @return true if obj is equal to this composite name, false otherwise.
 272       * @see #hashCode
 273       */
 274     public boolean equals(Object obj) {
 275         return (obj != null &&
 276                 obj instanceof CompositeName &&
 277                 impl.equals(((CompositeName)obj).impl));
 278     }
 279 
 280     /**
 281       * Computes the hash code of this composite name.
 282       * The hash code is the sum of the hash codes of individual components
 283       * of this composite name.
 284       *
 285       * @return An int representing the hash code of this name.
 286       * @see #equals
 287       */
 288     public int hashCode() {
 289         return impl.hashCode();
 290     }
 291 
 292 
 293     /**
 294      * Compares this CompositeName with the specified Object for order.
 295      * Returns a
 296      * negative integer, zero, or a positive integer as this Name is less
 297      * than, equal to, or greater than the given Object.
 298      * <p>
 299      * If obj is null or not an instance of CompositeName, ClassCastException
 300      * is thrown.
 301      * <p>
 302      * See equals() for what it means for two composite names to be equal.
 303      * If two composite names are equal, 0 is returned.
 304      * <p>
 305      * Ordering of composite names follows the lexicographical rules for
 306      * string comparison, with the extension that this applies to all
 307      * the components in the composite name. The effect is as if all the
 308      * components were lined up in their specified ordered and the
 309      * lexicographical rules applied over the two line-ups.
 310      * If this composite name is "lexicographically" lesser than obj,
 311      * a negative number is returned.
 312      * If this composite name is "lexicographically" greater than obj,
 313      * a positive number is returned.
 314      * @param obj The non-null object to compare against.
 315      *
 316      * @return  a negative integer, zero, or a positive integer as this Name
 317      *          is less than, equal to, or greater than the given Object.
 318      * @exception ClassCastException if obj is not a CompositeName.
 319      */
 320     public int compareTo(Object obj) {
 321         if (!(obj instanceof CompositeName)) {
 322             throw new ClassCastException("Not a CompositeName");
 323         }
 324         return impl.compareTo(((CompositeName)obj).impl);
 325     }
 326 
 327     /**
 328       * Generates a copy of this composite name.
 329       * Changes to the components of this composite name won't
 330       * affect the new copy and vice versa.
 331       *
 332       * @return A non-null copy of this composite name.
 333       */
 334     public Object clone() {
 335         return (new CompositeName(getAll()));
 336     }
 337 
 338     /**
 339       * Retrieves the number of components in this composite name.
 340       *
 341       * @return The nonnegative number of components in this composite name.
 342       */
 343     public int size() {
 344         return (impl.size());
 345     }
 346 
 347     /**
 348       * Determines whether this composite name is empty. A composite name
 349       * is empty if it has zero components.
 350       *
 351       * @return true if this composite name is empty, false otherwise.
 352       */
 353     public boolean isEmpty() {
 354         return (impl.isEmpty());
 355     }
 356 
 357     /**
 358       * Retrieves the components of this composite name as an enumeration
 359       * of strings.
 360       * The effects of updates to this composite name on this enumeration
 361       * is undefined.
 362       *
 363       * @return A non-null enumeration of the components of
 364       *         this composite name. Each element of the enumeration is of
 365       *         class String.
 366       */
 367     public Enumeration<String> getAll() {
 368         return (impl.getAll());
 369     }
 370 
 371     /**
 372       * Retrieves a component of this composite name.
 373       *
 374       * @param  posn    The 0-based index of the component to retrieve.
 375       *                 Must be in the range [0,size()).
 376       * @return The non-null component at index posn.
 377       * @exception ArrayIndexOutOfBoundsException if posn is outside the
 378       *         specified range.
 379       */
 380     public String get(int posn) {
 381         return (impl.get(posn));
 382     }
 383 
 384     /**
 385       * Creates a composite name whose components consist of a prefix of the
 386       * components in this composite name. Subsequent changes to
 387       * this composite name does not affect the name that is returned.
 388       *
 389       * @param  posn    The 0-based index of the component at which to stop.
 390       *                 Must be in the range [0,size()].
 391       * @return A composite name consisting of the components at indexes in
 392       *         the range [0,posn).
 393       * @exception ArrayIndexOutOfBoundsException
 394       *         If posn is outside the specified range.
 395       */
 396     public Name getPrefix(int posn) {
 397         Enumeration<String> comps = impl.getPrefix(posn);
 398         return (new CompositeName(comps));
 399     }
 400 
 401     /**
 402       * Creates a composite name whose components consist of a suffix of the
 403       * components in this composite name. Subsequent changes to
 404       * this composite name does not affect the name that is returned.
 405       *
 406       * @param  posn    The 0-based index of the component at which to start.
 407       *                 Must be in the range [0,size()].
 408       * @return A composite name consisting of the components at indexes in
 409       *         the range [posn,size()).  If posn is equal to
 410       *         size(), an empty composite name is returned.
 411       * @exception ArrayIndexOutOfBoundsException
 412       *         If posn is outside the specified range.
 413       */
 414     public Name getSuffix(int posn) {
 415         Enumeration<String> comps = impl.getSuffix(posn);
 416         return (new CompositeName(comps));
 417     }
 418 
 419     /**
 420       * Determines whether a composite name is a prefix of this composite name.
 421       * A composite name 'n' is a prefix if it is equal to
 422       * getPrefix(n.size())--in other words, this composite name
 423       * starts with 'n'. If 'n' is null or not a composite name, false is returned.
 424       *
 425       * @param  n       The possibly null name to check.
 426       * @return true if n is a CompositeName and
 427       *         is a prefix of this composite name, false otherwise.
 428       */
 429     public boolean startsWith(Name n) {
 430         if (n instanceof CompositeName) {
 431             return (impl.startsWith(n.size(), n.getAll()));
 432         } else {
 433             return false;
 434         }
 435     }
 436 
 437     /**
 438       * Determines whether a composite name is a suffix of this composite name.
 439       * A composite name 'n' is a suffix if it it is equal to
 440       * getSuffix(size()-n.size())--in other words, this
 441       * composite name ends with 'n'.
 442       * If n is null or not a composite name, false is returned.
 443       *
 444       * @param  n       The possibly null name to check.
 445       * @return true if n is a CompositeName and
 446       *         is a suffix of this composite name, false otherwise.
 447       */
 448     public boolean endsWith(Name n) {
 449         if (n instanceof CompositeName) {
 450             return (impl.endsWith(n.size(), n.getAll()));
 451         } else {
 452             return false;
 453         }
 454     }
 455 
 456     /**
 457       * Adds the components of a composite name -- in order -- to the end of
 458       * this composite name.
 459       *
 460       * @param suffix   The non-null components to add.
 461       * @return The updated CompositeName, not a new one. Cannot be null.
 462       * @exception InvalidNameException If suffix is not a composite name.
 463       */
 464     public Name addAll(Name suffix)
 465         throws InvalidNameException
 466     {
 467         if (suffix instanceof CompositeName) {
 468             impl.addAll(suffix.getAll());
 469             return this;
 470         } else {
 471             throw new InvalidNameException("Not a composite name: " +
 472                 suffix.toString());
 473         }
 474     }
 475 
 476     /**
 477       * Adds the components of a composite name -- in order -- at a specified
 478       * position within this composite name.
 479       * Components of this composite name at or after the index of the first
 480       * new component are shifted up (away from index 0)
 481       * to accommodate the new components.
 482       *
 483       * @param n        The non-null components to add.
 484       * @param posn     The index in this name at which to add the new
 485       *                 components.  Must be in the range [0,size()].
 486       * @return The updated CompositeName, not a new one. Cannot be null.
 487       * @exception InvalidNameException If n is not a composite name.
 488       * @exception ArrayIndexOutOfBoundsException
 489       *         If posn is outside the specified range.
 490       */
 491     public Name addAll(int posn, Name n)
 492         throws InvalidNameException
 493     {
 494         if (n instanceof CompositeName) {
 495             impl.addAll(posn, n.getAll());
 496             return this;
 497         } else {
 498             throw new InvalidNameException("Not a composite name: " +
 499                 n.toString());
 500         }
 501     }
 502 
 503     /**
 504       * Adds a single component to the end of this composite name.
 505       *
 506       * @param comp     The non-null component to add.
 507       * @return The updated CompositeName, not a new one. Cannot be null.
 508       * @exception InvalidNameException If adding comp at end of the name
 509       *                         would violate the name's syntax.
 510       */
 511     public Name add(String comp) throws InvalidNameException {
 512         impl.add(comp);
 513         return this;
 514     }
 515 
 516     /**
 517       * Adds a single component at a specified position within this
 518       * composite name.
 519       * Components of this composite name at or after the index of the new
 520       * component are shifted up by one (away from index 0) to accommodate
 521       * the new component.
 522       *
 523       * @param  comp    The non-null component to add.
 524       * @param  posn    The index at which to add the new component.
 525       *                 Must be in the range [0,size()].
 526       * @return The updated CompositeName, not a new one. Cannot be null.
 527       * @exception ArrayIndexOutOfBoundsException
 528       *         If posn is outside the specified range.
 529       * @exception InvalidNameException If adding comp at the specified position
 530       *                         would violate the name's syntax.
 531       */
 532     public Name add(int posn, String comp)
 533         throws InvalidNameException
 534     {
 535         impl.add(posn, comp);
 536         return this;
 537     }
 538 
 539     /**
 540       * Deletes a component from this composite name.
 541       * The component of this composite name at position 'posn' is removed,
 542       * and components at indices greater than 'posn'
 543       * are shifted down (towards index 0) by one.
 544       *
 545       * @param  posn    The index of the component to delete.
 546       *                 Must be in the range [0,size()).
 547       * @return The component removed (a String).
 548       * @exception ArrayIndexOutOfBoundsException
 549       *         If posn is outside the specified range (includes case where
 550       *         composite name is empty).
 551       * @exception InvalidNameException If deleting the component
 552       *                         would violate the name's syntax.
 553       */
 554     public Object remove(int posn) throws InvalidNameException{
 555         return impl.remove(posn);
 556     }
 557 
 558     /**
 559      * Overridden to avoid implementation dependency.
 560      * @serialData The number of components (an <tt>int</tt>) followed by
 561      * the individual components (each a <tt>String</tt>).
 562      */
 563     private void writeObject(java.io.ObjectOutputStream s)
 564             throws java.io.IOException {
 565         s.writeInt(size());
 566         Enumeration<String> comps = getAll();
 567         while (comps.hasMoreElements()) {
 568             s.writeObject(comps.nextElement());
 569         }
 570     }
 571 
 572     /**
 573      * Overridden to avoid implementation dependency.
 574      */
 575     private void readObject(java.io.ObjectInputStream s)
 576             throws java.io.IOException, ClassNotFoundException {
 577         impl = new NameImpl(null);  // null means use default syntax
 578         int n = s.readInt();    // number of components
 579         try {
 580             while (--n >= 0) {
 581                 add((String)s.readObject());
 582             }
 583         } catch (InvalidNameException e) {
 584             throw (new java.io.StreamCorruptedException("Invalid name"));
 585         }
 586     }
 587 
 588     /**
 589      * Use serialVersionUID from JNDI 1.1.1 for interoperability
 590      */
 591     private static final long serialVersionUID = 1667768148915813118L;
 592 
 593 /*
 594     // %%% Test code for serialization.
 595     public static void main(String[] args) throws Exception {
 596         CompositeName c = new CompositeName("aaa/bbb");
 597         java.io.FileOutputStream f1 = new java.io.FileOutputStream("/tmp/ser");
 598         java.io.ObjectOutputStream s1 = new java.io.ObjectOutputStream(f1);
 599         s1.writeObject(c);
 600         s1.close();
 601         java.io.FileInputStream f2 = new java.io.FileInputStream("/tmp/ser");
 602         java.io.ObjectInputStream s2 = new java.io.ObjectInputStream(f2);
 603         c = (CompositeName)s2.readObject();
 604 
 605         System.out.println("Size: " + c.size());
 606         System.out.println("Size: " + c.snit);
 607     }
 608 */
 609 
 610 /*
 611    %%% Testing code
 612     public static void main(String[] args) {
 613         try {
 614             for (int i = 0; i < args.length; i++) {
 615                 Name name;
 616                 Enumeration e;
 617                 System.out.println("Given name: " + args[i]);
 618                 name = new CompositeName(args[i]);
 619                 e = name.getComponents();
 620                 while (e.hasMoreElements()) {
 621                     System.out.println("Element: " + e.nextElement());
 622                 }
 623                 System.out.println("Constructed name: " + name.toString());
 624             }
 625         } catch (Exception ne) {
 626             ne.printStackTrace();
 627         }
 628     }
 629 */
 630 }