1 /* CorbalocParser.java -- handles corbaname: urls 2 Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 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 package gnu.javax.naming.giop; 39 40 import gnu.CORBA.IOR; 41 import gnu.CORBA.Minor; 42 import gnu.CORBA.Unexpected; 43 import gnu.CORBA.Version; 44 import gnu.CORBA.NamingService.NameTransformer; 45 46 import gnu.java.lang.CPStringBuilder; 47 48 import java.io.File; 49 import java.io.FileReader; 50 import java.io.IOException; 51 import java.io.InputStreamReader; 52 import java.io.UnsupportedEncodingException; 53 import java.net.MalformedURLException; 54 import java.net.URL; 55 import java.net.URLDecoder; 56 import java.util.StringTokenizer; 57 58 import javax.naming.InvalidNameException; 59 60 import org.omg.CORBA.BAD_PARAM; 61 import org.omg.CORBA.DATA_CONVERSION; 62 import org.omg.CORBA.ORB; 63 import org.omg.CORBA.Object; 64 import org.omg.CORBA.ORBPackage.InvalidName; 65 66 /** 67 * Parses the alternative IOR representations into our IOR structure. 68 * 69 * TODO This parser currently supports only one address per target string. A 70 * string with the multiple addresses will be accepted, but only the last 71 * address will be taken into consideration. The fault tolerance is not yet 72 * implemented. 73 * 74 * The key string is filtered using {@link java.net.URLDecoder} that replaces 75 * the agreed escape sequences by the corresponding non alphanumeric characters. 76 * 77 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) 78 */ 79 public class CorbalocParser 80 extends NameTransformer 81 { 82 /** 83 * The corbaloc prefix. 84 */ 85 public static final String pxCORBALOC = "corbaloc"; 86 87 /** 88 * The corbaname prefix. 89 */ 90 public static final String pxCORBANAME = "corbaname"; 91 92 /** 93 * The IOR prefix. 94 */ 95 public static final String pxIOR = "ior"; 96 97 /** 98 * The file:// prefix. 99 */ 100 public static final String pxFILE = "file://"; 101 102 /** 103 * The ftp:// prefix. 104 */ 105 public static final String pxFTP = "ftp://"; 106 107 /** 108 * The http:// prefix. 109 */ 110 public static final String pxHTTP = "http://"; 111 112 /** 113 * Marks iiop protocol. 114 */ 115 public static final String IIOP = "iiop"; 116 117 /** 118 * Marks rir protocol. 119 */ 120 public static final String RIR = "rir"; 121 122 /** 123 * The default port value, as specified in OMG documentation. 124 */ 125 public static final int DEFAULT_PORT = 2809; 126 127 /** 128 * The default name. 129 */ 130 public static final String DEFAULT_NAME = "NameService"; 131 132 /** 133 * The string to name converter, initialized on demand. 134 */ 135 static NameTransformer converter; 136 137 /** 138 * The current position. 139 */ 140 int p; 141 142 /** 143 * The address being parsed, splitted into tokens. 144 */ 145 String[] t; 146 147 /** 148 * Parse CORBALOC. 149 * 150 * The expected format is: <br> 151 * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key <br> 152 * 2. corbaloc:rir:[/key] <br> 153 * 3. corbaname:[iiop][version.subversion@]:host[:port]/key <br> 154 * 4. corbaname:rir:[/key] <br> 155 * 5. file://[file name]<br> 156 * 6. http://[url]<br> 157 * 7. ftp://[url]<br> 158 * 159 * Protocol defaults to IOP, the object key defaults to the NameService. 160 * 161 * @param corbaloc the string to parse. 162 * @param orb the ORB, needed to create IORs and resolve rir references. 163 * 164 * @return the arrey of strings, first member being the IOR of the 165 * naming service, second member the name in the naming service. 166 */ corbaloc(String corbaloc, ORB orb)167 public synchronized String[] corbaloc(String corbaloc, 168 ORB orb) 169 throws InvalidNameException 170 { 171 return corbaloc(corbaloc, orb, 0); 172 } 173 174 /** 175 * Parse controlling against the infinite recursion loop. 176 */ corbaloc(String corbaloc, ORB orb, int recursion)177 private String[] corbaloc(String corbaloc, 178 ORB orb, int recursion) throws InvalidNameException 179 { 180 // The used CORBA specification does not state how many times we should to 181 //redirect, but the infinite loop may be used to knock out the system. 182 // by malicious attempt. 183 if (recursion > 10) 184 throw new DATA_CONVERSION("More than 10 redirections"); 185 186 if (corbaloc.startsWith(pxFILE)) 187 return corbaloc(readFile(corbaloc.substring(pxFILE.length())), orb, recursion+1); 188 else if (corbaloc.startsWith(pxHTTP)) 189 return corbaloc(readUrl(corbaloc), orb, recursion+1); 190 else if (corbaloc.startsWith(pxFTP)) 191 return corbaloc(readUrl(corbaloc), orb, recursion+1); 192 193 // The version numbers with default values. 194 int major = 1; 195 int minor = 0; 196 197 // The host address. 198 String host; 199 200 // The port. 201 int port = DEFAULT_PORT; 202 203 // The object key as string. 204 String key; 205 206 StringTokenizer st = new StringTokenizer(corbaloc, ":@/.,#", true); 207 208 t = new String[st.countTokens()]; 209 210 for (int i = 0; i < t.length; i++) 211 { 212 t[i] = st.nextToken(); 213 } 214 215 p = 0; 216 217 if (!t[p].startsWith(pxCORBANAME)) 218 throw new InvalidNameException(corbaloc+" must start with "+pxCORBANAME); 219 220 p++; 221 222 if (!t[p++].equals(":")) 223 throw new BAD_PARAM("Syntax (':' expected after name prefix)"); 224 225 // Check for rir: 226 if (t[p].equals(RIR)) 227 { 228 p++; 229 if (!t[p++].equals(":")) 230 throw new BAD_PARAM("':' expected after 'rir'"); 231 232 key = readKey("/"); 233 234 Object object; 235 try 236 { 237 object = orb.resolve_initial_references(key); 238 return resolve(orb.object_to_string(object)); 239 } 240 catch (InvalidName e) 241 { 242 throw new BAD_PARAM("Unknown initial reference '" + key + "'"); 243 } 244 } 245 else 246 // Check for iiop. 247 if (t[p].equals(IIOP) || t[p].equals(":")) 248 { 249 IOR ior = new IOR(); 250 251 Addresses: do 252 { // Read addresses. 253 if (t[p].equals(":")) 254 { 255 p++; 256 } 257 else 258 { 259 p++; 260 if (!t[p++].equals(":")) 261 throw new BAD_PARAM("':' expected after 'iiop'"); 262 // Check if version is present. 263 if (t[p + 1].equals(".")) 264 if (t[p + 3].equals("@")) 265 { 266 // Version info present. 267 try 268 { 269 major = Integer.parseInt(t[p++]); 270 } 271 catch (NumberFormatException e) 272 { 273 throw new BAD_PARAM("Major version number '" 274 + t[p - 1] + "'"); 275 } 276 p++; // '.' at this point. 277 try 278 { 279 minor = Integer.parseInt(t[p++]); 280 } 281 catch (NumberFormatException e) 282 { 283 throw new BAD_PARAM("Major version number '" 284 + t[p - 1] + "'"); 285 } 286 p++; // '@' at this point. 287 } 288 } 289 290 ior.Internet.version = new Version(major, minor); 291 292 // Then host data goes till '/' or ':'. 293 CPStringBuilder bhost = new CPStringBuilder(corbaloc.length()); 294 while (!t[p].equals(":") && !t[p].equals("/") && !t[p].equals(",")) 295 bhost.append(t[p++]); 296 297 host = bhost.toString(); 298 299 ior.Internet.host = host; 300 301 if (t[p].equals(":")) 302 { 303 // Port specified. 304 p++; 305 try 306 { 307 port = Integer.parseInt(t[p++]); 308 } 309 catch (NumberFormatException e) 310 { 311 throw new BAD_PARAM("Invalid port '" + t[p - 1] + "'"); 312 } 313 } 314 315 ior.Internet.port = port; 316 317 // Id is not listed. 318 ior.Id = ""; 319 320 if (t[p].equals(",")) 321 p++; 322 else 323 break Addresses; 324 } 325 while (true); 326 327 key = readKey("/"); 328 ior.key = key.getBytes(); 329 330 return resolve(ior.toStringifiedReference()); 331 } 332 333 else 334 throw new InvalidNameException("Unsupported protocol '" + t[p] + 335 "' (iiop expected)"); 336 } 337 338 /** 339 * Read IOR from the file in the local file system. 340 */ readFile(String file)341 String readFile(String file) 342 { 343 File f = new File(file); 344 if (!f.exists()) 345 { 346 DATA_CONVERSION err = new DATA_CONVERSION(f.getAbsolutePath() 347 + " does not exist."); 348 err.minor = Minor.Missing_IOR; 349 } 350 try 351 { 352 char[] c = new char[(int) f.length()]; 353 FileReader fr = new FileReader(f); 354 fr.read(c); 355 fr.close(); 356 return new String(c).trim(); 357 } 358 catch (IOException ex) 359 { 360 DATA_CONVERSION d = new DATA_CONVERSION(); 361 d.initCause(ex); 362 d.minor = Minor.Missing_IOR; 363 throw (d); 364 } 365 } 366 367 /** 368 * Read IOR from the remote URL. 369 */ readUrl(String url)370 String readUrl(String url) 371 { 372 URL u; 373 try 374 { 375 u = new URL(url); 376 } 377 catch (MalformedURLException mex) 378 { 379 throw new BAD_PARAM("Malformed URL: '" + url + "'"); 380 } 381 382 try 383 { 384 InputStreamReader r = new InputStreamReader(u.openStream()); 385 386 CPStringBuilder b = new CPStringBuilder(); 387 int c; 388 389 while ((c = r.read()) > 0) 390 b.append((char) c); 391 392 return b.toString().trim(); 393 } 394 catch (Exception exc) 395 { 396 DATA_CONVERSION d = new DATA_CONVERSION("Reading " + url + " failed."); 397 d.minor = Minor.Missing_IOR; 398 throw d; 399 } 400 } 401 resolve(String nsIor)402 private String[] resolve(String nsIor) 403 { 404 String [] n = new String[2]; 405 n[0] = nsIor; 406 n[1] = readKey("#"); 407 return n; 408 } 409 readKey(String delimiter)410 private String readKey(String delimiter) 411 throws BAD_PARAM 412 { 413 if (p < t.length) 414 if (!t[p].equals(delimiter)) 415 { 416 if (t[p].equals("#")) 417 return DEFAULT_NAME; 418 else 419 throw new BAD_PARAM("'" + delimiter + "String' expected '" + t[p] 420 + "' found"); 421 } 422 423 CPStringBuilder bKey = new CPStringBuilder(); 424 p++; 425 426 while (p < t.length && !t[p].equals("#")) 427 bKey.append(t[p++]); 428 429 if (bKey.length() == 0) 430 return DEFAULT_NAME; 431 432 try 433 { 434 return URLDecoder.decode(bKey.toString(), "UTF-8"); 435 } 436 catch (UnsupportedEncodingException e) 437 { 438 throw new Unexpected("URLDecoder does not support UTF-8", e); 439 } 440 } 441 } 442