/* * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.naming; import java.util.Enumeration; import java.util.Properties; /** {@collect.stats} * This class represents a composite name -- a sequence of * component names spanning multiple namespaces. * Each component is a string name from the namespace of a * naming system. If the component comes from a hierarchical * namespace, that component can be further parsed into * its atomic parts by using the CompoundName class. *<p> * The components of a composite name are numbered. The indexes of a * composite name with N components range from 0 up to, but not including, N. * This range may be written as [0,N). * The most significant component is at index 0. * An empty composite name has no components. *<p> * <h4>JNDI Composite Name Syntax</h4> * JNDI defines a standard string representation for composite names. This * representation is the concatenation of the components of a composite name * from left to right using the component separator (a forward * slash character (/)) to separate each component. * The JNDI syntax defines the following meta characters: * <ul> * <li>escape (backward slash \), * <li>quote characters (single (') and double quotes (")), and * <li>component separator (forward slash character (/)). * </ul> * Any occurrence of a leading quote, an escape preceding any meta character, * an escape at the end of a component, or a component separator character * in an unquoted component must be preceded by an escape character when * that component is being composed into a composite name string. * Alternatively, to avoid adding escape characters as described, * the entire component can be quoted using matching single quotes * or matching double quotes. A single quote occurring within a double-quoted * component is not considered a meta character (and need not be escaped), * and vice versa. *<p> * When two composite names are compared, the case of the characters * is significant. *<p> * A leading component separator (the composite name string begins with * a separator) denotes a leading empty component (a component consisting * of an empty string). * A trailing component separator (the composite name string ends with * a separator) denotes a trailing empty component. * Adjacent component separators denote an empty component. *<p> *<h4>Composite Name Examples</h4> *This table shows examples of some composite names. Each row shows *the string form of a composite name and its corresponding structural form *(<tt>CompositeName</tt>). *<p> <table border="1" cellpadding=3 width="70%" summary="examples showing string form of composite name and its corresponding structural form (CompositeName)"> <tr> <th>String Name</th> <th>CompositeName</th> </tr> <tr> <td> "" </td> <td>{} (the empty name == new CompositeName("") == new CompositeName()) </td> </tr> <tr> <td> "x" </td> <td>{"x"} </td> </tr> <tr> <td> "x/y" </td> <td>{"x", "y"}</td> </tr> <tr> <td>"x/"</td> <td>{"x", ""}</td> </tr> <tr> <td>"/x"</td> <td>{"", "x"}</td> </tr> <tr> <td>"/"</td> <td>{""}</td> </tr> <tr> <td>"//"</td> <td>{"", ""}</td> </tr> <tr><td>"/x/"</td> <td>{"", "x", ""}</td> </tr> <tr><td>"x//y"</td> <td>{"x", "", "y"}</td> </tr> </table> * <p> *<h4>Composition Examples</h4> * Here are some composition examples. The right column shows composing * string composite names while the left column shows composing the * corresponding <tt>CompositeName</tt>s. Notice that composing the * string forms of two composite names simply involves concatenating * their string forms together. <p> <table border="1" cellpadding=3 width="70%" summary="composition examples showing string names and composite names"> <tr> <th>String Names</th> <th>CompositeNames</th> </tr> <tr> <td> "x/y" + "/" = x/y/ </td> <td> {"x", "y"} + {""} = {"x", "y", ""} </td> </tr> <tr> <td> "" + "x" = "x" </td> <td> {} + {"x"} = {"x"} </td> </tr> <tr> <td> "/" + "x" = "/x" </td> <td> {""} + {"x"} = {"", "x"} </td> </tr> <tr> <td> "x" + "" + "" = "x" </td> <td> {"x"} + {} + {} = {"x"} </td> </tr> </table> *<p> *<h4>Multithreaded Access</h4> * A <tt>CompositeName</tt> instance is not synchronized against concurrent * multithreaded access. Multiple threads trying to access and modify a * <tt>CompositeName</tt> should lock the object. * * @author Rosanna Lee * @author Scott Seligman * @since 1.3 */ public class CompositeName implements Name { private transient NameImpl impl; /** {@collect.stats} * Constructs a new composite name instance using the components * specified by 'comps'. This protected method is intended to be * to be used by subclasses of CompositeName when they override * methods such as clone(), getPrefix(), getSuffix(). * * @param comps A non-null enumeration containing the components for the new * composite name. Each element is of class String. * The enumeration will be consumed to extract its * elements. */ protected CompositeName(Enumeration<String> comps) { impl = new NameImpl(null, comps); // null means use default syntax } /** {@collect.stats} * Constructs a new composite name instance by parsing the string n * using the composite name syntax (left-to-right, slash separated). * The composite name syntax is described in detail in the class * description. * * @param n The non-null string to parse. * @exception InvalidNameException If n has invalid composite name syntax. */ public CompositeName(String n) throws InvalidNameException { impl = new NameImpl(null, n); // null means use default syntax } /** {@collect.stats} * Constructs a new empty composite name. Such a name returns true * when <code>isEmpty()</code> is invoked on it. */ public CompositeName() { impl = new NameImpl(null); // null means use default syntax } /** {@collect.stats} * Generates the string representation of this composite name. * The string representation consists of enumerating in order * each component of the composite name and separating * each component by a forward slash character. Quoting and * escape characters are applied where necessary according to * the JNDI syntax, which is described in the class description. * An empty component is represented by an empty string. * * The string representation thus generated can be passed to * the CompositeName constructor to create a new equivalent * composite name. * * @return A non-null string representation of this composite name. */ public String toString() { return impl.toString(); } /** {@collect.stats} * Determines whether two composite names are equal. * If obj is null or not a composite name, false is returned. * Two composite names are equal if each component in one is equal * to the corresponding component in the other. This implies * both have the same number of components, and each component's * equals() test against the corresponding component in the other name * returns true. * * @param obj The possibly null object to compare against. * @return true if obj is equal to this composite name, false otherwise. * @see #hashCode */ public boolean equals(Object obj) { return (obj != null && obj instanceof CompositeName && impl.equals(((CompositeName)obj).impl)); } /** {@collect.stats} * Computes the hash code of this composite name. * The hash code is the sum of the hash codes of individual components * of this composite name. * * @return An int representing the hash code of this name. * @see #equals */ public int hashCode() { return impl.hashCode(); } /** {@collect.stats} * Compares this CompositeName with the specified Object for order. * Returns a * negative integer, zero, or a positive integer as this Name is less * than, equal to, or greater than the given Object. * <p> * If obj is null or not an instance of CompositeName, ClassCastException * is thrown. * <p> * See equals() for what it means for two composite names to be equal. * If two composite names are equal, 0 is returned. * <p> * Ordering of composite names follows the lexicographical rules for * string comparison, with the extension that this applies to all * the components in the composite name. The effect is as if all the * components were lined up in their specified ordered and the * lexicographical rules applied over the two line-ups. * If this composite name is "lexicographically" lesser than obj, * a negative number is returned. * If this composite name is "lexicographically" greater than obj, * a positive number is returned. * @param obj The non-null object to compare against. * * @return a negative integer, zero, or a positive integer as this Name * is less than, equal to, or greater than the given Object. * @exception ClassCastException if obj is not a CompositeName. */ public int compareTo(Object obj) { if (!(obj instanceof CompositeName)) { throw new ClassCastException("Not a CompositeName"); } return impl.compareTo(((CompositeName)obj).impl); } /** {@collect.stats} * Generates a copy of this composite name. * Changes to the components of this composite name won't * affect the new copy and vice versa. * * @return A non-null copy of this composite name. */ public Object clone() { return (new CompositeName(getAll())); } /** {@collect.stats} * Retrieves the number of components in this composite name. * * @return The nonnegative number of components in this composite name. */ public int size() { return (impl.size()); } /** {@collect.stats} * Determines whether this composite name is empty. A composite name * is empty if it has zero components. * * @return true if this composite name is empty, false otherwise. */ public boolean isEmpty() { return (impl.isEmpty()); } /** {@collect.stats} * Retrieves the components of this composite name as an enumeration * of strings. * The effects of updates to this composite name on this enumeration * is undefined. * * @return A non-null enumeration of the components of * this composite name. Each element of the enumeration is of * class String. */ public Enumeration<String> getAll() { return (impl.getAll()); } /** {@collect.stats} * Retrieves a component of this composite name. * * @param posn The 0-based index of the component to retrieve. * Must be in the range [0,size()). * @return The non-null component at index posn. * @exception ArrayIndexOutOfBoundsException if posn is outside the * specified range. */ public String get(int posn) { return (impl.get(posn)); } /** {@collect.stats} * Creates a composite name whose components consist of a prefix of the * components in this composite name. Subsequent changes to * this composite name does not affect the name that is returned. * * @param posn The 0-based index of the component at which to stop. * Must be in the range [0,size()]. * @return A composite name consisting of the components at indexes in * the range [0,posn). * @exception ArrayIndexOutOfBoundsException * If posn is outside the specified range. */ public Name getPrefix(int posn) { Enumeration comps = impl.getPrefix(posn); return (new CompositeName(comps)); } /** {@collect.stats} * Creates a composite name whose components consist of a suffix of the * components in this composite name. Subsequent changes to * this composite name does not affect the name that is returned. * * @param posn The 0-based index of the component at which to start. * Must be in the range [0,size()]. * @return A composite name consisting of the components at indexes in * the range [posn,size()). If posn is equal to * size(), an empty composite name is returned. * @exception ArrayIndexOutOfBoundsException * If posn is outside the specified range. */ public Name getSuffix(int posn) { Enumeration comps = impl.getSuffix(posn); return (new CompositeName(comps)); } /** {@collect.stats} * Determines whether a composite name is a prefix of this composite name. * A composite name 'n' is a prefix if it is equal to * getPrefix(n.size())--in other words, this composite name * starts with 'n'. If 'n' is null or not a composite name, false is returned. * * @param n The possibly null name to check. * @return true if n is a CompositeName and * is a prefix of this composite name, false otherwise. */ public boolean startsWith(Name n) { if (n instanceof CompositeName) { return (impl.startsWith(n.size(), n.getAll())); } else { return false; } } /** {@collect.stats} * Determines whether a composite name is a suffix of this composite name. * A composite name 'n' is a suffix if it it is equal to * getSuffix(size()-n.size())--in other words, this * composite name ends with 'n'. * If n is null or not a composite name, false is returned. * * @param n The possibly null name to check. * @return true if n is a CompositeName and * is a suffix of this composite name, false otherwise. */ public boolean endsWith(Name n) { if (n instanceof CompositeName) { return (impl.endsWith(n.size(), n.getAll())); } else { return false; } } /** {@collect.stats} * Adds the components of a composite name -- in order -- to the end of * this composite name. * * @param suffix The non-null components to add. * @return The updated CompositeName, not a new one. Cannot be null. * @exception InvalidNameException If suffix is not a composite name. */ public Name addAll(Name suffix) throws InvalidNameException { if (suffix instanceof CompositeName) { impl.addAll(suffix.getAll()); return this; } else { throw new InvalidNameException("Not a composite name: " + suffix.toString()); } } /** {@collect.stats} * Adds the components of a composite name -- in order -- at a specified * position within this composite name. * Components of this composite name at or after the index of the first * new component are shifted up (away from index 0) * to accommodate the new components. * * @param n The non-null components to add. * @param posn The index in this name at which to add the new * components. Must be in the range [0,size()]. * @return The updated CompositeName, not a new one. Cannot be null. * @exception InvalidNameException If n is not a composite name. * @exception ArrayIndexOutOfBoundsException * If posn is outside the specified range. */ public Name addAll(int posn, Name n) throws InvalidNameException { if (n instanceof CompositeName) { impl.addAll(posn, n.getAll()); return this; } else { throw new InvalidNameException("Not a composite name: " + n.toString()); } } /** {@collect.stats} * Adds a single component to the end of this composite name. * * @param comp The non-null component to add. * @return The updated CompositeName, not a new one. Cannot be null. * @exception InvalidNameException If adding comp at end of the name * would violate the name's syntax. */ public Name add(String comp) throws InvalidNameException { impl.add(comp); return this; } /** {@collect.stats} * Adds a single component at a specified position within this * composite name. * Components of this composite name at or after the index of the new * component are shifted up by one (away from index 0) to accommodate * the new component. * * @param comp The non-null component to add. * @param posn The index at which to add the new component. * Must be in the range [0,size()]. * @return The updated CompositeName, not a new one. Cannot be null. * @exception ArrayIndexOutOfBoundsException * If posn is outside the specified range. * @exception InvalidNameException If adding comp at the specified position * would violate the name's syntax. */ public Name add(int posn, String comp) throws InvalidNameException { impl.add(posn, comp); return this; } /** {@collect.stats} * Deletes a component from this composite name. * The component of this composite name at position 'posn' is removed, * and components at indices greater than 'posn' * are shifted down (towards index 0) by one. * * @param posn The index of the component to delete. * Must be in the range [0,size()). * @return The component removed (a String). * @exception ArrayIndexOutOfBoundsException * If posn is outside the specified range (includes case where * composite name is empty). * @exception InvalidNameException If deleting the component * would violate the name's syntax. */ public Object remove(int posn) throws InvalidNameException{ return impl.remove(posn); } /** {@collect.stats} * Overridden to avoid implementation dependency. * @serialData The number of components (an <tt>int</tt>) followed by * the individual components (each a <tt>String</tt>). */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.writeInt(size()); Enumeration comps = getAll(); while (comps.hasMoreElements()) { s.writeObject(comps.nextElement()); } } /** {@collect.stats} * Overridden to avoid implementation dependency. */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { impl = new NameImpl(null); // null means use default syntax int n = s.readInt(); // number of components try { while (--n >= 0) { add((String)s.readObject()); } } catch (InvalidNameException e) { throw (new java.io.StreamCorruptedException("Invalid name")); } } /** {@collect.stats} * Use serialVersionUID from JNDI 1.1.1 for interoperability */ private static final long serialVersionUID = 1667768148915813118L; /* // %%% Test code for serialization. public static void main(String[] args) throws Exception { CompositeName c = new CompositeName("aaa/bbb"); java.io.FileOutputStream f1 = new java.io.FileOutputStream("/tmp/ser"); java.io.ObjectOutputStream s1 = new java.io.ObjectOutputStream(f1); s1.writeObject(c); s1.close(); java.io.FileInputStream f2 = new java.io.FileInputStream("/tmp/ser"); java.io.ObjectInputStream s2 = new java.io.ObjectInputStream(f2); c = (CompositeName)s2.readObject(); System.out.println("Size: " + c.size()); System.out.println("Size: " + c.snit); } */ /* %%% Testing code public static void main(String[] args) { try { for (int i = 0; i < args.length; i++) { Name name; Enumeration e; System.out.println("Given name: " + args[i]); name = new CompositeName(args[i]); e = name.getComponents(); while (e.hasMoreElements()) { System.out.println("Element: " + e.nextElement()); } System.out.println("Constructed name: " + name.toString()); } } catch (Exception ne) { ne.printStackTrace(); } } */ }