Source for gnu.javax.rmi.CORBA.RmiUtilities

   1: /* RmiUtilities.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.javax.rmi.CORBA;
  40: 
  41: import gnu.CORBA.OrbFunctional;
  42: import gnu.CORBA.Minor;
  43: import gnu.CORBA.Unexpected;
  44: import gnu.CORBA.CDR.Vio;
  45: import gnu.CORBA.CDR.gnuRuntime;
  46: import gnu.CORBA.CDR.gnuValueStream;
  47: import gnu.CORBA.CDR.HeadlessInput;
  48: 
  49: import org.omg.CORBA.MARSHAL;
  50: import org.omg.CORBA.StringValueHelper;
  51: import org.omg.CORBA.WStringValueHelper;
  52: import org.omg.CORBA.portable.Delegate;
  53: import org.omg.CORBA.portable.InputStream;
  54: import org.omg.CORBA.portable.ObjectImpl;
  55: import org.omg.CORBA.portable.OutputStream;
  56: import org.omg.CORBA.portable.ValueBase;
  57: import org.omg.PortableServer.POA;
  58: import org.omg.PortableServer.POAHelper;
  59: import org.omg.PortableServer.Servant;
  60: import org.omg.PortableServer.POAManagerPackage.State;
  61: import org.omg.SendingContext.RunTime;
  62: 
  63: import java.io.ByteArrayOutputStream;
  64: import java.io.DataOutputStream;
  65: import java.io.Externalizable;
  66: import java.io.IOException;
  67: import java.io.ObjectInputStream;
  68: import java.io.ObjectOutputStream;
  69: import java.io.Serializable;
  70: import java.lang.reflect.Field;
  71: import java.lang.reflect.Method;
  72: import java.lang.reflect.Modifier;
  73: import java.rmi.Remote;
  74: import java.security.MessageDigest;
  75: import java.util.Arrays;
  76: import java.util.Comparator;
  77: import java.util.Iterator;
  78: import java.util.TreeSet;
  79: import java.util.WeakHashMap;
  80: 
  81: import javax.rmi.PortableRemoteObject;
  82: import javax.rmi.CORBA.Stub;
  83: import javax.rmi.CORBA.Tie;
  84: import javax.rmi.CORBA.Util;
  85: 
  86: /**
  87:  * Defines methods that must be accessible in several derived classes.
  88:  * 
  89:  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
  90:  */
  91: public class RmiUtilities
  92: {
  93:   /**
  94:    * The currently used RMI-IIOP version format.
  95:    */
  96:   public static byte VERSION = 1;
  97: 
  98:   /**
  99:    * The non - writable class fields.
 100:    */
 101:   static final int NON_WRITABLE = Modifier.STATIC | Modifier.TRANSIENT;
 102: 
 103:   /**
 104:    * The standard String repository Id.
 105:    */
 106:   public static final String RMI_STRING_ID = StringValueHelper.id();
 107: 
 108:   /**
 109:    * The standard Class repository Id.
 110:    */
 111:   public static final String RMI_CLASS_ID = "RMI:javax.rmi.CORBA.ClassDesc:2BABDA04587ADCCC:CFBF02CF5294176B";
 112: 
 113:   /**
 114:    * The standard string array repository Id.
 115:    */
 116:   public static final String RMI_STRING_ARRAY_ID = "RMI:[Ljava.lang.String;:071DA8BE7F971128:A0F0A4387A3BB342";
 117: 
 118:   /**
 119:    * An instance of the wide string value helper for writing strings.
 120:    */
 121:   static WStringValueHelper wStringValueHelper = new WStringValueHelper();
 122: 
 123:   /**
 124:    * Set of serializable classes that have .writeObject and .readObject defined.
 125:    * Contains weak references to ensure that the classes will be unloadable.
 126:    */
 127:   WeakHashMap io_format = new WeakHashMap();
 128: 
 129:   /**
 130:    * The standard IO format with no .writeObject and .readObject defined.
 131:    */
 132:   static final Object STANDARD = new Object();
 133: 
 134:   /**
 135:    * The custom IO format with .writeObject and .readObject defined,
 136:    * defaultWriteObject called.
 137:    */
 138:   static final Object CUSTOM_DWO = new Object();
 139: 
 140:   /**
 141:    * The custom IO format with .writeObject and .readObject defined,
 142:    * defaultWriteObject has not been called.
 143:    */
 144:   static final Object CUSTOM_NO_DWO = new Object();
 145: 
 146:   /**
 147:    * The arguments for readObject.
 148:    */
 149:   static final Class[] READ_OBJECT_ARGS = new Class[] { ObjectInputStream.class };
 150: 
 151:   /**
 152:    * The arguments for writeObject.
 153:    */
 154:   static final Class[] WRITE_OBJECT_ARGS = new Class[] { ObjectOutputStream.class };
 155: 
 156:   /**
 157:    * The undocumented field that is heading the Sun's object data, written with
 158:    * writeObject.
 159:    */
 160:   static final int S_X = 16908034;
 161: 
 162:   /**
 163:    * Write all fields of the passed value.
 164:    */
 165:   void writeFields(OutputStream an_output, Serializable object)
 166:   {
 167:     org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output;
 168:     try
 169:       {
 170:         Class o_class = object.getClass();
 171:         Field[] fields = getWritableFields(o_class);
 172:         Field f;
 173: 
 174:         Class fc;
 175: 
 176:         for (int i = 0; i < fields.length; i++)
 177:           {
 178:             f = fields[i];
 179:             fc = f.getType();
 180:             Object v = f.get(object);
 181: 
 182:             if (fc == String.class)
 183:               {
 184:                 output.write_value((Serializable) v, wStringValueHelper);
 185:               }
 186:             else if (fc == int.class)
 187:               output.write_long(((Integer) v).intValue());
 188:             else if (fc == long.class)
 189:               output.write_longlong(((Number) v).longValue());
 190:             else if (fc == double.class)
 191:               output.write_double(((Number) v).doubleValue());
 192:             else if (fc == float.class)
 193:               output.write_float(((Number) v).floatValue());
 194:             else if (fc == boolean.class)
 195:               output.write_boolean(((Boolean) v).booleanValue());
 196:             else if (fc == short.class)
 197:               output.write_short(((Number) v).shortValue());
 198:             else if (fc == byte.class)
 199:               output.write_octet(((Number) v).byteValue());
 200:             else if (fc == char.class)
 201:               output.write_wchar(((Character) v).charValue());
 202:             else
 203:               {
 204:                 if (!fc.isInterface() && Remote.class.isAssignableFrom(fc))
 205:                   fc = getExportedInterface(fc);
 206:                 writeMember(output, v, fc);
 207:               }
 208:           }
 209:       }
 210:     catch (Exception ex)
 211:       {
 212:         MARSHAL m = new MARSHAL("Cannot write " + object);
 213:         m.minor = Minor.ValueFields;
 214:         m.initCause(ex);
 215:         throw m;
 216:       }
 217:   }
 218: 
 219:   /**
 220:    * Write a memeber (field) of the data structure.
 221:    */
 222:   void writeMember(org.omg.CORBA_2_3.portable.OutputStream output,
 223:     Object object, Class xClass)
 224:   {
 225:     if (output instanceof gnuValueStream)
 226:       {
 227:         gnuRuntime g = ((gnuValueStream) output).getRunTime();
 228:         // Reset the target as we are already beyond the critical point
 229:         // where is must have the value being written.
 230:         if (g != null)
 231:           g.target = null;
 232:       }
 233:     if (Serializable.class.isAssignableFrom(xClass)
 234:       || Remote.class.isAssignableFrom(xClass))
 235:       {
 236:         // Object handles null reference on its own.
 237:         if (org.omg.CORBA.Object.class.isAssignableFrom(xClass)
 238:           || Remote.class.isAssignableFrom(xClass))
 239:           {
 240:             if (object == null)
 241:               output.write_Object(null);
 242:             else if (isTieRequired(object))
 243:               exportTie(output, object, xClass);
 244:             else
 245:               writeValue(output, (Serializable) object);
 246:           }
 247:         else
 248:           output.write_value((Serializable) object, xClass);
 249:       }
 250:     else
 251:       {
 252:         MARSHAL m = new MARSHAL(xClass + " is not Serializable");
 253:         m.minor = Minor.NonSerializable;
 254:         throw m;
 255:       }
 256:   }
 257: 
 258:   /**
 259:    * Check if the object must be wrapped into Tie, connected to the ORB and then
 260:    * the corresponding Stub be written.
 261:    */
 262:   public boolean isTieRequired(Object object)
 263:   {
 264:     return object instanceof Remote && !(object instanceof Stub);
 265:   }
 266: 
 267:   /**
 268:    * Get the interface under that the class of this object must be exposed. The
 269:    * interface must be derived from Remote.
 270:    */
 271:   Class getExportedInterface(Object object)
 272:     throws MARSHAL
 273:   {
 274:     Class fc = null;
 275:     Class[] interfaces = object.getClass().getInterfaces();
 276:     for (int i = 0; i < interfaces.length; i++)
 277:       {
 278:         if (!Remote.class.equals(interfaces[i]))
 279:           if (Remote.class.isAssignableFrom(interfaces[i]))
 280:             {
 281:               if (fc == null)
 282:                 fc = interfaces[i];
 283:               else
 284:                 {
 285:                   MARSHAL m = new MARSHAL("Both " + fc + " and " + interfaces[i]
 286:                   + " extends Remote");
 287:                   m.minor = Minor.TargetConversion;
 288:                   throw m;
 289:                 }
 290:             }
 291:       }
 292:     if (fc == null)
 293:       {
 294:         MARSHAL m = new MARSHAL(object.getClass()
 295:         + " does not implement any interface, derived from Remote");
 296:         m.minor = Minor.TargetConversion;
 297:         throw m;
 298:       }
 299:     return fc;
 300:   }
 301: 
 302:   /**
 303:    * Get the persistent hash code for the given class, as defined by OMG
 304:    * standard. The inheritance, field names and types (but not the visibility)
 305:    * are taken into consideration as well as the presence of the writeObject
 306:    * method are taken into consideration. The class name and methods, if any,
 307:    * are not taken into consideration.
 308:    */
 309:   public static long getHashCode(Class c)
 310:   {
 311:     Class of = c.isArray() ? c.getComponentType() : null;
 312:     if (c.isArray()
 313:       && ((!Serializable.class.isAssignableFrom(of) || of.isPrimitive() || Remote.class.isAssignableFrom(of))))
 314:       return 0;
 315:     if (!Serializable.class.isAssignableFrom(c))
 316:       return 0;
 317:     try
 318:       {
 319:         ByteArrayOutputStream bout = new ByteArrayOutputStream();
 320:         DataOutputStream out = new DataOutputStream(bout);
 321: 
 322:         Class superClass = c.getSuperclass();
 323:         if (superClass != null)
 324:           out.writeLong(getHashCode(superClass));
 325: 
 326:         int writeObjectPresentCode;
 327:         try
 328:           {
 329:             c.getDeclaredMethod("writeObject",
 330:               new Class[] { ObjectOutputStream.class });
 331:             writeObjectPresentCode = 2; // Exists.
 332:           }
 333:         catch (NoSuchMethodException e)
 334:           {
 335:             writeObjectPresentCode = 1; // Missing.
 336:           }
 337:         out.writeInt(writeObjectPresentCode);
 338: 
 339:         Field[] fields = c.getDeclaredFields();
 340: 
 341:         Arrays.sort(fields, new Comparator()
 342:         {
 343:           public int compare(Object a, Object b)
 344:           {
 345:             Field fa = (Field) a;
 346:             Field fb = (Field) b;
 347:             return fa.getName().compareTo(fb.getName());
 348:           }
 349:         });
 350: 
 351:         Field f;
 352:         for (int i = 0; i < fields.length; i++)
 353:           {
 354:             f = fields[i];
 355:             if ((f.getModifiers() & NON_WRITABLE) == 0)
 356:               {
 357:                 out.writeUTF(f.getName());
 358:                 out.writeUTF(getDescriptor(f.getType()));
 359:               }
 360:           }
 361: 
 362:         out.flush();
 363:         out.close();
 364:         MessageDigest shaDigest;
 365:         try
 366:           {
 367:             shaDigest = MessageDigest.getInstance("SHA");
 368:           }
 369:         catch (Exception ex)
 370:           {
 371:             throw new InternalError("SHA digesting algorithm is not available");
 372:           }
 373: 
 374:         // Return the digest value to the calling
 375:         // method as an array of bytes.
 376:         byte[] sha = shaDigest.digest(bout.toByteArray());
 377: 
 378:         long hash = 0;
 379:         for (int i = 0; i < Math.min(8, sha.length); i++)
 380:           {
 381:             hash += (long) (sha[i] & 255) << (i * 8);
 382:           }
 383:         return hash;
 384:       }
 385:     catch (IOException ioex)
 386:       {
 387:         throw new Unexpected(ioex);
 388:       }
 389:   }
 390: 
 391:   /**
 392:    * Converts to hexadecimal string, supplementing leading zeros.
 393:    */
 394:   public static String toHex(long l)
 395:   {
 396:     StringBuffer b = new StringBuffer();
 397:     b.append(Long.toHexString(l).toUpperCase());
 398:     while (b.length() < 16)
 399:       b.insert(0, '0');
 400:     return b.toString();
 401:   }
 402: 
 403:   /**
 404:    * Returns a <code>String</code> representing the type-encoding of a class.
 405:    */
 406:   static String getDescriptor(Class type)
 407:   {
 408:     if (type.equals(boolean.class))
 409:       return "Z";
 410:     if (type.equals(byte.class))
 411:       return "B";
 412:     if (type.equals(short.class))
 413:       return "S";
 414:     if (type.equals(char.class))
 415:       return "C";
 416:     if (type.equals(int.class))
 417:       return "I";
 418:     if (type.equals(long.class))
 419:       return "J";
 420:     if (type.equals(float.class))
 421:       return "F";
 422:     if (type.equals(double.class))
 423:       return "D";
 424:     if (type.equals(void.class))
 425:       return "V";
 426:     else if (type.isArray())
 427:       {
 428:         StringBuffer l = new StringBuffer("[");
 429:         Class component = type.getComponentType();
 430: 
 431:         while (component.isArray())
 432:           {
 433:             l.append('[');
 434:             component = component.getComponentType();
 435:           }
 436: 
 437:         l.append('L');
 438:         l.append(component.getName().replace('.', '/'));
 439:         l.append(';');
 440:         return l.toString();
 441:       }
 442:     else
 443:       return "L" + type.getName().replace('.', '/') + ';';
 444:   }
 445: 
 446:   public static Field[] getWritableFields(Class c)
 447:   {
 448:     TreeSet set = new TreeSet(new Comparator()
 449:     {
 450:       public int compare(Object a, Object b)
 451:       {
 452:         return ((Field) a).getName().compareTo(((Field) b).getName());
 453:       }
 454:     });
 455: 
 456:     while (!c.equals(Object.class))
 457:       {
 458:         Field[] f = c.getDeclaredFields();
 459:         for (int i = 0; i < f.length; i++)
 460:           {
 461:             if ((f[i].getModifiers() & NON_WRITABLE) == 0)
 462:               {
 463:                 f[i].setAccessible(true);
 464:                 set.add(f[i]);
 465:               }
 466:           }
 467:         c = c.getSuperclass();
 468:       }
 469: 
 470:     Field[] r = new Field[set.size()];
 471:     int p = 0;
 472:     Iterator it = set.iterator();
 473:     while (it.hasNext())
 474:       {
 475:         r[p++] = (Field) it.next();
 476:       }
 477:     return r;
 478:   }
 479: 
 480:   /**
 481:    * The method is called for Remotes that are not Stubs. It is assumed, that
 482:    * the Remote is an implementation. The method searches for the suitable tie
 483:    * and, if found, exports it by creating and connecting the stub. Such export
 484:    * is supported since jdk 1.5.
 485:    */
 486:   void exportTie(org.omg.CORBA_2_3.portable.OutputStream output,
 487:     Object implementation, Class interfaceClass)
 488:   {
 489:     try
 490:       {
 491:         // Remote, but non - stub class (implementation)
 492:         // must be replaced by stub.
 493:         Tie t = Util.getTie((Remote) implementation);
 494:         if (t instanceof Servant)
 495:           {
 496:             POA rootPoa = POAHelper.narrow(output.orb().resolve_initial_references(
 497:               "RootPOA"));
 498:             org.omg.CORBA.Object co = rootPoa.servant_to_reference((Servant) t);
 499:             Stub stub = (Stub) PortableRemoteObject.narrow(co, interfaceClass);
 500:             writeRemoteObject(output, stub);
 501: 
 502:             if (rootPoa.the_POAManager().get_state().value() == State._HOLDING)
 503:               rootPoa.the_POAManager().activate();
 504:           }
 505:         else if (t instanceof org.omg.CORBA.Object)
 506:           {
 507:             org.omg.CORBA.Object co = (org.omg.CORBA.Object) t;
 508:             output.orb().connect(co);
 509: 
 510:             Stub stub = (Stub) PortableRemoteObject.narrow(co, interfaceClass);
 511:             writeRemoteObject(output, stub);
 512:           }
 513:       }
 514:     catch (Exception ex)
 515:       {
 516:         MARSHAL m = new MARSHAL("Unable to export " + implementation);
 517:         m.minor = Minor.TargetConversion;
 518:         m.initCause(ex);
 519:         throw m;
 520:       }
 521:   }
 522: 
 523:   /**
 524:    * Start the ORB, if it is not already runnning.
 525:    */
 526:   void ensureOrbRunning(org.omg.CORBA_2_3.portable.OutputStream output)
 527:   {
 528:     // Ensure ORB is running.
 529:     if (output.orb() instanceof OrbFunctional)
 530:       {
 531:         ((OrbFunctional) output.orb()).ensureRunning();
 532:       }
 533:   }
 534: 
 535:   /**
 536:    * Write data to the CORBA output stream. Writes the object contents only; the
 537:    * header must be already written. For object, containing objects, may be
 538:    * called recursively.
 539:    * 
 540:    * @param an_output a stream to write to, must be
 541:    * org.omg.CORBA_2_3.portable.OutputStream
 542:    * @param object an object to write.
 543:    */
 544:   public void writeRemoteObject(OutputStream an_output, Object object)
 545:   {
 546:     org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output;
 547: 
 548:     if (isTieRequired(object))
 549:       {
 550:         // Find the interface that is implemented by the object and extends
 551:         // Remote.
 552:         Class fc = getExportedInterface(object);
 553:         exportTie(output, object, fc);
 554:       }
 555:     else if (object instanceof org.omg.CORBA.Object)
 556:       {
 557:         ensureOrbRunning(output);
 558:         an_output.write_Object((org.omg.CORBA.Object) object);
 559:       }
 560:     else if (object != null && object instanceof Serializable)
 561:       writeFields(an_output, (Serializable) object);
 562:   }
 563: 
 564:   /**
 565:    * Write data to the CORBA output stream. Writes the object contents only; the
 566:    * header must be already written. For object, containing objects, may be
 567:    * called recursively.
 568:    * 
 569:    * @param an_output a stream to write to, must be
 570:    * org.omg.CORBA_2_3.portable.OutputStream
 571:    * @param object an object to write.
 572:    */
 573:   public void writeValue(OutputStream an_output, Serializable object)
 574:   {
 575:     org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output;
 576: 
 577:     if (isTieRequired(object))
 578:       {
 579:         // Find the interface that is implemented by the object and extends
 580:         // Remote.
 581:         Class fc = getExportedInterface(object);
 582:         exportTie(output, object, fc);
 583:       }
 584:     else if (object instanceof org.omg.CORBA.Object)
 585:       {
 586:         ensureOrbRunning(output);
 587:         an_output.write_Object((org.omg.CORBA.Object) object);
 588:       }
 589:     else if (object instanceof Externalizable)
 590:       {
 591:         try
 592:           {
 593:             ObjectOutputStream stream = new CorbaOutput(output, object,
 594:               this);
 595:             stream.write(VERSION);
 596:             ((Externalizable) object).writeExternal(stream);
 597:           }
 598:         catch (Exception ex)
 599:           {
 600:             MARSHAL m = new MARSHAL("writeExternal failed");
 601:             m.minor = Minor.Value;
 602:             m.initCause(ex);
 603:             throw m;
 604:           }
 605:       }
 606:     else if (object instanceof Serializable)
 607:       {
 608:         Object mode = null;
 609:         synchronized (io_format)
 610:           {
 611:             mode = io_format.get(object.getClass());
 612:             if (mode == STANDARD)
 613:               {
 614:                 writeFields(an_output, (Serializable) object);
 615:                 return;
 616:               }
 617:           }
 618:         try
 619:           {
 620:             Method m = object.getClass().getDeclaredMethod("writeObject",
 621:               WRITE_OBJECT_ARGS);
 622:             m.setAccessible(true); // May be private.
 623: 
 624:             try
 625:               {
 626:                 ObjectOutputStream stream = new CorbaOutput(output,
 627:                   object, this);
 628: 
 629:                 // Write version.
 630:                 stream.write(VERSION);
 631: 
 632:                 if (mode == CUSTOM_DWO)
 633:                   // Write true, supposing that the defaultWriteObject
 634:                   // has been called.
 635:                   stream.write(1);
 636:                 else if (mode == CUSTOM_NO_DWO)
 637:                   // Write false (has not been called)
 638:                   stream.write(0);
 639:                 else
 640:                   {
 641:                     // Measure.
 642:                     DefaultWriteObjectTester tester = new DefaultWriteObjectTester(object);
 643:                     m.invoke(object, new Object[] { tester });
 644: 
 645:                     synchronized (io_format)
 646:                       {
 647:                         io_format.put(object.getClass(),
 648:                           tester.dwo_called ? CUSTOM_DWO : CUSTOM_NO_DWO);
 649:                         stream.write(tester.dwo_called ? 1 : 0);
 650:                       }
 651:                   }
 652: 
 653:                 m.invoke(object, new Object[] { stream });
 654:                 stream.flush();
 655:               }
 656:             catch (Exception ex)
 657:               {
 658:                 MARSHAL mx = new MARSHAL(object.getClass().getName()
 659:                   + ".writeObject failed");
 660:                 mx.initCause(ex);
 661:                 throw mx;
 662:               }
 663:           }
 664:         catch (NoSuchMethodException e)
 665:           {
 666:             // Write in a standard way.
 667:             writeFields(an_output, (Serializable) object);
 668:             synchronized (io_format)
 669:               {
 670:                 io_format.put(object.getClass(), STANDARD);
 671:               }
 672:           }
 673:       }
 674:   }
 675: 
 676:   /**
 677:    * Read data from the CDR input stream. Reads the object contents only; the
 678:    * header must be already read (the repository id or ids ara passed). For
 679:    * object, containing objects, may be called recursively.
 680:    * 
 681:    * @param an_input the stream to read from, must be
 682:    * org.omg.CORBA_2_3.portable.InputStream
 683:    * @param object the instance of the object being read.
 684:    * @param id the repository Id from the stream in the case when single id was
 685:    * specified.
 686:    * @param ids the repository Ids from the stream in the case when multiple ids
 687:    * were specified.
 688:    * @param codebase the codebase, if it was included in the header of the value
 689:    * type. Null if not codebase was included.
 690:    * 
 691:    * @return the object, extracted from the stream.
 692:    */
 693:   /**
 694:    * Read value from the input stream in the case when the value is not
 695:    * Streamable or CustomMarshalled.
 696:    */
 697:   public Serializable readValue(InputStream in, int offset, Class clz,
 698:     String repositoryID, RunTime sender)
 699:   {
 700:     if (in instanceof HeadlessInput)
 701:       ((HeadlessInput) in).subsequentCalls = true;
 702: 
 703:     gnuRuntime g;
 704:     Serializable object = null;
 705: 
 706:     try
 707:       {
 708:         g = (gnuRuntime) sender;
 709:         object = g.target;
 710:       }
 711:     catch (ClassCastException e)
 712:       {
 713:         // Working with the other CORBA implementation.
 714:         g = null;
 715:       }
 716: 
 717:     org.omg.CORBA_2_3.portable.InputStream input = (org.omg.CORBA_2_3.portable.InputStream) in;
 718: 
 719:     if (Remote.class.isAssignableFrom(clz)
 720:       || ValueBase.class.isAssignableFrom(clz))
 721:       {
 722:         // Interface is narrowed into Stub.
 723:         if (clz.isInterface())
 724:           try
 725:             {
 726:               clz = Util.loadClass(
 727:                 PortableRemoteObjectDelegateImpl.getStubClassName(clz.getName()),
 728:                 null, clz.getClassLoader());
 729:             }
 730:           catch (ClassNotFoundException e)
 731:             {
 732:               MARSHAL m = new MARSHAL("Cannot get stub from interface "
 733:                 + clz.getClass().getName());
 734:               m.minor = Minor.TargetConversion;
 735:               m.initCause(e);
 736:               throw m;
 737:             }
 738: 
 739:         // Remote needs special handling.
 740:         if (ObjectImpl.class.isAssignableFrom(clz))
 741:           {
 742:             // First read CORBA object reference.
 743:             Object ro = input.read_Object();
 744: 
 745:             ObjectImpl obj = (ObjectImpl) ro;
 746:             if (obj == null)
 747:               return null;
 748: 
 749:             Delegate delegate = obj._get_delegate();
 750:             object = instantiate(offset, clz, g);
 751:             ((ObjectImpl) object)._set_delegate(delegate);
 752:           }
 753:         // The object - specific data follows.
 754:       }
 755:     else if (org.omg.CORBA.Object.class.isAssignableFrom(clz))
 756:       object = (Serializable) input.read_Object();
 757: 
 758:     if (object == null)
 759:       object = instantiate(offset, clz, g);
 760:     
 761:     // The sentence below prevents attempt to read the internal fields of the
 762:     // ObjectImpl (or RMI Stub) that might follow the object definition.
 763:     // Sun's jre 1.5 does not write this information. The stubs, generated
 764:     // by rmic, does not contain such fields.
 765:     if (object instanceof ObjectImpl)
 766:       return object;
 767: 
 768:     if (object instanceof Externalizable)
 769:       {
 770:         try
 771:           {
 772:             CorbaInput stream = new CorbaInput(input, object, this,
 773:               offset, repositoryID, g);
 774: 
 775:             byte version = stream.readByte();
 776:             if (version != 1)
 777:               throw new MARSHAL("Unsuported RMI-IIOP version " + version);
 778: 
 779:             ((Externalizable) object).readExternal(stream);
 780:           }
 781:         catch (Exception ex)
 782:           {
 783:             MARSHAL m = new MARSHAL("readExternal failed");
 784:             m.initCause(ex);
 785:             throw m;
 786:           }
 787:       }
 788:     else
 789:       {
 790:         Object mode = null;
 791:         synchronized (io_format)
 792:           {
 793:             mode = io_format.get(object.getClass());
 794:           }
 795: 
 796:         if (mode == STANDARD)
 797:           {
 798:             readFields(offset, repositoryID, object, input, g);
 799:           }
 800:         else
 801:           {
 802:             try
 803:               {
 804:                 Method m = object.getClass().getDeclaredMethod("readObject",
 805:                   READ_OBJECT_ARGS);
 806:                 try
 807:                   {
 808:                     m.setAccessible(true); // May be private.
 809: 
 810:                     CorbaInput stream = new CorbaInput(input,
 811:                       object, this, offset, repositoryID, g);
 812: 
 813:                     byte version = stream.readByte();
 814:                     if (version != 1)
 815:                       throw new MARSHAL("Unsuported RMI-IIOP version "
 816:                         + version);
 817: 
 818:                     // This would indicate is defaultWriteObject has been
 819:                     // called,
 820:                     // but the readObject method normally takes care about this.
 821:                     boolean dwo = stream.readByte() != 0;
 822: 
 823:                     m.invoke(object, new Object[] { stream });
 824:                     synchronized (io_format)
 825:                       {
 826:                         io_format.put(object.getClass(), dwo ? CUSTOM_DWO
 827:                           : CUSTOM_NO_DWO);
 828:                       }
 829:                   }
 830:                 catch (Exception ex)
 831:                   {
 832:                     ex.printStackTrace();
 833:                     MARSHAL mx = new MARSHAL(object.getClass().getName()
 834:                       + ".readObject failed");
 835:                     mx.initCause(ex);
 836:                     throw mx;
 837:                   }
 838:               }
 839:             catch (NoSuchMethodException e)
 840:               {
 841:                 // Read in a standard way.
 842:                 synchronized (io_format)
 843:                   {
 844:                     io_format.put(object.getClass(), STANDARD);
 845:                     readFields(offset, repositoryID, object, input, g);
 846:                   }
 847:               }
 848:           }
 849:       }
 850:     return object;
 851:   }
 852: 
 853:   /**
 854:    * Create an instance.
 855:    */
 856:   Serializable instantiate(int offset, Class clz, gnuRuntime g)
 857:     throws MARSHAL
 858:   {
 859:     Serializable object;
 860:     try
 861:       {
 862:         object = (Serializable) Vio.instantiateAnyWay(clz);
 863:         g.objectWritten(object, offset);
 864:       }
 865:     catch (Exception e)
 866:       {
 867:         MARSHAL m = new MARSHAL("Unable to instantiate " + clz);
 868:         m.minor = Minor.Instantiation;
 869:         m.initCause(e);
 870:         throw m;
 871:       }
 872:     return object;
 873:   }
 874: 
 875:   /**
 876:    * Read fields of the object.
 877:    */
 878:   void readFields(int offset, String repositoryID, Serializable object,
 879:     org.omg.CORBA_2_3.portable.InputStream input, gnuRuntime r)
 880:     throws MARSHAL
 881:   {
 882:     Field f = null;
 883:     Class o_class = object.getClass();
 884: 
 885:     try
 886:       {
 887:         // The returned field array must already be in canonical order.
 888:         Field[] fields = getWritableFields(o_class);
 889: 
 890:         Class fc;
 891: 
 892:         for (int i = 0; i < fields.length; i++)
 893:           {
 894:             // Full value type header expected ahead.
 895:             if (input instanceof HeadlessInput)
 896:               ((HeadlessInput) input).subsequentCalls = true;
 897: 
 898:             f = fields[i];
 899:             fc = f.getType();
 900: 
 901:             Object v;
 902: 
 903:             if (fc == String.class)
 904:               {
 905:                 v = input.read_value(wStringValueHelper);
 906:               }
 907:             else if (fc == int.class)
 908:               v = new Integer(input.read_long());
 909:             else if (fc == long.class)
 910:               v = new Long(input.read_longlong());
 911:             else if (fc == double.class)
 912:               v = new Double(input.read_double());
 913:             else if (fc == float.class)
 914:               v = new Float(input.read_float());
 915:             else if (fc == boolean.class)
 916:               v = input.read_boolean() ? Boolean.TRUE : Boolean.FALSE;
 917:             else if (fc == short.class)
 918:               v = new Short(input.read_short());
 919:             else if (fc == byte.class)
 920:               v = new Byte(input.read_octet());
 921:             else if (fc == char.class)
 922:               v = new Character(input.read_char());
 923:             else if (org.omg.CORBA.Object.class.isAssignableFrom(fc)
 924:               || Remote.class.isAssignableFrom(fc))
 925:               {
 926:                 v = readValue(input, offset, fc, null, r);
 927:               }
 928:             else
 929:               {
 930:                 v = Vio.read(input, fc);
 931:               }
 932: 
 933:             f.set(object, v);
 934:           }
 935:       }
 936:     catch (Exception ex)
 937:       {
 938:         MARSHAL m = new MARSHAL("Cannot read " + o_class.getName() + " field "
 939:           + f);
 940:         m.initCause(ex);
 941:         m.minor = Minor.ValueFields;
 942:         throw m;
 943:       }
 944:   }
 945: 
 946: }