Frames | No Frames |
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: