| /* |
| * Copyright (c) 1999, 2002, 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.Vector; |
| import java.util.Enumeration; |
| import java.util.Properties; |
| import java.util.NoSuchElementException; |
| |
| /** |
| * The implementation class for CompoundName and CompositeName. |
| * This class is package private. |
| * |
| * @author Rosanna Lee |
| * @author Scott Seligman |
| * @author Aravindan Ranganathan |
| * @since 1.3 |
| */ |
| |
| class NameImpl { |
| private static final byte LEFT_TO_RIGHT = 1; |
| private static final byte RIGHT_TO_LEFT = 2; |
| private static final byte FLAT = 0; |
| |
| private Vector components; |
| |
| private byte syntaxDirection = LEFT_TO_RIGHT; |
| private String syntaxSeparator = "/"; |
| private String syntaxSeparator2 = null; |
| private boolean syntaxCaseInsensitive = false; |
| private boolean syntaxTrimBlanks = false; |
| private String syntaxEscape = "\\"; |
| private String syntaxBeginQuote1 = "\""; |
| private String syntaxEndQuote1 = "\""; |
| private String syntaxBeginQuote2 = "'"; |
| private String syntaxEndQuote2 = "'"; |
| private String syntaxAvaSeparator = null; |
| private String syntaxTypevalSeparator = null; |
| |
| // escapingStyle gives the method used at creation time for |
| // quoting or escaping characters in the name. It is set to the |
| // first style of quote or escape encountered if and when the name |
| // is parsed. |
| private static final int STYLE_NONE = 0; |
| private static final int STYLE_QUOTE1 = 1; |
| private static final int STYLE_QUOTE2 = 2; |
| private static final int STYLE_ESCAPE = 3; |
| private int escapingStyle = STYLE_NONE; |
| |
| // Returns true if "match" is not null, and n contains "match" at |
| // position i. |
| private final boolean isA(String n, int i, String match) { |
| return (match != null && n.startsWith(match, i)); |
| } |
| |
| private final boolean isMeta(String n, int i) { |
| return (isA(n, i, syntaxEscape) || |
| isA(n, i, syntaxBeginQuote1) || |
| isA(n, i, syntaxBeginQuote2) || |
| isSeparator(n, i)); |
| } |
| |
| private final boolean isSeparator(String n, int i) { |
| return (isA(n, i, syntaxSeparator) || |
| isA(n, i, syntaxSeparator2)); |
| } |
| |
| private final int skipSeparator(String name, int i) { |
| if (isA(name, i, syntaxSeparator)) { |
| i += syntaxSeparator.length(); |
| } else if (isA(name, i, syntaxSeparator2)) { |
| i += syntaxSeparator2.length(); |
| } |
| return (i); |
| } |
| |
| private final int extractComp(String name, int i, int len, Vector comps) |
| throws InvalidNameException { |
| String beginQuote; |
| String endQuote; |
| boolean start = true; |
| boolean one = false; |
| StringBuffer answer = new StringBuffer(len); |
| |
| while (i < len) { |
| // handle quoted strings |
| if (start && ((one = isA(name, i, syntaxBeginQuote1)) || |
| isA(name, i, syntaxBeginQuote2))) { |
| |
| // record choice of quote chars being used |
| beginQuote = one ? syntaxBeginQuote1 : syntaxBeginQuote2; |
| endQuote = one ? syntaxEndQuote1 : syntaxEndQuote2; |
| if (escapingStyle == STYLE_NONE) { |
| escapingStyle = one ? STYLE_QUOTE1 : STYLE_QUOTE2; |
| } |
| |
| // consume string until matching quote |
| for (i += beginQuote.length(); |
| ((i < len) && !name.startsWith(endQuote, i)); |
| i++) { |
| // skip escape character if it is escaping ending quote |
| // otherwise leave as is. |
| if (isA(name, i, syntaxEscape) && |
| isA(name, i + syntaxEscape.length(), endQuote)) { |
| i += syntaxEscape.length(); |
| } |
| answer.append(name.charAt(i)); // copy char |
| } |
| |
| // no ending quote found |
| if (i >= len) |
| throw |
| new InvalidNameException(name + ": no close quote"); |
| // new Exception("no close quote"); |
| |
| i += endQuote.length(); |
| |
| // verify that end-quote occurs at separator or end of string |
| if (i == len || isSeparator(name, i)) { |
| break; |
| } |
| // throw (new Exception( |
| throw (new InvalidNameException(name + |
| ": close quote appears before end of component")); |
| |
| } else if (isSeparator(name, i)) { |
| break; |
| |
| } else if (isA(name, i, syntaxEscape)) { |
| if (isMeta(name, i + syntaxEscape.length())) { |
| // if escape precedes meta, consume escape and let |
| // meta through |
| i += syntaxEscape.length(); |
| if (escapingStyle == STYLE_NONE) { |
| escapingStyle = STYLE_ESCAPE; |
| } |
| } else if (i + syntaxEscape.length() >= len) { |
| throw (new InvalidNameException(name + |
| ": unescaped " + syntaxEscape + " at end of component")); |
| } |
| } else if (isA(name, i, syntaxTypevalSeparator) && |
| ((one = isA(name, i+syntaxTypevalSeparator.length(), syntaxBeginQuote1)) || |
| isA(name, i+syntaxTypevalSeparator.length(), syntaxBeginQuote2))) { |
| // Handle quote occurring after typeval separator |
| beginQuote = one ? syntaxBeginQuote1 : syntaxBeginQuote2; |
| endQuote = one ? syntaxEndQuote1 : syntaxEndQuote2; |
| |
| i += syntaxTypevalSeparator.length(); |
| answer.append(syntaxTypevalSeparator+beginQuote); // add back |
| |
| // consume string until matching quote |
| for (i += beginQuote.length(); |
| ((i < len) && !name.startsWith(endQuote, i)); |
| i++) { |
| // skip escape character if it is escaping ending quote |
| // otherwise leave as is. |
| if (isA(name, i, syntaxEscape) && |
| isA(name, i + syntaxEscape.length(), endQuote)) { |
| i += syntaxEscape.length(); |
| } |
| answer.append(name.charAt(i)); // copy char |
| } |
| |
| // no ending quote found |
| if (i >= len) |
| throw |
| new InvalidNameException(name + ": typeval no close quote"); |
| |
| i += endQuote.length(); |
| answer.append(endQuote); // add back |
| |
| // verify that end-quote occurs at separator or end of string |
| if (i == len || isSeparator(name, i)) { |
| break; |
| } |
| throw (new InvalidNameException(name.substring(i) + |
| ": typeval close quote appears before end of component")); |
| } |
| |
| answer.append(name.charAt(i++)); |
| start = false; |
| } |
| |
| if (syntaxDirection == RIGHT_TO_LEFT) |
| comps.insertElementAt(answer.toString(), 0); |
| else |
| comps.addElement(answer.toString()); |
| return i; |
| } |
| |
| private static boolean getBoolean(Properties p, String name) { |
| return toBoolean(p.getProperty(name)); |
| } |
| |
| private static boolean toBoolean(String name) { |
| return ((name != null) && name.toLowerCase().equals("true")); |
| } |
| |
| private final void recordNamingConvention(Properties p) { |
| String syntaxDirectionStr = |
| p.getProperty("jndi.syntax.direction", "flat"); |
| if (syntaxDirectionStr.equals("left_to_right")) { |
| syntaxDirection = LEFT_TO_RIGHT; |
| } else if (syntaxDirectionStr.equals("right_to_left")) { |
| syntaxDirection = RIGHT_TO_LEFT; |
| } else if (syntaxDirectionStr.equals("flat")) { |
| syntaxDirection = FLAT; |
| } else { |
| throw new IllegalArgumentException(syntaxDirectionStr + |
| "is not a valid value for the jndi.syntax.direction property"); |
| } |
| |
| if (syntaxDirection != FLAT) { |
| syntaxSeparator = p.getProperty("jndi.syntax.separator"); |
| syntaxSeparator2 = p.getProperty("jndi.syntax.separator2"); |
| if (syntaxSeparator == null) { |
| throw new IllegalArgumentException( |
| "jndi.syntax.separator property required for non-flat syntax"); |
| } |
| } else { |
| syntaxSeparator = null; |
| } |
| syntaxEscape = p.getProperty("jndi.syntax.escape"); |
| |
| syntaxCaseInsensitive = getBoolean(p, "jndi.syntax.ignorecase"); |
| syntaxTrimBlanks = getBoolean(p, "jndi.syntax.trimblanks"); |
| |
| syntaxBeginQuote1 = p.getProperty("jndi.syntax.beginquote"); |
| syntaxEndQuote1 = p.getProperty("jndi.syntax.endquote"); |
| if (syntaxEndQuote1 == null && syntaxBeginQuote1 != null) |
| syntaxEndQuote1 = syntaxBeginQuote1; |
| else if (syntaxBeginQuote1 == null && syntaxEndQuote1 != null) |
| syntaxBeginQuote1 = syntaxEndQuote1; |
| syntaxBeginQuote2 = p.getProperty("jndi.syntax.beginquote2"); |
| syntaxEndQuote2 = p.getProperty("jndi.syntax.endquote2"); |
| if (syntaxEndQuote2 == null && syntaxBeginQuote2 != null) |
| syntaxEndQuote2 = syntaxBeginQuote2; |
| else if (syntaxBeginQuote2 == null && syntaxEndQuote2 != null) |
| syntaxBeginQuote2 = syntaxEndQuote2; |
| |
| syntaxAvaSeparator = p.getProperty("jndi.syntax.separator.ava"); |
| syntaxTypevalSeparator = |
| p.getProperty("jndi.syntax.separator.typeval"); |
| } |
| |
| NameImpl(Properties syntax) { |
| if (syntax != null) { |
| recordNamingConvention(syntax); |
| } |
| components = new Vector(); |
| } |
| |
| NameImpl(Properties syntax, String n) throws InvalidNameException { |
| this(syntax); |
| |
| boolean rToL = (syntaxDirection == RIGHT_TO_LEFT); |
| boolean compsAllEmpty = true; |
| int len = n.length(); |
| |
| for (int i = 0; i < len; ) { |
| i = extractComp(n, i, len, components); |
| |
| String comp = rToL |
| ? (String)components.firstElement() |
| : (String)components.lastElement(); |
| if (comp.length() >= 1) { |
| compsAllEmpty = false; |
| } |
| |
| if (i < len) { |
| i = skipSeparator(n, i); |
| if ((i == len) && !compsAllEmpty) { |
| // Trailing separator found. Add an empty component. |
| if (rToL) { |
| components.insertElementAt("", 0); |
| } else { |
| components.addElement(""); |
| } |
| } |
| } |
| } |
| } |
| |
| NameImpl(Properties syntax, Enumeration comps) { |
| this(syntax); |
| |
| // %% comps could shrink in the middle. |
| while (comps.hasMoreElements()) |
| components.addElement(comps.nextElement()); |
| } |
| /* |
| // Determines whether this component needs any escaping. |
| private final boolean escapingNeeded(String comp) { |
| int len = comp.length(); |
| for (int i = 0; i < len; i++) { |
| if (i == 0) { |
| if (isA(comp, 0, syntaxBeginQuote1) || |
| isA(comp, 0, syntaxBeginQuote2)) { |
| return (true); |
| } |
| } |
| if (isSeparator(comp, i)) { |
| return (true); |
| } |
| if (isA(comp, i, syntaxEscape)) { |
| i += syntaxEscape.length(); |
| if (i >= len || isMeta(comp, i)) { |
| return (true); |
| } |
| } |
| } |
| return (false); |
| } |
| */ |
| private final String stringifyComp(String comp) { |
| int len = comp.length(); |
| boolean escapeSeparator = false, escapeSeparator2 = false; |
| String beginQuote = null, endQuote = null; |
| StringBuffer strbuf = new StringBuffer(len); |
| |
| // determine whether there are any separators; if so escape |
| // or quote them |
| if (syntaxSeparator != null && |
| comp.indexOf(syntaxSeparator) >= 0) { |
| if (syntaxBeginQuote1 != null) { |
| beginQuote = syntaxBeginQuote1; |
| endQuote = syntaxEndQuote1; |
| } else if (syntaxBeginQuote2 != null) { |
| beginQuote = syntaxBeginQuote2; |
| endQuote = syntaxEndQuote2; |
| } else if (syntaxEscape != null) |
| escapeSeparator = true; |
| } |
| if (syntaxSeparator2 != null && |
| comp.indexOf(syntaxSeparator2) >= 0) { |
| if (syntaxBeginQuote1 != null) { |
| if (beginQuote == null) { |
| beginQuote = syntaxBeginQuote1; |
| endQuote = syntaxEndQuote1; |
| } |
| } else if (syntaxBeginQuote2 != null) { |
| if (beginQuote == null) { |
| beginQuote = syntaxBeginQuote2; |
| endQuote = syntaxEndQuote2; |
| } |
| } else if (syntaxEscape != null) |
| escapeSeparator2 = true; |
| } |
| |
| // if quoting component, |
| if (beginQuote != null) { |
| |
| // start string off with opening quote |
| strbuf = strbuf.append(beginQuote); |
| |
| // component is being quoted, so we only need to worry about |
| // escaping end quotes that occur in component |
| for (int i = 0; i < len; ) { |
| if (comp.startsWith(endQuote, i)) { |
| // end-quotes must be escaped when inside a quoted string |
| strbuf.append(syntaxEscape).append(endQuote); |
| i += endQuote.length(); |
| } else { |
| // no special treatment required |
| strbuf.append(comp.charAt(i++)); |
| } |
| } |
| |
| // end with closing quote |
| strbuf.append(endQuote); |
| |
| } else { |
| |
| // When component is not quoted, add escape for: |
| // 1. leading quote |
| // 2. an escape preceding any meta char |
| // 3. an escape at the end of a component |
| // 4. separator |
| |
| // go through characters in component and escape where necessary |
| boolean start = true; |
| for (int i = 0; i < len; ) { |
| // leading quote must be escaped |
| if (start && isA(comp, i, syntaxBeginQuote1)) { |
| strbuf.append(syntaxEscape).append(syntaxBeginQuote1); |
| i += syntaxBeginQuote1.length(); |
| } else if (start && isA(comp, i, syntaxBeginQuote2)) { |
| strbuf.append(syntaxEscape).append(syntaxBeginQuote2); |
| i += syntaxBeginQuote2.length(); |
| } else |
| |
| // Escape an escape preceding meta characters, or at end. |
| // Other escapes pass through. |
| if (isA(comp, i, syntaxEscape)) { |
| if (i + syntaxEscape.length() >= len) { |
| // escape an ending escape |
| strbuf.append(syntaxEscape); |
| } else if (isMeta(comp, i + syntaxEscape.length())) { |
| // escape meta strings |
| strbuf.append(syntaxEscape); |
| } |
| strbuf.append(syntaxEscape); |
| i += syntaxEscape.length(); |
| } else |
| |
| // escape unescaped separator |
| if (escapeSeparator && comp.startsWith(syntaxSeparator, i)) { |
| // escape separator |
| strbuf.append(syntaxEscape).append(syntaxSeparator); |
| i += syntaxSeparator.length(); |
| } else if (escapeSeparator2 && |
| comp.startsWith(syntaxSeparator2, i)) { |
| // escape separator2 |
| strbuf.append(syntaxEscape).append(syntaxSeparator2); |
| i += syntaxSeparator2.length(); |
| } else { |
| // no special treatment required |
| strbuf.append(comp.charAt(i++)); |
| } |
| start = false; |
| } |
| } |
| return (strbuf.toString()); |
| } |
| |
| public String toString() { |
| StringBuffer answer = new StringBuffer(); |
| String comp; |
| boolean compsAllEmpty = true; |
| int size = components.size(); |
| |
| for (int i = 0; i < size; i++) { |
| if (syntaxDirection == RIGHT_TO_LEFT) { |
| comp = |
| stringifyComp((String) components.elementAt(size - 1 - i)); |
| } else { |
| comp = stringifyComp((String) components.elementAt(i)); |
| } |
| if ((i != 0) && (syntaxSeparator != null)) |
| answer.append(syntaxSeparator); |
| if (comp.length() >= 1) |
| compsAllEmpty = false; |
| answer = answer.append(comp); |
| } |
| if (compsAllEmpty && (size >= 1) && (syntaxSeparator != null)) |
| answer = answer.append(syntaxSeparator); |
| return (answer.toString()); |
| } |
| |
| public boolean equals(Object obj) { |
| if ((obj != null) && (obj instanceof NameImpl)) { |
| NameImpl target = (NameImpl)obj; |
| if (target.size() == this.size()) { |
| Enumeration mycomps = getAll(); |
| Enumeration comps = target.getAll(); |
| while (mycomps.hasMoreElements()) { |
| // %% comps could shrink in the middle. |
| String my = (String)mycomps.nextElement(); |
| String his = (String)comps.nextElement(); |
| if (syntaxTrimBlanks) { |
| my = my.trim(); |
| his = his.trim(); |
| } |
| if (syntaxCaseInsensitive) { |
| if (!(my.equalsIgnoreCase(his))) |
| return false; |
| } else { |
| if (!(my.equals(his))) |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Compares obj to this NameImpl to determine ordering. |
| * Takes into account syntactic properties such as |
| * elimination of blanks, case-ignore, etc, if relevant. |
| * |
| * Note: using syntax of this NameImpl and ignoring |
| * that of comparison target. |
| */ |
| public int compareTo(NameImpl obj) { |
| if (this == obj) { |
| return 0; |
| } |
| |
| int len1 = size(); |
| int len2 = obj.size(); |
| int n = Math.min(len1, len2); |
| |
| int index1 = 0, index2 = 0; |
| |
| while (n-- != 0) { |
| String comp1 = get(index1++); |
| String comp2 = obj.get(index2++); |
| |
| // normalize according to syntax |
| if (syntaxTrimBlanks) { |
| comp1 = comp1.trim(); |
| comp2 = comp2.trim(); |
| } |
| if (syntaxCaseInsensitive) { |
| comp1 = comp1.toLowerCase(); |
| comp2 = comp2.toLowerCase(); |
| } |
| int local = comp1.compareTo(comp2); |
| if (local != 0) { |
| return local; |
| } |
| } |
| |
| return len1 - len2; |
| } |
| |
| public int size() { |
| return (components.size()); |
| } |
| |
| public Enumeration getAll() { |
| return components.elements(); |
| } |
| |
| public String get(int posn) { |
| return ((String) components.elementAt(posn)); |
| } |
| |
| public Enumeration getPrefix(int posn) { |
| if (posn < 0 || posn > size()) { |
| throw new ArrayIndexOutOfBoundsException(posn); |
| } |
| return new NameImplEnumerator(components, 0, posn); |
| } |
| |
| public Enumeration getSuffix(int posn) { |
| int cnt = size(); |
| if (posn < 0 || posn > cnt) { |
| throw new ArrayIndexOutOfBoundsException(posn); |
| } |
| return new NameImplEnumerator(components, posn, cnt); |
| } |
| |
| public boolean isEmpty() { |
| return (components.isEmpty()); |
| } |
| |
| public boolean startsWith(int posn, Enumeration prefix) { |
| if (posn < 0 || posn > size()) { |
| return false; |
| } |
| try { |
| Enumeration mycomps = getPrefix(posn); |
| while (mycomps.hasMoreElements()) { |
| String my = (String)mycomps.nextElement(); |
| String his = (String)prefix.nextElement(); |
| if (syntaxTrimBlanks) { |
| my = my.trim(); |
| his = his.trim(); |
| } |
| if (syntaxCaseInsensitive) { |
| if (!(my.equalsIgnoreCase(his))) |
| return false; |
| } else { |
| if (!(my.equals(his))) |
| return false; |
| } |
| } |
| } catch (NoSuchElementException e) { |
| return false; |
| } |
| return true; |
| } |
| |
| public boolean endsWith(int posn, Enumeration suffix) { |
| // posn is number of elements in suffix |
| // startIndex is the starting position in this name |
| // at which to start the comparison. It is calculated by |
| // subtracting 'posn' from size() |
| int startIndex = size() - posn; |
| if (startIndex < 0 || startIndex > size()) { |
| return false; |
| } |
| try { |
| Enumeration mycomps = getSuffix(startIndex); |
| while (mycomps.hasMoreElements()) { |
| String my = (String)mycomps.nextElement(); |
| String his = (String)suffix.nextElement(); |
| if (syntaxTrimBlanks) { |
| my = my.trim(); |
| his = his.trim(); |
| } |
| if (syntaxCaseInsensitive) { |
| if (!(my.equalsIgnoreCase(his))) |
| return false; |
| } else { |
| if (!(my.equals(his))) |
| return false; |
| } |
| } |
| } catch (NoSuchElementException e) { |
| return false; |
| } |
| return true; |
| } |
| |
| public boolean addAll(Enumeration comps) throws InvalidNameException { |
| boolean added = false; |
| while (comps.hasMoreElements()) { |
| try { |
| Object comp = comps.nextElement(); |
| if (size() > 0 && syntaxDirection == FLAT) { |
| throw new InvalidNameException( |
| "A flat name can only have a single component"); |
| } |
| components.addElement(comp); |
| added = true; |
| } catch (NoSuchElementException e) { |
| break; // "comps" has shrunk. |
| } |
| } |
| return added; |
| } |
| |
| public boolean addAll(int posn, Enumeration comps) |
| throws InvalidNameException { |
| boolean added = false; |
| for (int i = posn; comps.hasMoreElements(); i++) { |
| try { |
| Object comp = comps.nextElement(); |
| if (size() > 0 && syntaxDirection == FLAT) { |
| throw new InvalidNameException( |
| "A flat name can only have a single component"); |
| } |
| components.insertElementAt(comp, i); |
| added = true; |
| } catch (NoSuchElementException e) { |
| break; // "comps" has shrunk. |
| } |
| } |
| return added; |
| } |
| |
| public void add(String comp) throws InvalidNameException { |
| if (size() > 0 && syntaxDirection == FLAT) { |
| throw new InvalidNameException( |
| "A flat name can only have a single component"); |
| } |
| components.addElement(comp); |
| } |
| |
| public void add(int posn, String comp) throws InvalidNameException { |
| if (size() > 0 && syntaxDirection == FLAT) { |
| throw new InvalidNameException( |
| "A flat name can only zero or one component"); |
| } |
| components.insertElementAt(comp, posn); |
| } |
| |
| public Object remove(int posn) { |
| Object r = components.elementAt(posn); |
| components.removeElementAt(posn); |
| return r; |
| } |
| |
| public int hashCode() { |
| int hash = 0; |
| for (Enumeration e = getAll(); e.hasMoreElements();) { |
| String comp = (String)e.nextElement(); |
| if (syntaxTrimBlanks) { |
| comp = comp.trim(); |
| } |
| if (syntaxCaseInsensitive) { |
| comp = comp.toLowerCase(); |
| } |
| |
| hash += comp.hashCode(); |
| } |
| return hash; |
| } |
| } |
| |
| final |
| class NameImplEnumerator implements Enumeration { |
| Vector vector; |
| int count; |
| int limit; |
| |
| NameImplEnumerator(Vector v, int start, int lim) { |
| vector = v; |
| count = start; |
| limit = lim; |
| } |
| |
| public boolean hasMoreElements() { |
| return count < limit; |
| } |
| |
| public Object nextElement() { |
| if (count < limit) { |
| return vector.elementAt(count++); |
| } |
| throw new NoSuchElementException("NameImplEnumerator"); |
| } |
| } |