OSDN Git Service

libjava/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / naming / CompoundName.java
1 /* CompoundName.java --
2    Copyright (C) 2001, 2004, 2005  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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.
20
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.
25
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. */
37
38
39 package javax.naming;
40
41 import gnu.java.lang.CPStringBuilder;
42
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;
51
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. 
56  * 
57  * @author Tom Tromey (tromey@redhat.com)
58  * @date May 16, 2001
59  *
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.
64  *
65  * @since 1.3
66  */
67 public class CompoundName implements Name, Cloneable, Serializable
68 {
69   private static final long serialVersionUID = 3513100557083972036L;
70
71   private CompoundName (Properties syntax)
72   {
73     elts = new Vector<String> ();
74     mySyntax = syntax;
75     initializeSyntax ();
76   }
77
78   protected CompoundName (Enumeration<String> comps, Properties syntax)
79   {
80     elts = new Vector<String> ();
81     mySyntax = syntax;
82     initializeSyntax ();
83     try
84       {
85         while (comps.hasMoreElements ())
86           elts.add (comps.nextElement ());
87       }
88     catch (NoSuchElementException ignore)
89       {
90       }
91   }
92
93   public CompoundName (String n, Properties syntax)
94     throws InvalidNameException
95   {
96     elts = new Vector<String> ();
97     mySyntax = syntax;
98     initializeSyntax ();
99
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 ())
106       {
107         String special = isSpecial (n, i);
108
109         if (special == escape && escape != null)
110           {
111             if (n.length () == i + special.length ())
112               {
113                 // A trailing escape is treated as itself.
114                 new_element.append (special);
115                 i += special.length ();
116               }
117             else
118               {
119                 String eSpecial = isSpecial (n, i + special.length ());
120                 if (eSpecial != null)
121                   {
122                     // Treat the escape as an escape.
123                     new_element.append (eSpecial);
124                     i += special.length () + eSpecial.length ();
125                   }
126                 else
127                   {
128                     // Treat the escape as itself.
129                     new_element.append (special);
130                     i += special.length ();
131                   }
132                 continue;
133               }
134           }
135         else if (quote != null)
136           {
137             // It is safe to use == here.
138             if (quote == special)
139               {
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;
149               }
150             // Otherwise, fall through.
151           }
152         // Quotes are only special at the start of a component.
153         else if (new_element.length () == 0
154                  && special == beginQuote
155                  && beginQuote != null)
156           {
157             quote = endQuote;
158             i += special.length ();
159             continue;
160           }
161         else if (new_element.length () == 0
162                  && special == beginQuote2
163                  && beginQuote2 != null)
164           {
165             quote = endQuote2;
166             i += special.length ();
167             continue;
168           }
169         else if (direction != FLAT && special == separator)
170           {
171             elts.add (new_element.toString ());
172             new_element.setLength (0);
173             i += special.length ();
174             continue;
175           }
176
177         // Nothing in particular, so try the next character.
178         new_element.append (n.charAt (i));
179         ++i;
180       }
181
182     if (new_element.length () != 0)
183       elts.add (new_element.toString ());
184
185     if (direction == RIGHT_TO_LEFT)
186       {
187         // Reverse the order of the elements.
188         int len = elts.size ();
189         for (i = 0; i < len / 2; ++i)
190           {
191             String t = elts.set (i, elts.get (len - i - 1));
192             elts.set (len - i - 1, t);
193           }
194       }
195
196     // Error checking.
197     if (quote != null)
198       throw new InvalidNameException ("unterminated quote");
199   }
200
201   public Name add (int posn, String comp) throws InvalidNameException
202   {
203     elts.add (posn, comp);
204     return this;
205   }
206
207   public Name add (String comp) throws InvalidNameException
208   {
209     elts.add (comp);
210     return this;
211   }
212
213   public Name addAll (int posn, Name n) throws InvalidNameException
214   {
215     Enumeration<String> e = n.getAll ();
216     try
217       {
218         while (e.hasMoreElements ())
219           {
220             elts.add (posn, e.nextElement ());
221             ++posn;
222           }
223       }
224     catch (NoSuchElementException ignore)
225       {
226       }
227     return this;
228   }
229
230   public Name addAll (Name suffix) throws InvalidNameException
231   {
232     Enumeration<String> e = suffix.getAll ();
233     try
234       {
235         while (e.hasMoreElements ())
236           elts.add (e.nextElement ());
237       }
238     catch (NoSuchElementException ignore)
239       {
240       }
241     return this;
242   }
243
244   public Object clone ()
245   {
246     return new CompoundName (elts.elements (), mySyntax);
247   }
248
249   public int compareTo (Object obj)
250   {
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)
256       {
257         String f = canonicalize (elts.get (i));
258         int comp = f.compareTo (canonicalize (cn.elts.get (i)));
259         if (comp != 0)
260           return comp;
261       }
262     return elts.size () - cn.elts.size ();
263   }
264
265   public boolean endsWith (Name n)
266   {
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)
274       {
275         String f = canonicalize (elts.get (delta + i));
276         if (! f.equals (canonicalize (cn.elts.get (i))))
277           return false;
278       }
279     return true;
280   }
281
282   public boolean equals (Object obj)
283   {
284     if (! (obj instanceof CompoundName))
285       return false;
286     return compareTo (obj) == 0;
287   }
288
289   public String get (int posn)
290   {
291     return elts.get (posn);
292   }
293
294   public Enumeration<String> getAll ()
295   {
296     return elts.elements ();
297   }
298
299   public Name getPrefix (int posn)
300   {
301     CompoundName cn = new CompoundName (mySyntax);
302     for (int i = 0; i < posn; ++i)
303       cn.elts.add (elts.get (i));
304     return cn;
305   }
306
307   public Name getSuffix (int posn)
308   {
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;
315   }
316
317   public int hashCode ()
318   {
319     int h = 0;
320     for (int i = 0; i < elts.size (); ++i)
321       h += canonicalize (elts.get (i)).hashCode ();
322     return h;
323   }
324
325   public boolean isEmpty ()
326   {
327     return elts.isEmpty ();
328   }
329
330   public Object remove (int posn) throws InvalidNameException
331   {
332     return elts.remove (posn);
333   }
334
335   public int size ()
336   {
337     return elts.size ();
338   }
339
340   public boolean startsWith (Name n)
341   {
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)
348       {
349         String f = canonicalize (elts.get (i));
350         if (! f.equals (canonicalize (cn.elts.get (i))))
351           return false;
352       }
353     return true;
354   }
355
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)
360   {
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;
375
376     return special;
377   }
378
379   public String toString ()
380   {
381     CPStringBuilder result = new CPStringBuilder ();
382     int size = elts.size ();
383     for (int i = 0; i < size; ++i)
384       {
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);
392
393         int k = 0;
394         while (k < element.length ())
395           {
396             String special = isSpecial (element, k);
397             if (special != null)
398               {
399                 result.append (escape);
400                 result.append (special);
401                 k += special.length ();
402               }
403             else
404               {
405                 result.append (element.charAt (k));
406                 ++k;
407               }
408           }
409       }
410
411     return result.toString ();
412   }
413
414   // This canonicalizes a String, based on the syntax, for comparison
415   // or other similar purposes.
416   private String canonicalize (String element)
417   {
418     String ret = element;
419
420     if (ignoreCase)
421       ret = ret.toLowerCase ();
422
423     if (trimBlanks)
424       {
425         int first = 0;
426         while (first < ret.length ()
427                && Character.isWhitespace (ret.charAt (first)))
428           ++first;
429
430         int last = ret.length () - 1;
431         while (last >= first
432                && Character.isWhitespace (ret.charAt (last)))
433           --last;
434
435         ret = ret.substring (first, last);
436       }
437
438     return ret;
439   }
440
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 ()
446   {
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
453       {
454         // If we don't recognize it, default to flat.
455         this.direction = FLAT;
456       }
457
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", "");
461
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 ();
476   }
477
478   private void readObject(ObjectInputStream s)
479     throws IOException, ClassNotFoundException
480   {
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());
486   }
487
488   private void writeObject(ObjectOutputStream s)
489     throws IOException
490   {
491     s.writeObject(mySyntax);
492     s.writeInt(elts.size());
493     for (int i = 0; i < elts.size(); i++)
494         s.writeObject(elts.elementAt(i));
495   }
496
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;
502
503   // The actual elements.
504   private transient Vector<String> elts;
505
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;
519
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;
523 }