Path: blob/master/src/java.naming/share/classes/javax/naming/NameImpl.java
41152 views
/*1* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.naming;2627import java.util.Locale;28import java.util.Vector;29import java.util.Enumeration;30import java.util.Properties;31import java.util.NoSuchElementException;3233/**34* The implementation class for CompoundName and CompositeName.35* This class is package private.36*37* @author Rosanna Lee38* @author Scott Seligman39* @author Aravindan Ranganathan40* @since 1.341*/4243class NameImpl {44private static final byte LEFT_TO_RIGHT = 1;45private static final byte RIGHT_TO_LEFT = 2;46private static final byte FLAT = 0;4748private Vector<String> components;4950private byte syntaxDirection = LEFT_TO_RIGHT;51private String syntaxSeparator = "/";52private String syntaxSeparator2 = null;53private boolean syntaxCaseInsensitive = false;54private boolean syntaxTrimBlanks = false;55private String syntaxEscape = "\\";56private String syntaxBeginQuote1 = "\"";57private String syntaxEndQuote1 = "\"";58private String syntaxBeginQuote2 = "'";59private String syntaxEndQuote2 = "'";60private String syntaxAvaSeparator = null;61private String syntaxTypevalSeparator = null;6263// escapingStyle gives the method used at creation time for64// quoting or escaping characters in the name. It is set to the65// first style of quote or escape encountered if and when the name66// is parsed.67private static final int STYLE_NONE = 0;68private static final int STYLE_QUOTE1 = 1;69private static final int STYLE_QUOTE2 = 2;70private static final int STYLE_ESCAPE = 3;71private int escapingStyle = STYLE_NONE;7273// Returns true if "match" is not null, and n contains "match" at74// position i.75private final boolean isA(String n, int i, String match) {76return (match != null && n.startsWith(match, i));77}7879private final boolean isMeta(String n, int i) {80return (isA(n, i, syntaxEscape) ||81isA(n, i, syntaxBeginQuote1) ||82isA(n, i, syntaxBeginQuote2) ||83isSeparator(n, i));84}8586private final boolean isSeparator(String n, int i) {87return (isA(n, i, syntaxSeparator) ||88isA(n, i, syntaxSeparator2));89}9091private final int skipSeparator(String name, int i) {92if (isA(name, i, syntaxSeparator)) {93i += syntaxSeparator.length();94} else if (isA(name, i, syntaxSeparator2)) {95i += syntaxSeparator2.length();96}97return (i);98}99100private final int extractComp(String name, int i, int len, Vector<String> comps)101throws InvalidNameException {102String beginQuote;103String endQuote;104boolean start = true;105boolean one = false;106StringBuilder answer = new StringBuilder(len);107108while (i < len) {109// handle quoted strings110if (start && ((one = isA(name, i, syntaxBeginQuote1)) ||111isA(name, i, syntaxBeginQuote2))) {112113// record choice of quote chars being used114beginQuote = one ? syntaxBeginQuote1 : syntaxBeginQuote2;115endQuote = one ? syntaxEndQuote1 : syntaxEndQuote2;116if (escapingStyle == STYLE_NONE) {117escapingStyle = one ? STYLE_QUOTE1 : STYLE_QUOTE2;118}119120// consume string until matching quote121for (i += beginQuote.length();122((i < len) && !name.startsWith(endQuote, i));123i++) {124// skip escape character if it is escaping ending quote125// otherwise leave as is.126if (isA(name, i, syntaxEscape) &&127isA(name, i + syntaxEscape.length(), endQuote)) {128i += syntaxEscape.length();129}130answer.append(name.charAt(i)); // copy char131}132133// no ending quote found134if (i >= len)135throw136new InvalidNameException(name + ": no close quote");137// new Exception("no close quote");138139i += endQuote.length();140141// verify that end-quote occurs at separator or end of string142if (i == len || isSeparator(name, i)) {143break;144}145// throw (new Exception(146throw (new InvalidNameException(name +147": close quote appears before end of component"));148149} else if (isSeparator(name, i)) {150break;151152} else if (isA(name, i, syntaxEscape)) {153if (isMeta(name, i + syntaxEscape.length())) {154// if escape precedes meta, consume escape and let155// meta through156i += syntaxEscape.length();157if (escapingStyle == STYLE_NONE) {158escapingStyle = STYLE_ESCAPE;159}160} else if (i + syntaxEscape.length() >= len) {161throw (new InvalidNameException(name +162": unescaped " + syntaxEscape + " at end of component"));163}164} else if (isA(name, i, syntaxTypevalSeparator) &&165((one = isA(name, i+syntaxTypevalSeparator.length(), syntaxBeginQuote1)) ||166isA(name, i+syntaxTypevalSeparator.length(), syntaxBeginQuote2))) {167// Handle quote occurring after typeval separator168beginQuote = one ? syntaxBeginQuote1 : syntaxBeginQuote2;169endQuote = one ? syntaxEndQuote1 : syntaxEndQuote2;170171i += syntaxTypevalSeparator.length();172answer.append(syntaxTypevalSeparator).append(beginQuote); // add back173174// consume string until matching quote175for (i += beginQuote.length();176((i < len) && !name.startsWith(endQuote, i));177i++) {178// skip escape character if it is escaping ending quote179// otherwise leave as is.180if (isA(name, i, syntaxEscape) &&181isA(name, i + syntaxEscape.length(), endQuote)) {182i += syntaxEscape.length();183}184answer.append(name.charAt(i)); // copy char185}186187// no ending quote found188if (i >= len)189throw190new InvalidNameException(name + ": typeval no close quote");191192i += endQuote.length();193answer.append(endQuote); // add back194195// verify that end-quote occurs at separator or end of string196if (i == len || isSeparator(name, i)) {197break;198}199throw (new InvalidNameException(name.substring(i) +200": typeval close quote appears before end of component"));201}202203answer.append(name.charAt(i++));204start = false;205}206207if (syntaxDirection == RIGHT_TO_LEFT)208comps.insertElementAt(answer.toString(), 0);209else210comps.addElement(answer.toString());211return i;212}213214private static boolean getBoolean(Properties p, String name) {215return toBoolean(p.getProperty(name));216}217218private static boolean toBoolean(String name) {219return ((name != null) &&220name.toLowerCase(Locale.ENGLISH).equals("true"));221}222223private final void recordNamingConvention(Properties p) {224String syntaxDirectionStr =225p.getProperty("jndi.syntax.direction", "flat");226if (syntaxDirectionStr.equals("left_to_right")) {227syntaxDirection = LEFT_TO_RIGHT;228} else if (syntaxDirectionStr.equals("right_to_left")) {229syntaxDirection = RIGHT_TO_LEFT;230} else if (syntaxDirectionStr.equals("flat")) {231syntaxDirection = FLAT;232} else {233throw new IllegalArgumentException(syntaxDirectionStr +234" is not a valid value for the jndi.syntax.direction property");235}236237if (syntaxDirection != FLAT) {238syntaxSeparator = p.getProperty("jndi.syntax.separator");239syntaxSeparator2 = p.getProperty("jndi.syntax.separator2");240if (syntaxSeparator == null) {241throw new IllegalArgumentException(242"jndi.syntax.separator property required for non-flat syntax");243}244} else {245syntaxSeparator = null;246}247syntaxEscape = p.getProperty("jndi.syntax.escape");248249syntaxCaseInsensitive = getBoolean(p, "jndi.syntax.ignorecase");250syntaxTrimBlanks = getBoolean(p, "jndi.syntax.trimblanks");251252syntaxBeginQuote1 = p.getProperty("jndi.syntax.beginquote");253syntaxEndQuote1 = p.getProperty("jndi.syntax.endquote");254if (syntaxEndQuote1 == null && syntaxBeginQuote1 != null)255syntaxEndQuote1 = syntaxBeginQuote1;256else if (syntaxBeginQuote1 == null && syntaxEndQuote1 != null)257syntaxBeginQuote1 = syntaxEndQuote1;258syntaxBeginQuote2 = p.getProperty("jndi.syntax.beginquote2");259syntaxEndQuote2 = p.getProperty("jndi.syntax.endquote2");260if (syntaxEndQuote2 == null && syntaxBeginQuote2 != null)261syntaxEndQuote2 = syntaxBeginQuote2;262else if (syntaxBeginQuote2 == null && syntaxEndQuote2 != null)263syntaxBeginQuote2 = syntaxEndQuote2;264265syntaxAvaSeparator = p.getProperty("jndi.syntax.separator.ava");266syntaxTypevalSeparator =267p.getProperty("jndi.syntax.separator.typeval");268}269270NameImpl(Properties syntax) {271if (syntax != null) {272recordNamingConvention(syntax);273}274components = new Vector<>();275}276277NameImpl(Properties syntax, String n) throws InvalidNameException {278this(syntax);279280boolean rToL = (syntaxDirection == RIGHT_TO_LEFT);281boolean compsAllEmpty = true;282int len = n.length();283284for (int i = 0; i < len; ) {285i = extractComp(n, i, len, components);286287String comp = rToL288? components.firstElement()289: components.lastElement();290if (comp.length() >= 1) {291compsAllEmpty = false;292}293294if (i < len) {295i = skipSeparator(n, i);296if ((i == len) && !compsAllEmpty) {297// Trailing separator found. Add an empty component.298if (rToL) {299components.insertElementAt("", 0);300} else {301components.addElement("");302}303}304}305}306}307308NameImpl(Properties syntax, Enumeration<String> comps) {309this(syntax);310311// %% comps could shrink in the middle.312while (comps.hasMoreElements())313components.addElement(comps.nextElement());314}315/*316// Determines whether this component needs any escaping.317private final boolean escapingNeeded(String comp) {318int len = comp.length();319for (int i = 0; i < len; i++) {320if (i == 0) {321if (isA(comp, 0, syntaxBeginQuote1) ||322isA(comp, 0, syntaxBeginQuote2)) {323return (true);324}325}326if (isSeparator(comp, i)) {327return (true);328}329if (isA(comp, i, syntaxEscape)) {330i += syntaxEscape.length();331if (i >= len || isMeta(comp, i)) {332return (true);333}334}335}336return (false);337}338*/339private final String stringifyComp(String comp) {340int len = comp.length();341boolean escapeSeparator = false, escapeSeparator2 = false;342String beginQuote = null, endQuote = null;343StringBuffer strbuf = new StringBuffer(len);344345// determine whether there are any separators; if so escape346// or quote them347if (syntaxSeparator != null &&348comp.indexOf(syntaxSeparator) >= 0) {349if (syntaxBeginQuote1 != null) {350beginQuote = syntaxBeginQuote1;351endQuote = syntaxEndQuote1;352} else if (syntaxBeginQuote2 != null) {353beginQuote = syntaxBeginQuote2;354endQuote = syntaxEndQuote2;355} else if (syntaxEscape != null)356escapeSeparator = true;357}358if (syntaxSeparator2 != null &&359comp.indexOf(syntaxSeparator2) >= 0) {360if (syntaxBeginQuote1 != null) {361if (beginQuote == null) {362beginQuote = syntaxBeginQuote1;363endQuote = syntaxEndQuote1;364}365} else if (syntaxBeginQuote2 != null) {366if (beginQuote == null) {367beginQuote = syntaxBeginQuote2;368endQuote = syntaxEndQuote2;369}370} else if (syntaxEscape != null)371escapeSeparator2 = true;372}373374// if quoting component,375if (beginQuote != null) {376377// start string off with opening quote378strbuf = strbuf.append(beginQuote);379380// component is being quoted, so we only need to worry about381// escaping end quotes that occur in component382for (int i = 0; i < len; ) {383if (comp.startsWith(endQuote, i)) {384// end-quotes must be escaped when inside a quoted string385strbuf.append(syntaxEscape).append(endQuote);386i += endQuote.length();387} else {388// no special treatment required389strbuf.append(comp.charAt(i++));390}391}392393// end with closing quote394strbuf.append(endQuote);395396} else {397398// When component is not quoted, add escape for:399// 1. leading quote400// 2. an escape preceding any meta char401// 3. an escape at the end of a component402// 4. separator403404// go through characters in component and escape where necessary405boolean start = true;406for (int i = 0; i < len; ) {407// leading quote must be escaped408if (start && isA(comp, i, syntaxBeginQuote1)) {409strbuf.append(syntaxEscape).append(syntaxBeginQuote1);410i += syntaxBeginQuote1.length();411} else if (start && isA(comp, i, syntaxBeginQuote2)) {412strbuf.append(syntaxEscape).append(syntaxBeginQuote2);413i += syntaxBeginQuote2.length();414} else415416// Escape an escape preceding meta characters, or at end.417// Other escapes pass through.418if (isA(comp, i, syntaxEscape)) {419if (i + syntaxEscape.length() >= len) {420// escape an ending escape421strbuf.append(syntaxEscape);422} else if (isMeta(comp, i + syntaxEscape.length())) {423// escape meta strings424strbuf.append(syntaxEscape);425}426strbuf.append(syntaxEscape);427i += syntaxEscape.length();428} else429430// escape unescaped separator431if (escapeSeparator && comp.startsWith(syntaxSeparator, i)) {432// escape separator433strbuf.append(syntaxEscape).append(syntaxSeparator);434i += syntaxSeparator.length();435} else if (escapeSeparator2 &&436comp.startsWith(syntaxSeparator2, i)) {437// escape separator2438strbuf.append(syntaxEscape).append(syntaxSeparator2);439i += syntaxSeparator2.length();440} else {441// no special treatment required442strbuf.append(comp.charAt(i++));443}444start = false;445}446}447return (strbuf.toString());448}449450public String toString() {451StringBuffer answer = new StringBuffer();452String comp;453boolean compsAllEmpty = true;454int size = components.size();455456for (int i = 0; i < size; i++) {457if (syntaxDirection == RIGHT_TO_LEFT) {458comp =459stringifyComp(components.elementAt(size - 1 - i));460} else {461comp = stringifyComp(components.elementAt(i));462}463if ((i != 0) && (syntaxSeparator != null))464answer.append(syntaxSeparator);465if (comp.length() >= 1)466compsAllEmpty = false;467answer = answer.append(comp);468}469if (compsAllEmpty && (size >= 1) && (syntaxSeparator != null))470answer = answer.append(syntaxSeparator);471return (answer.toString());472}473474public boolean equals(Object obj) {475if ((obj != null) && (obj instanceof NameImpl)) {476NameImpl target = (NameImpl)obj;477if (target.size() == this.size()) {478Enumeration<String> mycomps = getAll();479Enumeration<String> comps = target.getAll();480while (mycomps.hasMoreElements()) {481// %% comps could shrink in the middle.482String my = mycomps.nextElement();483String his = comps.nextElement();484if (syntaxTrimBlanks) {485my = my.trim();486his = his.trim();487}488if (syntaxCaseInsensitive) {489if (!(my.equalsIgnoreCase(his)))490return false;491} else {492if (!(my.equals(his)))493return false;494}495}496return true;497}498}499return false;500}501502/**503* Compares obj to this NameImpl to determine ordering.504* Takes into account syntactic properties such as505* elimination of blanks, case-ignore, etc, if relevant.506*507* Note: using syntax of this NameImpl and ignoring508* that of comparison target.509*/510public int compareTo(NameImpl obj) {511if (this == obj) {512return 0;513}514515int len1 = size();516int len2 = obj.size();517int n = Math.min(len1, len2);518519int index1 = 0, index2 = 0;520521while (n-- != 0) {522String comp1 = get(index1++);523String comp2 = obj.get(index2++);524525// normalize according to syntax526if (syntaxTrimBlanks) {527comp1 = comp1.trim();528comp2 = comp2.trim();529}530531int local;532if (syntaxCaseInsensitive) {533local = comp1.compareToIgnoreCase(comp2);534} else {535local = comp1.compareTo(comp2);536}537538if (local != 0) {539return local;540}541}542543return len1 - len2;544}545546public int size() {547return (components.size());548}549550public Enumeration<String> getAll() {551return components.elements();552}553554public String get(int posn) {555return components.elementAt(posn);556}557558public Enumeration<String> getPrefix(int posn) {559if (posn < 0 || posn > size()) {560throw new ArrayIndexOutOfBoundsException(posn);561}562return new NameImplEnumerator(components, 0, posn);563}564565public Enumeration<String> getSuffix(int posn) {566int cnt = size();567if (posn < 0 || posn > cnt) {568throw new ArrayIndexOutOfBoundsException(posn);569}570return new NameImplEnumerator(components, posn, cnt);571}572573public boolean isEmpty() {574return (components.isEmpty());575}576577public boolean startsWith(int posn, Enumeration<String> prefix) {578if (posn < 0 || posn > size()) {579return false;580}581try {582Enumeration<String> mycomps = getPrefix(posn);583while (mycomps.hasMoreElements()) {584String my = mycomps.nextElement();585String his = prefix.nextElement();586if (syntaxTrimBlanks) {587my = my.trim();588his = his.trim();589}590if (syntaxCaseInsensitive) {591if (!(my.equalsIgnoreCase(his)))592return false;593} else {594if (!(my.equals(his)))595return false;596}597}598} catch (NoSuchElementException e) {599return false;600}601return true;602}603604public boolean endsWith(int posn, Enumeration<String> suffix) {605// posn is number of elements in suffix606// startIndex is the starting position in this name607// at which to start the comparison. It is calculated by608// subtracting 'posn' from size()609int startIndex = size() - posn;610if (startIndex < 0 || startIndex > size()) {611return false;612}613try {614Enumeration<String> mycomps = getSuffix(startIndex);615while (mycomps.hasMoreElements()) {616String my = mycomps.nextElement();617String his = suffix.nextElement();618if (syntaxTrimBlanks) {619my = my.trim();620his = his.trim();621}622if (syntaxCaseInsensitive) {623if (!(my.equalsIgnoreCase(his)))624return false;625} else {626if (!(my.equals(his)))627return false;628}629}630} catch (NoSuchElementException e) {631return false;632}633return true;634}635636public boolean addAll(Enumeration<String> comps) throws InvalidNameException {637boolean added = false;638while (comps.hasMoreElements()) {639try {640String comp = comps.nextElement();641if (size() > 0 && syntaxDirection == FLAT) {642throw new InvalidNameException(643"A flat name can only have a single component");644}645components.addElement(comp);646added = true;647} catch (NoSuchElementException e) {648break; // "comps" has shrunk.649}650}651return added;652}653654public boolean addAll(int posn, Enumeration<String> comps)655throws InvalidNameException {656boolean added = false;657for (int i = posn; comps.hasMoreElements(); i++) {658try {659String comp = comps.nextElement();660if (size() > 0 && syntaxDirection == FLAT) {661throw new InvalidNameException(662"A flat name can only have a single component");663}664components.insertElementAt(comp, i);665added = true;666} catch (NoSuchElementException e) {667break; // "comps" has shrunk.668}669}670return added;671}672673public void add(String comp) throws InvalidNameException {674if (size() > 0 && syntaxDirection == FLAT) {675throw new InvalidNameException(676"A flat name can only have a single component");677}678components.addElement(comp);679}680681public void add(int posn, String comp) throws InvalidNameException {682if (size() > 0 && syntaxDirection == FLAT) {683throw new InvalidNameException(684"A flat name can only zero or one component");685}686components.insertElementAt(comp, posn);687}688689public Object remove(int posn) {690Object r = components.elementAt(posn);691components.removeElementAt(posn);692return r;693}694695public int hashCode() {696int hash = 0;697for (Enumeration<String> e = getAll(); e.hasMoreElements();) {698String comp = e.nextElement();699if (syntaxTrimBlanks) {700comp = comp.trim();701}702if (syntaxCaseInsensitive) {703comp = comp.toLowerCase(Locale.ENGLISH);704}705706hash += comp.hashCode();707}708return hash;709}710}711712final713class NameImplEnumerator implements Enumeration<String> {714Vector<String> vector;715int count;716int limit;717718NameImplEnumerator(Vector<String> v, int start, int lim) {719vector = v;720count = start;721limit = lim;722}723724public boolean hasMoreElements() {725return count < limit;726}727728public String nextElement() {729if (count < limit) {730return vector.elementAt(count++);731}732throw new NoSuchElementException("NameImplEnumerator");733}734}735736737