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 }