Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / javax / naming / CompoundName.java
blob2299715877e335fcb2aa2b3ec9e21e0435797d98
1 /* CompoundName.java --
2 Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
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.
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. */
39 package javax.naming;
41 import java.io.Serializable;
42 import java.util.Enumeration;
43 import java.util.NoSuchElementException;
44 import java.util.Properties;
45 import java.util.Vector;
47 /**
48 * @author Tom Tromey (tromey@redhat.com)
49 * @date May 16, 2001
51 * FIXME: must write readObject and writeObject to conform to
52 * serialization spec.
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.
59 * @since 1.3
61 public class CompoundName implements Name, Cloneable, Serializable
63 private static final long serialVersionUID = 3513100557083972036L;
65 private CompoundName (Properties syntax)
67 elts = new Vector ();
68 mySyntax = syntax;
69 initializeSyntax ();
72 protected CompoundName (Enumeration comps, Properties syntax)
74 elts = new Vector ();
75 mySyntax = syntax;
76 initializeSyntax ();
77 try
79 while (comps.hasMoreElements ())
80 elts.add (comps.nextElement ());
82 catch (NoSuchElementException ignore)
87 public CompoundName (String n, Properties syntax)
88 throws InvalidNameException
90 elts = new Vector ();
91 mySyntax = syntax;
92 initializeSyntax ();
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 ())
101 String special = isSpecial (n, i);
103 if (special == escape && escape != null)
105 if (n.length () == i + special.length ())
107 // A trailing escape is treated as itself.
108 new_element.append (special);
109 i += special.length ();
111 else
113 String eSpecial = isSpecial (n, i + special.length ());
114 if (eSpecial != null)
116 // Treat the escape as an escape.
117 new_element.append (eSpecial);
118 i += special.length () + eSpecial.length ();
120 else
122 // Treat the escape as itself.
123 new_element.append (special);
124 i += special.length ();
126 continue;
129 else if (quote != null)
131 // It is safe to use == here.
132 if (quote == special)
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;
144 // Otherwise, fall through.
146 // Quotes are only special at the start of a component.
147 else if (new_element.length () == 0
148 && special == beginQuote
149 && beginQuote != null)
151 quote = endQuote;
152 i += special.length ();
153 continue;
155 else if (new_element.length () == 0
156 && special == beginQuote2
157 && beginQuote2 != null)
159 quote = endQuote2;
160 i += special.length ();
161 continue;
163 else if (direction != FLAT && special == separator)
165 elts.add (new_element.toString ());
166 new_element.setLength (0);
167 i += special.length ();
168 continue;
171 // Nothing in particular, so try the next character.
172 new_element.append (n.charAt (i));
173 ++i;
176 if (new_element.length () != 0)
177 elts.add (new_element.toString ());
179 if (direction == RIGHT_TO_LEFT)
181 // Reverse the order of the elements.
182 int len = elts.size ();
183 for (i = 0; i < len / 2; ++i)
185 Object t = elts.set (i, elts.get (len - i - 1));
186 elts.set (len - i - 1, t);
190 // Error checking.
191 if (quote != null)
192 throw new InvalidNameException ("unterminated quote");
195 public Name add (int posn, String comp) throws InvalidNameException
197 elts.add (posn, comp);
198 return this;
201 public Name add (String comp) throws InvalidNameException
203 elts.add (comp);
204 return this;
207 public Name addAll (int posn, Name n) throws InvalidNameException
209 Enumeration e = n.getAll ();
212 while (e.hasMoreElements ())
214 elts.add (posn, e.nextElement ());
215 ++posn;
218 catch (NoSuchElementException ignore)
221 return this;
224 public Name addAll (Name suffix) throws InvalidNameException
226 Enumeration e = suffix.getAll ();
229 while (e.hasMoreElements ())
230 elts.add (e.nextElement ());
232 catch (NoSuchElementException ignore)
235 return this;
238 public Object clone ()
240 return new CompoundName (elts.elements (), mySyntax);
243 public int compareTo (Object obj)
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)
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;
256 return elts.size () - cn.elts.size ();
259 public boolean endsWith (Name n)
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)
269 String f = canonicalize ((String) elts.get (delta + i));
270 if (! f.equals (canonicalize ((String) cn.elts.get (i))))
271 return false;
273 return true;
276 public boolean equals (Object obj)
278 if (! (obj instanceof CompoundName))
279 return false;
280 return compareTo (obj) == 0;
283 public String get (int posn)
285 return (String) elts.get (posn);
288 public Enumeration getAll ()
290 return elts.elements ();
293 public Name getPrefix (int posn)
295 CompoundName cn = new CompoundName (mySyntax);
296 for (int i = 0; i < posn; ++i)
297 cn.elts.add (elts.get (i));
298 return cn;
301 public Name getSuffix (int posn)
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;
311 public int hashCode ()
313 int h = 0;
314 for (int i = 0; i < elts.size (); ++i)
315 h += canonicalize ((String) elts.get (i)).hashCode ();
316 return h;
319 public boolean isEmpty ()
321 return elts.isEmpty ();
324 public Object remove (int posn) throws InvalidNameException
326 return elts.remove (posn);
329 public int size ()
331 return elts.size ();
334 public boolean startsWith (Name n)
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)
343 String f = canonicalize ((String) elts.get (i));
344 if (! f.equals (canonicalize ((String) cn.elts.get (i))))
345 return false;
347 return true;
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)
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;
370 return special;
373 public String toString ()
375 StringBuffer result = new StringBuffer ();
376 int size = elts.size ();
377 for (int i = 0; i < size; ++i)
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);
387 int k = 0;
388 while (k < element.length ())
390 String special = isSpecial (element, k);
391 if (special != null)
393 result.append (escape);
394 result.append (special);
395 k += special.length ();
397 else
399 result.append (element.charAt (k));
400 ++k;
405 return result.toString ();
408 // This canonicalizes a String, based on the syntax, for comparison
409 // or other similar purposes.
410 private String canonicalize (String element)
412 String ret = element;
414 if (ignoreCase)
415 ret = ret.toLowerCase ();
417 if (trimBlanks)
419 int first = 0;
420 while (first < ret.length ()
421 && Character.isWhitespace (ret.charAt (first)))
422 ++first;
424 int last = ret.length () - 1;
425 while (last >= first
426 && Character.isWhitespace (ret.charAt (last)))
427 --last;
429 ret = ret.substring (first, last);
432 return ret;
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 ()
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
448 // If we don't recognize it, default to flat.
449 this.direction = FLAT;
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", "");
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 ();
472 // The spec specifies this but does not document it in any way (it
473 // is a package-private class). It is useless as far as I can tell.
474 // So we ignore it.
475 // protected transient NameImpl impl;
476 protected transient Properties mySyntax;
478 // The actual elements.
479 private transient Vector elts;
481 // The following are all used for syntax.
482 private transient int direction;
483 private transient String separator;
484 private transient boolean ignoreCase;
485 private transient String escape;
486 private transient String beginQuote;
487 private transient String endQuote;
488 private transient String beginQuote2;
489 private transient String endQuote2;
490 private transient boolean trimBlanks;
491 // We didn't need these for parsing, so they are gone.
492 // private transient String avaSeparator;
493 // private transient String typevalSeparator;
495 private static final int RIGHT_TO_LEFT = -1;
496 private static final int LEFT_TO_RIGHT = 1;
497 private static final int FLAT = 0;