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 gnu.java.lang.CPStringBuilder;
042
043 import java.io.IOException;
044 import java.io.ObjectInputStream;
045 import java.io.ObjectOutputStream;
046 import java.io.Serializable;
047 import java.util.Enumeration;
048 import java.util.NoSuchElementException;
049 import java.util.Vector;
050
051 /**
052 * Represents names that may span over several namespaces. For instance,
053 * the composite name http://www.gnu.org/software/classpath/index.html spans
054 * over three namespaces (the protocol http, the web server location
055 * (www.gnu.org) and the index.html location on the server).
056 *
057 * @author Tom Tromey (tromey@redhat.com)
058 */
059 public class CompositeName implements Name, Cloneable, Serializable
060 {
061 private static final long serialVersionUID = 1667768148915813118L;
062
063 private transient Vector<String> elts;
064
065 public CompositeName ()
066 {
067 elts = new Vector<String> ();
068 }
069
070 protected CompositeName (Enumeration<String> comps)
071 {
072 elts = new Vector<String> ();
073 try
074 {
075 while (comps.hasMoreElements ())
076 elts.add (comps.nextElement ());
077 }
078 catch (NoSuchElementException ignore)
079 {
080 }
081 }
082
083 public CompositeName (String n) throws InvalidNameException
084 {
085 elts = new Vector<String> ();
086 // Parse the string into its components.
087 final char no_quote = 'x'; // Use 'x' to mean no quoting.
088 char quote = no_quote;
089 boolean escaped = false;
090 StringBuilder new_element = new StringBuilder ();
091 for (int i = 0; i < n.length (); ++i)
092 {
093 char c = n.charAt (i);
094 if (escaped)
095 escaped = false;
096 else if (c == '\\')
097 {
098 escaped = true;
099 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
142 public Name add (int posn, String comp) throws InvalidNameException
143 {
144 elts.add (posn, comp);
145 return this;
146 }
147
148 public Name add (String comp) throws InvalidNameException
149 {
150 elts.add (comp);
151 return this;
152 }
153
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
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
185 public Object clone ()
186 {
187 return new CompositeName (elts.elements ());
188 }
189
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
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
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
230 public String get (int posn)
231 {
232 return elts.get (posn);
233 }
234
235 public Enumeration<String> getAll ()
236 {
237 return elts.elements ();
238 }
239
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
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
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
267 public boolean isEmpty ()
268 {
269 return elts.isEmpty ();
270 }
271
272 public Object remove (int posn) throws InvalidNameException
273 {
274 return elts.remove (posn);
275 }
276
277 public int size ()
278 {
279 return elts.size ();
280 }
281
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
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
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
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 }