1 /* CompositeName.java --
2    Copyright (C) 2001, 2005, 2006  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.Vector;
50 
51 /**
52  * Represents names that may span over several namespaces. For instance,
53  * the composite name http://www.gnu.org/software/classpath/index.html spans
54  * over three namespaces (the protocol http, the web server location
55  * (www.gnu.org) and the index.html location on the server).
56  *
57  * @author Tom Tromey (tromey@redhat.com)
58  */
59 public class CompositeName implements Name, Cloneable, Serializable
60 {
61   private static final long serialVersionUID = 1667768148915813118L;
62 
63   private transient Vector<String> elts;
64 
CompositeName()65   public CompositeName ()
66   {
67     elts = new Vector<String> ();
68   }
69 
CompositeName(Enumeration<String> comps)70   protected CompositeName (Enumeration<String> comps)
71   {
72     elts = new Vector<String> ();
73     try
74       {
75         while (comps.hasMoreElements ())
76           elts.add (comps.nextElement ());
77       }
78     catch (NoSuchElementException ignore)
79       {
80       }
81   }
82 
CompositeName(String n)83   public CompositeName (String n) throws InvalidNameException
84   {
85     elts = new Vector<String> ();
86     // Parse the string into its components.
87     final char no_quote = 'x';  // Use 'x' to mean no quoting.
88     char quote = no_quote;
89     boolean escaped = false;
90     StringBuilder new_element = new StringBuilder ();
91     for (int i = 0; i < n.length (); ++i)
92       {
93         char c = n.charAt (i);
94         if (escaped)
95           escaped = false;
96         else if (c == '\\')
97           {
98             escaped = true;
99             continue;
100           }
101         else if (quote != no_quote)
102           {
103             if (quote == c)
104               {
105                 // The quotes must surround a complete component.
106                 if (i + 1 < n.length () && n.charAt (i + 1) != '/')
107                   throw new InvalidNameException ("close quote before end of component");
108                 elts.add (new_element.toString ());
109                 new_element.setLength (0);
110                 quote = no_quote;
111                 continue;
112               }
113             // Otherwise, fall through.
114           }
115         // Quotes are only special at the start of a component.
116         else if (new_element.length () == 0
117                  && (c == '\'' || c == '"'))
118           {
119             quote = c;
120             continue;
121           }
122         else if (c == '/')
123           {
124             elts.add (new_element.toString ());
125             new_element.setLength (0);
126             continue;
127           }
128 
129         new_element.append (c);
130       }
131 
132     if (new_element.length () != 0)
133       elts.add (new_element.toString ());
134 
135     // Error checking.
136     if (quote != no_quote)
137       throw new InvalidNameException ("unterminated quote");
138     if (escaped)
139       throw new InvalidNameException ("trailing escape character");
140   }
141 
add(int posn, String comp)142   public Name add (int posn, String comp) throws InvalidNameException
143   {
144     elts.add (posn, comp);
145     return this;
146   }
147 
add(String comp)148   public Name add (String comp) throws InvalidNameException
149   {
150     elts.add (comp);
151     return this;
152   }
153 
addAll(int posn, Name n)154   public Name addAll (int posn, Name n) throws InvalidNameException
155   {
156     Enumeration<String> e = n.getAll ();
157     try
158       {
159         while (e.hasMoreElements ())
160           {
161             elts.add (posn, e.nextElement ());
162             ++posn;
163           }
164       }
165     catch (NoSuchElementException ignore)
166       {
167       }
168     return this;
169   }
170 
addAll(Name suffix)171   public Name addAll (Name suffix) throws InvalidNameException
172   {
173     Enumeration<String> e = suffix.getAll ();
174     try
175       {
176         while (e.hasMoreElements ())
177           elts.add (e.nextElement ());
178       }
179     catch (NoSuchElementException ignore)
180       {
181       }
182     return this;
183   }
184 
clone()185   public Object clone ()
186   {
187     return new CompositeName (elts.elements ());
188   }
189 
compareTo(Object obj)190   public int compareTo (Object obj)
191   {
192     if (obj == null || ! (obj instanceof CompositeName))
193       throw new ClassCastException ("CompositeName.compareTo() expected CompositeName");
194     CompositeName cn = (CompositeName) obj;
195     int last = Math.min (cn.elts.size (), elts.size ());
196     for (int i = 0; i < last; ++i)
197       {
198         String f = elts.get (i);
199         int comp = f.compareTo (cn.elts.get (i));
200         if (comp != 0)
201           return comp;
202       }
203     return elts.size () - cn.elts.size ();
204   }
205 
endsWith(Name n)206   public boolean endsWith (Name n)
207   {
208     if (! (n instanceof CompositeName))
209       return false;
210     CompositeName cn = (CompositeName) n;
211     if (cn.elts.size () > elts.size ())
212       return false;
213     int delta = elts.size () - cn.elts.size ();
214     for (int i = 0; i < cn.elts.size (); ++i)
215       {
216         if (! cn.elts.get (i).equals (elts.get (delta + i)))
217           return false;
218       }
219     return true;
220   }
221 
equals(Object obj)222   public boolean equals (Object obj)
223   {
224     if (! (obj instanceof CompositeName))
225       return false;
226     CompositeName cn = (CompositeName) obj;
227     return elts.equals (cn.elts);
228   }
229 
get(int posn)230   public String get (int posn)
231   {
232     return elts.get (posn);
233   }
234 
getAll()235   public Enumeration<String> getAll ()
236   {
237     return elts.elements ();
238   }
239 
getPrefix(int posn)240   public Name getPrefix (int posn)
241   {
242     CompositeName cn = new CompositeName ();
243     for (int i = 0; i < posn; ++i)
244       cn.elts.add (elts.get (i));
245     return cn;
246   }
247 
getSuffix(int posn)248   public Name getSuffix (int posn)
249   {
250     if (posn > elts.size ())
251       throw new ArrayIndexOutOfBoundsException (posn);
252     CompositeName cn = new CompositeName ();
253     for (int i = posn; i < elts.size (); ++i)
254       cn.elts.add (elts.get (i));
255     return cn;
256   }
257 
hashCode()258   public int hashCode ()
259   {
260     // Specified in documentation.
261     int h = 0;
262     for (int i = 0; i < elts.size (); ++i)
263       h += elts.get (i).hashCode ();
264     return h;
265   }
266 
isEmpty()267   public boolean isEmpty ()
268   {
269     return elts.isEmpty ();
270   }
271 
remove(int posn)272   public Object remove (int posn) throws InvalidNameException
273   {
274     return elts.remove (posn);
275   }
276 
size()277   public int size ()
278   {
279     return elts.size ();
280   }
281 
startsWith(Name n)282   public boolean startsWith (Name n)
283   {
284     if (! (n instanceof CompositeName))
285       return false;
286     CompositeName cn = (CompositeName) n;
287     if (cn.elts.size () > elts.size ())
288       return false;
289     for (int i = 0; i < cn.elts.size (); ++i)
290       {
291         if (! cn.elts.get (i).equals (elts.get (i)))
292           return false;
293       }
294     return true;
295   }
296 
toString()297   public String toString ()
298   {
299     CPStringBuilder result = new CPStringBuilder ();
300     for (int i = 0; i < elts.size (); ++i)
301       {
302         // For simplicity we choose to always quote using escapes and
303         // never quotes.
304         String elt = elts.get (i);
305         if (i > 0
306             || (i == elts.size () - 1 && elt.equals ("")))
307           result.append ('/');
308         for (int k = 0; k < elt.length (); ++k)
309           {
310             char c = elt.charAt (k);
311             // We must quote
312             //     ... a leading quote,
313             if ((k == 0 && (c == '"' || c == '\''))
314                 // ... an escape preceding a meta character,
315                 //     or at the end of a component,
316                 || (c == '\\'
317                     && (k == elt.length () - 1
318                         || "\\'\"/".indexOf (elt.charAt (k + 1)) != -1))
319                 // ... or a component separator.
320                 || c == '/')
321               result.append ('\\');
322             result.append (c);
323           }
324       }
325     return result.toString ();
326   }
327 
readObject(ObjectInputStream s)328   private void readObject(ObjectInputStream s)
329     throws IOException, ClassNotFoundException
330   {
331     int size = s.readInt();
332     elts = new Vector<String>(size);
333     for (int i = 0; i < size; i++)
334       elts.add((String) s.readObject());
335   }
336 
writeObject(ObjectOutputStream s)337   private void writeObject(ObjectOutputStream s) throws IOException
338   {
339     s.writeInt(elts.size());
340     for (int i = 0; i < elts.size(); i++)
341       s.writeObject(elts.get(i));
342   }
343 }
344