jdk/src/share/classes/javax/naming/NameImpl.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1999-2002 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package javax.naming;
       
    27 
       
    28 import java.util.Vector;
       
    29 import java.util.Enumeration;
       
    30 import java.util.Properties;
       
    31 import java.util.NoSuchElementException;
       
    32 
       
    33 /**
       
    34   * The implementation class for CompoundName and CompositeName.
       
    35   * This class is package private.
       
    36   *
       
    37   * @author Rosanna Lee
       
    38   * @author Scott Seligman
       
    39   * @author Aravindan Ranganathan
       
    40   * @since 1.3
       
    41   */
       
    42 
       
    43 class NameImpl {
       
    44     private static final byte LEFT_TO_RIGHT = 1;
       
    45     private static final byte RIGHT_TO_LEFT = 2;
       
    46     private static final byte FLAT = 0;
       
    47 
       
    48     private Vector components;
       
    49 
       
    50     private byte syntaxDirection = LEFT_TO_RIGHT;
       
    51     private String syntaxSeparator = "/";
       
    52     private String syntaxSeparator2 = null;
       
    53     private boolean syntaxCaseInsensitive = false;
       
    54     private boolean syntaxTrimBlanks = false;
       
    55     private String syntaxEscape = "\\";
       
    56     private String syntaxBeginQuote1 = "\"";
       
    57     private String syntaxEndQuote1 = "\"";
       
    58     private String syntaxBeginQuote2 = "'";
       
    59     private String syntaxEndQuote2 = "'";
       
    60     private String syntaxAvaSeparator = null;
       
    61     private String syntaxTypevalSeparator = null;
       
    62 
       
    63     // escapingStyle gives the method used at creation time for
       
    64     // quoting or escaping characters in the name.  It is set to the
       
    65     // first style of quote or escape encountered if and when the name
       
    66     // is parsed.
       
    67     private static final int STYLE_NONE = 0;
       
    68     private static final int STYLE_QUOTE1 = 1;
       
    69     private static final int STYLE_QUOTE2 = 2;
       
    70     private static final int STYLE_ESCAPE = 3;
       
    71     private int escapingStyle = STYLE_NONE;
       
    72 
       
    73     // Returns true if "match" is not null, and n contains "match" at
       
    74     // position i.
       
    75     private final boolean isA(String n, int i, String match) {
       
    76         return (match != null && n.startsWith(match, i));
       
    77     }
       
    78 
       
    79     private final boolean isMeta(String n, int i) {
       
    80         return (isA(n, i, syntaxEscape) ||
       
    81                 isA(n, i, syntaxBeginQuote1) ||
       
    82                 isA(n, i, syntaxBeginQuote2) ||
       
    83                 isSeparator(n, i));
       
    84     }
       
    85 
       
    86     private final boolean isSeparator(String n, int i) {
       
    87         return (isA(n, i, syntaxSeparator) ||
       
    88                 isA(n, i, syntaxSeparator2));
       
    89     }
       
    90 
       
    91     private final int skipSeparator(String name, int i) {
       
    92         if (isA(name, i, syntaxSeparator)) {
       
    93             i += syntaxSeparator.length();
       
    94         } else if (isA(name, i, syntaxSeparator2)) {
       
    95             i += syntaxSeparator2.length();
       
    96         }
       
    97         return (i);
       
    98     }
       
    99 
       
   100     private final int extractComp(String name, int i, int len, Vector comps)
       
   101     throws InvalidNameException {
       
   102         String beginQuote;
       
   103         String endQuote;
       
   104         boolean start = true;
       
   105         boolean one = false;
       
   106         StringBuffer answer = new StringBuffer(len);
       
   107 
       
   108         while (i < len) {
       
   109             // handle quoted strings
       
   110             if (start && ((one = isA(name, i, syntaxBeginQuote1)) ||
       
   111                           isA(name, i, syntaxBeginQuote2))) {
       
   112 
       
   113                 // record choice of quote chars being used
       
   114                 beginQuote = one ? syntaxBeginQuote1 : syntaxBeginQuote2;
       
   115                 endQuote = one ? syntaxEndQuote1 : syntaxEndQuote2;
       
   116                 if (escapingStyle == STYLE_NONE) {
       
   117                     escapingStyle = one ? STYLE_QUOTE1 : STYLE_QUOTE2;
       
   118                 }
       
   119 
       
   120                 // consume string until matching quote
       
   121                 for (i += beginQuote.length();
       
   122                      ((i < len) && !name.startsWith(endQuote, i));
       
   123                      i++) {
       
   124                     // skip escape character if it is escaping ending quote
       
   125                     // otherwise leave as is.
       
   126                     if (isA(name, i, syntaxEscape) &&
       
   127                         isA(name, i + syntaxEscape.length(), endQuote)) {
       
   128                         i += syntaxEscape.length();
       
   129                     }
       
   130                     answer.append(name.charAt(i));  // copy char
       
   131                 }
       
   132 
       
   133                 // no ending quote found
       
   134                 if (i >= len)
       
   135                     throw
       
   136                         new InvalidNameException(name + ": no close quote");
       
   137 //                      new Exception("no close quote");
       
   138 
       
   139                 i += endQuote.length();
       
   140 
       
   141                 // verify that end-quote occurs at separator or end of string
       
   142                 if (i == len || isSeparator(name, i)) {
       
   143                     break;
       
   144                 }
       
   145 //              throw (new Exception(
       
   146                 throw (new InvalidNameException(name +
       
   147                     ": close quote appears before end of component"));
       
   148 
       
   149             } else if (isSeparator(name, i)) {
       
   150                 break;
       
   151 
       
   152             } else if (isA(name, i, syntaxEscape)) {
       
   153                 if (isMeta(name, i + syntaxEscape.length())) {
       
   154                     // if escape precedes meta, consume escape and let
       
   155                     // meta through
       
   156                     i += syntaxEscape.length();
       
   157                     if (escapingStyle == STYLE_NONE) {
       
   158                         escapingStyle = STYLE_ESCAPE;
       
   159                     }
       
   160                 } else if (i + syntaxEscape.length() >= len) {
       
   161                     throw (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)) ||
       
   166             isA(name, i+syntaxTypevalSeparator.length(), syntaxBeginQuote2))) {
       
   167                 // Handle quote occurring after typeval separator
       
   168                 beginQuote = one ? syntaxBeginQuote1 : syntaxBeginQuote2;
       
   169                 endQuote = one ? syntaxEndQuote1 : syntaxEndQuote2;
       
   170 
       
   171                 i += syntaxTypevalSeparator.length();
       
   172                 answer.append(syntaxTypevalSeparator+beginQuote); // add back
       
   173 
       
   174                 // consume string until matching quote
       
   175                 for (i += beginQuote.length();
       
   176                      ((i < len) && !name.startsWith(endQuote, i));
       
   177                      i++) {
       
   178                     // skip escape character if it is escaping ending quote
       
   179                     // otherwise leave as is.
       
   180                     if (isA(name, i, syntaxEscape) &&
       
   181                         isA(name, i + syntaxEscape.length(), endQuote)) {
       
   182                         i += syntaxEscape.length();
       
   183                     }
       
   184                     answer.append(name.charAt(i));  // copy char
       
   185                 }
       
   186 
       
   187                 // no ending quote found
       
   188                 if (i >= len)
       
   189                     throw
       
   190                         new InvalidNameException(name + ": typeval no close quote");
       
   191 
       
   192                 i += endQuote.length();
       
   193                 answer.append(endQuote); // add back
       
   194 
       
   195                 // verify that end-quote occurs at separator or end of string
       
   196                 if (i == len || isSeparator(name, i)) {
       
   197                     break;
       
   198                 }
       
   199                 throw (new InvalidNameException(name.substring(i) +
       
   200                     ": typeval close quote appears before end of component"));
       
   201             }
       
   202 
       
   203             answer.append(name.charAt(i++));
       
   204             start = false;
       
   205         }
       
   206 
       
   207         if (syntaxDirection == RIGHT_TO_LEFT)
       
   208             comps.insertElementAt(answer.toString(), 0);
       
   209         else
       
   210             comps.addElement(answer.toString());
       
   211         return i;
       
   212     }
       
   213 
       
   214     private static boolean getBoolean(Properties p, String name) {
       
   215         return toBoolean(p.getProperty(name));
       
   216     }
       
   217 
       
   218     private static boolean toBoolean(String name) {
       
   219         return ((name != null) && name.toLowerCase().equals("true"));
       
   220     }
       
   221 
       
   222     private final void recordNamingConvention(Properties p) {
       
   223         String syntaxDirectionStr =
       
   224             p.getProperty("jndi.syntax.direction", "flat");
       
   225         if (syntaxDirectionStr.equals("left_to_right")) {
       
   226             syntaxDirection = LEFT_TO_RIGHT;
       
   227         } else if (syntaxDirectionStr.equals("right_to_left")) {
       
   228             syntaxDirection = RIGHT_TO_LEFT;
       
   229         } else if (syntaxDirectionStr.equals("flat")) {
       
   230             syntaxDirection = FLAT;
       
   231         } else {
       
   232             throw new IllegalArgumentException(syntaxDirectionStr +
       
   233                 "is not a valid value for the jndi.syntax.direction property");
       
   234         }
       
   235 
       
   236         if (syntaxDirection != FLAT) {
       
   237             syntaxSeparator = p.getProperty("jndi.syntax.separator");
       
   238             syntaxSeparator2 = p.getProperty("jndi.syntax.separator2");
       
   239             if (syntaxSeparator == null) {
       
   240                 throw new IllegalArgumentException(
       
   241                     "jndi.syntax.separator property required for non-flat syntax");
       
   242             }
       
   243         } else {
       
   244             syntaxSeparator = null;
       
   245         }
       
   246         syntaxEscape = p.getProperty("jndi.syntax.escape");
       
   247 
       
   248         syntaxCaseInsensitive = getBoolean(p, "jndi.syntax.ignorecase");
       
   249         syntaxTrimBlanks = getBoolean(p, "jndi.syntax.trimblanks");
       
   250 
       
   251         syntaxBeginQuote1 = p.getProperty("jndi.syntax.beginquote");
       
   252         syntaxEndQuote1 = p.getProperty("jndi.syntax.endquote");
       
   253         if (syntaxEndQuote1 == null && syntaxBeginQuote1 != null)
       
   254             syntaxEndQuote1 = syntaxBeginQuote1;
       
   255         else if (syntaxBeginQuote1 == null && syntaxEndQuote1 != null)
       
   256             syntaxBeginQuote1 = syntaxEndQuote1;
       
   257         syntaxBeginQuote2 = p.getProperty("jndi.syntax.beginquote2");
       
   258         syntaxEndQuote2 = p.getProperty("jndi.syntax.endquote2");
       
   259         if (syntaxEndQuote2 == null && syntaxBeginQuote2 != null)
       
   260             syntaxEndQuote2 = syntaxBeginQuote2;
       
   261         else if (syntaxBeginQuote2 == null && syntaxEndQuote2 != null)
       
   262             syntaxBeginQuote2 = syntaxEndQuote2;
       
   263 
       
   264         syntaxAvaSeparator = p.getProperty("jndi.syntax.separator.ava");
       
   265         syntaxTypevalSeparator =
       
   266             p.getProperty("jndi.syntax.separator.typeval");
       
   267     }
       
   268 
       
   269     NameImpl(Properties syntax) {
       
   270         if (syntax != null) {
       
   271             recordNamingConvention(syntax);
       
   272         }
       
   273         components = new Vector();
       
   274     }
       
   275 
       
   276     NameImpl(Properties syntax, String n) throws InvalidNameException {
       
   277         this(syntax);
       
   278 
       
   279         boolean rToL = (syntaxDirection == RIGHT_TO_LEFT);
       
   280         boolean compsAllEmpty = true;
       
   281         int len = n.length();
       
   282 
       
   283         for (int i = 0; i < len; ) {
       
   284             i = extractComp(n, i, len, components);
       
   285 
       
   286             String comp = rToL
       
   287                 ? (String)components.firstElement()
       
   288                 : (String)components.lastElement();
       
   289             if (comp.length() >= 1) {
       
   290                 compsAllEmpty = false;
       
   291             }
       
   292 
       
   293             if (i < len) {
       
   294                 i = skipSeparator(n, i);
       
   295                 if ((i == len) && !compsAllEmpty) {
       
   296                     // Trailing separator found.  Add an empty component.
       
   297                     if (rToL) {
       
   298                         components.insertElementAt("", 0);
       
   299                     } else {
       
   300                         components.addElement("");
       
   301                     }
       
   302                 }
       
   303             }
       
   304         }
       
   305     }
       
   306 
       
   307     NameImpl(Properties syntax, Enumeration comps) {
       
   308         this(syntax);
       
   309 
       
   310         // %% comps could shrink in the middle.
       
   311         while (comps.hasMoreElements())
       
   312             components.addElement(comps.nextElement());
       
   313     }
       
   314 /*
       
   315     // Determines whether this component needs any escaping.
       
   316     private final boolean escapingNeeded(String comp) {
       
   317         int len = comp.length();
       
   318         for (int i = 0; i < len; i++) {
       
   319             if (i == 0) {
       
   320                 if (isA(comp, 0, syntaxBeginQuote1) ||
       
   321                     isA(comp, 0, syntaxBeginQuote2)) {
       
   322                     return (true);
       
   323                 }
       
   324             }
       
   325             if (isSeparator(comp, i)) {
       
   326                 return (true);
       
   327             }
       
   328             if (isA(comp, i, syntaxEscape)) {
       
   329                 i += syntaxEscape.length();
       
   330                 if (i >= len || isMeta(comp, i)) {
       
   331                     return (true);
       
   332                 }
       
   333             }
       
   334         }
       
   335         return (false);
       
   336     }
       
   337 */
       
   338     private final String stringifyComp(String comp) {
       
   339         int len = comp.length();
       
   340         boolean escapeSeparator = false, escapeSeparator2 = false;
       
   341         String beginQuote = null, endQuote = null;
       
   342         StringBuffer strbuf = new StringBuffer(len);
       
   343 
       
   344         // determine whether there are any separators; if so escape
       
   345         // or quote them
       
   346         if (syntaxSeparator != null &&
       
   347             comp.indexOf(syntaxSeparator) >= 0) {
       
   348             if (syntaxBeginQuote1 != null) {
       
   349                 beginQuote = syntaxBeginQuote1;
       
   350                 endQuote = syntaxEndQuote1;
       
   351             } else if (syntaxBeginQuote2 != null) {
       
   352                 beginQuote = syntaxBeginQuote2;
       
   353                 endQuote = syntaxEndQuote2;
       
   354             } else if (syntaxEscape != null)
       
   355                 escapeSeparator = true;
       
   356         }
       
   357         if (syntaxSeparator2 != null &&
       
   358             comp.indexOf(syntaxSeparator2) >= 0) {
       
   359             if (syntaxBeginQuote1 != null) {
       
   360                 if (beginQuote == null) {
       
   361                     beginQuote = syntaxBeginQuote1;
       
   362                     endQuote = syntaxEndQuote1;
       
   363                 }
       
   364             } else if (syntaxBeginQuote2 != null) {
       
   365                 if (beginQuote == null) {
       
   366                     beginQuote = syntaxBeginQuote2;
       
   367                     endQuote = syntaxEndQuote2;
       
   368                 }
       
   369             } else if (syntaxEscape != null)
       
   370                 escapeSeparator2 = true;
       
   371         }
       
   372 
       
   373         // if quoting component,
       
   374         if (beginQuote != null) {
       
   375 
       
   376             // start string off with opening quote
       
   377             strbuf = strbuf.append(beginQuote);
       
   378 
       
   379             // component is being quoted, so we only need to worry about
       
   380             // escaping end quotes that occur in component
       
   381             for (int i = 0; i < len; ) {
       
   382                 if (comp.startsWith(endQuote, i)) {
       
   383                     // end-quotes must be escaped when inside a quoted string
       
   384                     strbuf.append(syntaxEscape).append(endQuote);
       
   385                     i += endQuote.length();
       
   386                 } else {
       
   387                     // no special treatment required
       
   388                     strbuf.append(comp.charAt(i++));
       
   389                 }
       
   390             }
       
   391 
       
   392             // end with closing quote
       
   393             strbuf.append(endQuote);
       
   394 
       
   395         } else {
       
   396 
       
   397             // When component is not quoted, add escape for:
       
   398             // 1. leading quote
       
   399             // 2. an escape preceding any meta char
       
   400             // 3. an escape at the end of a component
       
   401             // 4. separator
       
   402 
       
   403             // go through characters in component and escape where necessary
       
   404             boolean start = true;
       
   405             for (int i = 0; i < len; ) {
       
   406                 // leading quote must be escaped
       
   407                 if (start && isA(comp, i, syntaxBeginQuote1)) {
       
   408                     strbuf.append(syntaxEscape).append(syntaxBeginQuote1);
       
   409                     i += syntaxBeginQuote1.length();
       
   410                 } else if (start && isA(comp, i, syntaxBeginQuote2)) {
       
   411                     strbuf.append(syntaxEscape).append(syntaxBeginQuote2);
       
   412                     i += syntaxBeginQuote2.length();
       
   413                 } else
       
   414 
       
   415                 // Escape an escape preceding meta characters, or at end.
       
   416                 // Other escapes pass through.
       
   417                 if (isA(comp, i, syntaxEscape)) {
       
   418                     if (i + syntaxEscape.length() >= len) {
       
   419                         // escape an ending escape
       
   420                         strbuf.append(syntaxEscape);
       
   421                     } else if (isMeta(comp, i + syntaxEscape.length())) {
       
   422                         // escape meta strings
       
   423                         strbuf.append(syntaxEscape);
       
   424                     }
       
   425                     strbuf.append(syntaxEscape);
       
   426                     i += syntaxEscape.length();
       
   427                 } else
       
   428 
       
   429                 // escape unescaped separator
       
   430                 if (escapeSeparator && comp.startsWith(syntaxSeparator, i)) {
       
   431                     // escape separator
       
   432                     strbuf.append(syntaxEscape).append(syntaxSeparator);
       
   433                     i += syntaxSeparator.length();
       
   434                 } else if (escapeSeparator2 &&
       
   435                            comp.startsWith(syntaxSeparator2, i)) {
       
   436                     // escape separator2
       
   437                     strbuf.append(syntaxEscape).append(syntaxSeparator2);
       
   438                     i += syntaxSeparator2.length();
       
   439                 } else {
       
   440                     // no special treatment required
       
   441                     strbuf.append(comp.charAt(i++));
       
   442                 }
       
   443                 start = false;
       
   444             }
       
   445         }
       
   446         return (strbuf.toString());
       
   447     }
       
   448 
       
   449     public String toString() {
       
   450         StringBuffer answer = new StringBuffer();
       
   451         String comp;
       
   452         boolean compsAllEmpty = true;
       
   453         int size = components.size();
       
   454 
       
   455         for (int i = 0; i < size; i++) {
       
   456             if (syntaxDirection == RIGHT_TO_LEFT) {
       
   457                 comp =
       
   458                     stringifyComp((String) components.elementAt(size - 1 - i));
       
   459             } else {
       
   460                 comp = stringifyComp((String) components.elementAt(i));
       
   461             }
       
   462             if ((i != 0) && (syntaxSeparator != null))
       
   463                 answer.append(syntaxSeparator);
       
   464             if (comp.length() >= 1)
       
   465                 compsAllEmpty = false;
       
   466             answer = answer.append(comp);
       
   467         }
       
   468         if (compsAllEmpty && (size >= 1) && (syntaxSeparator != null))
       
   469             answer = answer.append(syntaxSeparator);
       
   470         return (answer.toString());
       
   471     }
       
   472 
       
   473     public boolean equals(Object obj) {
       
   474         if ((obj != null) && (obj instanceof NameImpl)) {
       
   475             NameImpl target = (NameImpl)obj;
       
   476             if (target.size() ==  this.size()) {
       
   477                 Enumeration mycomps = getAll();
       
   478                 Enumeration comps = target.getAll();
       
   479                 while (mycomps.hasMoreElements()) {
       
   480                     // %% comps could shrink in the middle.
       
   481                     String my = (String)mycomps.nextElement();
       
   482                     String his = (String)comps.nextElement();
       
   483                     if (syntaxTrimBlanks) {
       
   484                         my = my.trim();
       
   485                         his = his.trim();
       
   486                     }
       
   487                     if (syntaxCaseInsensitive) {
       
   488                         if (!(my.equalsIgnoreCase(his)))
       
   489                             return false;
       
   490                     } else {
       
   491                         if (!(my.equals(his)))
       
   492                             return false;
       
   493                     }
       
   494                 }
       
   495                 return true;
       
   496             }
       
   497         }
       
   498         return false;
       
   499     }
       
   500 
       
   501     /**
       
   502       * Compares obj to this NameImpl to determine ordering.
       
   503       * Takes into account syntactic properties such as
       
   504       * elimination of blanks, case-ignore, etc, if relevant.
       
   505       *
       
   506       * Note: using syntax of this NameImpl and ignoring
       
   507       * that of comparison target.
       
   508       */
       
   509     public int compareTo(NameImpl obj) {
       
   510         if (this == obj) {
       
   511             return 0;
       
   512         }
       
   513 
       
   514         int len1 = size();
       
   515         int len2 = obj.size();
       
   516         int n = Math.min(len1, len2);
       
   517 
       
   518         int index1 = 0, index2 = 0;
       
   519 
       
   520         while (n-- != 0) {
       
   521             String comp1 = get(index1++);
       
   522             String comp2 = obj.get(index2++);
       
   523 
       
   524             // normalize according to syntax
       
   525             if (syntaxTrimBlanks) {
       
   526                 comp1 = comp1.trim();
       
   527                 comp2 = comp2.trim();
       
   528             }
       
   529             if (syntaxCaseInsensitive) {
       
   530                 comp1 = comp1.toLowerCase();
       
   531                 comp2 = comp2.toLowerCase();
       
   532             }
       
   533             int local = comp1.compareTo(comp2);
       
   534             if (local != 0) {
       
   535                 return local;
       
   536             }
       
   537         }
       
   538 
       
   539         return len1 - len2;
       
   540     }
       
   541 
       
   542     public int size() {
       
   543         return (components.size());
       
   544     }
       
   545 
       
   546     public Enumeration getAll() {
       
   547         return components.elements();
       
   548     }
       
   549 
       
   550     public String get(int posn) {
       
   551         return ((String) components.elementAt(posn));
       
   552     }
       
   553 
       
   554     public Enumeration getPrefix(int posn) {
       
   555         if (posn < 0 || posn > size()) {
       
   556             throw new ArrayIndexOutOfBoundsException(posn);
       
   557         }
       
   558         return new NameImplEnumerator(components, 0, posn);
       
   559     }
       
   560 
       
   561     public Enumeration getSuffix(int posn) {
       
   562         int cnt = size();
       
   563         if (posn < 0 || posn > cnt) {
       
   564             throw new ArrayIndexOutOfBoundsException(posn);
       
   565         }
       
   566         return new NameImplEnumerator(components, posn, cnt);
       
   567     }
       
   568 
       
   569     public boolean isEmpty() {
       
   570         return (components.isEmpty());
       
   571     }
       
   572 
       
   573     public boolean startsWith(int posn, Enumeration prefix) {
       
   574         if (posn < 0 || posn > size()) {
       
   575             return false;
       
   576         }
       
   577         try {
       
   578             Enumeration mycomps = getPrefix(posn);
       
   579             while (mycomps.hasMoreElements()) {
       
   580                 String my = (String)mycomps.nextElement();
       
   581                 String his = (String)prefix.nextElement();
       
   582                 if (syntaxTrimBlanks) {
       
   583                     my = my.trim();
       
   584                     his = his.trim();
       
   585                 }
       
   586                 if (syntaxCaseInsensitive) {
       
   587                     if (!(my.equalsIgnoreCase(his)))
       
   588                         return false;
       
   589                 } else {
       
   590                     if (!(my.equals(his)))
       
   591                         return false;
       
   592                 }
       
   593             }
       
   594         } catch (NoSuchElementException e) {
       
   595             return false;
       
   596         }
       
   597         return true;
       
   598     }
       
   599 
       
   600     public boolean endsWith(int posn, Enumeration suffix) {
       
   601         // posn is number of elements in suffix
       
   602         // startIndex is the starting position in this name
       
   603         // at which to start the comparison. It is calculated by
       
   604         // subtracting 'posn' from size()
       
   605         int startIndex = size() - posn;
       
   606         if (startIndex < 0 || startIndex > size()) {
       
   607             return false;
       
   608         }
       
   609         try {
       
   610             Enumeration mycomps = getSuffix(startIndex);
       
   611             while (mycomps.hasMoreElements()) {
       
   612                 String my = (String)mycomps.nextElement();
       
   613                 String his = (String)suffix.nextElement();
       
   614                 if (syntaxTrimBlanks) {
       
   615                     my = my.trim();
       
   616                     his = his.trim();
       
   617                 }
       
   618                 if (syntaxCaseInsensitive) {
       
   619                     if (!(my.equalsIgnoreCase(his)))
       
   620                         return false;
       
   621                 } else {
       
   622                     if (!(my.equals(his)))
       
   623                         return false;
       
   624                 }
       
   625             }
       
   626         } catch (NoSuchElementException e) {
       
   627             return false;
       
   628         }
       
   629         return true;
       
   630     }
       
   631 
       
   632     public boolean addAll(Enumeration comps) throws InvalidNameException {
       
   633         boolean added = false;
       
   634         while (comps.hasMoreElements()) {
       
   635             try {
       
   636                 Object comp = comps.nextElement();
       
   637                 if (size() > 0 && syntaxDirection == FLAT) {
       
   638                     throw new InvalidNameException(
       
   639                         "A flat name can only have a single component");
       
   640                 }
       
   641                 components.addElement(comp);
       
   642                 added = true;
       
   643             } catch (NoSuchElementException e) {
       
   644                 break;  // "comps" has shrunk.
       
   645             }
       
   646         }
       
   647         return added;
       
   648     }
       
   649 
       
   650     public boolean addAll(int posn, Enumeration comps)
       
   651     throws InvalidNameException {
       
   652         boolean added = false;
       
   653         for (int i = posn; comps.hasMoreElements(); i++) {
       
   654             try {
       
   655                 Object comp = comps.nextElement();
       
   656                 if (size() > 0 && syntaxDirection == FLAT) {
       
   657                     throw new InvalidNameException(
       
   658                         "A flat name can only have a single component");
       
   659                 }
       
   660                 components.insertElementAt(comp, i);
       
   661                 added = true;
       
   662             } catch (NoSuchElementException e) {
       
   663                 break;  // "comps" has shrunk.
       
   664             }
       
   665         }
       
   666         return added;
       
   667     }
       
   668 
       
   669     public void add(String comp) throws InvalidNameException {
       
   670         if (size() > 0 && syntaxDirection == FLAT) {
       
   671             throw new InvalidNameException(
       
   672                 "A flat name can only have a single component");
       
   673         }
       
   674         components.addElement(comp);
       
   675     }
       
   676 
       
   677     public void add(int posn, String comp) throws InvalidNameException {
       
   678         if (size() > 0 && syntaxDirection == FLAT) {
       
   679             throw new InvalidNameException(
       
   680                 "A flat name can only zero or one component");
       
   681         }
       
   682         components.insertElementAt(comp, posn);
       
   683     }
       
   684 
       
   685     public Object remove(int posn) {
       
   686         Object r = components.elementAt(posn);
       
   687         components.removeElementAt(posn);
       
   688         return r;
       
   689     }
       
   690 
       
   691     public int hashCode() {
       
   692         int hash = 0;
       
   693         for (Enumeration e = getAll(); e.hasMoreElements();) {
       
   694             String comp = (String)e.nextElement();
       
   695             if (syntaxTrimBlanks) {
       
   696                 comp = comp.trim();
       
   697             }
       
   698             if (syntaxCaseInsensitive) {
       
   699                 comp = comp.toLowerCase();
       
   700             }
       
   701 
       
   702             hash += comp.hashCode();
       
   703         }
       
   704         return hash;
       
   705     }
       
   706 }
       
   707 
       
   708 final
       
   709 class NameImplEnumerator implements Enumeration {
       
   710     Vector vector;
       
   711     int count;
       
   712     int limit;
       
   713 
       
   714     NameImplEnumerator(Vector v, int start, int lim) {
       
   715         vector = v;
       
   716         count = start;
       
   717         limit = lim;
       
   718     }
       
   719 
       
   720     public boolean hasMoreElements() {
       
   721         return count < limit;
       
   722     }
       
   723 
       
   724     public Object nextElement() {
       
   725         if (count < limit) {
       
   726             return vector.elementAt(count++);
       
   727         }
       
   728         throw new NoSuchElementException("NameImplEnumerator");
       
   729     }
       
   730 }