Source for gnu.CORBA.NamingService.NameParser

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