1 /* CompoundName.java --
2 Copyright (C) 2001, 2004 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)
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
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
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. */
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
;
48 * @author Tom Tromey <tromey@redhat.com>
51 * FIXME: must write readObject and writeObject to conform to
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.
61 public class CompoundName
implements Name
, Cloneable
, Serializable
63 private static final long serialVersionUID
= 3513100557083972036L;
65 private CompoundName (Properties syntax
)
72 protected CompoundName (Enumeration comps
, Properties syntax
)
79 while (comps
.hasMoreElements ())
80 elts
.add (comps
.nextElement ());
82 catch (NoSuchElementException ignore
)
87 public CompoundName (String n
, Properties syntax
)
88 throws InvalidNameException
94 StringBuffer new_element
= new StringBuffer ();
96 // QUOTE==null means no quoting right now. When it is set it is
97 // the value of the closing quote.
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 ();
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 ();
122 // Treat the escape as itself.
123 new_element
.append (special
);
124 i
+= special
.length ();
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 ();
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)
152 i
+= special
.length ();
155 else if (new_element
.length () == 0
156 && special
== beginQuote2
157 && beginQuote2
!= null)
160 i
+= special
.length ();
163 else if (direction
!= FLAT
&& special
== separator
)
165 elts
.add (new_element
.toString ());
166 new_element
.setLength (0);
167 i
+= special
.length ();
171 // Nothing in particular, so try the next character.
172 new_element
.append (n
.charAt (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
);
192 throw new InvalidNameException ("unterminated quote");
195 public Name
add (int posn
, String comp
) throws InvalidNameException
197 elts
.add (posn
, comp
);
201 public Name
add (String comp
) throws InvalidNameException
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 ());
218 catch (NoSuchElementException ignore
)
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
)
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
)));
256 return elts
.size () - cn
.elts
.size ();
259 public boolean endsWith (Name n
)
261 if (! (n
instanceof CompoundName
))
263 CompoundName cn
= (CompoundName
) n
;
264 if (cn
.elts
.size () > elts
.size ())
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
))))
276 public boolean equals (Object obj
)
278 if (! (obj
instanceof CompoundName
))
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
));
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
));
311 public int hashCode ()
314 for (int i
= 0; i
< elts
.size (); ++i
)
315 h
+= canonicalize ((String
) elts
.get (i
)).hashCode ();
319 public boolean isEmpty ()
321 return elts
.isEmpty ();
324 public Object
remove (int posn
) throws InvalidNameException
326 return elts
.remove (posn
);
334 public boolean startsWith (Name n
)
336 if (! (n
instanceof CompoundName
))
338 CompoundName cn
= (CompoundName
) n
;
339 if (cn
.elts
.size () > elts
.size ())
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
))))
350 // If ELEMENT starts with some meta-sequence at OFFSET, then return
351 // the string representing the meta-sequence. Otherwise return
353 private String
isSpecial (String element
, int offset
)
355 String special
= null;
356 if (separator
!= null && element
.startsWith (separator
, offset
))
358 else if (escape
!= null && element
.startsWith (escape
, offset
))
360 else if (beginQuote
!= null && element
.startsWith (beginQuote
, offset
))
361 special
= beginQuote
;
362 else if (endQuote
!= null && element
.startsWith (endQuote
, offset
))
364 else if (beginQuote2
!= null
365 && element
.startsWith (beginQuote2
, offset
))
366 special
= beginQuote2
;
367 else if (endQuote2
!= null && element
.startsWith (endQuote2
, offset
))
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
381 int offset
= (direction
== RIGHT_TO_LEFT
) ?
(size
- i
- 1) : i
;
382 String element
= (String
) elts
.get (offset
);
384 || (i
== size
- 1 && element
.equals ("")))
385 result
.append (separator
);
388 while (k
< element
.length ())
390 String special
= isSpecial (element
, k
);
393 result
.append (escape
);
394 result
.append (special
);
395 k
+= special
.length ();
399 result
.append (element
.charAt (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
;
415 ret
= ret
.toLowerCase ();
420 while (first
< ret
.length ()
421 && Character
.isWhitespace (ret
.charAt (first
)))
424 int last
= ret
.length () - 1;
426 && Character
.isWhitespace (ret
.charAt (last
)))
429 ret
= ret
.substring (first
, last
);
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
;
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", "");
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",
463 this.beginQuote2
= mySyntax
.getProperty ("jndi.syntax.beginquote2",
465 this.endQuote2
= mySyntax
.getProperty ("jndi.syntax.endquote2",
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.
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;