Source for javax.naming.CompoundName

   1: /* CompoundName.java --
   2:    Copyright (C) 2001, 2004, 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.naming;
  40: 
  41: import java.io.IOException;
  42: import java.io.ObjectInputStream;
  43: import java.io.ObjectOutputStream;
  44: import java.io.Serializable;
  45: import java.util.Enumeration;
  46: import java.util.NoSuchElementException;
  47: import java.util.Properties;
  48: import java.util.Vector;
  49: 
  50: /**
  51:  * @author Tom Tromey (tromey@redhat.com)
  52:  * @date May 16, 2001
  53:  *
  54:  * FIXME: this class is underspecified.  For instance, the `flat'
  55:  * direction is never described.  If it means that the CompoundName
  56:  * can only have a single element, then the Enumeration-based
  57:  * constructor ought to throw InvalidNameException.
  58:  *
  59:  * @since 1.3
  60:  */
  61: public class CompoundName implements Name, Cloneable, Serializable
  62: {
  63:   private static final long serialVersionUID = 3513100557083972036L;
  64: 
  65:   private CompoundName (Properties syntax)
  66:   {
  67:     elts = new Vector ();
  68:     mySyntax = syntax;
  69:     initializeSyntax ();
  70:   }
  71: 
  72:   protected CompoundName (Enumeration comps, Properties syntax)
  73:   {
  74:     elts = new Vector ();
  75:     mySyntax = syntax;
  76:     initializeSyntax ();
  77:     try
  78:       {
  79:     while (comps.hasMoreElements ())
  80:       elts.add (comps.nextElement ());
  81:       }
  82:     catch (NoSuchElementException ignore)
  83:       {
  84:       }
  85:   }
  86: 
  87:   public CompoundName (String n, Properties syntax)
  88:     throws InvalidNameException
  89:   {
  90:     elts = new Vector ();
  91:     mySyntax = syntax;
  92:     initializeSyntax ();
  93: 
  94:     StringBuffer new_element = new StringBuffer ();
  95:     int i = 0;
  96:     // QUOTE==null means no quoting right now.  When it is set it is
  97:     // the value of the closing quote.
  98:     String quote = null;
  99:     while (i < n.length ())
 100:       {
 101:     String special = isSpecial (n, i);
 102: 
 103:     if (special == escape && escape != null)
 104:       {
 105:         if (n.length () == i + special.length ())
 106:           {
 107:         // A trailing escape is treated as itself.
 108:         new_element.append (special);
 109:         i += special.length ();
 110:           }
 111:         else
 112:           {
 113:         String eSpecial = isSpecial (n, i + special.length ());
 114:         if (eSpecial != null)
 115:           {
 116:             // Treat the escape as an escape.
 117:             new_element.append (eSpecial);
 118:             i += special.length () + eSpecial.length ();
 119:           }
 120:         else
 121:           {
 122:             // Treat the escape as itself.
 123:             new_element.append (special);
 124:             i += special.length ();
 125:           }
 126:         continue;
 127:           }
 128:       }
 129:     else if (quote != null)
 130:       {
 131:         // It is safe to use == here.
 132:         if (quote == special)
 133:           {
 134:         // Quotes must surround a complete component.
 135:         if (i + quote.length () < n.length ()
 136:             && ! n.startsWith (separator, i + quote.length ()))
 137:           throw new InvalidNameException ("close quote before end of component");
 138:         elts.add (new_element.toString ());
 139:         new_element.setLength (0);
 140:         i += quote.length ();
 141:         quote = null;
 142:         continue;
 143:           }
 144:         // Otherwise, fall through.
 145:       }
 146:     // Quotes are only special at the start of a component.
 147:     else if (new_element.length () == 0
 148:          && special == beginQuote
 149:          && beginQuote != null)
 150:       {
 151:         quote = endQuote;
 152:         i += special.length ();
 153:         continue;
 154:       }
 155:     else if (new_element.length () == 0
 156:          && special == beginQuote2
 157:          && beginQuote2 != null)
 158:       {
 159:         quote = endQuote2;
 160:         i += special.length ();
 161:         continue;
 162:       }
 163:     else if (direction != FLAT && special == separator)
 164:       {
 165:         elts.add (new_element.toString ());
 166:         new_element.setLength (0);
 167:         i += special.length ();
 168:         continue;
 169:       }
 170: 
 171:     // Nothing in particular, so try the next character.
 172:     new_element.append (n.charAt (i));
 173:     ++i;
 174:       }
 175: 
 176:     if (new_element.length () != 0)
 177:       elts.add (new_element.toString ());
 178: 
 179:     if (direction == RIGHT_TO_LEFT)
 180:       {
 181:     // Reverse the order of the elements.
 182:     int len = elts.size ();
 183:     for (i = 0; i < len / 2; ++i)
 184:       {
 185:         Object t = elts.set (i, elts.get (len - i - 1));
 186:         elts.set (len - i - 1, t);
 187:       }
 188:       }
 189: 
 190:     // Error checking.
 191:     if (quote != null)
 192:       throw new InvalidNameException ("unterminated quote");
 193:   }
 194: 
 195:   public Name add (int posn, String comp) throws InvalidNameException
 196:   {
 197:     elts.add (posn, comp);
 198:     return this;
 199:   }
 200: 
 201:   public Name add (String comp) throws InvalidNameException
 202:   {
 203:     elts.add (comp);
 204:     return this;
 205:   }
 206: 
 207:   public Name addAll (int posn, Name n) throws InvalidNameException
 208:   {
 209:     Enumeration e = n.getAll ();
 210:     try
 211:       {
 212:     while (e.hasMoreElements ())
 213:       {
 214:         elts.add (posn, e.nextElement ());
 215:         ++posn;
 216:       }
 217:       }
 218:     catch (NoSuchElementException ignore)
 219:       {
 220:       }
 221:     return this;
 222:   }
 223: 
 224:   public Name addAll (Name suffix) throws InvalidNameException
 225:   {
 226:     Enumeration e = suffix.getAll ();
 227:     try
 228:       {
 229:     while (e.hasMoreElements ())
 230:       elts.add (e.nextElement ());
 231:       }
 232:     catch (NoSuchElementException ignore)
 233:       {
 234:       }
 235:     return this;
 236:   }
 237: 
 238:   public Object clone ()
 239:   {
 240:     return new CompoundName (elts.elements (), mySyntax);
 241:   }
 242: 
 243:   public int compareTo (Object obj)
 244:   {
 245:     if (! (obj instanceof CompoundName))
 246:       throw new ClassCastException ("CompoundName.compareTo() expected CompoundName");
 247:     CompoundName cn = (CompoundName) obj;
 248:     int last = Math.min (cn.elts.size (), elts.size ());
 249:     for (int i = 0; i < last; ++i)
 250:       {
 251:     String f = canonicalize ((String) elts.get (i));
 252:     int comp = f.compareTo (canonicalize ((String) cn.elts.get (i)));
 253:     if (comp != 0)
 254:       return comp;
 255:       }
 256:     return elts.size () - cn.elts.size ();
 257:   }
 258: 
 259:   public boolean endsWith (Name n)
 260:   {
 261:     if (! (n instanceof CompoundName))
 262:       return false;
 263:     CompoundName cn = (CompoundName) n;
 264:     if (cn.elts.size () > elts.size ())
 265:       return false;
 266:     int delta = elts.size () - cn.elts.size ();
 267:     for (int i = 0; i < cn.elts.size (); ++i)
 268:       {
 269:     String f = canonicalize ((String) elts.get (delta + i));
 270:     if (! f.equals (canonicalize ((String) cn.elts.get (i))))
 271:       return false;
 272:       }
 273:     return true;
 274:   }
 275: 
 276:   public boolean equals (Object obj)
 277:   {
 278:     if (! (obj instanceof CompoundName))
 279:       return false;
 280:     return compareTo (obj) == 0;
 281:   }
 282: 
 283:   public String get (int posn)
 284:   {
 285:     return (String) elts.get (posn);
 286:   }
 287: 
 288:   public Enumeration getAll ()
 289:   {
 290:     return elts.elements ();
 291:   }
 292: 
 293:   public Name getPrefix (int posn)
 294:   {
 295:     CompoundName cn = new CompoundName (mySyntax);
 296:     for (int i = 0; i < posn; ++i)
 297:       cn.elts.add (elts.get (i));
 298:     return cn;
 299:   }
 300: 
 301:   public Name getSuffix (int posn)
 302:   {
 303:     if (posn > elts.size ())
 304:       throw new ArrayIndexOutOfBoundsException (posn);
 305:     CompoundName cn = new CompoundName (mySyntax);
 306:     for (int i = posn; i < elts.size (); ++i)
 307:       cn.elts.add (elts.get (i));
 308:     return cn;
 309:   }
 310: 
 311:   public int hashCode ()
 312:   {
 313:     int h = 0;
 314:     for (int i = 0; i < elts.size (); ++i)
 315:       h += canonicalize ((String) elts.get (i)).hashCode ();
 316:     return h;
 317:   }
 318: 
 319:   public boolean isEmpty ()
 320:   {
 321:     return elts.isEmpty ();
 322:   }
 323: 
 324:   public Object remove (int posn) throws InvalidNameException
 325:   {
 326:     return elts.remove (posn);
 327:   }
 328: 
 329:   public int size ()
 330:   {
 331:     return elts.size ();
 332:   }
 333: 
 334:   public boolean startsWith (Name n)
 335:   {
 336:     if (! (n instanceof CompoundName))
 337:       return false;
 338:     CompoundName cn = (CompoundName) n;
 339:     if (cn.elts.size () > elts.size ())
 340:       return false;
 341:     for (int i = 0; i < cn.elts.size (); ++i)
 342:       {
 343:     String f = canonicalize ((String) elts.get (i));
 344:     if (! f.equals (canonicalize ((String) cn.elts.get (i))))
 345:       return false;
 346:       }
 347:     return true;
 348:   }
 349: 
 350:   // If ELEMENT starts with some meta-sequence at OFFSET, then return
 351:   // the string representing the meta-sequence.  Otherwise return
 352:   // null.
 353:   private String isSpecial (String element, int offset)
 354:   {
 355:     String special = null;
 356:     if (separator != null && element.startsWith (separator, offset))
 357:       special = separator;
 358:     else if (escape != null && element.startsWith (escape, offset))
 359:       special = escape;
 360:     else if (beginQuote != null && element.startsWith (beginQuote, offset))
 361:       special = beginQuote;
 362:     else if (endQuote != null && element.startsWith (endQuote, offset))
 363:       special = endQuote;
 364:     else if (beginQuote2 != null
 365:          && element.startsWith (beginQuote2, offset))
 366:       special = beginQuote2;
 367:     else if (endQuote2 != null && element.startsWith (endQuote2, offset))
 368:       special = endQuote2;
 369: 
 370:     return special;
 371:   }
 372: 
 373:   public String toString ()
 374:   {
 375:     StringBuffer result = new StringBuffer ();
 376:     int size = elts.size ();
 377:     for (int i = 0; i < size; ++i)
 378:       {
 379:     // Find the appropriate element.  FIXME: not clear what FLAT
 380:     // means.
 381:     int offset = (direction == RIGHT_TO_LEFT) ? (size - i - 1) : i;
 382:     String element = (String) elts.get (offset);
 383:     if (i > 0
 384:         || (i == size - 1 && element.equals ("")))
 385:       result.append (separator);
 386: 
 387:     int k = 0;
 388:     while (k < element.length ())
 389:       {
 390:         String special = isSpecial (element, k);
 391:         if (special != null)
 392:           {
 393:         result.append (escape);
 394:         result.append (special);
 395:         k += special.length ();
 396:           }
 397:         else
 398:           {
 399:         result.append (element.charAt (k));
 400:         ++k;
 401:           }
 402:       }
 403:       }
 404: 
 405:     return result.toString ();
 406:   }
 407: 
 408:   // This canonicalizes a String, based on the syntax, for comparison
 409:   // or other similar purposes.
 410:   private String canonicalize (String element)
 411:   {
 412:     String ret = element;
 413: 
 414:     if (ignoreCase)
 415:       ret = ret.toLowerCase ();
 416: 
 417:     if (trimBlanks)
 418:       {
 419:     int first = 0;
 420:     while (first < ret.length ()
 421:            && Character.isWhitespace (ret.charAt (first)))
 422:       ++first;
 423: 
 424:     int last = ret.length () - 1;
 425:     while (last >= first
 426:            && Character.isWhitespace (ret.charAt (last)))
 427:       --last;
 428: 
 429:     ret = ret.substring (first, last);
 430:       }
 431: 
 432:     return ret;
 433:   }
 434: 
 435:   // This initializes all the syntax variables.  This seems easier
 436:   // than re-querying the properties every time.  We're allowed to do
 437:   // this because the spec says that subclasses should consider the
 438:   // syntax as being read-only.
 439:   private void initializeSyntax ()
 440:   {
 441:     String t = mySyntax.getProperty ("jndi.syntax.direction", "flat");
 442:     if (t.equals ("right_to_left"))
 443:       this.direction = RIGHT_TO_LEFT;
 444:     else if (t.equals ("left_to_right"))
 445:       this.direction = LEFT_TO_RIGHT;
 446:     else
 447:       {
 448:     // If we don't recognize it, default to flat.
 449:     this.direction = FLAT;
 450:       }
 451: 
 452:     // This is required unless the direction is FLAT.  Unfortunately
 453:     // there is no way to report this error.
 454:     this.separator = mySyntax.getProperty ("jndi.syntax.separator", "");
 455: 
 456:     this.ignoreCase
 457:       = Boolean.valueOf (mySyntax.getProperty ("jndi.syntax.ignorecase",
 458:                            "false")).booleanValue ();
 459:     this.escape = mySyntax.getProperty ("jndi.syntax.escape", null);
 460:     this.beginQuote = mySyntax.getProperty ("jndi.syntax.beginquote", null);
 461:     this.endQuote = mySyntax.getProperty ("jndi.syntax.endquote",
 462:                       this.beginQuote);
 463:     this.beginQuote2 = mySyntax.getProperty ("jndi.syntax.beginquote2",
 464:                          null);
 465:     this.endQuote2 = mySyntax.getProperty ("jndi.syntax.endquote2",
 466:                        this.beginQuote2);
 467:     this.trimBlanks
 468:       = Boolean.valueOf (mySyntax.getProperty ("jndi.syntax.trimblanks",
 469:                            "false")).booleanValue ();
 470:   }
 471: 
 472:   private void readObject(ObjectInputStream s)
 473:     throws IOException, ClassNotFoundException
 474:   {
 475:     mySyntax = (Properties) s.readObject();
 476:     int count = s.readInt();
 477:     elts = new Vector(count);
 478:     for (int i = 0; i < count; i++)
 479:       elts.addElement((String) s.readObject());
 480:   }
 481: 
 482:   private void writeObject(ObjectOutputStream s)
 483:     throws IOException
 484:   {
 485:     s.writeObject(mySyntax);
 486:     s.writeInt(elts.size());
 487:     for (int i = 0; i < elts.size(); i++)
 488:         s.writeObject(elts.elementAt(i));
 489:   }
 490: 
 491:   // The spec specifies this but does not document it in any way (it
 492:   // is a package-private class).  It is useless as far as I can tell.
 493:   // So we ignore it.
 494:   // protected transient NameImpl impl;
 495:   protected transient Properties mySyntax;
 496: 
 497:   // The actual elements.
 498:   private transient Vector elts;
 499: 
 500:   // The following are all used for syntax.
 501:   private transient int direction;
 502:   private transient String separator;
 503:   private transient boolean ignoreCase;
 504:   private transient String escape;
 505:   private transient String beginQuote;
 506:   private transient String endQuote;
 507:   private transient String beginQuote2;
 508:   private transient String endQuote2;
 509:   private transient boolean trimBlanks;
 510:   // We didn't need these for parsing, so they are gone.
 511:   // private transient String avaSeparator;
 512:   // private transient String typevalSeparator;
 513: 
 514:   private static final int RIGHT_TO_LEFT = -1;
 515:   private static final int LEFT_TO_RIGHT = 1;
 516:   private static final int FLAT = 0;
 517: }