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       */
CompositeName(Enumeration<String> comps)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       */
CompositeName(String n)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       */
CompositeName()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       */
toString()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       */
equals(Object obj)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       */
hashCode()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      */
compareTo(Object obj)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       */
clone()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       */
size()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       */
isEmpty()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       */
getAll()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       */
get(int posn)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       */
getPrefix(int posn)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       */
getSuffix(int posn)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       */
startsWith(Name n)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       */
endsWith(Name n)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       */
addAll(Name suffix)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       */
addAll(int posn, Name n)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       */
add(String comp)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       */
add(int posn, String comp)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       */
remove(int posn)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      */
writeObject(java.io.ObjectOutputStream s)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      */
readObject(java.io.ObjectInputStream s)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 }
637