Source for gnu.CORBA.ObjectCreator

   1: /* ObjectCreator.java --
   2:    Copyright (C) 2005 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;
  40: 
  41: import gnu.CORBA.CDR.UnknownExceptionCtxHandler;
  42: import gnu.CORBA.CDR.BufferredCdrInput;
  43: import gnu.CORBA.CDR.BufferedCdrOutput;
  44: import gnu.CORBA.CDR.AbstractCdrInput;
  45: import gnu.CORBA.GIOP.ServiceContext;
  46: import gnu.CORBA.typecodes.RecordTypeCode;
  47: import gnu.classpath.VMStackWalker;
  48: 
  49: import org.omg.CORBA.Any;
  50: import org.omg.CORBA.CompletionStatus;
  51: import org.omg.CORBA.CompletionStatusHelper;
  52: import org.omg.CORBA.MARSHAL;
  53: import org.omg.CORBA.SystemException;
  54: import org.omg.CORBA.TCKind;
  55: import org.omg.CORBA.UNKNOWN;
  56: import org.omg.CORBA.UserException;
  57: import org.omg.CORBA.portable.IDLEntity;
  58: import org.omg.CORBA.portable.InputStream;
  59: import org.omg.CORBA.portable.OutputStream;
  60: import org.omg.CORBA.portable.ValueBase;
  61: 
  62: import java.lang.reflect.Method;
  63: import java.util.Map;
  64: import java.util.WeakHashMap;
  65: 
  66: import javax.rmi.CORBA.Util;
  67: 
  68: /**
  69:  * Creates java objects from the agreed IDL names for the simple case when the
  70:  * CORBA object is directly mapped into the locally defined java class.
  71:  *
  72:  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
  73:  */
  74: public class ObjectCreator
  75: {
  76:   /**
  77:    * The standard OMG prefix.
  78:    */
  79:   public static final String OMG_PREFIX = "omg.org/";
  80: 
  81:   /**
  82:    * The standard java prefix.
  83:    */
  84:   public static final String JAVA_PREFIX = "org.omg.";
  85: 
  86:   /**
  87:    * The prefix for classes that are placed instide the gnu.CORBA namespace.
  88:    */
  89:   public static final String CLASSPATH_PREFIX = "gnu.CORBA.";
  90: 
  91:   /**
  92:    * Maps classes to they IDL or RMI names. Computing RMI name is an expensive
  93:    * operations, so frequently used RMI keys are reused. The map must be weak to
  94:    * ensure that the class can be unloaded, when applicable.
  95:    */
  96:   public static Map m_names = new WeakHashMap();
  97: 
  98:   /**
  99:    * Maps IDL strings into known classes. The map must be weak to ensure that
 100:    * the class can be unloaded, when applicable.
 101:    */
 102:   public static Map m_classes = new WeakHashMap();
 103: 
 104:   /**
 105:    * Maps IDL types to they helpers.
 106:    */
 107:   public static Map m_helpers = new WeakHashMap();
 108: 
 109:   /**
 110:    * Try to instantiate an object with the given IDL name. The object must be
 111:    * mapped to the local java class. The omg.org domain must be mapped into the
 112:    * object in either org/omg or gnu/CORBA namespace.
 113:    *
 114:    * @param idl name
 115:    * @return instantiated object instance or null if no such available.
 116:    */
 117:   public static java.lang.Object createObject(String idl, String suffix)
 118:   {
 119:     synchronized (m_classes)
 120:       {
 121:         Class known = (Class) (suffix == null ? m_classes.get(idl)
 122:           : m_classes.get(idl + 0xff + suffix));
 123:         Object object;
 124: 
 125:         if (known != null)
 126:           {
 127:             try
 128:               {
 129:                 return known.newInstance();
 130:               }
 131:             catch (Exception ex)
 132:               {
 133:                 RuntimeException rex = new RuntimeException(idl + " suffix "
 134:                   + suffix, ex);
 135:                 throw rex;
 136:               }
 137:           }
 138:         else
 139:           {
 140:             if (suffix == null)
 141:               suffix = "";
 142:             try
 143:               {
 144:                 known = forName(toClassName(JAVA_PREFIX, idl) + suffix);
 145:                 object = known.newInstance();
 146:               }
 147:             catch (Exception ex)
 148:               {
 149:                 try
 150:                   {
 151:                     known = forName(toClassName(CLASSPATH_PREFIX, idl)
 152:                       + suffix);
 153:                     object = known.newInstance();
 154:                   }
 155:                 catch (Exception exex)
 156:                   {
 157:                     return null;
 158:                   }
 159:               }
 160:             m_classes.put(idl + 0xff + suffix, known);
 161:             return object;
 162:           }
 163:       }
 164:   }
 165: 
 166:   /**
 167:    * Read the system exception from the given stream.
 168:    *
 169:    * @param input the CDR stream to read from.
 170:    * @param contexts the service contexts in request/reply header/
 171:    *
 172:    * @return the exception that has been stored in the stream (IDL name, minor
 173:    * code and completion status).
 174:    */
 175:   public static SystemException readSystemException(InputStream input,
 176:     ServiceContext[] contexts)
 177:   {
 178:     SystemException exception;
 179: 
 180:     String idl = input.read_string();
 181:     int minor = input.read_ulong();
 182:     CompletionStatus completed = CompletionStatusHelper.read(input);
 183: 
 184:     try
 185:       {
 186:         exception = (SystemException) createObject(idl, null);
 187:         exception.minor = minor;
 188:         exception.completed = completed;
 189:       }
 190:     catch (Exception ex)
 191:       {
 192:         UNKNOWN u = new UNKNOWN("Unsupported system exception " + idl, minor,
 193:           completed);
 194:         u.initCause(ex);
 195:         throw u;
 196:       }
 197: 
 198:     try
 199:       {
 200:         // If UnknownExceptionInfo is present in the contexts, read it and
 201:         // set as a cause of this exception.
 202:         ServiceContext uEx = ServiceContext.find(
 203:           ServiceContext.UnknownExceptionInfo, contexts);
 204: 
 205:         if (uEx != null)
 206:           {
 207:             BufferredCdrInput in = new BufferredCdrInput(uEx.context_data);
 208:             in.setOrb(in.orb());
 209:             if (input instanceof AbstractCdrInput)
 210:               {
 211:                 ((AbstractCdrInput) input).cloneSettings(in);
 212:               }
 213: 
 214:             Throwable t = UnknownExceptionCtxHandler.read(in, contexts);
 215:             exception.initCause(t);
 216:           }
 217:       }
 218:     catch (Exception ex)
 219:       {
 220:         // Unsupported context format. Do not terminate as the user program may
 221:         // not need it.
 222:       }
 223: 
 224:     return exception;
 225:   }
 226: 
 227:   /**
 228:    * Reads the user exception, having the given Id, from the input stream. The
 229:    * id is expected to be in the form like
 230:    * 'IDL:test/org/omg/CORBA/ORB/communication/ourUserException:1.0'
 231:    *
 232:    * @param idl the exception idl name.
 233:    * @param input the stream to read from.
 234:    *
 235:    * @return the loaded exception.
 236:    * @return null if the helper class cannot be found.
 237:    */
 238:   public static UserException readUserException(String idl, InputStream input)
 239:   {
 240:     try
 241:       {
 242:         Class helperClass = findHelper(idl);
 243: 
 244:         Method read = helperClass.getMethod("read",
 245:           new Class[] { org.omg.CORBA.portable.InputStream.class });
 246: 
 247:         return (UserException) read.invoke(null, new Object[] { input });
 248:       }
 249:     catch (MARSHAL mex)
 250:       {
 251:         // This one is ok to throw
 252:         throw mex;
 253:       }
 254:     catch (Exception ex)
 255:       {
 256:         ex.printStackTrace();
 257:         return null;
 258:       }
 259:   }
 260: 
 261:   /**
 262:    * Gets the helper class name from the string like
 263:    * 'IDL:test/org/omg/CORBA/ORB/communication/ourUserException:1.0'
 264:    *
 265:    * @param IDL the idl name.
 266:    */
 267:   public static String toHelperName(String IDL)
 268:   {
 269:     String s = IDL;
 270:     int a = s.indexOf(':') + 1;
 271:     int b = s.lastIndexOf(':');
 272: 
 273:     s = IDL.substring(a, b);
 274: 
 275:     if (s.startsWith(OMG_PREFIX))
 276:       s = JAVA_PREFIX + s.substring(OMG_PREFIX.length());
 277: 
 278:     return s.replace('/', '.') + "Helper";
 279:   }
 280: 
 281:   /**
 282:    * Writes the system exception data to CDR output stream.
 283:    *
 284:    * @param output a stream to write data to.
 285:    * @param ex an exception to write.
 286:    */
 287:   public static void writeSystemException(OutputStream output,
 288:     SystemException ex)
 289:   {
 290:     String exIDL = getRepositoryId(ex.getClass());
 291:     output.write_string(exIDL);
 292:     output.write_ulong(ex.minor);
 293:     CompletionStatusHelper.write(output, ex.completed);
 294:   }
 295: 
 296:   /**
 297:    * Converts the given IDL name to class name.
 298:    *
 299:    * @param IDL the idl name.
 300:    *
 301:    */
 302:   protected static String toClassName(String prefix, String IDL)
 303:   {
 304:     String s = IDL;
 305:     int a = s.indexOf(':') + 1;
 306:     int b = s.lastIndexOf(':');
 307: 
 308:     s = IDL.substring(a, b);
 309: 
 310:     if (s.startsWith(OMG_PREFIX))
 311:       s = prefix + s.substring(OMG_PREFIX.length());
 312: 
 313:     return s.replace('/', '.');
 314:   }
 315: 
 316:   /**
 317:    * Converts the given IDL name to class name and tries to load the matching
 318:    * class. The OMG prefix (omg.org) is replaced by the java prefix org.omg. No
 319:    * other prefixes are added.
 320:    *
 321:    * @param IDL the idl name.
 322:    *
 323:    * @return the matching class or null if no such is available.
 324:    */
 325:   public static Class Idl2class(String IDL)
 326:   {
 327:     synchronized (m_classes)
 328:       {
 329:         Class c = (Class) m_classes.get(IDL);
 330: 
 331:         if (c != null)
 332:           return c;
 333:         else
 334:           {
 335:             String s = IDL;
 336:             int a = s.indexOf(':') + 1;
 337:             int b = s.lastIndexOf(':');
 338: 
 339:             s = IDL.substring(a, b);
 340: 
 341:             if (s.startsWith(OMG_PREFIX))
 342:               s = JAVA_PREFIX + s.substring(OMG_PREFIX.length());
 343: 
 344:             String cn = s.replace('/', '.');
 345: 
 346:             try
 347:               {
 348:                 c = forName(cn);
 349:                 m_classes.put(IDL, c);
 350:                 return c;
 351:               }
 352:             catch (ClassNotFoundException ex)
 353:               {
 354:                 return null;
 355:               }
 356:           }
 357:       }
 358:   }
 359: 
 360:   /**
 361:    * Converts the given IDL name to class name, tries to load the matching class
 362:    * and create an object instance with parameterless constructor. The OMG
 363:    * prefix (omg.org) is replaced by the java prefix org.omg. No other prefixes
 364:    * are added.
 365:    *
 366:    * @param IDL the idl name.
 367:    *
 368:    * @return instantiated object instance or null if such attempt was not
 369:    * successful.
 370:    */
 371:   public static java.lang.Object Idl2Object(String IDL)
 372:   {
 373:     Class cx = Idl2class(IDL);
 374: 
 375:     try
 376:       {
 377:         if (cx != null)
 378:           return cx.newInstance();
 379:         else
 380:           return null;
 381:       }
 382:     catch (Exception ex)
 383:       {
 384:         return null;
 385:       }
 386:   }
 387: 
 388:   /**
 389:    * Convert the class name to IDL or RMI name (repository id). If the class
 390:    * inherits from IDLEntity, ValueBase or SystemException, returns repository
 391:    * Id in the IDL:(..) form. If it does not, returns repository Id in the
 392:    * RMI:(..) form.
 393:    *
 394:    * @param cx the class for that the name must be computed.
 395:    *
 396:    * @return the idl or rmi name.
 397:    */
 398:   public static synchronized String getRepositoryId(Class cx)
 399:   {
 400:     String name = (String) m_names.get(cx);
 401:     if (name != null)
 402:       return name;
 403: 
 404:     String cn = cx.getName();
 405:     if (!(IDLEntity.class.isAssignableFrom(cx)
 406:       || ValueBase.class.isAssignableFrom(cx) || SystemException.class.isAssignableFrom(cx)))
 407:       {
 408:         // Not an IDL entity.
 409:         name = Util.createValueHandler().getRMIRepositoryID(cx);
 410:       }
 411:     else
 412:       {
 413:         if (cn.startsWith(JAVA_PREFIX))
 414:           cn = OMG_PREFIX
 415:             + cn.substring(JAVA_PREFIX.length()).replace('.', '/');
 416:         else if (cn.startsWith(CLASSPATH_PREFIX))
 417:           cn = OMG_PREFIX
 418:             + cn.substring(CLASSPATH_PREFIX.length()).replace('.', '/');
 419: 
 420:         name = "IDL:" + cn + ":1.0";
 421:       }
 422:     m_names.put(cx, name);
 423:     return name;
 424:   }
 425: 
 426:   /**
 427:    * Insert the passed parameter into the given Any, assuming that the helper
 428:    * class is available. The helper class must have the "Helper" suffix and be
 429:    * in the same package as the class of the object being inserted.
 430:    *
 431:    * @param into the target to insert.
 432:    *
 433:    * @param object the object to insert. It can be any object as far as the
 434:    * corresponding helper is provided.
 435:    *
 436:    * @return true on success, false otherwise.
 437:    */
 438:   public static boolean insertWithHelper(Any into, Object object)
 439:   {
 440:     try
 441:       {
 442:         String helperClassName = object.getClass().getName() + "Helper";
 443:         Class helperClass = forName(helperClassName);
 444: 
 445:         Method insert = helperClass.getMethod("insert", new Class[] {
 446:           Any.class, object.getClass() });
 447: 
 448:         insert.invoke(null, new Object[] { into, object });
 449: 
 450:         return true;
 451:       }
 452:     catch (Exception exc)
 453:       {
 454:         // Failed due some reason.
 455:         return false;
 456:       }
 457:   }
 458: 
 459:   /**
 460:    * Insert the system exception into the given Any.
 461:    */
 462:   public static boolean insertSysException(Any into, SystemException exception)
 463:   {
 464:     try
 465:       {
 466:         BufferedCdrOutput output = new BufferedCdrOutput();
 467: 
 468:         String m_exception_id = getRepositoryId(exception.getClass());
 469:         output.write_string(m_exception_id);
 470:         output.write_ulong(exception.minor);
 471:         CompletionStatusHelper.write(output, exception.completed);
 472: 
 473:         String name = getDefaultName(m_exception_id);
 474: 
 475:         GeneralHolder h = new GeneralHolder(output);
 476: 
 477:         into.insert_Streamable(h);
 478: 
 479:         RecordTypeCode r = new RecordTypeCode(TCKind.tk_except);
 480:         r.setId(m_exception_id);
 481:         r.setName(name);
 482:         into.type(r);
 483: 
 484:         return true;
 485:       }
 486:     catch (Exception ex)
 487:       {
 488:         ex.printStackTrace();
 489:         return false;
 490:       }
 491:   }
 492: 
 493:   /**
 494:    * Get the type name from the IDL string.
 495:    */
 496:   public static String getDefaultName(String idl)
 497:   {
 498:     int f1 = idl.lastIndexOf("/");
 499:     int p1 = (f1 < 0) ? 0 : f1;
 500:     int p2 = idl.indexOf(":", p1);
 501:     if (p2 < 0)
 502:       p2 = idl.length();
 503: 
 504:     String name = idl.substring(f1 + 1, p2);
 505:     return name;
 506:   }
 507: 
 508:   /**
 509:    * Insert this exception into the given Any. On failure, insert the UNKNOWN
 510:    * exception.
 511:    */
 512:   public static void insertException(Any into, Throwable exception)
 513:   {
 514:     boolean ok = false;
 515:     if (exception instanceof SystemException)
 516:       ok = insertSysException(into, (SystemException) exception);
 517:     else if (exception instanceof UserException)
 518:       ok = insertWithHelper(into, exception);
 519: 
 520:     if (!ok)
 521:       ok = insertSysException(into, new UNKNOWN());
 522:     if (!ok)
 523:       throw new InternalError("Exception wrapping broken");
 524:   }
 525: 
 526:   /**
 527:    * Find helper for the class with the given name.
 528:    */
 529:   public static Class findHelper(String idl)
 530:   {
 531:     synchronized (m_helpers)
 532:       {
 533:         Class c = (Class) m_helpers.get(idl);
 534:         if (c != null)
 535:           return c;
 536:         try
 537:           {
 538:             String helper = toHelperName(idl);
 539:             c = forName(helper);
 540: 
 541:             m_helpers.put(idl, c);
 542:             return c;
 543:           }
 544:         catch (Exception ex)
 545:           {
 546:             return null;
 547:           }
 548:       }
 549:   }
 550: 
 551:   /**
 552:    * Load the class with the given name. This method tries to use the context
 553:    * class loader first. If this fails, it searches for the suitable class
 554:    * loader in the caller stack trace. This method is a central point where all
 555:    * requests to find a class by name are delegated.
 556:    */
 557:   public static Class forName(String className) throws ClassNotFoundException
 558:   {
 559:     try
 560:       {
 561:         return Class.forName(className, true,
 562:                              Thread.currentThread().getContextClassLoader());
 563:       }
 564:     catch (ClassNotFoundException nex)
 565:       {
 566:         /**
 567:          * Returns the first user defined class loader on the call stack, or
 568:          * null when no non-null class loader was found.
 569:          */
 570:         Class[] ctx = VMStackWalker.getClassContext();
 571:         for (int i = 0; i < ctx.length; i++)
 572:           {
 573:             // Since we live in a class loaded by the bootstrap
 574:             // class loader, getClassLoader is safe to call without
 575:             // needing to be wrapped in a privileged action.
 576:             ClassLoader cl = ctx[i].getClassLoader();
 577:             try
 578:               {
 579:                 if (cl != null)
 580:                   return Class.forName(className, true, cl);
 581:               }
 582:             catch (ClassNotFoundException nex2)
 583:               {
 584:                 // Try next.
 585:               }
 586:           }
 587:       }
 588:     throw new ClassNotFoundException(className);
 589:   }
 590: }