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
26package javax.naming;
27
28import java.util.Enumeration;
29import 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
209public 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}
637