001 /*
002 * Copyright 1999-2004 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.naming;
027
028 import java.util.Enumeration;
029 import java.util.Properties;
030
031 /**
032 * This class represents a composite name -- a sequence of
033 * component names spanning multiple namespaces.
034 * Each component is a string name from the namespace of a
035 * naming system. If the component comes from a hierarchical
036 * namespace, that component can be further parsed into
037 * its atomic parts by using the CompoundName class.
038 *<p>
039 * The components of a composite name are numbered. The indexes of a
040 * composite name with N components range from 0 up to, but not including, N.
041 * This range may be written as [0,N).
042 * The most significant component is at index 0.
043 * An empty composite name has no components.
044 *<p>
045 * <h4>JNDI Composite Name Syntax</h4>
046 * JNDI defines a standard string representation for composite names. This
047 * representation is the concatenation of the components of a composite name
048 * from left to right using the component separator (a forward
049 * slash character (/)) to separate each component.
050 * The JNDI syntax defines the following meta characters:
051 * <ul>
052 * <li>escape (backward slash \),
053 * <li>quote characters (single (') and double quotes (")), and
054 * <li>component separator (forward slash character (/)).
055 * </ul>
056 * Any occurrence of a leading quote, an escape preceding any meta character,
057 * an escape at the end of a component, or a component separator character
058 * in an unquoted component must be preceded by an escape character when
059 * that component is being composed into a composite name string.
060 * Alternatively, to avoid adding escape characters as described,
061 * the entire component can be quoted using matching single quotes
062 * or matching double quotes. A single quote occurring within a double-quoted
063 * component is not considered a meta character (and need not be escaped),
064 * and vice versa.
065 *<p>
066 * When two composite names are compared, the case of the characters
067 * is significant.
068 *<p>
069 * A leading component separator (the composite name string begins with
070 * a separator) denotes a leading empty component (a component consisting
071 * of an empty string).
072 * A trailing component separator (the composite name string ends with
073 * a separator) denotes a trailing empty component.
074 * Adjacent component separators denote an empty component.
075 *<p>
076 *<h4>Composite Name Examples</h4>
077 *This table shows examples of some composite names. Each row shows
078 *the string form of a composite name and its corresponding structural form
079 *(<tt>CompositeName</tt>).
080 *<p>
081 <table border="1" cellpadding=3 width="70%" summary="examples showing string form of composite name and its corresponding structural form (CompositeName)">
082
083 <tr>
084 <th>String Name</th>
085 <th>CompositeName</th>
086 </tr>
087
088 <tr>
089 <td>
090 ""
091 </td>
092 <td>{} (the empty name == new CompositeName("") == new CompositeName())
093 </td>
094 </tr>
095
096 <tr>
097 <td>
098 "x"
099 </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 * <p>
140 *<h4>Composition Examples</h4>
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 <p> <table border="1" cellpadding=3 width="70%" 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 *<p>
192 *<h4>Multithreaded Access</h4>
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 * @version 1.21 07/05/05
200 * @since 1.3
201 */
202
203 public class CompositeName implements Name {
204
205 private transient NameImpl impl;
206
207 /**
208 * Constructs a new composite name instance using the components
209 * specified by 'comps'. This protected method is intended to be
210 * to be used by subclasses of CompositeName when they override
211 * methods such as clone(), getPrefix(), getSuffix().
212 *
213 * @param comps A non-null enumeration containing the components for the new
214 * composite name. Each element is of class String.
215 * The enumeration will be consumed to extract its
216 * elements.
217 */
218 protected CompositeName(Enumeration<String> comps) {
219 impl = new NameImpl(null, comps); // null means use default syntax
220 }
221
222 /**
223 * Constructs a new composite name instance by parsing the string n
224 * using the composite name syntax (left-to-right, slash separated).
225 * The composite name syntax is described in detail in the class
226 * description.
227 *
228 * @param n The non-null string to parse.
229 * @exception InvalidNameException If n has invalid composite name syntax.
230 */
231 public CompositeName(String n) throws InvalidNameException {
232 impl = new NameImpl(null, n); // null means use default syntax
233 }
234
235 /**
236 * Constructs a new empty composite name. Such a name returns true
237 * when <code>isEmpty()</code> is invoked on it.
238 */
239 public CompositeName() {
240 impl = new NameImpl(null); // null means use default syntax
241 }
242
243 /**
244 * Generates the string representation of this composite name.
245 * The string representation consists of enumerating in order
246 * each component of the composite name and separating
247 * each component by a forward slash character. Quoting and
248 * escape characters are applied where necessary according to
249 * the JNDI syntax, which is described in the class description.
250 * An empty component is represented by an empty string.
251 *
252 * The string representation thus generated can be passed to
253 * the CompositeName constructor to create a new equivalent
254 * composite name.
255 *
256 * @return A non-null string representation of this composite name.
257 */
258 public String toString() {
259 return impl.toString();
260 }
261
262 /**
263 * Determines whether two composite names are equal.
264 * If obj is null or not a composite name, false is returned.
265 * Two composite names are equal if each component in one is equal
266 * to the corresponding component in the other. This implies
267 * both have the same number of components, and each component's
268 * equals() test against the corresponding component in the other name
269 * returns true.
270 *
271 * @param obj The possibly null object to compare against.
272 * @return true if obj is equal to this composite name, false otherwise.
273 * @see #hashCode
274 */
275 public boolean equals(Object obj) {
276 return (obj != null && obj instanceof CompositeName && impl
277 .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 * Compares this CompositeName with the specified Object for order.
294 * Returns a
295 * negative integer, zero, or a positive integer as this Name is less
296 * than, equal to, or greater than the given Object.
297 * <p>
298 * If obj is null or not an instance of CompositeName, ClassCastException
299 * is thrown.
300 * <p>
301 * See equals() for what it means for two composite names to be equal.
302 * If two composite names are equal, 0 is returned.
303 * <p>
304 * Ordering of composite names follows the lexicographical rules for
305 * string comparison, with the extension that this applies to all
306 * the components in the composite name. The effect is as if all the
307 * components were lined up in their specified ordered and the
308 * lexicographical rules applied over the two line-ups.
309 * If this composite name is "lexicographically" lesser than obj,
310 * a negative number is returned.
311 * If this composite name is "lexicographically" greater than obj,
312 * a positive number is returned.
313 * @param obj The non-null object to compare against.
314 *
315 * @return a negative integer, zero, or a positive integer as this Name
316 * is less than, equal to, or greater than the given Object.
317 * @exception ClassCastException if obj is not a CompositeName.
318 */
319 public int compareTo(Object obj) {
320 if (!(obj instanceof CompositeName)) {
321 throw new ClassCastException("Not a CompositeName");
322 }
323 return impl.compareTo(((CompositeName) obj).impl);
324 }
325
326 /**
327 * Generates a copy of this composite name.
328 * Changes to the components of this composite name won't
329 * affect the new copy and vice versa.
330 *
331 * @return A non-null copy of this composite name.
332 */
333 public Object clone() {
334 return (new CompositeName(getAll()));
335 }
336
337 /**
338 * Retrieves the number of components in this composite name.
339 *
340 * @return The nonnegative number of components in this composite name.
341 */
342 public int size() {
343 return (impl.size());
344 }
345
346 /**
347 * Determines whether this composite name is empty. A composite name
348 * is empty if it has zero components.
349 *
350 * @return true if this composite name is empty, false otherwise.
351 */
352 public boolean isEmpty() {
353 return (impl.isEmpty());
354 }
355
356 /**
357 * Retrieves the components of this composite name as an enumeration
358 * of strings.
359 * The effects of updates to this composite name on this enumeration
360 * is undefined.
361 *
362 * @return A non-null enumeration of the components of
363 * this composite name. Each element of the enumeration is of
364 * class String.
365 */
366 public Enumeration<String> getAll() {
367 return (impl.getAll());
368 }
369
370 /**
371 * Retrieves a component of this composite name.
372 *
373 * @param posn The 0-based index of the component to retrieve.
374 * Must be in the range [0,size()).
375 * @return The non-null component at index posn.
376 * @exception ArrayIndexOutOfBoundsException if posn is outside the
377 * specified range.
378 */
379 public String get(int posn) {
380 return (impl.get(posn));
381 }
382
383 /**
384 * Creates a composite name whose components consist of a prefix of the
385 * components in this composite name. Subsequent changes to
386 * this composite name does not affect the name that is returned.
387 *
388 * @param posn The 0-based index of the component at which to stop.
389 * Must be in the range [0,size()].
390 * @return A composite name consisting of the components at indexes in
391 * the range [0,posn).
392 * @exception ArrayIndexOutOfBoundsException
393 * If posn is outside the specified range.
394 */
395 public Name getPrefix(int posn) {
396 Enumeration comps = impl.getPrefix(posn);
397 return (new CompositeName(comps));
398 }
399
400 /**
401 * Creates a composite name whose components consist of a suffix of the
402 * components in this composite name. Subsequent changes to
403 * this composite name does not affect the name that is returned.
404 *
405 * @param posn The 0-based index of the component at which to start.
406 * Must be in the range [0,size()].
407 * @return A composite name consisting of the components at indexes in
408 * the range [posn,size()). If posn is equal to
409 * size(), an empty composite name is returned.
410 * @exception ArrayIndexOutOfBoundsException
411 * If posn is outside the specified range.
412 */
413 public Name getSuffix(int posn) {
414 Enumeration comps = impl.getSuffix(posn);
415 return (new CompositeName(comps));
416 }
417
418 /**
419 * Determines whether a composite name is a prefix of this composite name.
420 * A composite name 'n' is a prefix if it is equal to
421 * getPrefix(n.size())--in other words, this composite name
422 * starts with 'n'. If 'n' is null or not a composite name, false is returned.
423 *
424 * @param n The possibly null name to check.
425 * @return true if n is a CompositeName and
426 * is a prefix of this composite name, false otherwise.
427 */
428 public boolean startsWith(Name n) {
429 if (n instanceof CompositeName) {
430 return (impl.startsWith(n.size(), n.getAll()));
431 } else {
432 return false;
433 }
434 }
435
436 /**
437 * Determines whether a composite name is a suffix of this composite name.
438 * A composite name 'n' is a suffix if it it is equal to
439 * getSuffix(size()-n.size())--in other words, this
440 * composite name ends with 'n'.
441 * If n is null or not a composite name, false is returned.
442 *
443 * @param n The possibly null name to check.
444 * @return true if n is a CompositeName and
445 * is a suffix of this composite name, false otherwise.
446 */
447 public boolean endsWith(Name n) {
448 if (n instanceof CompositeName) {
449 return (impl.endsWith(n.size(), n.getAll()));
450 } else {
451 return false;
452 }
453 }
454
455 /**
456 * Adds the components of a composite name -- in order -- to the end of
457 * this composite name.
458 *
459 * @param suffix The non-null components to add.
460 * @return The updated CompositeName, not a new one. Cannot be null.
461 * @exception InvalidNameException If suffix is not a composite name.
462 */
463 public Name addAll(Name suffix) throws InvalidNameException {
464 if (suffix instanceof CompositeName) {
465 impl.addAll(suffix.getAll());
466 return this ;
467 } else {
468 throw new InvalidNameException("Not a composite name: "
469 + suffix.toString());
470 }
471 }
472
473 /**
474 * Adds the components of a composite name -- in order -- at a specified
475 * position within this composite name.
476 * Components of this composite name at or after the index of the first
477 * new component are shifted up (away from index 0)
478 * to accommodate the new components.
479 *
480 * @param n The non-null components to add.
481 * @param posn The index in this name at which to add the new
482 * components. Must be in the range [0,size()].
483 * @return The updated CompositeName, not a new one. Cannot be null.
484 * @exception InvalidNameException If n is not a composite name.
485 * @exception ArrayIndexOutOfBoundsException
486 * If posn is outside the specified range.
487 */
488 public Name addAll(int posn, Name n) throws InvalidNameException {
489 if (n instanceof CompositeName) {
490 impl.addAll(posn, n.getAll());
491 return this ;
492 } else {
493 throw new InvalidNameException("Not a composite name: "
494 + n.toString());
495 }
496 }
497
498 /**
499 * Adds a single component to the end of this composite name.
500 *
501 * @param comp The non-null component to add.
502 * @return The updated CompositeName, not a new one. Cannot be null.
503 * @exception InvalidNameException If adding comp at end of the name
504 * would violate the name's syntax.
505 */
506 public Name add(String comp) throws InvalidNameException {
507 impl.add(comp);
508 return this ;
509 }
510
511 /**
512 * Adds a single component at a specified position within this
513 * composite name.
514 * Components of this composite name at or after the index of the new
515 * component are shifted up by one (away from index 0) to accommodate
516 * the new component.
517 *
518 * @param comp The non-null component to add.
519 * @param posn The index at which to add the new component.
520 * Must be in the range [0,size()].
521 * @return The updated CompositeName, not a new one. Cannot be null.
522 * @exception ArrayIndexOutOfBoundsException
523 * If posn is outside the specified range.
524 * @exception InvalidNameException If adding comp at the specified position
525 * would violate the name's syntax.
526 */
527 public Name add(int posn, String comp) throws InvalidNameException {
528 impl.add(posn, comp);
529 return this ;
530 }
531
532 /**
533 * Deletes a component from this composite name.
534 * The component of this composite name at position 'posn' is removed,
535 * and components at indices greater than 'posn'
536 * are shifted down (towards index 0) by one.
537 *
538 * @param posn The index of the component to delete.
539 * Must be in the range [0,size()).
540 * @return The component removed (a String).
541 * @exception ArrayIndexOutOfBoundsException
542 * If posn is outside the specified range (includes case where
543 * composite name is empty).
544 * @exception InvalidNameException If deleting the component
545 * would violate the name's syntax.
546 */
547 public Object remove(int posn) throws InvalidNameException {
548 return impl.remove(posn);
549 }
550
551 /**
552 * Overridden to avoid implementation dependency.
553 * @serialData The number of components (an <tt>int</tt>) followed by
554 * the individual components (each a <tt>String</tt>).
555 */
556 private void writeObject(java.io.ObjectOutputStream s)
557 throws java.io.IOException {
558 s.writeInt(size());
559 Enumeration comps = getAll();
560 while (comps.hasMoreElements()) {
561 s.writeObject(comps.nextElement());
562 }
563 }
564
565 /**
566 * Overridden to avoid implementation dependency.
567 */
568 private void readObject(java.io.ObjectInputStream s)
569 throws java.io.IOException, ClassNotFoundException {
570 impl = new NameImpl(null); // null means use default syntax
571 int n = s.readInt(); // number of components
572 try {
573 while (--n >= 0) {
574 add((String) s.readObject());
575 }
576 } catch (InvalidNameException e) {
577 throw (new java.io.StreamCorruptedException("Invalid name"));
578 }
579 }
580
581 /**
582 * Use serialVersionUID from JNDI 1.1.1 for interoperability
583 */
584 private static final long serialVersionUID = 1667768148915813118L;
585
586 /*
587 // %%% Test code for serialization.
588 public static void main(String[] args) throws Exception {
589 CompositeName c = new CompositeName("aaa/bbb");
590 java.io.FileOutputStream f1 = new java.io.FileOutputStream("/tmp/ser");
591 java.io.ObjectOutputStream s1 = new java.io.ObjectOutputStream(f1);
592 s1.writeObject(c);
593 s1.close();
594 java.io.FileInputStream f2 = new java.io.FileInputStream("/tmp/ser");
595 java.io.ObjectInputStream s2 = new java.io.ObjectInputStream(f2);
596 c = (CompositeName)s2.readObject();
597
598 System.out.println("Size: " + c.size());
599 System.out.println("Size: " + c.snit);
600 }
601 */
602
603 /*
604 %%% Testing code
605 public static void main(String[] args) {
606 try {
607 for (int i = 0; i < args.length; i++) {
608 Name name;
609 Enumeration e;
610 System.out.println("Given name: " + args[i]);
611 name = new CompositeName(args[i]);
612 e = name.getComponents();
613 while (e.hasMoreElements()) {
614 System.out.println("Element: " + e.nextElement());
615 }
616 System.out.println("Constructed name: " + name.toString());
617 }
618 } catch (Exception ne) {
619 ne.printStackTrace();
620 }
621 }
622 */
623 }
|