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 alternative addresses, if given.
 197:     ArrayList alt_addr = new ArrayList();
 198: 
 199:     // The version numbers with default values.
 200:     int major = 1;
 201:     int minor = 0;
 202: 
 203:     // The host address.
 204:     String host;
 205: 
 206:     // The port.
 207:     int port = DEFAULT_PORT;
 208: 
 209:     // The object key as string.
 210:     String key;
 211: 
 212:     StringTokenizer st = new StringTokenizer(corbaloc, ":@/.,#", true);
 213: 
 214:     t = new String[st.countTokens()];
 215: 
 216:     for (int i = 0; i < t.length; i++)
 217:       {
 218:         t[i] = st.nextToken();
 219:       }
 220: 
 221:     p = 0;
 222: 
 223:     if (t[p].startsWith(pxCORBANAME))
 224:       corbaname = true;
 225:     else if (t[p].equalsIgnoreCase(pxCORBALOC))
 226:       corbaname = false;
 227:     else if (t[p].equalsIgnoreCase(pxIOR))
 228:       {
 229:         IOR ior = IOR.parse(corbaloc);
 230:         return orb.ior_to_object(ior);
 231:       }
 232:     else
 233:       throw new DATA_CONVERSION("Unsupported protocol: '" + t[p] + "'");
 234: 
 235:     p++;
 236: 
 237:     if (!t[p++].equals(":"))
 238:       throw new BAD_PARAM("Syntax (':' expected after name prefix)");
 239: 
 240:     // Check for rir:
 241:     if (t[p].equals(RIR))
 242:       {
 243:         p++;
 244:         if (!t[p++].equals(":"))
 245:           throw new BAD_PARAM("':' expected after 'rir'");
 246: 
 247:         key = readKey("/");
 248: 
 249:         Object object;
 250:         try
 251:           {
 252:             object = orb.resolve_initial_references(key);
 253:             return corbaname ? resolve(object) : object;
 254:           }
 255:         catch (InvalidName e)
 256:           {
 257:             throw new BAD_PARAM("Unknown initial reference '" + key + "'");
 258:           }
 259:       }
 260:     else
 261:     // Check for iiop.
 262:     if (t[p].equals(IIOP) || t[p].equals(":"))
 263:       {
 264:         IOR ior = new IOR();
 265: 
 266:         Addresses: do
 267:           { // Read addresses.
 268:             if (t[p].equals(":"))
 269:               {
 270:                 p++;
 271:               }
 272:             else
 273:               {
 274:                 p++;
 275:                 if (!t[p++].equals(":"))
 276:                   throw new BAD_PARAM("':' expected after 'iiop'");
 277:                 // Check if version is present.
 278:                 if (t[p + 1].equals("."))
 279:                   if (t[p + 3].equals("@"))
 280:                     {
 281:                       // Version info present.
 282:                       try
 283:                         {
 284:                           major = Integer.parseInt(t[p++]);
 285:                         }
 286:                       catch (NumberFormatException e)
 287:                         {
 288:                           throw new BAD_PARAM("Major version number '"
 289:                             + t[p - 1] + "'");
 290:                         }
 291:                       p++; // '.' at this point.
 292:                       try
 293:                         {
 294:                           minor = Integer.parseInt(t[p++]);
 295:                         }
 296:                       catch (NumberFormatException e)
 297:                         {
 298:                           throw new BAD_PARAM("Major version number '"
 299:                             + t[p - 1] + "'");
 300:                         }
 301:                       p++; // '@' at this point.
 302:                     }
 303:               }
 304: 
 305:             ior.Internet.version = new Version(major, minor);
 306: 
 307:             // Then host data goes till '/' or ':'.
 308:             StringBuffer bhost = new StringBuffer(corbaloc.length());
 309:             while (!t[p].equals(":") && !t[p].equals("/") && !t[p].equals(","))
 310:               bhost.append(t[p++]);
 311: 
 312:             host = bhost.toString();
 313: 
 314:             ior.Internet.host = host;
 315: 
 316:             if (t[p].equals(":"))
 317:               {
 318:                 // Port specified.
 319:                 p++;
 320:                 try
 321:                   {
 322:                     port = Integer.parseInt(t[p++]);
 323:                   }
 324:                 catch (NumberFormatException e)
 325:                   {
 326:                     throw new BAD_PARAM("Invalid port '" + t[p - 1] + "'");
 327:                   }
 328:               }
 329: 
 330:             ior.Internet.port = port;
 331: 
 332:             // Id is not listed.
 333:             ior.Id = "";
 334: 
 335:             if (t[p].equals(","))
 336:               p++;
 337:             else
 338:               break Addresses;
 339:           }
 340:         while (true);
 341: 
 342:         key = readKey("/");
 343:         ior.key = key.getBytes();
 344: 
 345:         org.omg.CORBA.Object object = orb.ior_to_object(ior);
 346:         return corbaname ? resolve(object) : object;
 347:       }
 348: 
 349:     else
 350:       throw new DATA_CONVERSION("Unsupported protocol '" + t[p] + "'");
 351:   }
 352:   
 353:   /**
 354:    * Read IOR from the file in the local file system.
 355:    */
 356:   String readFile(String file)
 357:   {
 358:     File f = new File(file);
 359:     if (!f.exists())
 360:       {
 361:         DATA_CONVERSION err = new DATA_CONVERSION(f.getAbsolutePath()
 362:           + " does not exist.");
 363:         err.minor = Minor.Missing_IOR;
 364:       }
 365:     try
 366:       {
 367:         char[] c = new char[(int) f.length()];
 368:         FileReader fr = new FileReader(f);
 369:         fr.read(c);
 370:         fr.close();
 371:         return new String(c).trim();
 372:       }
 373:     catch (IOException ex)
 374:       {
 375:         DATA_CONVERSION d = new DATA_CONVERSION();
 376:         d.initCause(ex);
 377:         d.minor = Minor.Missing_IOR;
 378:         throw (d);
 379:       }
 380:   }
 381:   
 382:   /**
 383:    * Read IOR from the remote URL.
 384:    */
 385:   String readUrl(String url)
 386:   {
 387:     URL u;
 388:     try
 389:       {
 390:         u = new URL(url);
 391:       }
 392:     catch (MalformedURLException mex)
 393:       {
 394:         throw new BAD_PARAM("Malformed URL: '" + url + "'");
 395:       }
 396: 
 397:     try
 398:       {
 399:         InputStreamReader r = new InputStreamReader(u.openStream());
 400: 
 401:         StringBuffer b = new StringBuffer();
 402:         int c;
 403: 
 404:         while ((c = r.read()) > 0)
 405:           b.append((char) c);
 406: 
 407:         return b.toString().trim();
 408:       }
 409:     catch (Exception exc)
 410:       {
 411:         DATA_CONVERSION d = new DATA_CONVERSION("Reading " + url + " failed.");
 412:         d.minor = Minor.Missing_IOR;
 413:         throw d;
 414:       }
 415:   }
 416: 
 417:   private org.omg.CORBA.Object resolve(org.omg.CORBA.Object object)
 418:   {
 419:     NamingContext ns;
 420:     String key = "?";
 421:     try
 422:       {
 423:         if (object instanceof NamingContext)
 424:           ns = (NamingContext) object;
 425:         else
 426:           {
 427:             Delegate delegate = ((ObjectImpl) object)._get_delegate();
 428:             ns = new _NamingContextStub();
 429:             ((_NamingContextStub) ns)._set_delegate(delegate);
 430:           }
 431:       }
 432:     catch (Exception ex)
 433:       {
 434:         BAD_PARAM bad = new BAD_PARAM("The CORBANAME target " + object
 435:           + " is not a NamingContext");
 436:         bad.minor = 10;
 437:         bad.initCause(ex);
 438:         throw bad;
 439:       }
 440: 
 441:     if (converter == null)
 442:       converter = new NameTransformer();
 443: 
 444:     try
 445:       {
 446:         key = readKey("#");
 447:         object = ns.resolve(converter.toName(key));
 448:         return object;
 449:       }
 450:     catch (Exception ex)
 451:       {
 452:         BAD_PARAM bad = new BAD_PARAM("Wrong CORBANAME '" + key + "'");
 453:         bad.minor = 10;
 454:         bad.initCause(ex);
 455:         throw bad;
 456:       }
 457:   }
 458: 
 459:   private String readKey(String delimiter)
 460:     throws BAD_PARAM
 461:   {
 462:     if (p < t.length)
 463:       if (!t[p].equals(delimiter))
 464:         {
 465:           if (t[p].equals("#"))
 466:             return DEFAULT_NAME;
 467:           else
 468:             throw new BAD_PARAM("'" + delimiter + "String' expected '" + t[p]
 469:               + "' found");
 470:         }
 471: 
 472:     StringBuffer bKey = new StringBuffer();
 473:     p++;
 474: 
 475:     while (p < t.length && !t[p].equals("#"))
 476:       bKey.append(t[p++]);
 477: 
 478:     if (bKey.length() == 0)
 479:       return DEFAULT_NAME;
 480: 
 481:     try
 482:       {
 483:         return URLDecoder.decode(bKey.toString(), "UTF-8");
 484:       }
 485:     catch (UnsupportedEncodingException e)
 486:       {
 487:         throw new Unexpected("URLDecoder does not support UTF-8", e);
 488:       }
 489:   }
 490: 
 491:   static NameParser n = new NameParser();
 492: 
 493:   static void corbalocT(String ior, OrbFunctional orb)
 494:   {
 495:     System.out.println(ior);
 496:     System.out.println(n.corbaloc(ior, orb));
 497:     System.out.println();
 498:   }
 499: 
 500:   public static void main(String[] args)
 501:   {
 502:     try
 503:       {
 504:         OrbFunctional orb = (OrbFunctional) ORB.init(args, null);
 505:         corbalocT("corbaloc:iiop:1.3@155axyz.com/Prod/aTradingService", orb);
 506:         corbalocT("corbaloc:iiop:2.7@255bxyz.com/Prod/bTradingService", orb);
 507:         corbalocT("corbaloc:iiop:355cxyz.com/Prod/cTradingService", orb);
 508:         corbalocT("corbaloc:iiop:2.7@255bxyz.com/Prod/bTradingService", orb);
 509:         corbalocT("corbaloc:iiop:355cxyz.com:7777/Prod/cTradingService", orb);
 510: 
 511:         corbalocT("corbaloc::556xyz.com:80/Dev/NameService", orb);
 512:         corbalocT("corbaloc:iiop:1.2@host1:3076/0", orb);
 513: 
 514:         corbalocT("corbaloc:rir:/NameService", orb);
 515:         corbalocT("corbaloc:rir:/", orb);
 516:         corbalocT("corbaloc:rir:", orb);
 517: 
 518:         corbalocT("corbaloc:rir:/NameService", orb);
 519:         corbalocT("corbaloc:rir:/", orb);
 520:         corbalocT("corbaloc:rir:", orb);
 521: 
 522:         corbalocT("corbaloc::555xyz.com,:556xyz.com:80/Dev/NameService", orb);
 523:       }
 524:     catch (BAD_PARAM e)
 525:       {
 526:         e.printStackTrace(System.out);
 527:       }
 528:   }
 529: }