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 }