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 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:    */
 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:    */
 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:    */
 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:    */
 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: 
 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: 
 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: 
 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: 
 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: }