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