Source for gnu.javax.rmi.CORBA.UtilDelegateImpl

   1: /* UtilDelegateImpl.java --
   2:    Copyright (C) 2002, 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.javax.rmi.CORBA;
  40: 
  41: import gnu.CORBA.Minor;
  42: import gnu.CORBA.ObjectCreator;
  43: import gnu.CORBA.Poa.ORB_1_4;
  44: import gnu.CORBA.Poa.AOM;
  45: import gnu.CORBA.Poa.gnuPOA;
  46: import gnu.CORBA.typecodes.GeneralTypeCode;
  47: 
  48: import org.omg.CORBA.Any;
  49: import org.omg.CORBA.BAD_PARAM;
  50: import org.omg.CORBA.COMM_FAILURE;
  51: import org.omg.CORBA.CompletionStatus;
  52: import org.omg.CORBA.INVALID_TRANSACTION;
  53: import org.omg.CORBA.INV_OBJREF;
  54: import org.omg.CORBA.MARSHAL;
  55: import org.omg.CORBA.NO_PERMISSION;
  56: import org.omg.CORBA.OBJECT_NOT_EXIST;
  57: import org.omg.CORBA.OMGVMCID;
  58: import org.omg.CORBA.ORB;
  59: import org.omg.CORBA.SystemException;
  60: import org.omg.CORBA.TCKind;
  61: import org.omg.CORBA.TRANSACTION_REQUIRED;
  62: import org.omg.CORBA.TRANSACTION_ROLLEDBACK;
  63: import org.omg.CORBA.TypeCode;
  64: import org.omg.CORBA.UNKNOWN;
  65: import org.omg.CORBA.portable.InputStream;
  66: import org.omg.CORBA.portable.OutputStream;
  67: 
  68: import java.io.ByteArrayInputStream;
  69: import java.io.ByteArrayOutputStream;
  70: import java.io.ObjectInputStream;
  71: import java.io.ObjectOutputStream;
  72: import java.io.Serializable;
  73: import java.rmi.AccessException;
  74: import java.rmi.MarshalException;
  75: import java.rmi.NoSuchObjectException;
  76: import java.rmi.Remote;
  77: import java.rmi.RemoteException;
  78: import java.rmi.ServerError;
  79: import java.rmi.ServerException;
  80: import java.rmi.UnexpectedException;
  81: import java.rmi.server.RMIClassLoader;
  82: import java.util.Hashtable;
  83: 
  84: import javax.rmi.CORBA.Stub;
  85: import javax.rmi.CORBA.Tie;
  86: import javax.rmi.CORBA.Util;
  87: import javax.rmi.CORBA.UtilDelegate;
  88: import javax.rmi.CORBA.ValueHandler;
  89: import javax.transaction.InvalidTransactionException;
  90: import javax.transaction.TransactionRequiredException;
  91: import javax.transaction.TransactionRolledbackException;
  92: 
  93: /**
  94:  * The implementation of UtilDelegate.
  95:  * 
  96:  * @author Wu Gansha (gansha.wu@intel.com) (stub)
  97:  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) (implementation)
  98:  */
  99: public class UtilDelegateImpl
 100:   extends RmiUtilities
 101:   implements UtilDelegate
 102: {
 103:   /**
 104:    * The instance of the value handler, requested once.
 105:    */
 106:   static ValueHandler m_ValueHandler;
 107: 
 108:   /**
 109:    * The global map of all ties to they records.
 110:    */
 111:   static Hashtable m_Ties = new Hashtable();
 112: 
 113:   /**
 114:    * The global map of all targets to they records.
 115:    */
 116:   static Hashtable m_Targets = new Hashtable();
 117: 
 118:   /**
 119:    * The standard package for that the exception names are omitted.
 120:    */
 121:   static final String m_StandardPackage = "org.omg.CORBA.";
 122: 
 123:   /**
 124:    * Make a deep copy of the object.
 125:    */
 126:   public Object copyObject(Object obj, ORB orb)
 127:     throws RemoteException
 128:   {
 129:     // Strings are immutable, can be shared.
 130:     if (obj instanceof String)
 131:       return obj;
 132:     else if (obj == null)
 133:       return null;
 134:     else if (obj instanceof String[] || obj instanceof String[][]
 135:       || obj instanceof String[][][])
 136:       {
 137:         // String arrays can be just cloned.
 138:         return ((Object[]) obj).clone();
 139:       }
 140:     else if (obj instanceof Serializable)
 141:       {
 142:         try
 143:           {
 144:             ByteArrayOutputStream a = new ByteArrayOutputStream();
 145:             ObjectOutputStream ou = new ObjectOutputStream(a);
 146:             ou.writeObject(obj);
 147:             ou.close();
 148:             ObjectInputStream input = new ObjectInputStream(
 149:               new ByteArrayInputStream(a.toByteArray()));
 150:             return input.readObject();
 151:           }
 152:         catch (Exception ex)
 153:           {
 154:             RemoteException rex = new RemoteException("Cannot copy " + obj);
 155:             throw rex;
 156:           }
 157:       }
 158:     else
 159:       return obj;
 160:   }
 161: 
 162:   /**
 163:    * Make a deep copy of the object array.
 164:    */
 165:   public Object[] copyObjects(Object[] obj, ORB orb)
 166:     throws RemoteException
 167:   {
 168:     return (Object[]) copyObject(obj, orb);
 169:   }
 170: 
 171:   public ValueHandler createValueHandler()
 172:   {
 173:     if (m_ValueHandler == null)
 174:       m_ValueHandler = (ValueHandler) DelegateFactory.getInstance(DelegateFactory.VALUEHANDLER);
 175:     return m_ValueHandler;
 176:   }
 177: 
 178:   /**
 179:    * Returns the codebase of the given class.
 180:    */
 181:   public String getCodebase(Class clz)
 182:   {
 183:     return RMIClassLoader.getClassAnnotation(clz);
 184:   }
 185: 
 186:   /**
 187:    * Get the Tie that handles invocations on the given target. If the target/Tie
 188:    * pair has not been previously registered using {@link #registerTarget},
 189:    * this method tries to locate a tie class by the name pattern. If this
 190:    * succeeds, the tie-target pair is also registered.
 191:    * 
 192:    * @return the Tie.
 193:    */
 194:   public Tie getTie(Remote target)
 195:   {
 196:     synchronized (m_Targets)
 197:       {
 198:         Tie tie;
 199:         TieTargetRecord r = ((TieTargetRecord) m_Targets.get(target));
 200:         if (r == null)
 201:           {
 202:             if (target instanceof Stub)
 203:               {
 204:                 tie = StubDelegateImpl.getTieFromStub(target);
 205:                 registerTarget(tie, target);
 206:               }
 207:             else
 208:               {
 209:                 // Treat this as implementation.
 210:                 String tieClassName = getTieClassName(target.getClass().getName());
 211:                 try
 212:                   {
 213:                     Class tieClass = Util.loadClass(tieClassName, null,
 214:                       target.getClass().getClassLoader());
 215:                     tie = (Tie) tieClass.newInstance();
 216:                   }
 217:                 catch (Exception e)
 218:                   {
 219:                     MARSHAL m = new MARSHAL("Unable to instantiate "
 220:                       + tieClassName);
 221:                     m.minor = Minor.TargetConversion;
 222:                     m.initCause(e);
 223:                     throw m;
 224:                   }
 225:                 tie.setTarget(target);
 226:                 registerTarget(tie, target);
 227:               }
 228:           }
 229:         else
 230:           tie = r.tie;
 231:         return tie;
 232:       }
 233:   }
 234: 
 235:   /**
 236:    * Get the Stub class name for the name, representing the given interface.
 237:    */
 238:   private String getTieClassName(String interf)
 239:   {
 240:     String stubClassName;
 241:     int p = interf.lastIndexOf('.');
 242: 
 243:     if (p < 0)
 244:       // The interface is defined in the default package.
 245:       stubClassName = "_" + interf + "_Tie";
 246:     else
 247:       stubClassName = interf.substring(0, p + 1) + "_"
 248:         + interf.substring(p + 1) + "_Tie";
 249:     return stubClassName;
 250:   }
 251: 
 252:   /**
 253:    * Register the Tie-target pair. As the Tie is a Servant, it can potentially
 254:    * be connected to several objects and hence may be registered with several
 255:    * targets.
 256:    */
 257:   public void registerTarget(Tie tie, Remote target)
 258:   {
 259:     synchronized (m_Ties)
 260:       {
 261:         synchronized (m_Targets)
 262:           {
 263:             TieTargetRecord r = (TieTargetRecord) m_Ties.get(tie);
 264:             if (r == null)
 265:               {
 266:                 // First registration for this Tie.
 267:                 r = new TieTargetRecord(tie);
 268:                 m_Ties.put(tie, r);
 269:               }
 270:             if (target != null)
 271:               {
 272:                 r.add(target);
 273:                 m_Targets.put(target, r);
 274:               }
 275:           }
 276:       }
 277:   }
 278: 
 279:   /**
 280:    * Deactivate the associated Tie, if it is found and is not connected to other
 281:    * registered targets. Independing from the POA policies, the transparent
 282:    * reactivation will not be possible.
 283:    */
 284:   public void unexportObject(Remote target)
 285:     throws NoSuchObjectException
 286:   {
 287:     synchronized (m_Ties)
 288:       {
 289:         synchronized (m_Targets)
 290:           {
 291:             TieTargetRecord r = ((TieTargetRecord) m_Targets.get(target));
 292:             if (r != null)
 293:               {
 294:                 if (target instanceof org.omg.CORBA.Object)
 295:                   r.tie.orb().disconnect((org.omg.CORBA.Object) target);
 296: 
 297:                 if (r.unused())
 298:                   {
 299:                     m_Targets.remove(target);
 300:                     m_Ties.remove(r.tie);
 301:                     r.tie.deactivate();
 302: 
 303:                     if (r.tie.orb() instanceof ORB_1_4)
 304:                       {
 305:                         // Standard case, when more deep cleanup is possible.
 306:                         // Independing from the POA policies, the object will
 307:                         // not be activable transparently.
 308:                         ORB_1_4 orb = (ORB_1_4) r.tie.orb();
 309: 
 310:                         if (target instanceof org.omg.CORBA.Object)
 311:                           {
 312:                             AOM.Obj record = orb.rootPOA.findObject((org.omg.CORBA.Object) target);
 313: 
 314:                             if (record != null && record.servant == r.tie
 315:                               && record.poa instanceof gnuPOA)
 316:                               {
 317:                                 ((gnuPOA) record.poa).aom.remove(record.key);
 318:                                 record.deactivated = true;
 319:                                 record.servant = null;
 320:                               }
 321:                           }
 322:                       }
 323:                   }
 324:               }
 325:           }
 326:       }
 327:   }
 328: 
 329:   /**
 330:    * Checks if the given stub is local.
 331:    * 
 332:    * @param stub a stub to check.
 333:    * @return true if the stub is local, false otherwise.
 334:    */
 335:   public boolean isLocal(Stub stub)
 336:     throws RemoteException
 337:   {
 338:     try
 339:       {
 340:         return stub._is_local();
 341:       }
 342:     catch (SystemException e)
 343:       {
 344:         RemoteException rex = new RemoteException();
 345:         rex.initCause(e);
 346:         throw rex;
 347:       }
 348:   }
 349: 
 350:   /**
 351:    * Load the class. The method uses class loaders from the call stact first. If
 352:    * this fails, the further behaviour depends on the System Property
 353:    * "java.rmi.server.useCodebaseOnly" with default value "false".
 354:    * 
 355:    * <ul>
 356:    * <li>Try the current thread context class loader first.</li>
 357:    * <li>If remoteCodebase is non-null and useCodebaseOnly is "false" then call
 358:    * java.rmi.server.RMIClassLoader.loadClass (remoteCodebase, className)</li>
 359:    * <li> If remoteCodebase is null or useCodebaseOnly is true then call
 360:    * java.rmi.server.RMIClassLoader.loadClass(className)</li>
 361:    * <li>If a class is still not successfully loaded and the loader != null
 362:    * then try Class.forName(className, false, loader). </li>
 363:    * </ul>
 364:    * 
 365:    * @param className the name of the class.
 366:    * @param remoteCodebase the codebase.
 367:    * @param loader the class loader.
 368:    * @return the loaded class.
 369:    * 
 370:    * @throws ClassNotFoundException of the class cannot be loaded.
 371:    */
 372:   public Class loadClass(String className, String remoteCodebase,
 373:     ClassLoader loader)
 374:     throws ClassNotFoundException
 375:   {
 376:     if (loader == null)
 377:       loader = Thread.currentThread().getContextClassLoader();
 378: 
 379:     String p_useCodebaseOnly = System.getProperty("java.rmi.server.useCodebaseOnly");
 380: 
 381:     boolean useCodebaseOnly = p_useCodebaseOnly != null
 382:       && p_useCodebaseOnly.trim().equalsIgnoreCase("true");
 383: 
 384:     try
 385:       {
 386:         if (remoteCodebase != null && !useCodebaseOnly)
 387:           return RMIClassLoader.loadClass(remoteCodebase, className);
 388:       }
 389:     catch (Exception e)
 390:       {
 391:         // This failed but try others.
 392:       }
 393: 
 394:     try
 395:       {
 396:         if (remoteCodebase == null || useCodebaseOnly)
 397:           return RMIClassLoader.loadClass(remoteCodebase, className);
 398:       }
 399:     catch (Exception e)
 400:       {
 401:         // This failed but try others.
 402:       }
 403: 
 404:     if (loader != null)
 405:       return Class.forName(className, true, loader);
 406: 
 407:     throw new ClassNotFoundException(className + " at " + remoteCodebase);
 408:   }
 409: 
 410:   /**
 411:    * Converts CORBA {@link SystemException} into RMI {@link RemoteException}.
 412:    * The exception is converted as defined in the following table:
 413:    * <p>
 414:    * <table border = "1">
 415:    * <tr>
 416:    * <th>CORBA Exception</th>
 417:    * <th>RMI Exception</th>
 418:    * </tr>
 419:    * <tr>
 420:    * <td>{@link COMM_FAILURE}</td>
 421:    * <td>{@link MarshalException}</td>
 422:    * </tr>
 423:    * <tr>
 424:    * <td>{@link INV_OBJREF}</td>
 425:    * <td>{@link  NoSuchObjectException}</td>
 426:    * </tr>
 427:    * <tr>
 428:    * <td>{@link NO_PERMISSION}</td>
 429:    * <td>{@link  AccessException}</td>
 430:    * </tr>
 431:    * <tr>
 432:    * <td>{@link MARSHAL}</td>
 433:    * <td>{@link  MarshalException}</td>
 434:    * </tr>
 435:    * <tr>
 436:    * <td>{@link BAD_PARAM} (all other cases)</td>
 437:    * <td>{@link  MarshalException}</td>
 438:    * </tr>
 439:    * <tr>
 440:    * <td>{@link OBJECT_NOT_EXIST}</td>
 441:    * <td>{@link  NoSuchObjectException}</td>
 442:    * </tr>
 443:    * <tr>
 444:    * <td>{@link TRANSACTION_REQUIRED}</td>
 445:    * <td>{@link  TransactionRequiredException}</td>
 446:    * </tr>
 447:    * <tr>
 448:    * <td>{@link TRANSACTION_ROLLEDBACK}</td>
 449:    * <td>{@link  TransactionRolledbackException}</td>
 450:    * </tr>
 451:    * <tr>
 452:    * <td>{@link INVALID_TRANSACTION}</td>
 453:    * <td>{@link  InvalidTransactionException}</td>
 454:    * </tr>
 455:    * <tr>
 456:    * <td bgcolor="lightgray">Any other {@link SystemException}</td>
 457:    * <td bgcolor="lightgray">{@link RemoteException}</td>
 458:    * </tr>
 459:    * </table>
 460:    * </p>
 461:    * <p>
 462:    * The exception detailed message always consists of
 463:    * <ol>
 464:    * <li>the string "CORBA "</li>
 465:    * <li>the CORBA name of the system exception</li>
 466:    * <li>single space</li>
 467:    * <li>the hexadecimal value of the system exception's minor code, preceeded
 468:    * by 0x (higher bits contain {@link OMGVMCID}).</li>
 469:    * <li>single space</li>
 470:    * <li>the {@link CompletionStatus} of the exception: "Yes", "No" or "Maybe".</li>
 471:    * </ol>
 472:    * <p>
 473:    * For instance, if the Internet connection was refused:
 474:    * </p>
 475:    * <p>
 476:    * <pre>
 477:    * <code>CORBA COMM_FAILURE 0x535500C9 No</code>
 478:    * </p>
 479:    * <p>
 480:    * The original CORBA exception is set as the cause of the RemoteException
 481:    * being created.
 482:    * </p>
 483:    */
 484:   public RemoteException mapSystemException(SystemException ex)
 485:   {
 486:     RemoteException rex;
 487: 
 488:     String status;
 489: 
 490:     switch (ex.completed.value())
 491:       {
 492:         case CompletionStatus._COMPLETED_MAYBE:
 493:           status = "Maybe";
 494:           break;
 495: 
 496:         case CompletionStatus._COMPLETED_NO:
 497:           status = "No";
 498:           break;
 499: 
 500:         case CompletionStatus._COMPLETED_YES:
 501:           status = "Yes";
 502:           break;
 503: 
 504:         default:
 505:           status = "Unexpected completion status " + ex.completed.value();
 506:       }
 507: 
 508:     String name = ex.getClass().getName();
 509: 
 510:     if (name.startsWith(m_StandardPackage))
 511:       name = name.substring(m_StandardPackage.length());
 512: 
 513:     String message = "CORBA " + name + " 0x" + Integer.toHexString(ex.minor)
 514:       + " " + status;
 515: 
 516:     if (ex instanceof COMM_FAILURE)
 517:       rex = new MarshalException(message, ex);
 518:     else if (ex instanceof INV_OBJREF)
 519:       {
 520:         rex = new NoSuchObjectException(message);
 521:         rex.detail = ex;
 522:       }
 523:     else if (ex instanceof NO_PERMISSION)
 524:       rex = new AccessException(message, ex);
 525:     else if (ex instanceof MARSHAL)
 526:       rex = new MarshalException(message, ex);
 527:     else if (ex instanceof BAD_PARAM)
 528:       rex = new MarshalException(message, ex);
 529:     else if (ex instanceof OBJECT_NOT_EXIST)
 530:       {
 531:         rex = new NoSuchObjectException(message);
 532:         rex.detail = ex;
 533:       }
 534:     else if (ex instanceof TRANSACTION_REQUIRED)
 535:       {
 536:         rex = new TransactionRequiredException(message);
 537:         rex.detail = ex;
 538:       }
 539:     else if (ex instanceof TRANSACTION_ROLLEDBACK)
 540:       {
 541:         rex = new TransactionRolledbackException(message);
 542:         rex.detail = ex;
 543:       }
 544:     else if (ex instanceof INVALID_TRANSACTION)
 545:       {
 546:         rex = new InvalidTransactionException(message);
 547:         rex.detail = ex;
 548:       }
 549:     else if (ex instanceof UNKNOWN)
 550:       rex = wrapException(ex.getCause());
 551:     else
 552:       rex = new RemoteException(message, ex);
 553: 
 554:     return rex;
 555:   }
 556: 
 557:   /**
 558:    * Converts the exception that was thrown by the implementation method on a
 559:    * server side into RemoteException that can be transferred and re-thrown on a
 560:    * client side. The method converts exceptions as defined in the following
 561:    * table: <table border = "1">
 562:    * <tr>
 563:    * <th>Exception to map (or subclass)</th>
 564:    * <th>Maps into</th>
 565:    * </tr>
 566:    * <tr>
 567:    * <td>{@link Error}</td>
 568:    * <td>{@link ServerError}</td>
 569:    * </tr>
 570:    * <tr>
 571:    * <td>{@link RemoteException}</td>
 572:    * <td>{@link ServerException}</td>
 573:    * </tr>
 574:    * <tr>
 575:    * <td>{@link SystemException}</td>
 576:    * <td>wrapException({@link #mapSystemException})</td>
 577:    * </tr>
 578:    * <tr>
 579:    * <td>{@link RuntimeException}</td>
 580:    * <td><b>rethrows</b></td>
 581:    * </tr>
 582:    * <tr>
 583:    * <td>Any other exception</td>
 584:    * <td>{@link UnexpectedException}</td>
 585:    * </tr>
 586:    * </table>
 587:    * 
 588:    * @param ex an exception that was thrown on a server side implementation.
 589:    * 
 590:    * @return the corresponding RemoteException unless it is a RuntimeException.
 591:    * 
 592:    * @throws RuntimeException the passed exception if it is an instance of
 593:    * RuntimeException.
 594:    * 
 595:    * @specnote It is the same behavior, as in Suns implementations 1.4.0-1.5.0.
 596:    */
 597:   public RemoteException wrapException(Throwable ex)
 598:     throws RuntimeException
 599:   {
 600:     if (ex instanceof RuntimeException)
 601:       throw (RuntimeException) ex;
 602:     else if (ex instanceof Error)
 603:       return new ServerError(ex.getMessage(), (Error) ex);
 604:     else if (ex instanceof RemoteException)
 605:       return new ServerException(ex.getMessage(), (Exception) ex);
 606:     else if (ex instanceof SystemException)
 607:       return wrapException(mapSystemException((SystemException) ex));
 608:     else
 609:       return new UnexpectedException("Unexpected", (Exception) ex);
 610:   }
 611: 
 612:   /**
 613:    * Write abstract interface to the CORBA output stream. The write format is
 614:    * matching CORBA abstract interface. Remotes and CORBA objects are written as
 615:    * objects, other classes are supposed to be value types and are written as
 616:    * such. {@link Remote}s are processed as defined in
 617:    * {@link #writeRemoteObject}. The written data contains discriminator,
 618:    * defining, that was written. Another method that writes the same content is
 619:    * {@link org.omg.CORBA_2_3.portable.OutputStream#write_abstract_interface(java.lang.Object)}.
 620:    * 
 621:    * @param output a stream to write to, must be
 622:    * {@link org.omg.CORBA_2_3.portable.OutputStream}.
 623:    * 
 624:    * @param object an object to write, must be CORBA object, Remote
 625:    */
 626:   public void writeAbstractObject(OutputStream output, Object object)
 627:   {
 628:     ((org.omg.CORBA_2_3.portable.OutputStream) output).write_abstract_interface(object);
 629:   }
 630: 
 631:   /**
 632:    * Write the passed java object to the output stream in the form of the CORBA
 633:    * {@link Any}. This includes creating an writing the object {@link TypeCode}
 634:    * first. Such Any can be later read by a non-RMI-IIOP CORBA implementation
 635:    * and manipulated, for instance, by means, provided in
 636:    * {@link org.omg.DynamicAny.DynAny}. Depending from the passed value, this
 637:    * method writes CORBA object, value type or value box. For value types Null
 638:    * is written with the abstract interface, its typecode having repository id
 639:    * "IDL:omg.org/CORBA/AbstractBase:1.0" and the empty string name.
 640:    * 
 641:    * @param output the object to write.
 642:    * @param object the java object that must be written in the form of the CORBA
 643:    * {@link Any}.
 644:    */
 645:   public void writeAny(OutputStream output, Object object)
 646:   {
 647:     Any any = output.orb().create_any();
 648:     if (object == null)
 649:       {
 650:         GeneralTypeCode t = new GeneralTypeCode(TCKind.tk_abstract_interface);
 651:         t.setId("IDL:omg.org/CORBA/AbstractBase:1.0");
 652:         t.setName("");
 653:         any.type(t);
 654:         output.write_any(any);
 655:         return;
 656:       }
 657:     else if (object instanceof org.omg.CORBA.Object
 658:       && !(object instanceof Remote))
 659:       {
 660:         // Write as value type.
 661:         boolean inserted = ObjectCreator.insertWithHelper(any, object);
 662:         if (inserted)
 663:           {
 664:             output.write_any(any);
 665:             return;
 666:           }
 667:       }
 668: 
 669:     if (object instanceof org.omg.CORBA.Object)
 670:       writeAnyAsRemote(output, object);
 671:     else if (object instanceof Serializable)
 672:       {
 673:         any.insert_Value((Serializable) object);
 674:         output.write_any(any);
 675:       }
 676:     else
 677:       {
 678:         MARSHAL m = new MARSHAL(object.getClass().getName()
 679:           + " must be CORBA Object, Remote or Serializable");
 680:         m.minor = Minor.NonSerializable;
 681:         throw m;
 682:       }
 683:   }
 684: 
 685:   /**
 686:    * Write Any as for remote object.
 687:    */
 688:   void writeAnyAsRemote(OutputStream output, Object object)
 689:   {
 690:     GeneralTypeCode t = new GeneralTypeCode(TCKind.tk_objref);
 691:     t.setId(m_ValueHandler.getRMIRepositoryID(object.getClass()));
 692:     t.setName(object.getClass().getName());
 693: 
 694:     // Writing Any (typecode, followed by value).
 695:     output.write_TypeCode(t);
 696:     writeRemoteObject(output, object);
 697:   }
 698: 
 699:   /**
 700:    * Get the class name excluding the package name.
 701:    */
 702:   String getName(String n)
 703:   {
 704:     int p = n.lastIndexOf('.');
 705:     if (p < 0)
 706:       return n;
 707:     else
 708:       return n.substring(p + 1);
 709:   }
 710: 
 711:   /**
 712:    * Read Any from the input stream.
 713:    */
 714:   public Object readAny(InputStream input)
 715:   {
 716:     return input.read_any();
 717:   }
 718: 
 719:   /**
 720:    * Write the passed parameter to the output stream as CORBA object. If the
 721:    * parameter is an instance of Remote and not an instance of Stub, the method
 722:    * instantiates a suitable Tie, connects the parameter to this Tie and then
 723:    * connects that Tie to the ORB that is requested from the output stream. Then
 724:    * the object reference is written to the stream, making remote invocations
 725:    * possible. This method is used in write_value(..) method group in
 726:    * {@link org.omg.CORBA_2_3.portable.OutputStream} and also may be called
 727:    * directly from generated Stubs and Ties.
 728:    * 
 729:    * @param output a stream to write to, must be
 730:    * org.omg.CORBA_2_3.portable.OutputStream
 731:    * @param object an object to write.
 732:    */
 733:   public void writeRemoteObject(OutputStream an_output, Object object)
 734:   {
 735:     org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output;
 736:     if (object == null)
 737:       an_output.write_Object(null);
 738:     else if (isTieRequired(object))
 739:       {
 740:         // Find the interface that is implemented by the object and extends
 741:         // Remote.
 742:         Class fc = getExportedInterface(object);
 743:         exportTie(output, object, fc);
 744:       }
 745:     else if (object instanceof org.omg.CORBA.Object)
 746:       {
 747:         ensureOrbRunning(output);
 748:         an_output.write_Object((org.omg.CORBA.Object) object);
 749:       }
 750:     else if (object != null && object instanceof Serializable)
 751:       writeFields(an_output, (Serializable) object);
 752:   }
 753: