1 /* Copyright (C) 2001 Free Software Foundation
3 This file is part of libgcj.
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
11 import java.io.Serializable;
12 import java.util.Enumeration;
13 import java.util.Properties;
14 import java.util.NoSuchElementException;
15 import java.util.Vector;
18 * @author Tom Tromey <tromey@redhat.com>
21 * FIXME: must write readObject and writeObject to conform to
24 * FIXME: this class is underspecified. For instance, the `flat'
25 * direction is never described. If it means that the CompoundName
26 * can only have a single element, then the Enumeration-based
27 * constructor ought to throw InvalidNameException.
29 public class CompoundName implements Name, Cloneable, Serializable
31 private CompoundName (Properties syntax)
38 protected CompoundName (Enumeration comps, Properties syntax)
45 while (comps.hasMoreElements ())
46 elts.add (comps.nextElement ());
48 catch (NoSuchElementException ignore)
53 public CompoundName (String n, Properties syntax)
54 throws InvalidNameException
60 StringBuffer new_element = new StringBuffer ();
62 // QUOTE==null means no quoting right now. When it is set it is
63 // the value of the closing quote.
65 while (i < n.length ())
67 String special = isSpecial (n, i);
69 if (special == escape && escape != null)
71 if (n.length () == i + special.length ())
73 // A trailing escape is treated as itself.
74 new_element.append (special);
75 i += special.length ();
79 String eSpecial = isSpecial (n, i + special.length ());
82 // Treat the escape as an escape.
83 new_element.append (eSpecial);
84 i += special.length () + eSpecial.length ();
88 // Treat the escape as itself.
89 new_element.append (special);
90 i += special.length ();
95 else if (quote != null)
97 // It is safe to use == here.
100 // Quotes must surround a complete component.
101 if (i + quote.length () < n.length ()
102 && ! n.startsWith (separator, i + quote.length ()))
103 throw new InvalidNameException ("close quote before end of component");
104 elts.add (new_element.toString ());
105 new_element.setLength (0);
106 i += quote.length ();
110 // Otherwise, fall through.
112 // Quotes are only special at the start of a component.
113 else if (new_element.length () == 0 && special == beginQuote)
116 i += special.length ();
119 else if (new_element.length () == 0 && special == beginQuote2)
122 i += special.length ();
125 else if (special == separator)
127 elts.add (new_element.toString ());
128 new_element.setLength (0);
129 i += special.length ();
133 // Nothing in particular, so try the next character.
134 new_element.append (n.charAt (i));
138 if (new_element.length () != 0)
139 elts.add (new_element.toString ());
141 if (direction == RIGHT_TO_LEFT)
143 // Reverse the order of the elements.
144 int len = elts.size ();
145 for (i = 0; i < len / 2; ++i)
147 Object t = elts.set (i, elts.get (len - i - 1));
148 elts.set (len - i - 1, t);
154 throw new InvalidNameException ("unterminated quote");
157 public Name add (int posn, String comp) throws InvalidNameException
159 elts.add (posn, comp);
163 public Name add (String comp) throws InvalidNameException
169 public Name addAll (int posn, Name n) throws InvalidNameException
171 Enumeration e = n.getAll ();
174 while (e.hasMoreElements ())
176 elts.add (posn, e.nextElement ());
180 catch (NoSuchElementException ignore)
186 public Name addAll (Name suffix) throws InvalidNameException
188 Enumeration e = suffix.getAll ();
191 while (e.hasMoreElements ())
192 elts.add (e.nextElement ());
194 catch (NoSuchElementException ignore)
200 public Object clone ()
202 return new CompoundName (elts.elements (), mySyntax);
205 public int compareTo (Object obj)
207 if (obj == null || ! (obj instanceof CompoundName))
208 throw new ClassCastException ("CompoundName.compareTo() expected CompoundName");
209 CompoundName cn = (CompoundName) obj;
210 int last = Math.min (cn.elts.size (), elts.size ());
211 for (int i = 0; i < last; ++i)
213 String f = canonicalize ((String) elts.get (i));
214 int comp = f.compareTo (canonicalize ((String) cn.elts.get (i)));
218 return elts.size () - cn.elts.size ();
221 public boolean endsWith (Name n)
223 if (! (n instanceof CompoundName))
225 CompoundName cn = (CompoundName) n;
226 if (cn.elts.size () > elts.size ())
228 int delta = elts.size () - cn.elts.size ();
229 for (int i = 0; i < cn.elts.size (); ++i)
231 String f = canonicalize ((String) elts.get (i));
232 if (! f.equals (canonicalize ((String) cn.elts.get (i))))
238 public boolean equals (Object obj)
240 if (! (obj instanceof CompoundName))
242 return compareTo (obj) == 0;
245 public String get (int posn)
247 return (String) elts.get (posn);
250 public Enumeration getAll ()
252 return elts.elements ();
255 public Name getPrefix (int posn)
257 CompoundName cn = new CompoundName (mySyntax);
258 for (int i = 0; i < posn; ++i)
259 cn.elts.add (elts.get (i));
263 public Name getSuffix (int posn)
265 if (posn > elts.size ())
266 throw new ArrayIndexOutOfBoundsException (posn);
267 CompoundName cn = new CompoundName (mySyntax);
268 for (int i = posn; i < elts.size (); ++i)
269 cn.elts.add (elts.get (i));
273 public int hashCode ()
276 for (int i = 0; i < elts.size (); ++i)
277 h += canonicalize ((String) elts.get (i)).hashCode ();
281 public boolean isEmpty ()
283 return elts.isEmpty ();
286 public Object remove (int posn) throws InvalidNameException
288 return elts.remove (posn);
296 public boolean startsWith (Name n)
298 if (! (n instanceof CompoundName))
300 CompoundName cn = (CompoundName) n;
301 if (cn.elts.size () > elts.size ())
303 for (int i = 0; i < cn.elts.size (); ++i)
305 String f = canonicalize ((String) elts.get (i));
306 if (! f.equals (canonicalize ((String) cn.elts.get (i))))
312 // If ELEMENT starts with some meta-sequence at OFFSET, then return
313 // the string representing the meta-sequence. Otherwise return
315 private String isSpecial (String element, int offset)
317 String special = null;
318 if (separator != null && element.startsWith (separator, offset))
320 else if (escape != null && element.startsWith (escape, offset))
322 else if (beginQuote != null && element.startsWith (beginQuote, offset))
323 special = beginQuote;
324 else if (endQuote != null && element.startsWith (endQuote, offset))
326 else if (beginQuote2 != null
327 && element.startsWith (beginQuote2, offset))
328 special = beginQuote2;
329 else if (endQuote2 != null && element.startsWith (endQuote2, offset))
335 public String toString ()
337 StringBuffer result = new StringBuffer ();
338 int size = elts.size ();
339 for (int i = 0; i < size; ++i)
341 // Find the appropriate element. FIXME: not clear what FLAT
343 int offset = (direction == RIGHT_TO_LEFT) ? (size - i - 1) : i;
344 String element = (String) elts.get (offset);
346 || (i == size - 1 && element.equals ("")))
347 result.append (separator);
350 while (k < element.length ())
352 String special = isSpecial (element, k);
355 result.append (escape);
356 result.append (special);
357 k += special.length ();
361 result.append (element.charAt (k));
367 return result.toString ();
370 // This canonicalizes a String, based on the syntax, for comparison
371 // or other similar purposes.
372 private String canonicalize (String element)
374 String ret = element;
377 ret = ret.toLowerCase ();
382 while (first < ret.length ()
383 && Character.isWhitespace (ret.charAt (first)))
386 int last = ret.length () - 1;
388 && Character.isWhitespace (ret.charAt (last)))
391 ret = ret.substring (first, last);
397 // This initializes all the syntax variables. This seems easier
398 // than re-querying the properties every time. We're allowed to do
399 // this because the spec says that subclasses should consider the
400 // syntax as being read-only.
401 private void initializeSyntax ()
403 String t = mySyntax.getProperty ("jndi.syntax.direction", "flat");
404 if (t.equals ("right_to_left"))
405 this.direction = RIGHT_TO_LEFT;
406 else if (t.equals ("left_to_right"))
407 this.direction = LEFT_TO_RIGHT;
410 // If we don't recognize it, default to flat.
411 this.direction = FLAT;
414 // This is required unless the direction is FLAT. Unfortunately
415 // there is no way to report this error.
416 this.separator = mySyntax.getProperty ("jndi.syntax.separator", "");
419 = Boolean.valueOf (mySyntax.getProperty ("jndi.syntax.ignorecase",
420 "false")).booleanValue ();
421 this.escape = mySyntax.getProperty ("jndi.syntax.escape", null);
422 this.beginQuote = mySyntax.getProperty ("jndi.syntax.beginquote", null);
423 this.endQuote = mySyntax.getProperty ("jndi.syntax.endquote",
425 this.beginQuote2 = mySyntax.getProperty ("jndi.syntax.beginquote2",
427 this.endQuote2 = mySyntax.getProperty ("jndi.syntax.endquote2",
430 = Boolean.valueOf (mySyntax.getProperty ("jndi.syntax.trimblanks",
431 "false")).booleanValue ();
434 // The spec specifies this but does not document it in any way (it
435 // is a package-private class). It is useless as far as I can tell.
437 // protected transient NameImpl impl;
438 protected transient Properties mySyntax;
440 // The actual elements.
441 private transient Vector elts;
443 // The following are all used for syntax.
444 private transient int direction;
445 private transient String separator;
446 private transient boolean ignoreCase;
447 private transient String escape;
448 private transient String beginQuote;
449 private transient String endQuote;
450 private transient String beginQuote2;
451 private transient String endQuote2;
452 private transient boolean trimBlanks;
453 // We didn't need these for parsing, so they are gone.
454 // private transient String avaSeparator;
455 // private transient String typevalSeparator;
457 private static final int RIGHT_TO_LEFT = -1;
458 private static final int LEFT_TO_RIGHT = 1;
459 private static final int FLAT = 0;