1 /* CompoundName.java --
2 Copyright (C) 2001 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
.Properties
;
44 import java
.util
.NoSuchElementException
;
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.
59 public class CompoundName
implements Name
, Cloneable
, Serializable
61 private static final long serialVersionUID
= 3513100557083972036L;
63 private CompoundName (Properties syntax
)
70 protected CompoundName (Enumeration comps
, Properties syntax
)
77 while (comps
.hasMoreElements ())
78 elts
.add (comps
.nextElement ());
80 catch (NoSuchElementException ignore
)
85 public CompoundName (String n
, Properties syntax
)
86 throws InvalidNameException
92 StringBuffer new_element
= new StringBuffer ();
94 // QUOTE==null means no quoting right now. When it is set it is
95 // the value of the closing quote.
97 while (i
< n
.length ())
99 String special
= isSpecial (n
, i
);
101 if (special
== escape
&& escape
!= null)
103 if (n
.length () == i
+ special
.length ())
105 // A trailing escape is treated as itself.
106 new_element
.append (special
);
107 i
+= special
.length ();
111 String eSpecial
= isSpecial (n
, i
+ special
.length ());
112 if (eSpecial
!= null)
114 // Treat the escape as an escape.
115 new_element
.append (eSpecial
);
116 i
+= special
.length () + eSpecial
.length ();
120 // Treat the escape as itself.
121 new_element
.append (special
);
122 i
+= special
.length ();
127 else if (quote
!= null)
129 // It is safe to use == here.
130 if (quote
== special
)
132 // Quotes must surround a complete component.
133 if (i
+ quote
.length () < n
.length ()
134 && ! n
.startsWith (separator
, i
+ quote
.length ()))
135 throw new InvalidNameException ("close quote before end of component");
136 elts
.add (new_element
.toString ());
137 new_element
.setLength (0);
138 i
+= quote
.length ();
142 // Otherwise, fall through.
144 // Quotes are only special at the start of a component.
145 else if (new_element
.length () == 0
146 && special
== beginQuote
147 && beginQuote
!= null)
150 i
+= special
.length ();
153 else if (new_element
.length () == 0
154 && special
== beginQuote2
155 && beginQuote2
!= null)
158 i
+= special
.length ();
161 else if (special
== separator
)
163 elts
.add (new_element
.toString ());
164 new_element
.setLength (0);
165 i
+= special
.length ();
169 // Nothing in particular, so try the next character.
170 new_element
.append (n
.charAt (i
));
174 if (new_element
.length () != 0)
175 elts
.add (new_element
.toString ());
177 if (direction
== RIGHT_TO_LEFT
)
179 // Reverse the order of the elements.
180 int len
= elts
.size ();
181 for (i
= 0; i
< len
/ 2; ++i
)
183 Object t
= elts
.set (i
, elts
.get (len
- i
- 1));
184 elts
.set (len
- i
- 1, t
);
190 throw new InvalidNameException ("unterminated quote");
193 public Name
add (int posn
, String comp
) throws InvalidNameException
195 elts
.add (posn
, comp
);
199 public Name
add (String comp
) throws InvalidNameException
205 public Name
addAll (int posn
, Name n
) throws InvalidNameException
207 Enumeration e
= n
.getAll ();
210 while (e
.hasMoreElements ())
212 elts
.add (posn
, e
.nextElement ());
216 catch (NoSuchElementException ignore
)
222 public Name
addAll (Name suffix
) throws InvalidNameException
224 Enumeration e
= suffix
.getAll ();
227 while (e
.hasMoreElements ())
228 elts
.add (e
.nextElement ());
230 catch (NoSuchElementException ignore
)
236 public Object
clone ()
238 return new CompoundName (elts
.elements (), mySyntax
);
241 public int compareTo (Object obj
)
243 if (! (obj
instanceof CompoundName
))
244 throw new ClassCastException ("CompoundName.compareTo() expected CompoundName");
245 CompoundName cn
= (CompoundName
) obj
;
246 int last
= Math
.min (cn
.elts
.size (), elts
.size ());
247 for (int i
= 0; i
< last
; ++i
)
249 String f
= canonicalize ((String
) elts
.get (i
));
250 int comp
= f
.compareTo (canonicalize ((String
) cn
.elts
.get (i
)));
254 return elts
.size () - cn
.elts
.size ();
257 public boolean endsWith (Name n
)
259 if (! (n
instanceof CompoundName
))
261 CompoundName cn
= (CompoundName
) n
;
262 if (cn
.elts
.size () > elts
.size ())
264 int delta
= elts
.size () - cn
.elts
.size ();
265 for (int i
= 0; i
< cn
.elts
.size (); ++i
)
267 String f
= canonicalize ((String
) elts
.get (i
));
268 if (! f
.equals (canonicalize ((String
) cn
.elts
.get (i
))))
274 public boolean equals (Object obj
)
276 if (! (obj
instanceof CompoundName
))
278 return compareTo (obj
) == 0;
281 public String
get (int posn
)
283 return (String
) elts
.get (posn
);
286 public Enumeration
getAll ()
288 return elts
.elements ();
291 public Name
getPrefix (int posn
)
293 CompoundName cn
= new CompoundName (mySyntax
);
294 for (int i
= 0; i
< posn
; ++i
)
295 cn
.elts
.add (elts
.get (i
));
299 public Name
getSuffix (int posn
)
301 if (posn
> elts
.size ())
302 throw new ArrayIndexOutOfBoundsException (posn
);
303 CompoundName cn
= new CompoundName (mySyntax
);
304 for (int i
= posn
; i
< elts
.size (); ++i
)
305 cn
.elts
.add (elts
.get (i
));
309 public int hashCode ()
312 for (int i
= 0; i
< elts
.size (); ++i
)
313 h
+= canonicalize ((String
) elts
.get (i
)).hashCode ();
317 public boolean isEmpty ()
319 return elts
.isEmpty ();
322 public Object
remove (int posn
) throws InvalidNameException
324 return elts
.remove (posn
);
332 public boolean startsWith (Name n
)
334 if (! (n
instanceof CompoundName
))
336 CompoundName cn
= (CompoundName
) n
;
337 if (cn
.elts
.size () > elts
.size ())
339 for (int i
= 0; i
< cn
.elts
.size (); ++i
)
341 String f
= canonicalize ((String
) elts
.get (i
));
342 if (! f
.equals (canonicalize ((String
) cn
.elts
.get (i
))))
348 // If ELEMENT starts with some meta-sequence at OFFSET, then return
349 // the string representing the meta-sequence. Otherwise return
351 private String
isSpecial (String element
, int offset
)
353 String special
= null;
354 if (separator
!= null && element
.startsWith (separator
, offset
))
356 else if (escape
!= null && element
.startsWith (escape
, offset
))
358 else if (beginQuote
!= null && element
.startsWith (beginQuote
, offset
))
359 special
= beginQuote
;
360 else if (endQuote
!= null && element
.startsWith (endQuote
, offset
))
362 else if (beginQuote2
!= null
363 && element
.startsWith (beginQuote2
, offset
))
364 special
= beginQuote2
;
365 else if (endQuote2
!= null && element
.startsWith (endQuote2
, offset
))
371 public String
toString ()
373 StringBuffer result
= new StringBuffer ();
374 int size
= elts
.size ();
375 for (int i
= 0; i
< size
; ++i
)
377 // Find the appropriate element. FIXME: not clear what FLAT
379 int offset
= (direction
== RIGHT_TO_LEFT
) ?
(size
- i
- 1) : i
;
380 String element
= (String
) elts
.get (offset
);
382 || (i
== size
- 1 && element
.equals ("")))
383 result
.append (separator
);
386 while (k
< element
.length ())
388 String special
= isSpecial (element
, k
);
391 result
.append (escape
);
392 result
.append (special
);
393 k
+= special
.length ();
397 result
.append (element
.charAt (k
));
403 return result
.toString ();
406 // This canonicalizes a String, based on the syntax, for comparison
407 // or other similar purposes.
408 private String
canonicalize (String element
)
410 String ret
= element
;
413 ret
= ret
.toLowerCase ();
418 while (first
< ret
.length ()
419 && Character
.isWhitespace (ret
.charAt (first
)))
422 int last
= ret
.length () - 1;
424 && Character
.isWhitespace (ret
.charAt (last
)))
427 ret
= ret
.substring (first
, last
);
433 // This initializes all the syntax variables. This seems easier
434 // than re-querying the properties every time. We're allowed to do
435 // this because the spec says that subclasses should consider the
436 // syntax as being read-only.
437 private void initializeSyntax ()
439 String t
= mySyntax
.getProperty ("jndi.syntax.direction", "flat");
440 if (t
.equals ("right_to_left"))
441 this.direction
= RIGHT_TO_LEFT
;
442 else if (t
.equals ("left_to_right"))
443 this.direction
= LEFT_TO_RIGHT
;
446 // If we don't recognize it, default to flat.
447 this.direction
= FLAT
;
450 // This is required unless the direction is FLAT. Unfortunately
451 // there is no way to report this error.
452 this.separator
= mySyntax
.getProperty ("jndi.syntax.separator", "");
455 = Boolean
.valueOf (mySyntax
.getProperty ("jndi.syntax.ignorecase",
456 "false")).booleanValue ();
457 this.escape
= mySyntax
.getProperty ("jndi.syntax.escape", null);
458 this.beginQuote
= mySyntax
.getProperty ("jndi.syntax.beginquote", null);
459 this.endQuote
= mySyntax
.getProperty ("jndi.syntax.endquote",
461 this.beginQuote2
= mySyntax
.getProperty ("jndi.syntax.beginquote2",
463 this.endQuote2
= mySyntax
.getProperty ("jndi.syntax.endquote2",
466 = Boolean
.valueOf (mySyntax
.getProperty ("jndi.syntax.trimblanks",
467 "false")).booleanValue ();
470 // The spec specifies this but does not document it in any way (it
471 // is a package-private class). It is useless as far as I can tell.
473 // protected transient NameImpl impl;
474 protected transient Properties mySyntax
;
476 // The actual elements.
477 private transient Vector elts
;
479 // The following are all used for syntax.
480 private transient int direction
;
481 private transient String separator
;
482 private transient boolean ignoreCase
;
483 private transient String escape
;
484 private transient String beginQuote
;
485 private transient String endQuote
;
486 private transient String beginQuote2
;
487 private transient String endQuote2
;
488 private transient boolean trimBlanks
;
489 // We didn't need these for parsing, so they are gone.
490 // private transient String avaSeparator;
491 // private transient String typevalSeparator;
493 private static final int RIGHT_TO_LEFT
= -1;
494 private static final int LEFT_TO_RIGHT
= 1;
495 private static final int FLAT
= 0;