1. /*
  2. * @(#)CompositeName.java 1.12 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.naming;
  8. import java.util.Enumeration;
  9. import java.util.Properties;
  10. /**
  11. * This class represents a composite name -- a sequence of
  12. * component names spanning multiple namespaces.
  13. * Each component is a string name from the namespace of a
  14. * naming system. If the component comes from a hierarchical
  15. * namespace, that component can be further parsed into
  16. * its atomic parts by using the CompoundName class.
  17. *<p>
  18. * The components of a composite name are numbered. The indexes of a
  19. * composite name with N components range from 0 up to, but not including, N.
  20. * This range may be written as [0,N).
  21. * The most significant component is at index 0.
  22. * An empty composite name has no components.
  23. *<p>
  24. * <h4>JNDI Composite Name Syntax</h4>
  25. * JNDI defines a standard string representation for composite names. This
  26. * representation is the concatenation of the components of a composite name
  27. * from left to right using the component separator (a forward
  28. * slash character (/)) to separate each component.
  29. * The JNDI syntax defines the following meta characters:
  30. * <ul>
  31. * <li>escape (backward slash \),
  32. * <li>quote characters (single (') and double quotes (")), and
  33. * <li>component separator (forward slash character (/)).
  34. * </ul>
  35. * Any occurrence of a leading quote, an escape preceding any meta character,
  36. * an escape at the end of a component, or a component separator character
  37. * in an unquoted component must be preceded by an escape character when
  38. * that component is being composed into a composite name string.
  39. * Alternatively, to avoid adding escape characters as described,
  40. * the entire component can be quoted using matching single quotes
  41. * or matching double quotes. A single quote occurring within a double-quoted
  42. * component is not considered a meta character (and need not be escaped),
  43. * and vice versa.
  44. *<p>
  45. * When two composite names are compared, the case of the characters
  46. * is significant.
  47. *<p>
  48. * A leading component separator (the composite name string begins with
  49. * a separator) denotes a leading empty component (a component consisting
  50. * of an empty string).
  51. * A trailing component separator (the composite name string ends with
  52. * a separator) denotes a trailing empty component.
  53. * Adjacent component separators denote an empty component.
  54. *<p>
  55. *<h4>Composite Name Examples</h4>
  56. *This table shows examples of some composite names. Each row shows
  57. *the string form of a composite name and its corresponding structural form
  58. *(<tt>CompositeName</tt>).
  59. *<p>
  60. <table border="1" cellpadding=3 width="70%" summary="examples showing string form of composite name and its corresponding structural form (CompositeName)">
  61. <tr>
  62. <th>String Name</th>
  63. <th>CompositeName</th>
  64. </tr>
  65. <tr>
  66. <td>
  67. ""
  68. </td>
  69. <td>{} (the empty name == new CompositeName("") == new CompositeName())
  70. </td>
  71. </tr>
  72. <tr>
  73. <td>
  74. "x"
  75. </td>
  76. <td>{"x"}
  77. </td>
  78. </tr>
  79. <tr>
  80. <td>
  81. "x/y"
  82. </td>
  83. <td>{"x", "y"}</td>
  84. </tr>
  85. <tr>
  86. <td>"x/"</td>
  87. <td>{"x", ""}</td>
  88. </tr>
  89. <tr>
  90. <td>"/x"</td>
  91. <td>{"", "x"}</td>
  92. </tr>
  93. <tr>
  94. <td>"/"</td>
  95. <td>{""}</td>
  96. </tr>
  97. <tr>
  98. <td>"//"</td>
  99. <td>{"", ""}</td>
  100. </tr>
  101. <tr><td>"/x/"</td>
  102. <td>{"", "x", ""}</td>
  103. </tr>
  104. <tr><td>"x//y"</td>
  105. <td>{"x", "", "y"}</td>
  106. </tr>
  107. </table>
  108. * <p>
  109. *<h4>Composition Examples</h4>
  110. * Here are some composition examples. The right column shows composing
  111. * string composite names while the left column shows composing the
  112. * corresponding <tt>CompositeName</tt>s. Notice that composing the
  113. * string forms of two composite names simply involves concatenating
  114. * their string forms together.
  115. <p> <table border="1" cellpadding=3 width="70%" summary="composition examples showing string names and composite names">
  116. <tr>
  117. <th>String Names</th>
  118. <th>CompositeNames</th>
  119. </tr>
  120. <tr>
  121. <td>
  122. "x/y" + "/" = x/y/
  123. </td>
  124. <td>
  125. {"x", "y"} + {""} = {"x", "y", ""}
  126. </td>
  127. </tr>
  128. <tr>
  129. <td>
  130. "" + "x" = "x"
  131. </td>
  132. <td>
  133. {} + {"x"} = {"x"}
  134. </td>
  135. </tr>
  136. <tr>
  137. <td>
  138. "/" + "x" = "/x"
  139. </td>
  140. <td>
  141. {""} + {"x"} = {"", "x"}
  142. </td>
  143. </tr>
  144. <tr>
  145. <td>
  146. "x" + "" + "" = "x"
  147. </td>
  148. <td>
  149. {"x"} + {} + {} = {"x"}
  150. </td>
  151. </tr>
  152. </table>
  153. *<p>
  154. *<h4>Multithreaded Access</h4>
  155. * A <tt>CompositeName</tt> instance is not synchronized against concurrent
  156. * multithreaded access. Multiple threads trying to access and modify a
  157. * <tt>CompositeName</tt> should lock the object.
  158. *
  159. * @author Rosanna Lee
  160. * @author Scott Seligman
  161. * @version 1.12 03/01/23
  162. * @since 1.3
  163. */
  164. public class CompositeName implements Name {
  165. private transient NameImpl impl;
  166. /**
  167. * Constructs a new composite name instance using the components
  168. * specified by 'comps'. This protected method is intended to be
  169. * to be used by subclasses of CompositeName when they override
  170. * methods such as clone(), getPrefix(), getSuffix().
  171. *
  172. * @param comps A non-null enumeration containing the components for the new
  173. * composite name. Each element is of class String.
  174. * The enumeration will be consumed to extract its
  175. * elements.
  176. */
  177. protected CompositeName(Enumeration comps) {
  178. impl = new NameImpl(null, comps); // null means use default syntax
  179. }
  180. /**
  181. * Constructs a new composite name instance by parsing the string n
  182. * using the composite name syntax (left-to-right, slash separated).
  183. * The composite name syntax is described in detail in the class
  184. * description.
  185. *
  186. * @param n The non-null string to parse.
  187. * @exception InvalidNameException If n has invalid composite name syntax.
  188. */
  189. public CompositeName(String n) throws InvalidNameException {
  190. impl = new NameImpl(null, n); // null means use default syntax
  191. }
  192. /**
  193. * Constructs a new empty composite name. Such a name returns true
  194. * when <code>isEmpty()</code> is invoked on it.
  195. */
  196. public CompositeName() {
  197. impl = new NameImpl(null); // null means use default syntax
  198. }
  199. /**
  200. * Generates the string representation of this composite name.
  201. * The string representation consists of enumerating in order
  202. * each component of the composite name and separating
  203. * each component by a forward slash character. Quoting and
  204. * escape characters are applied where necessary according to
  205. * the JNDI syntax, which is described in the class description.
  206. * An empty component is represented by an empty string.
  207. *
  208. * The string representation thus generated can be passed to
  209. * the CompositeName constructor to create a new equivalent
  210. * composite name.
  211. *
  212. * @return A non-null string representation of this composite name.
  213. */
  214. public String toString() {
  215. return impl.toString();
  216. }
  217. /**
  218. * Determines whether two composite names are equal.
  219. * If obj is null or not a composite name, false is returned.
  220. * Two composite names are equal if each component in one is equal
  221. * to the corresponding component in the other. This implies
  222. * both have the same number of components, and each component's
  223. * equals() test against the corresponding component in the other name
  224. * returns true.
  225. *
  226. * @param obj The possibly null object to compare against.
  227. * @return true if obj is equal to this composite name, false otherwise.
  228. * @see #hashCode
  229. */
  230. public boolean equals(Object obj) {
  231. return (obj != null &&
  232. obj instanceof CompositeName &&
  233. impl.equals(((CompositeName)obj).impl));
  234. }
  235. /**
  236. * Computes the hash code of this composite name.
  237. * The hash code is the sum of the hash codes of individual components
  238. * of this composite name.
  239. *
  240. * @return An int representing the hash code of this name.
  241. * @see #equals
  242. */
  243. public int hashCode() {
  244. return impl.hashCode();
  245. }
  246. /**
  247. * Compares this CompositeName with the specified Object for order.
  248. * Returns a
  249. * negative integer, zero, or a positive integer as this Name is less
  250. * than, equal to, or greater than the given Object.
  251. * <p>
  252. * If obj is null or not an instance of CompositeName, ClassCastException
  253. * is thrown.
  254. * <p>
  255. * See equals() for what it means for two composite names to be equal.
  256. * If two composite names are equal, 0 is returned.
  257. * <p>
  258. * Ordering of composite names follows the lexicographical rules for
  259. * string comparison, with the extension that this applies to all
  260. * the components in the composite name. The effect is as if all the
  261. * components were lined up in their specified ordered and the
  262. * lexicographical rules applied over the two line-ups.
  263. * If this composite name is "lexicographically" lesser than obj,
  264. * a negative number is returned.
  265. * If this composite name is "lexicographically" greater than obj,
  266. * a positive number is returned.
  267. * @param obj The non-null object to compare against.
  268. *
  269. * @return a negative integer, zero, or a positive integer as this Name
  270. * is less than, equal to, or greater than the given Object.
  271. * @exception ClassCastException if obj is not a CompositeName.
  272. */
  273. public int compareTo(Object obj) {
  274. if (!(obj instanceof CompositeName)) {
  275. throw new ClassCastException("Not a CompositeName");
  276. }
  277. return impl.compareTo(((CompositeName)obj).impl);
  278. }
  279. /**
  280. * Generates a copy of this composite name.
  281. * Changes to the components of this composite name won't
  282. * affect the new copy and vice versa.
  283. *
  284. * @return A non-null copy of this composite name.
  285. */
  286. public Object clone() {
  287. return (new CompositeName(getAll()));
  288. }
  289. /**
  290. * Retrieves the number of components in this composite name.
  291. *
  292. * @return The nonnegative number of components in this composite name.
  293. */
  294. public int size() {
  295. return (impl.size());
  296. }
  297. /**
  298. * Determines whether this composite name is empty. A composite name
  299. * is empty if it has zero components.
  300. *
  301. * @return true if this composite name is empty, false otherwise.
  302. */
  303. public boolean isEmpty() {
  304. return (impl.isEmpty());
  305. }
  306. /**
  307. * Retrieves the components of this composite name as an enumeration
  308. * of strings.
  309. * The effects of updates to this composite name on this enumeration
  310. * is undefined.
  311. *
  312. * @return A non-null enumeration of the components of
  313. * this composite name. Each element of the enumeration is of
  314. * class String.
  315. */
  316. public Enumeration getAll() {
  317. return (impl.getAll());
  318. }
  319. /**
  320. * Retrieves a component of this composite name.
  321. *
  322. * @param posn The 0-based index of the component to retrieve.
  323. * Must be in the range [0,size()).
  324. * @return The non-null component at index posn.
  325. * @exception ArrayIndexOutOfBoundsException if posn is outside the
  326. * specified range.
  327. */
  328. public String get(int posn) {
  329. return (impl.get(posn));
  330. }
  331. /**
  332. * Creates a composite name whose components consist of a prefix of the
  333. * components in this composite name. Subsequent changes to
  334. * this composite name does not affect the name that is returned.
  335. *
  336. * @param posn The 0-based index of the component at which to stop.
  337. * Must be in the range [0,size()].
  338. * @return A composite name consisting of the components at indexes in
  339. * the range [0,posn).
  340. * @exception ArrayIndexOutOfBoundsException
  341. * If posn is outside the specified range.
  342. */
  343. public Name getPrefix(int posn) {
  344. Enumeration comps = impl.getPrefix(posn);
  345. return (new CompositeName(comps));
  346. }
  347. /**
  348. * Creates a composite name whose components consist of a suffix of the
  349. * components in this composite name. Subsequent changes to
  350. * this composite name does not affect the name that is returned.
  351. *
  352. * @param posn The 0-based index of the component at which to start.
  353. * Must be in the range [0,size()].
  354. * @return A composite name consisting of the components at indexes in
  355. * the range [posn,size()). If posn is equal to
  356. * size(), an empty composite name is returned.
  357. * @exception ArrayIndexOutOfBoundsException
  358. * If posn is outside the specified range.
  359. */
  360. public Name getSuffix(int posn) {
  361. Enumeration comps = impl.getSuffix(posn);
  362. return (new CompositeName(comps));
  363. }
  364. /**
  365. * Determines whether a composite name is a prefix of this composite name.
  366. * A composite name 'n' is a prefix if it is equal to
  367. * getPrefix(n.size())--in other words, this composite name
  368. * starts with 'n'. If 'n' is null or not a composite name, false is returned.
  369. *
  370. * @param n The possibly null name to check.
  371. * @return true if n is a CompositeName and
  372. * is a prefix of this composite name, false otherwise.
  373. */
  374. public boolean startsWith(Name n) {
  375. if (n instanceof CompositeName) {
  376. return (impl.startsWith(n.size(), n.getAll()));
  377. } else {
  378. return false;
  379. }
  380. }
  381. /**
  382. * Determines whether a composite name is a suffix of this composite name.
  383. * A composite name 'n' is a suffix if it it is equal to
  384. * getSuffix(size()-n.size())--in other words, this
  385. * composite name ends with 'n'.
  386. * If n is null or not a composite name, false is returned.
  387. *
  388. * @param n The possibly null name to check.
  389. * @return true if n is a CompositeName and
  390. * is a suffix of this composite name, false otherwise.
  391. */
  392. public boolean endsWith(Name n) {
  393. if (n instanceof CompositeName) {
  394. return (impl.endsWith(n.size(), n.getAll()));
  395. } else {
  396. return false;
  397. }
  398. }
  399. /**
  400. * Adds the components of a composite name -- in order -- to the end of
  401. * this composite name.
  402. *
  403. * @param suffix The non-null components to add.
  404. * @return The updated CompositeName, not a new one. Cannot be null.
  405. * @exception InvalidNameException If suffix is not a composite name.
  406. */
  407. public Name addAll(Name suffix) throws InvalidNameException {
  408. if (suffix instanceof CompositeName) {
  409. impl.addAll(suffix.getAll());
  410. return this;
  411. } else {
  412. throw new InvalidNameException("Not a composite name: " +
  413. suffix.toString());
  414. }
  415. }
  416. /**
  417. * Adds the components of a composite name -- in order -- at a specified
  418. * position within this composite name.
  419. * Components of this composite name at or after the index of the first
  420. * new component are shifted up (away from index 0)
  421. * to accommodate the new components.
  422. *
  423. * @param n The non-null components to add.
  424. * @param posn The index in this name at which to add the new
  425. * components. Must be in the range [0,size()].
  426. * @return The updated CompositeName, not a new one. Cannot be null.
  427. * @exception InvalidNameException If n is not a composite name.
  428. * @exception ArrayIndexOutOfBoundsException
  429. * If posn is outside the specified range.
  430. */
  431. public Name addAll(int posn, Name n) throws InvalidNameException {
  432. if (n instanceof CompositeName) {
  433. impl.addAll(posn, n.getAll());
  434. return this;
  435. } else {
  436. throw new InvalidNameException("Not a composite name: " +
  437. n.toString());
  438. }
  439. }
  440. /**
  441. * Adds a single component to the end of this composite name.
  442. *
  443. * @param comp The non-null component to add.
  444. * @return The updated CompositeName, not a new one. Cannot be null.
  445. * @exception InvalidNameException If adding comp at end of the name
  446. * would violate the name's syntax.
  447. */
  448. public Name add(String comp) throws InvalidNameException {
  449. impl.add(comp);
  450. return this;
  451. }
  452. /**
  453. * Adds a single component at a specified position within this
  454. * composite name.
  455. * Components of this composite name at or after the index of the new
  456. * component are shifted up by one (away from index 0) to accommodate
  457. * the new component.
  458. *
  459. * @param comp The non-null component to add.
  460. * @param posn The index at which to add the new component.
  461. * Must be in the range [0,size()].
  462. * @return The updated CompositeName, not a new one. Cannot be null.
  463. * @exception ArrayIndexOutOfBoundsException
  464. * If posn is outside the specified range.
  465. * @exception InvalidNameException If adding comp at the specified position
  466. * would violate the name's syntax.
  467. */
  468. public Name add(int posn, String comp) throws InvalidNameException {
  469. impl.add(posn, comp);
  470. return this;
  471. }
  472. /**
  473. * Deletes a component from this composite name.
  474. * The component of this composite name at position 'posn' is removed,
  475. * and components at indices greater than 'posn'
  476. * are shifted down (towards index 0) by one.
  477. *
  478. * @param posn The index of the component to delete.
  479. * Must be in the range [0,size()).
  480. * @return The component removed (a String).
  481. * @exception ArrayIndexOutOfBoundsException
  482. * If posn is outside the specified range (includes case where
  483. * composite name is empty).
  484. * @exception InvalidNameException If deleting the component
  485. * would violate the name's syntax.
  486. */
  487. public Object remove(int posn) throws InvalidNameException{
  488. return impl.remove(posn);
  489. }
  490. /**
  491. * Overridden to avoid implementation dependency.
  492. * @serialData The number of components (an <tt>int</tt>) followed by
  493. * the individual components (each a <tt>String</tt>).
  494. */
  495. private void writeObject(java.io.ObjectOutputStream s)
  496. throws java.io.IOException {
  497. s.writeInt(size());
  498. Enumeration comps = getAll();
  499. while (comps.hasMoreElements()) {
  500. s.writeObject(comps.nextElement());
  501. }
  502. }
  503. /**
  504. * Overridden to avoid implementation dependency.
  505. */
  506. private void readObject(java.io.ObjectInputStream s)
  507. throws java.io.IOException, ClassNotFoundException {
  508. impl = new NameImpl(null); // null means use default syntax
  509. int n = s.readInt(); // number of components
  510. try {
  511. while (--n >= 0) {
  512. add((String)s.readObject());
  513. }
  514. } catch (InvalidNameException e) {
  515. throw (new java.io.StreamCorruptedException("Invalid name"));
  516. }
  517. }
  518. /**
  519. * Use serialVersionUID from JNDI 1.1.1 for interoperability
  520. */
  521. private static final long serialVersionUID = 1667768148915813118L;
  522. /*
  523. // %%% Test code for serialization.
  524. public static void main(String[] args) throws Exception {
  525. CompositeName c = new CompositeName("aaa/bbb");
  526. java.io.FileOutputStream f1 = new java.io.FileOutputStream("/tmp/ser");
  527. java.io.ObjectOutputStream s1 = new java.io.ObjectOutputStream(f1);
  528. s1.writeObject(c);
  529. s1.close();
  530. java.io.FileInputStream f2 = new java.io.FileInputStream("/tmp/ser");
  531. java.io.ObjectInputStream s2 = new java.io.ObjectInputStream(f2);
  532. c = (CompositeName)s2.readObject();
  533. System.out.println("Size: " + c.size());
  534. System.out.println("Size: " + c.snit);
  535. }
  536. */
  537. /*
  538. %%% Testing code
  539. public static void main(String[] args) {
  540. try {
  541. for (int i = 0; i < args.length; i++) {
  542. Name name;
  543. Enumeration e;
  544. System.out.println("Given name: " + args[i]);
  545. name = new CompositeName(args[i]);
  546. e = name.getComponents();
  547. while (e.hasMoreElements()) {
  548. System.out.println("Element: " + e.nextElement());
  549. }
  550. System.out.println("Constructed name: " + name.toString());
  551. }
  552. } catch (Exception ne) {
  553. ne.printStackTrace();
  554. }
  555. }
  556. */
  557. }