1 /*
   2  * Copyright (c) 1999, 2017, 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  *({@code CompositeName}).
  80  *
  81 <table class="striped"><caption style="display:none">examples showing string
  82  form of composite name and its corresponding structural form (CompositeName)</caption>
  83 <thead>
  84 <tr>
  85 <th scope="col">String Name</th>
  86 <th scope="col">CompositeName</th>
  87 </tr>
  88 </thead>
  89 <tbody style="text-align:left">
  90 <tr>
  91 <th scope="row">
  92 ""
  93 </th>
  94 <td>{} (the empty name == new CompositeName("") == new CompositeName())
  95 </td>
  96 </tr>
  97 
  98 <tr>
  99 <th scope="row">
 100 "x"
 101 </th>
 102 <td>{"x"}
 103 </td>
 104 </tr>
 105 
 106 <tr>
 107 <th scope="row">
 108 "x/y"
 109 </th>
 110 <td>{"x", "y"}</td>
 111 </tr>
 112 
 113 <tr>
 114 <th scope="row">"x/"</th>
 115 <td>{"x", ""}</td>
 116 </tr>
 117 
 118 <tr>
 119 <th scope="row">"/x"</th>
 120 <td>{"", "x"}</td>
 121 </tr>
 122 
 123 <tr>
 124 <th scope="row">"/"</th>
 125 <td>{""}</td>
 126 </tr>
 127 
 128 <tr>
 129 <th scope="row">"//"</th>
 130 <td>{"", ""}</td>
 131 </tr>
 132 
 133 <tr><th scope="row">"/x/"</th>
 134 <td>{"", "x", ""}</td>
 135 </tr>
 136 
 137 <tr><th scope="row">"x//y"</th>
 138 <td>{"x", "", "y"}</td>
 139 </tr>
 140 </tbody>
 141 </table>
 142  *
 143  *<h1>Composition Examples</h1>
 144  * Here are some composition examples.  The right column shows composing
 145  * string composite names while the left column shows composing the
 146  * corresponding {@code CompositeName}s.  Notice that composing the
 147  * string forms of two composite names simply involves concatenating
 148  * their string forms together.
 149 
 150 <table class="striped"><caption style="display:none">composition examples
 151  showing string names and composite names</caption>
 152 <thead>
 153 <tr>
 154 <th scope="col">String Names</th>
 155 <th scope="col">CompositeNames</th>
 156 </tr>
 157 </thead>
 158 
 159 <tbody style="text-align:left">
 160 <tr>
 161 <th scope="row">
 162 "x/y"           + "/"   = x/y/
 163 </th>
 164 <td>
 165 {"x", "y"}      + {""}  = {"x", "y", ""}
 166 </td>
 167 </tr>
 168 
 169 <tr>
 170 <th scope="row">
 171 ""              + "x"   = "x"
 172 </th>
 173 <td>
 174 {}              + {"x"} = {"x"}
 175 </td>
 176 </tr>
 177 
 178 <tr>
 179 <th scope="row">
 180 "/"             + "x"   = "/x"
 181 </th>
 182 <td>
 183 {""}            + {"x"} = {"", "x"}
 184 </td>
 185 </tr>
 186 
 187 <tr>
 188 <th scope="row">
 189 "x"   + ""      + ""    = "x"
 190 </th>
 191 <td>
 192 {"x"} + {}      + {}    = {"x"}
 193 </td>
 194 </tr>
 195 </tbody>
 196 </table>
 197  *
 198  *<h1>Multithreaded Access</h1>
 199  * A {@code CompositeName} instance is not synchronized against concurrent
 200  * multithreaded access. Multiple threads trying to access and modify a
 201  * {@code CompositeName} should lock the object.
 202  *
 203  * @author Rosanna Lee
 204  * @author Scott Seligman
 205  * @since 1.3
 206  */
 207 
 208 
 209 public class CompositeName implements Name {
 210 
 211     private transient NameImpl impl;
 212     /**
 213       * Constructs a new composite name instance using the components
 214       * specified by 'comps'. This protected method is intended
 215       * to be used by subclasses of CompositeName when they override
 216       * methods such as clone(), getPrefix(), getSuffix().
 217       *
 218       * @param comps A non-null enumeration containing the components for the new
 219       *              composite name. Each element is of class String.
 220       *               The enumeration will be consumed to extract its
 221       *               elements.
 222       */
 223     protected CompositeName(Enumeration<String> comps) {
 224         impl = new NameImpl(null, comps); // null means use default syntax
 225     }
 226 
 227     /**
 228       * Constructs a new composite name instance by parsing the string n
 229       * using the composite name syntax (left-to-right, slash separated).
 230       * The composite name syntax is described in detail in the class
 231       * description.
 232       *
 233       * @param  n       The non-null string to parse.
 234       * @exception InvalidNameException If n has invalid composite name syntax.
 235       */
 236     public CompositeName(String n) throws InvalidNameException {
 237         impl = new NameImpl(null, n);  // null means use default syntax
 238     }
 239 
 240     /**
 241       * Constructs a new empty composite name. Such a name returns true
 242       * when <code>isEmpty()</code> is invoked on it.
 243       */
 244     public CompositeName() {
 245         impl = new NameImpl(null);  // null means use default syntax
 246     }
 247 
 248     /**
 249       * Generates the string representation of this composite name.
 250       * The string representation consists of enumerating in order
 251       * each component of the composite name and separating
 252       * each component by a forward slash character. Quoting and
 253       * escape characters are applied where necessary according to
 254       * the JNDI syntax, which is described in the class description.
 255       * An empty component is represented by an empty string.
 256       *
 257       * The string representation thus generated can be passed to
 258       * the CompositeName constructor to create a new equivalent
 259       * composite name.
 260       *
 261       * @return A non-null string representation of this composite name.
 262       */
 263     public String toString() {
 264         return impl.toString();
 265     }
 266 
 267     /**
 268       * Determines whether two composite names are equal.
 269       * If obj is null or not a composite name, false is returned.
 270       * Two composite names are equal if each component in one is equal
 271       * to the corresponding component in the other. This implies
 272       * both have the same number of components, and each component's
 273       * equals() test against the corresponding component in the other name
 274       * returns true.
 275       *
 276       * @param  obj     The possibly null object to compare against.
 277       * @return true if obj is equal to this composite name, false otherwise.
 278       * @see #hashCode
 279       */
 280     public boolean equals(Object obj) {
 281         return (obj != null &&
 282                 obj instanceof CompositeName &&
 283                 impl.equals(((CompositeName)obj).impl));
 284     }
 285 
 286     /**
 287       * Computes the hash code of this composite name.
 288       * The hash code is the sum of the hash codes of individual components
 289       * of this composite name.
 290       *
 291       * @return An int representing the hash code of this name.
 292       * @see #equals
 293       */
 294     public int hashCode() {
 295         return impl.hashCode();
 296     }
 297 
 298 
 299     /**
 300      * Compares this CompositeName with the specified Object for order.
 301      * Returns a
 302      * negative integer, zero, or a positive integer as this Name is less
 303      * than, equal to, or greater than the given Object.
 304      * <p>
 305      * If obj is null or not an instance of CompositeName, ClassCastException
 306      * is thrown.
 307      * <p>
 308      * See equals() for what it means for two composite names to be equal.
 309      * If two composite names are equal, 0 is returned.
 310      * <p>
 311      * Ordering of composite names follows the lexicographical rules for
 312      * string comparison, with the extension that this applies to all
 313      * the components in the composite name. The effect is as if all the
 314      * components were lined up in their specified ordered and the
 315      * lexicographical rules applied over the two line-ups.
 316      * If this composite name is "lexicographically" lesser than obj,
 317      * a negative number is returned.
 318      * If this composite name is "lexicographically" greater than obj,
 319      * a positive number is returned.
 320      * @param obj The non-null object to compare against.
 321      *
 322      * @return  a negative integer, zero, or a positive integer as this Name
 323      *          is less than, equal to, or greater than the given Object.
 324      * @exception ClassCastException if obj is not a CompositeName.
 325      */
 326     public int compareTo(Object obj) {
 327         if (!(obj instanceof CompositeName)) {
 328             throw new ClassCastException("Not a CompositeName");
 329         }
 330         return impl.compareTo(((CompositeName)obj).impl);
 331     }
 332 
 333     /**
 334       * Generates a copy of this composite name.
 335       * Changes to the components of this composite name won't
 336       * affect the new copy and vice versa.
 337       *
 338       * @return A non-null copy of this composite name.
 339       */
 340     public Object clone() {
 341         return (new CompositeName(getAll()));
 342     }
 343 
 344     /**
 345       * Retrieves the number of components in this composite name.
 346       *
 347       * @return The nonnegative number of components in this composite name.
 348       */
 349     public int size() {
 350         return (impl.size());
 351     }
 352 
 353     /**
 354       * Determines whether this composite name is empty. A composite name
 355       * is empty if it has zero components.
 356       *
 357       * @return true if this composite name is empty, false otherwise.
 358       */
 359     public boolean isEmpty() {
 360         return (impl.isEmpty());
 361     }
 362 
 363     /**
 364       * Retrieves the components of this composite name as an enumeration
 365       * of strings.
 366       * The effects of updates to this composite name on this enumeration
 367       * is undefined.
 368       *
 369       * @return A non-null enumeration of the components of
 370       *         this composite name. Each element of the enumeration is of
 371       *         class String.
 372       */
 373     public Enumeration<String> getAll() {
 374         return (impl.getAll());
 375     }
 376 
 377     /**
 378       * Retrieves a component of this composite name.
 379       *
 380       * @param  posn    The 0-based index of the component to retrieve.
 381       *                 Must be in the range [0,size()).
 382       * @return The non-null component at index posn.
 383       * @exception ArrayIndexOutOfBoundsException if posn is outside the
 384       *         specified range.
 385       */
 386     public String get(int posn) {
 387         return (impl.get(posn));
 388     }
 389 
 390     /**
 391       * Creates a composite name whose components consist of a prefix of the
 392       * components in this composite name. Subsequent changes to
 393       * this composite name does not affect the name that is returned.
 394       *
 395       * @param  posn    The 0-based index of the component at which to stop.
 396       *                 Must be in the range [0,size()].
 397       * @return A composite name consisting of the components at indexes in
 398       *         the range [0,posn).
 399       * @exception ArrayIndexOutOfBoundsException
 400       *         If posn is outside the specified range.
 401       */
 402     public Name getPrefix(int posn) {
 403         Enumeration<String> comps = impl.getPrefix(posn);
 404         return (new CompositeName(comps));
 405     }
 406 
 407     /**
 408       * Creates a composite name whose components consist of a suffix of the
 409       * components in this composite name. Subsequent changes to
 410       * this composite name does not affect the name that is returned.
 411       *
 412       * @param  posn    The 0-based index of the component at which to start.
 413       *                 Must be in the range [0,size()].
 414       * @return A composite name consisting of the components at indexes in
 415       *         the range [posn,size()).  If posn is equal to
 416       *         size(), an empty composite name is returned.
 417       * @exception ArrayIndexOutOfBoundsException
 418       *         If posn is outside the specified range.
 419       */
 420     public Name getSuffix(int posn) {
 421         Enumeration<String> comps = impl.getSuffix(posn);
 422         return (new CompositeName(comps));
 423     }
 424 
 425     /**
 426       * Determines whether a composite name is a prefix of this composite name.
 427       * A composite name 'n' is a prefix if it is equal to
 428       * getPrefix(n.size())--in other words, this composite name
 429       * starts with 'n'. If 'n' is null or not a composite name, false is returned.
 430       *
 431       * @param  n       The possibly null name to check.
 432       * @return true if n is a CompositeName and
 433       *         is a prefix of this composite name, false otherwise.
 434       */
 435     public boolean startsWith(Name n) {
 436         if (n instanceof CompositeName) {
 437             return (impl.startsWith(n.size(), n.getAll()));
 438         } else {
 439             return false;
 440         }
 441     }
 442 
 443     /**
 444       * Determines whether a composite name is a suffix of this composite name.
 445       * A composite name 'n' is a suffix if it is equal to
 446       * getSuffix(size()-n.size())--in other words, this
 447       * composite name ends with 'n'.
 448       * If n is null or not a composite name, false is returned.
 449       *
 450       * @param  n       The possibly null name to check.
 451       * @return true if n is a CompositeName and
 452       *         is a suffix of this composite name, false otherwise.
 453       */
 454     public boolean endsWith(Name n) {
 455         if (n instanceof CompositeName) {
 456             return (impl.endsWith(n.size(), n.getAll()));
 457         } else {
 458             return false;
 459         }
 460     }
 461 
 462     /**
 463       * Adds the components of a composite name -- in order -- to the end of
 464       * this composite name.
 465       *
 466       * @param suffix   The non-null components to add.
 467       * @return The updated CompositeName, not a new one. Cannot be null.
 468       * @exception InvalidNameException If suffix is not a composite name.
 469       */
 470     public Name addAll(Name suffix)
 471         throws InvalidNameException
 472     {
 473         if (suffix instanceof CompositeName) {
 474             impl.addAll(suffix.getAll());
 475             return this;
 476         } else {
 477             throw new InvalidNameException("Not a composite name: " +
 478                 suffix.toString());
 479         }
 480     }
 481 
 482     /**
 483       * Adds the components of a composite name -- in order -- at a specified
 484       * position within this composite name.
 485       * Components of this composite name at or after the index of the first
 486       * new component are shifted up (away from index 0)
 487       * to accommodate the new components.
 488       *
 489       * @param n        The non-null components to add.
 490       * @param posn     The index in this name at which to add the new
 491       *                 components.  Must be in the range [0,size()].
 492       * @return The updated CompositeName, not a new one. Cannot be null.
 493       * @exception InvalidNameException If n is not a composite name.
 494       * @exception ArrayIndexOutOfBoundsException
 495       *         If posn is outside the specified range.
 496       */
 497     public Name addAll(int posn, Name n)
 498         throws InvalidNameException
 499     {
 500         if (n instanceof CompositeName) {
 501             impl.addAll(posn, n.getAll());
 502             return this;
 503         } else {
 504             throw new InvalidNameException("Not a composite name: " +
 505                 n.toString());
 506         }
 507     }
 508 
 509     /**
 510       * Adds a single component to the end of this composite name.
 511       *
 512       * @param comp     The non-null component to add.
 513       * @return The updated CompositeName, not a new one. Cannot be null.
 514       * @exception InvalidNameException If adding comp at end of the name
 515       *                         would violate the name's syntax.
 516       */
 517     public Name add(String comp) throws InvalidNameException {
 518         impl.add(comp);
 519         return this;
 520     }
 521 
 522     /**
 523       * Adds a single component at a specified position within this
 524       * composite name.
 525       * Components of this composite name at or after the index of the new
 526       * component are shifted up by one (away from index 0) to accommodate
 527       * the new component.
 528       *
 529       * @param  comp    The non-null component to add.
 530       * @param  posn    The index at which to add the new component.
 531       *                 Must be in the range [0,size()].
 532       * @return The updated CompositeName, not a new one. Cannot be null.
 533       * @exception ArrayIndexOutOfBoundsException
 534       *         If posn is outside the specified range.
 535       * @exception InvalidNameException If adding comp at the specified position
 536       *                         would violate the name's syntax.
 537       */
 538     public Name add(int posn, String comp)
 539         throws InvalidNameException
 540     {
 541         impl.add(posn, comp);
 542         return this;
 543     }
 544 
 545     /**
 546       * Deletes a component from this composite name.
 547       * The component of this composite name at position 'posn' is removed,
 548       * and components at indices greater than 'posn'
 549       * are shifted down (towards index 0) by one.
 550       *
 551       * @param  posn    The index of the component to delete.
 552       *                 Must be in the range [0,size()).
 553       * @return The component removed (a String).
 554       * @exception ArrayIndexOutOfBoundsException
 555       *         If posn is outside the specified range (includes case where
 556       *         composite name is empty).
 557       * @exception InvalidNameException If deleting the component
 558       *                         would violate the name's syntax.
 559       */
 560     public Object remove(int posn) throws InvalidNameException{
 561         return impl.remove(posn);
 562     }
 563 
 564     /**
 565      * Overridden to avoid implementation dependency.
 566      * @serialData The number of components (an {@code int}) followed by
 567      * the individual components (each a {@code String}).
 568      */
 569     private void writeObject(java.io.ObjectOutputStream s)
 570             throws java.io.IOException {
 571         s.writeInt(size());
 572         Enumeration<String> comps = getAll();
 573         while (comps.hasMoreElements()) {
 574             s.writeObject(comps.nextElement());
 575         }
 576     }
 577 
 578     /**
 579      * Overridden to avoid implementation dependency.
 580      */
 581     private void readObject(java.io.ObjectInputStream s)
 582             throws java.io.IOException, ClassNotFoundException {
 583         impl = new NameImpl(null);  // null means use default syntax
 584         int n = s.readInt();    // number of components
 585         try {
 586             while (--n >= 0) {
 587                 add((String)s.readObject());
 588             }
 589         } catch (InvalidNameException e) {
 590             throw (new java.io.StreamCorruptedException("Invalid name"));
 591         }
 592     }
 593 
 594     /**
 595      * Use serialVersionUID from JNDI 1.1.1 for interoperability
 596      */
 597     private static final long serialVersionUID = 1667768148915813118L;
 598 
 599 /*
 600     // %%% Test code for serialization.
 601     public static void main(String[] args) throws Exception {
 602         CompositeName c = new CompositeName("aaa/bbb");
 603         java.io.FileOutputStream f1 = new java.io.FileOutputStream("/tmp/ser");
 604         java.io.ObjectOutputStream s1 = new java.io.ObjectOutputStream(f1);
 605         s1.writeObject(c);
 606         s1.close();
 607         java.io.FileInputStream f2 = new java.io.FileInputStream("/tmp/ser");
 608         java.io.ObjectInputStream s2 = new java.io.ObjectInputStream(f2);
 609         c = (CompositeName)s2.readObject();
 610 
 611         System.out.println("Size: " + c.size());
 612         System.out.println("Size: " + c.snit);
 613     }
 614 */
 615 
 616 /*
 617    %%% Testing code
 618     public static void main(String[] args) {
 619         try {
 620             for (int i = 0; i < args.length; i++) {
 621                 Name name;
 622                 Enumeration e;
 623                 System.out.println("Given name: " + args[i]);
 624                 name = new CompositeName(args[i]);
 625                 e = name.getComponents();
 626                 while (e.hasMoreElements()) {
 627                     System.out.println("Element: " + e.nextElement());
 628                 }
 629                 System.out.println("Constructed name: " + name.toString());
 630             }
 631         } catch (Exception ne) {
 632             ne.printStackTrace();
 633         }
 634     }
 635 */
 636 }