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