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