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 }
637