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