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)
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
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 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
;
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)
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.
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
> ();
78 protected CompoundName (Enumeration
<String
> comps
, Properties syntax
)
80 elts
= new Vector
<String
> ();
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
> ();
100 StringBuilder new_element
= new StringBuilder ();
102 // QUOTE==null means no quoting right now. When it is set it is
103 // the value of the closing quote.
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 ();
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 ();
128 // Treat the escape as itself.
129 new_element
.append (special
);
130 i
+= special
.length ();
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 ();
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)
158 i
+= special
.length ();
161 else if (new_element
.length () == 0
162 && special
== beginQuote2
163 && beginQuote2
!= null)
166 i
+= special
.length ();
169 else if (direction
!= FLAT
&& special
== separator
)
171 elts
.add (new_element
.toString ());
172 new_element
.setLength (0);
173 i
+= special
.length ();
177 // Nothing in particular, so try the next character.
178 new_element
.append (n
.charAt (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
);
198 throw new InvalidNameException ("unterminated quote");
201 public Name
add (int posn
, String comp
) throws InvalidNameException
203 elts
.add (posn
, comp
);
207 public Name
add (String comp
) throws InvalidNameException
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 ());
224 catch (NoSuchElementException ignore
)
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
)
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
)));
262 return elts
.size () - cn
.elts
.size ();
265 public boolean endsWith (Name n
)
267 if (! (n
instanceof CompoundName
))
269 CompoundName cn
= (CompoundName
) n
;
270 if (cn
.elts
.size () > elts
.size ())
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
))))
282 public boolean equals (Object obj
)
284 if (! (obj
instanceof CompoundName
))
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
));
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
));
317 public int hashCode ()
320 for (int i
= 0; i
< elts
.size (); ++i
)
321 h
+= canonicalize (elts
.get (i
)).hashCode ();
325 public boolean isEmpty ()
327 return elts
.isEmpty ();
330 public Object
remove (int posn
) throws InvalidNameException
332 return elts
.remove (posn
);
340 public boolean startsWith (Name n
)
342 if (! (n
instanceof CompoundName
))
344 CompoundName cn
= (CompoundName
) n
;
345 if (cn
.elts
.size () > elts
.size ())
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
))))
356 // If ELEMENT starts with some meta-sequence at OFFSET, then return
357 // the string representing the meta-sequence. Otherwise return
359 private String
isSpecial (String element
, int offset
)
361 String special
= null;
362 if (separator
!= null && element
.startsWith (separator
, offset
))
364 else if (escape
!= null && element
.startsWith (escape
, offset
))
366 else if (beginQuote
!= null && element
.startsWith (beginQuote
, offset
))
367 special
= beginQuote
;
368 else if (endQuote
!= null && element
.startsWith (endQuote
, offset
))
370 else if (beginQuote2
!= null
371 && element
.startsWith (beginQuote2
, offset
))
372 special
= beginQuote2
;
373 else if (endQuote2
!= null && element
.startsWith (endQuote2
, offset
))
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
387 int offset
= (direction
== RIGHT_TO_LEFT
) ?
(size
- i
- 1) : i
;
388 String element
= elts
.get (offset
);
390 || (i
== size
- 1 && element
.equals ("")))
391 result
.append (separator
);
394 while (k
< element
.length ())
396 String special
= isSpecial (element
, k
);
399 result
.append (escape
);
400 result
.append (special
);
401 k
+= special
.length ();
405 result
.append (element
.charAt (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
;
421 ret
= ret
.toLowerCase ();
426 while (first
< ret
.length ()
427 && Character
.isWhitespace (ret
.charAt (first
)))
430 int last
= ret
.length () - 1;
432 && Character
.isWhitespace (ret
.charAt (last
)))
435 ret
= ret
.substring (first
, last
);
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
;
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", "");
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",
469 this.beginQuote2
= mySyntax
.getProperty ("jndi.syntax.beginquote2",
471 this.endQuote2
= mySyntax
.getProperty ("jndi.syntax.endquote2",
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
)
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.
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;