1 /* CompoundName.java -- 2 Copyright (C) 2001 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., 59 Temple Place, Suite 330, Boston, MA 19 02111-1307 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 java.io.Serializable; 42 import java.util.Enumeration; 43 import java.util.Properties; 44 import java.util.NoSuchElementException; 45 import java.util.Vector; 46 47 /** 48 * @author Tom Tromey <tromey@redhat.com> 49 * @date May 16, 2001 50 * 51 * FIXME: must write readObject and writeObject to conform to 52 * serialization spec. 53 * 54 * FIXME: this class is underspecified. For instance, the `flat' 55 * direction is never described. If it means that the CompoundName 56 * can only have a single element, then the Enumeration-based 57 * constructor ought to throw InvalidNameException. 58 */ 59 public class CompoundName implements Name, Cloneable, Serializable 60 { 61 private static final long serialVersionUID = 3513100557083972036L; 62 CompoundName(Properties syntax)63 private CompoundName (Properties syntax) 64 { 65 elts = new Vector (); 66 mySyntax = syntax; 67 initializeSyntax (); 68 } 69 CompoundName(Enumeration comps, Properties syntax)70 protected CompoundName (Enumeration comps, Properties syntax) 71 { 72 elts = new Vector (); 73 mySyntax = syntax; 74 initializeSyntax (); 75 try 76 { 77 while (comps.hasMoreElements ()) 78 elts.add (comps.nextElement ()); 79 } 80 catch (NoSuchElementException ignore) 81 { 82 } 83 } 84 CompoundName(String n, Properties syntax)85 public CompoundName (String n, Properties syntax) 86 throws InvalidNameException 87 { 88 elts = new Vector (); 89 mySyntax = syntax; 90 initializeSyntax (); 91 92 StringBuffer new_element = new StringBuffer (); 93 int i = 0; 94 // QUOTE==null means no quoting right now. When it is set it is 95 // the value of the closing quote. 96 String quote = null; 97 while (i < n.length ()) 98 { 99 String special = isSpecial (n, i); 100 101 if (special == escape && escape != null) 102 { 103 if (n.length () == i + special.length ()) 104 { 105 // A trailing escape is treated as itself. 106 new_element.append (special); 107 i += special.length (); 108 } 109 else 110 { 111 String eSpecial = isSpecial (n, i + special.length ()); 112 if (eSpecial != null) 113 { 114 // Treat the escape as an escape. 115 new_element.append (eSpecial); 116 i += special.length () + eSpecial.length (); 117 } 118 else 119 { 120 // Treat the escape as itself. 121 new_element.append (special); 122 i += special.length (); 123 } 124 continue; 125 } 126 } 127 else if (quote != null) 128 { 129 // It is safe to use == here. 130 if (quote == special) 131 { 132 // Quotes must surround a complete component. 133 if (i + quote.length () < n.length () 134 && ! n.startsWith (separator, i + quote.length ())) 135 throw new InvalidNameException ("close quote before end of component"); 136 elts.add (new_element.toString ()); 137 new_element.setLength (0); 138 i += quote.length (); 139 quote = null; 140 continue; 141 } 142 // Otherwise, fall through. 143 } 144 // Quotes are only special at the start of a component. 145 else if (new_element.length () == 0 146 && special == beginQuote 147 && beginQuote != null) 148 { 149 quote = endQuote; 150 i += special.length (); 151 continue; 152 } 153 else if (new_element.length () == 0 154 && special == beginQuote2 155 && beginQuote2 != null) 156 { 157 quote = endQuote2; 158 i += special.length (); 159 continue; 160 } 161 else if (special == separator) 162 { 163 elts.add (new_element.toString ()); 164 new_element.setLength (0); 165 i += special.length (); 166 continue; 167 } 168 169 // Nothing in particular, so try the next character. 170 new_element.append (n.charAt (i)); 171 ++i; 172 } 173 174 if (new_element.length () != 0) 175 elts.add (new_element.toString ()); 176 177 if (direction == RIGHT_TO_LEFT) 178 { 179 // Reverse the order of the elements. 180 int len = elts.size (); 181 for (i = 0; i < len / 2; ++i) 182 { 183 Object t = elts.set (i, elts.get (len - i - 1)); 184 elts.set (len - i - 1, t); 185 } 186 } 187 188 // Error checking. 189 if (quote != null) 190 throw new InvalidNameException ("unterminated quote"); 191 } 192 add(int posn, String comp)193 public Name add (int posn, String comp) throws InvalidNameException 194 { 195 elts.add (posn, comp); 196 return this; 197 } 198 add(String comp)199 public Name add (String comp) throws InvalidNameException 200 { 201 elts.add (comp); 202 return this; 203 } 204 addAll(int posn, Name n)205 public Name addAll (int posn, Name n) throws InvalidNameException 206 { 207 Enumeration e = n.getAll (); 208 try 209 { 210 while (e.hasMoreElements ()) 211 { 212 elts.add (posn, e.nextElement ()); 213 ++posn; 214 } 215 } 216 catch (NoSuchElementException ignore) 217 { 218 } 219 return this; 220 } 221 addAll(Name suffix)222 public Name addAll (Name suffix) throws InvalidNameException 223 { 224 Enumeration e = suffix.getAll (); 225 try 226 { 227 while (e.hasMoreElements ()) 228 elts.add (e.nextElement ()); 229 } 230 catch (NoSuchElementException ignore) 231 { 232 } 233 return this; 234 } 235 clone()236 public Object clone () 237 { 238 return new CompoundName (elts.elements (), mySyntax); 239 } 240 compareTo(Object obj)241 public int compareTo (Object obj) 242 { 243 if (! (obj instanceof CompoundName)) 244 throw new ClassCastException ("CompoundName.compareTo() expected CompoundName"); 245 CompoundName cn = (CompoundName) obj; 246 int last = Math.min (cn.elts.size (), elts.size ()); 247 for (int i = 0; i < last; ++i) 248 { 249 String f = canonicalize ((String) elts.get (i)); 250 int comp = f.compareTo (canonicalize ((String) cn.elts.get (i))); 251 if (comp != 0) 252 return comp; 253 } 254 return elts.size () - cn.elts.size (); 255 } 256 endsWith(Name n)257 public boolean endsWith (Name n) 258 { 259 if (! (n instanceof CompoundName)) 260 return false; 261 CompoundName cn = (CompoundName) n; 262 if (cn.elts.size () > elts.size ()) 263 return false; 264 int delta = elts.size () - cn.elts.size (); 265 for (int i = 0; i < cn.elts.size (); ++i) 266 { 267 String f = canonicalize ((String) elts.get (i)); 268 if (! f.equals (canonicalize ((String) cn.elts.get (i)))) 269 return false; 270 } 271 return true; 272 } 273 equals(Object obj)274 public boolean equals (Object obj) 275 { 276 if (! (obj instanceof CompoundName)) 277 return false; 278 return compareTo (obj) == 0; 279 } 280 get(int posn)281 public String get (int posn) 282 { 283 return (String) elts.get (posn); 284 } 285 getAll()286 public Enumeration getAll () 287 { 288 return elts.elements (); 289 } 290 getPrefix(int posn)291 public Name getPrefix (int posn) 292 { 293 CompoundName cn = new CompoundName (mySyntax); 294 for (int i = 0; i < posn; ++i) 295 cn.elts.add (elts.get (i)); 296 return cn; 297 } 298 getSuffix(int posn)299 public Name getSuffix (int posn) 300 { 301 if (posn > elts.size ()) 302 throw new ArrayIndexOutOfBoundsException (posn); 303 CompoundName cn = new CompoundName (mySyntax); 304 for (int i = posn; i < elts.size (); ++i) 305 cn.elts.add (elts.get (i)); 306 return cn; 307 } 308 hashCode()309 public int hashCode () 310 { 311 int h = 0; 312 for (int i = 0; i < elts.size (); ++i) 313 h += canonicalize ((String) elts.get (i)).hashCode (); 314 return h; 315 } 316 isEmpty()317 public boolean isEmpty () 318 { 319 return elts.isEmpty (); 320 } 321 remove(int posn)322 public Object remove (int posn) throws InvalidNameException 323 { 324 return elts.remove (posn); 325 } 326 size()327 public int size () 328 { 329 return elts.size (); 330 } 331 startsWith(Name n)332 public boolean startsWith (Name n) 333 { 334 if (! (n instanceof CompoundName)) 335 return false; 336 CompoundName cn = (CompoundName) n; 337 if (cn.elts.size () > elts.size ()) 338 return false; 339 for (int i = 0; i < cn.elts.size (); ++i) 340 { 341 String f = canonicalize ((String) elts.get (i)); 342 if (! f.equals (canonicalize ((String) cn.elts.get (i)))) 343 return false; 344 } 345 return true; 346 } 347 348 // If ELEMENT starts with some meta-sequence at OFFSET, then return 349 // the string representing the meta-sequence. Otherwise return 350 // null. isSpecial(String element, int offset)351 private String isSpecial (String element, int offset) 352 { 353 String special = null; 354 if (separator != null && element.startsWith (separator, offset)) 355 special = separator; 356 else if (escape != null && element.startsWith (escape, offset)) 357 special = escape; 358 else if (beginQuote != null && element.startsWith (beginQuote, offset)) 359 special = beginQuote; 360 else if (endQuote != null && element.startsWith (endQuote, offset)) 361 special = endQuote; 362 else if (beginQuote2 != null 363 && element.startsWith (beginQuote2, offset)) 364 special = beginQuote2; 365 else if (endQuote2 != null && element.startsWith (endQuote2, offset)) 366 special = endQuote2; 367 368 return special; 369 } 370 toString()371 public String toString () 372 { 373 StringBuffer result = new StringBuffer (); 374 int size = elts.size (); 375 for (int i = 0; i < size; ++i) 376 { 377 // Find the appropriate element. FIXME: not clear what FLAT 378 // means. 379 int offset = (direction == RIGHT_TO_LEFT) ? (size - i - 1) : i; 380 String element = (String) elts.get (offset); 381 if (i > 0 382 || (i == size - 1 && element.equals (""))) 383 result.append (separator); 384 385 int k = 0; 386 while (k < element.length ()) 387 { 388 String special = isSpecial (element, k); 389 if (special != null) 390 { 391 result.append (escape); 392 result.append (special); 393 k += special.length (); 394 } 395 else 396 { 397 result.append (element.charAt (k)); 398 ++k; 399 } 400 } 401 } 402 403 return result.toString (); 404 } 405 406 // This canonicalizes a String, based on the syntax, for comparison 407 // or other similar purposes. canonicalize(String element)408 private String canonicalize (String element) 409 { 410 String ret = element; 411 412 if (ignoreCase) 413 ret = ret.toLowerCase (); 414 415 if (trimBlanks) 416 { 417 int first = 0; 418 while (first < ret.length () 419 && Character.isWhitespace (ret.charAt (first))) 420 ++first; 421 422 int last = ret.length () - 1; 423 while (last >= first 424 && Character.isWhitespace (ret.charAt (last))) 425 --last; 426 427 ret = ret.substring (first, last); 428 } 429 430 return ret; 431 } 432 433 // This initializes all the syntax variables. This seems easier 434 // than re-querying the properties every time. We're allowed to do 435 // this because the spec says that subclasses should consider the 436 // syntax as being read-only. initializeSyntax()437 private void initializeSyntax () 438 { 439 String t = mySyntax.getProperty ("jndi.syntax.direction", "flat"); 440 if (t.equals ("right_to_left")) 441 this.direction = RIGHT_TO_LEFT; 442 else if (t.equals ("left_to_right")) 443 this.direction = LEFT_TO_RIGHT; 444 else 445 { 446 // If we don't recognize it, default to flat. 447 this.direction = FLAT; 448 } 449 450 // This is required unless the direction is FLAT. Unfortunately 451 // there is no way to report this error. 452 this.separator = mySyntax.getProperty ("jndi.syntax.separator", ""); 453 454 this.ignoreCase 455 = Boolean.valueOf (mySyntax.getProperty ("jndi.syntax.ignorecase", 456 "false")).booleanValue (); 457 this.escape = mySyntax.getProperty ("jndi.syntax.escape", null); 458 this.beginQuote = mySyntax.getProperty ("jndi.syntax.beginquote", null); 459 this.endQuote = mySyntax.getProperty ("jndi.syntax.endquote", 460 this.beginQuote); 461 this.beginQuote2 = mySyntax.getProperty ("jndi.syntax.beginquote2", 462 null); 463 this.endQuote2 = mySyntax.getProperty ("jndi.syntax.endquote2", 464 this.beginQuote2); 465 this.trimBlanks 466 = Boolean.valueOf (mySyntax.getProperty ("jndi.syntax.trimblanks", 467 "false")).booleanValue (); 468 } 469 470 // The spec specifies this but does not document it in any way (it 471 // is a package-private class). It is useless as far as I can tell. 472 // So we ignore it. 473 // protected transient NameImpl impl; 474 protected transient Properties mySyntax; 475 476 // The actual elements. 477 private transient Vector elts; 478 479 // The following are all used for syntax. 480 private transient int direction; 481 private transient String separator; 482 private transient boolean ignoreCase; 483 private transient String escape; 484 private transient String beginQuote; 485 private transient String endQuote; 486 private transient String beginQuote2; 487 private transient String endQuote2; 488 private transient boolean trimBlanks; 489 // We didn't need these for parsing, so they are gone. 490 // private transient String avaSeparator; 491 // private transient String typevalSeparator; 492 493 private static final int RIGHT_TO_LEFT = -1; 494 private static final int LEFT_TO_RIGHT = 1; 495 private static final int FLAT = 0; 496 } 497