libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / javax / naming / CompoundName.java
blob26b44c16fdb3b28a72abfa5707a5f3052355977d
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., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 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 gnu.java.lang.CPStringBuilder;
43 import java.io.IOException;
44 import java.io.ObjectInputStream;
45 import java.io.ObjectOutputStream;
46 import java.io.Serializable;
47 import java.util.Enumeration;
48 import java.util.NoSuchElementException;
49 import java.util.Properties;
50 import java.util.Vector;
52 /**
53 * Represents hierarchical names from the single namespace. For instance,
54 * the path /home/audriusa/classpath/file.txt is the compound name, using
55 * the filesystem namespace.
57 * @author Tom Tromey (tromey@redhat.com)
58 * @date May 16, 2001
60 * FIXME: this class is underspecified. For instance, the `flat'
61 * direction is never described. If it means that the CompoundName
62 * can only have a single element, then the Enumeration-based
63 * constructor ought to throw InvalidNameException.
65 * @since 1.3
67 public class CompoundName implements Name, Cloneable, Serializable
69 private static final long serialVersionUID = 3513100557083972036L;
71 private CompoundName (Properties syntax)
73 elts = new Vector<String> ();
74 mySyntax = syntax;
75 initializeSyntax ();
78 protected CompoundName (Enumeration<String> comps, Properties syntax)
80 elts = new Vector<String> ();
81 mySyntax = syntax;
82 initializeSyntax ();
83 try
85 while (comps.hasMoreElements ())
86 elts.add (comps.nextElement ());
88 catch (NoSuchElementException ignore)
93 public CompoundName (String n, Properties syntax)
94 throws InvalidNameException
96 elts = new Vector<String> ();
97 mySyntax = syntax;
98 initializeSyntax ();
100 StringBuilder new_element = new StringBuilder ();
101 int i = 0;
102 // QUOTE==null means no quoting right now. When it is set it is
103 // the value of the closing quote.
104 String quote = null;
105 while (i < n.length ())
107 String special = isSpecial (n, i);
109 if (special == escape && escape != null)
111 if (n.length () == i + special.length ())
113 // A trailing escape is treated as itself.
114 new_element.append (special);
115 i += special.length ();
117 else
119 String eSpecial = isSpecial (n, i + special.length ());
120 if (eSpecial != null)
122 // Treat the escape as an escape.
123 new_element.append (eSpecial);
124 i += special.length () + eSpecial.length ();
126 else
128 // Treat the escape as itself.
129 new_element.append (special);
130 i += special.length ();
132 continue;
135 else if (quote != null)
137 // It is safe to use == here.
138 if (quote == special)
140 // Quotes must surround a complete component.
141 if (i + quote.length () < n.length ()
142 && ! n.startsWith (separator, i + quote.length ()))
143 throw new InvalidNameException ("close quote before end of component");
144 elts.add (new_element.toString ());
145 new_element.setLength (0);
146 i += quote.length ();
147 quote = null;
148 continue;
150 // Otherwise, fall through.
152 // Quotes are only special at the start of a component.
153 else if (new_element.length () == 0
154 && special == beginQuote
155 && beginQuote != null)
157 quote = endQuote;
158 i += special.length ();
159 continue;
161 else if (new_element.length () == 0
162 && special == beginQuote2
163 && beginQuote2 != null)
165 quote = endQuote2;
166 i += special.length ();
167 continue;
169 else if (direction != FLAT && special == separator)
171 elts.add (new_element.toString ());
172 new_element.setLength (0);
173 i += special.length ();
174 continue;
177 // Nothing in particular, so try the next character.
178 new_element.append (n.charAt (i));
179 ++i;
182 if (new_element.length () != 0)
183 elts.add (new_element.toString ());
185 if (direction == RIGHT_TO_LEFT)
187 // Reverse the order of the elements.
188 int len = elts.size ();
189 for (i = 0; i < len / 2; ++i)
191 String t = elts.set (i, elts.get (len - i - 1));
192 elts.set (len - i - 1, t);
196 // Error checking.
197 if (quote != null)
198 throw new InvalidNameException ("unterminated quote");
201 public Name add (int posn, String comp) throws InvalidNameException
203 elts.add (posn, comp);
204 return this;
207 public Name add (String comp) throws InvalidNameException
209 elts.add (comp);
210 return this;
213 public Name addAll (int posn, Name n) throws InvalidNameException
215 Enumeration<String> e = n.getAll ();
218 while (e.hasMoreElements ())
220 elts.add (posn, e.nextElement ());
221 ++posn;
224 catch (NoSuchElementException ignore)
227 return this;
230 public Name addAll (Name suffix) throws InvalidNameException
232 Enumeration<String> e = suffix.getAll ();
235 while (e.hasMoreElements ())
236 elts.add (e.nextElement ());
238 catch (NoSuchElementException ignore)
241 return this;
244 public Object clone ()
246 return new CompoundName (elts.elements (), mySyntax);
249 public int compareTo (Object obj)
251 if (! (obj instanceof CompoundName))
252 throw new ClassCastException ("CompoundName.compareTo() expected CompoundName");
253 CompoundName cn = (CompoundName) obj;
254 int last = Math.min (cn.elts.size (), elts.size ());
255 for (int i = 0; i < last; ++i)
257 String f = canonicalize (elts.get (i));
258 int comp = f.compareTo (canonicalize (cn.elts.get (i)));
259 if (comp != 0)
260 return comp;
262 return elts.size () - cn.elts.size ();
265 public boolean endsWith (Name n)
267 if (! (n instanceof CompoundName))
268 return false;
269 CompoundName cn = (CompoundName) n;
270 if (cn.elts.size () > elts.size ())
271 return false;
272 int delta = elts.size () - cn.elts.size ();
273 for (int i = 0; i < cn.elts.size (); ++i)
275 String f = canonicalize (elts.get (delta + i));
276 if (! f.equals (canonicalize (cn.elts.get (i))))
277 return false;
279 return true;
282 public boolean equals (Object obj)
284 if (! (obj instanceof CompoundName))
285 return false;
286 return compareTo (obj) == 0;
289 public String get (int posn)
291 return elts.get (posn);
294 public Enumeration<String> getAll ()
296 return elts.elements ();
299 public Name getPrefix (int posn)
301 CompoundName cn = new CompoundName (mySyntax);
302 for (int i = 0; i < posn; ++i)
303 cn.elts.add (elts.get (i));
304 return cn;
307 public Name getSuffix (int posn)
309 if (posn > elts.size ())
310 throw new ArrayIndexOutOfBoundsException (posn);
311 CompoundName cn = new CompoundName (mySyntax);
312 for (int i = posn; i < elts.size (); ++i)
313 cn.elts.add (elts.get (i));
314 return cn;
317 public int hashCode ()
319 int h = 0;
320 for (int i = 0; i < elts.size (); ++i)
321 h += canonicalize (elts.get (i)).hashCode ();
322 return h;
325 public boolean isEmpty ()
327 return elts.isEmpty ();
330 public Object remove (int posn) throws InvalidNameException
332 return elts.remove (posn);
335 public int size ()
337 return elts.size ();
340 public boolean startsWith (Name n)
342 if (! (n instanceof CompoundName))
343 return false;
344 CompoundName cn = (CompoundName) n;
345 if (cn.elts.size () > elts.size ())
346 return false;
347 for (int i = 0; i < cn.elts.size (); ++i)
349 String f = canonicalize (elts.get (i));
350 if (! f.equals (canonicalize (cn.elts.get (i))))
351 return false;
353 return true;
356 // If ELEMENT starts with some meta-sequence at OFFSET, then return
357 // the string representing the meta-sequence. Otherwise return
358 // null.
359 private String isSpecial (String element, int offset)
361 String special = null;
362 if (separator != null && element.startsWith (separator, offset))
363 special = separator;
364 else if (escape != null && element.startsWith (escape, offset))
365 special = escape;
366 else if (beginQuote != null && element.startsWith (beginQuote, offset))
367 special = beginQuote;
368 else if (endQuote != null && element.startsWith (endQuote, offset))
369 special = endQuote;
370 else if (beginQuote2 != null
371 && element.startsWith (beginQuote2, offset))
372 special = beginQuote2;
373 else if (endQuote2 != null && element.startsWith (endQuote2, offset))
374 special = endQuote2;
376 return special;
379 public String toString ()
381 CPStringBuilder result = new CPStringBuilder ();
382 int size = elts.size ();
383 for (int i = 0; i < size; ++i)
385 // Find the appropriate element. FIXME: not clear what FLAT
386 // means.
387 int offset = (direction == RIGHT_TO_LEFT) ? (size - i - 1) : i;
388 String element = elts.get (offset);
389 if (i > 0
390 || (i == size - 1 && element.equals ("")))
391 result.append (separator);
393 int k = 0;
394 while (k < element.length ())
396 String special = isSpecial (element, k);
397 if (special != null)
399 result.append (escape);
400 result.append (special);
401 k += special.length ();
403 else
405 result.append (element.charAt (k));
406 ++k;
411 return result.toString ();
414 // This canonicalizes a String, based on the syntax, for comparison
415 // or other similar purposes.
416 private String canonicalize (String element)
418 String ret = element;
420 if (ignoreCase)
421 ret = ret.toLowerCase ();
423 if (trimBlanks)
425 int first = 0;
426 while (first < ret.length ()
427 && Character.isWhitespace (ret.charAt (first)))
428 ++first;
430 int last = ret.length () - 1;
431 while (last >= first
432 && Character.isWhitespace (ret.charAt (last)))
433 --last;
435 ret = ret.substring (first, last);
438 return ret;
441 // This initializes all the syntax variables. This seems easier
442 // than re-querying the properties every time. We're allowed to do
443 // this because the spec says that subclasses should consider the
444 // syntax as being read-only.
445 private void initializeSyntax ()
447 String t = mySyntax.getProperty ("jndi.syntax.direction", "flat");
448 if (t.equals ("right_to_left"))
449 this.direction = RIGHT_TO_LEFT;
450 else if (t.equals ("left_to_right"))
451 this.direction = LEFT_TO_RIGHT;
452 else
454 // If we don't recognize it, default to flat.
455 this.direction = FLAT;
458 // This is required unless the direction is FLAT. Unfortunately
459 // there is no way to report this error.
460 this.separator = mySyntax.getProperty ("jndi.syntax.separator", "");
462 this.ignoreCase
463 = Boolean.valueOf (mySyntax.getProperty ("jndi.syntax.ignorecase",
464 "false")).booleanValue ();
465 this.escape = mySyntax.getProperty ("jndi.syntax.escape", null);
466 this.beginQuote = mySyntax.getProperty ("jndi.syntax.beginquote", null);
467 this.endQuote = mySyntax.getProperty ("jndi.syntax.endquote",
468 this.beginQuote);
469 this.beginQuote2 = mySyntax.getProperty ("jndi.syntax.beginquote2",
470 null);
471 this.endQuote2 = mySyntax.getProperty ("jndi.syntax.endquote2",
472 this.beginQuote2);
473 this.trimBlanks
474 = Boolean.valueOf (mySyntax.getProperty ("jndi.syntax.trimblanks",
475 "false")).booleanValue ();
478 private void readObject(ObjectInputStream s)
479 throws IOException, ClassNotFoundException
481 mySyntax = (Properties) s.readObject();
482 int count = s.readInt();
483 elts = new Vector<String>(count);
484 for (int i = 0; i < count; i++)
485 elts.addElement((String) s.readObject());
488 private void writeObject(ObjectOutputStream s)
489 throws IOException
491 s.writeObject(mySyntax);
492 s.writeInt(elts.size());
493 for (int i = 0; i < elts.size(); i++)
494 s.writeObject(elts.elementAt(i));
497 // The spec specifies this but does not document it in any way (it
498 // is a package-private class). It is useless as far as I can tell.
499 // So we ignore it.
500 // protected transient NameImpl impl;
501 protected transient Properties mySyntax;
503 // The actual elements.
504 private transient Vector<String> elts;
506 // The following are all used for syntax.
507 private transient int direction;
508 private transient String separator;
509 private transient boolean ignoreCase;
510 private transient String escape;
511 private transient String beginQuote;
512 private transient String endQuote;
513 private transient String beginQuote2;
514 private transient String endQuote2;
515 private transient boolean trimBlanks;
516 // We didn't need these for parsing, so they are gone.
517 // private transient String avaSeparator;
518 // private transient String typevalSeparator;
520 private static final int RIGHT_TO_LEFT = -1;
521 private static final int LEFT_TO_RIGHT = 1;
522 private static final int FLAT = 0;