jdk/src/java.naming/share/classes/javax/naming/CompositeName.java
author chegar
Sun, 17 Aug 2014 15:54:13 +0100
changeset 25859 3317bb8137f4
parent 22974 jdk/src/share/classes/javax/naming/CompositeName.java@4bf6c0d73bb8
child 32029 a5538163e144
permissions -rw-r--r--
8054834: Modular Source Code Reviewed-by: alanb, chegar, ihse, mduigou Contributed-by: alan.bateman@oracle.com, alex.buckley@oracle.com, chris.hegarty@oracle.com, erik.joelsson@oracle.com, jonathan.gibbons@oracle.com, karen.kinnear@oracle.com, magnus.ihse.bursie@oracle.com, mandy.chung@oracle.com, mark.reinhold@oracle.com, paul.sandoz@oracle.com

/*
 * Copyright (c) 1999, 2013, 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;

/**
 * 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.
 *
 * <h1>JNDI Composite Name Syntax</h1>
 * 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.
 *
 *<h1>Composite Name Examples</h1>
 *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>).
 *
<table border="1" cellpadding=3 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>
 *
 *<h1>Composition Examples</h1>
 * 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.

<table border="1" cellpadding=3 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>
 *
 *<h1>Multithreaded Access</h1>
 * 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;
    /**
      * Constructs a new composite name instance using the components
      * specified by 'comps'. This protected method is intended
      * 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
    }

    /**
      * 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
    }

    /**
      * 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
    }

    /**
      * 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();
    }

    /**
      * 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));
    }

    /**
      * 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();
    }


    /**
     * 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);
    }

    /**
      * 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()));
    }

    /**
      * 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());
    }

    /**
      * 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());
    }

    /**
      * 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());
    }

    /**
      * 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));
    }

    /**
      * 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<String> comps = impl.getPrefix(posn);
        return (new CompositeName(comps));
    }

    /**
      * 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<String> comps = impl.getSuffix(posn);
        return (new CompositeName(comps));
    }

    /**
      * 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;
        }
    }

    /**
      * Determines whether a composite name is a suffix of this composite name.
      * A composite name 'n' is a suffix if 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;
        }
    }

    /**
      * 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());
        }
    }

    /**
      * 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());
        }
    }

    /**
      * 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;
    }

    /**
      * 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;
    }

    /**
      * 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);
    }

    /**
     * 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<String> comps = getAll();
        while (comps.hasMoreElements()) {
            s.writeObject(comps.nextElement());
        }
    }

    /**
     * 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"));
        }
    }

    /**
     * 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();
        }
    }
*/
}