001 /* CompositeName.java --
002 Copyright (C) 2001, 2005, 2006 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.naming;
040
041 import java.io.IOException;
042 import java.io.ObjectInputStream;
043 import java.io.ObjectOutputStream;
044 import java.io.Serializable;
045 import java.util.Enumeration;
046 import java.util.NoSuchElementException;
047 import java.util.Vector;
048
049 /**
050 * Represents names that may span over several namespaces. For instance,
051 * the composite name http://www.gnu.org/software/classpath/index.html spans
052 * over three namespaces (the protocol http, the web server location
053 * (www.gnu.org) and the index.html location on the server).
054 *
055 * @author Tom Tromey (tromey@redhat.com)
056 */
057 public class CompositeName implements Name, Cloneable, Serializable
058 {
059 private static final long serialVersionUID = 1667768148915813118L;
060
061 private transient Vector<String> elts;
062
063 public CompositeName ()
064 {
065 elts = new Vector<String> ();
066 }
067
068 protected CompositeName (Enumeration<String> comps)
069 {
070 elts = new Vector<String> ();
071 try
072 {
073 while (comps.hasMoreElements ())
074 elts.add (comps.nextElement ());
075 }
076 catch (NoSuchElementException ignore)
077 {
078 }
079 }
080
081 public CompositeName (String n) throws InvalidNameException
082 {
083 elts = new Vector<String> ();
084 // Parse the string into its components.
085 final char no_quote = 'x'; // Use 'x' to mean no quoting.
086 char quote = no_quote;
087 boolean escaped = false;
088 StringBuffer new_element = new StringBuffer ();
089 for (int i = 0; i < n.length (); ++i)
090 {
091 char c = n.charAt (i);
092 if (escaped)
093 escaped = false;
094 else if (c == '\\')
095 {
096 escaped = true;
097 continue;
098 }
099 else if (quote != no_quote)
100 {
101 if (quote == c)
102 {
103 // The quotes must surround a complete component.
104 if (i + 1 < n.length () && n.charAt (i + 1) != '/')
105 throw new InvalidNameException ("close quote before end of component");
106 elts.add (new_element.toString ());
107 new_element.setLength (0);
108 quote = no_quote;
109 continue;
110 }
111 // Otherwise, fall through.
112 }
113 // Quotes are only special at the start of a component.
114 else if (new_element.length () == 0
115 && (c == '\'' || c == '"'))
116 {
117 quote = c;
118 continue;
119 }
120 else if (c == '/')
121 {
122 elts.add (new_element.toString ());
123 new_element.setLength (0);
124 continue;
125 }
126
127 new_element.append (c);
128 }
129
130 if (new_element.length () != 0)
131 elts.add (new_element.toString ());
132
133 // Error checking.
134 if (quote != no_quote)
135 throw new InvalidNameException ("unterminated quote");
136 if (escaped)
137 throw new InvalidNameException ("trailing escape character");
138 }
139
140 public Name add (int posn, String comp) throws InvalidNameException
141 {
142 elts.add (posn, comp);
143 return this;
144 }
145
146 public Name add (String comp) throws InvalidNameException
147 {
148 elts.add (comp);
149 return this;
150 }
151
152 public Name addAll (int posn, Name n) throws InvalidNameException
153 {
154 Enumeration<String> e = n.getAll ();
155 try
156 {
157 while (e.hasMoreElements ())
158 {
159 elts.add (posn, e.nextElement ());
160 ++posn;
161 }
162 }
163 catch (NoSuchElementException ignore)
164 {
165 }
166 return this;
167 }
168
169 public Name addAll (Name suffix) throws InvalidNameException
170 {
171 Enumeration<String> e = suffix.getAll ();
172 try
173 {
174 while (e.hasMoreElements ())
175 elts.add (e.nextElement ());
176 }
177 catch (NoSuchElementException ignore)
178 {
179 }
180 return this;
181 }
182
183 public Object clone ()
184 {
185 return new CompositeName (elts.elements ());
186 }
187
188 public int compareTo (Object obj)
189 {
190 if (obj == null || ! (obj instanceof CompositeName))
191 throw new ClassCastException ("CompositeName.compareTo() expected CompositeName");
192 CompositeName cn = (CompositeName) obj;
193 int last = Math.min (cn.elts.size (), elts.size ());
194 for (int i = 0; i < last; ++i)
195 {
196 String f = elts.get (i);
197 int comp = f.compareTo (cn.elts.get (i));
198 if (comp != 0)
199 return comp;
200 }
201 return elts.size () - cn.elts.size ();
202 }
203
204 public boolean endsWith (Name n)
205 {
206 if (! (n instanceof CompositeName))
207 return false;
208 CompositeName cn = (CompositeName) n;
209 if (cn.elts.size () > elts.size ())
210 return false;
211 int delta = elts.size () - cn.elts.size ();
212 for (int i = 0; i < cn.elts.size (); ++i)
213 {
214 if (! cn.elts.get (i).equals (elts.get (delta + i)))
215 return false;
216 }
217 return true;
218 }
219
220 public boolean equals (Object obj)
221 {
222 if (! (obj instanceof CompositeName))
223 return false;
224 CompositeName cn = (CompositeName) obj;
225 return elts.equals (cn.elts);
226 }
227
228 public String get (int posn)
229 {
230 return elts.get (posn);
231 }
232
233 public Enumeration<String> getAll ()
234 {
235 return elts.elements ();
236 }
237
238 public Name getPrefix (int posn)
239 {
240 CompositeName cn = new CompositeName ();
241 for (int i = 0; i < posn; ++i)
242 cn.elts.add (elts.get (i));
243 return cn;
244 }
245
246 public Name getSuffix (int posn)
247 {
248 if (posn > elts.size ())
249 throw new ArrayIndexOutOfBoundsException (posn);
250 CompositeName cn = new CompositeName ();
251 for (int i = posn; i < elts.size (); ++i)
252 cn.elts.add (elts.get (i));
253 return cn;
254 }
255
256 public int hashCode ()
257 {
258 // Specified in documentation.
259 int h = 0;
260 for (int i = 0; i < elts.size (); ++i)
261 h += elts.get (i).hashCode ();
262 return h;
263 }
264
265 public boolean isEmpty ()
266 {
267 return elts.isEmpty ();
268 }
269
270 public Object remove (int posn) throws InvalidNameException
271 {
272 return elts.remove (posn);
273 }
274
275 public int size ()
276 {
277 return elts.size ();
278 }
279
280 public boolean startsWith (Name n)
281 {
282 if (! (n instanceof CompositeName))
283 return false;
284 CompositeName cn = (CompositeName) n;
285 if (cn.elts.size () > elts.size ())
286 return false;
287 for (int i = 0; i < cn.elts.size (); ++i)
288 {
289 if (! cn.elts.get (i).equals (elts.get (i)))
290 return false;
291 }
292 return true;
293 }
294
295 public String toString ()
296 {
297 StringBuffer result = new StringBuffer ();
298 for (int i = 0; i < elts.size (); ++i)
299 {
300 // For simplicity we choose to always quote using escapes and
301 // never quotes.
302 String elt = elts.get (i);
303 if (i > 0
304 || (i == elts.size () - 1 && elt.equals ("")))
305 result.append ('/');
306 for (int k = 0; k < elt.length (); ++k)
307 {
308 char c = elt.charAt (k);
309 // We must quote
310 // ... a leading quote,
311 if ((k == 0 && (c == '"' || c == '\''))
312 // ... an escape preceding a meta character,
313 // or at the end of a component,
314 || (c == '\\'
315 && (k == elt.length () - 1
316 || "\\'\"/".indexOf (elt.charAt (k + 1)) != -1))
317 // ... or a component separator.
318 || c == '/')
319 result.append ('\\');
320 result.append (c);
321 }
322 }
323 return result.toString ();
324 }
325
326 private void readObject(ObjectInputStream s)
327 throws IOException, ClassNotFoundException
328 {
329 int size = s.readInt();
330 elts = new Vector<String>(size);
331 for (int i = 0; i < size; i++)
332 elts.add((String) s.readObject());
333 }
334
335 private void writeObject(ObjectOutputStream s) throws IOException
336 {
337 s.writeInt(elts.size());
338 for (int i = 0; i < elts.size(); i++)
339 s.writeObject(elts.get(i));
340 }
341 }