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 }