View Javadoc
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 }