001/* CompositeName.java -- 002 Copyright (C) 2001, 2005, 2006 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.naming; 040 041import gnu.java.lang.CPStringBuilder; 042 043import java.io.IOException; 044import java.io.ObjectInputStream; 045import java.io.ObjectOutputStream; 046import java.io.Serializable; 047import java.util.Enumeration; 048import java.util.NoSuchElementException; 049import 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 */ 059public 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}