Source for gnu.CORBA.CDR.Vio

   1: /* Vio.java -- Value type IO operations.
   2:    Copyright (C) 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.CORBA.CDR;
  40: 
  41: import gnu.CORBA.Minor;
  42: import gnu.CORBA.ObjectCreator;
  43: 
  44: import org.omg.CORBA.CustomMarshal;
  45: import org.omg.CORBA.DataInputStream;
  46: import org.omg.CORBA.DataOutputStream;
  47: import org.omg.CORBA.MARSHAL;
  48: import org.omg.CORBA.NO_IMPLEMENT;
  49: import org.omg.CORBA.StringSeqHelper;
  50: import org.omg.CORBA.StringValueHelper;
  51: import org.omg.CORBA.SystemException;
  52: import org.omg.CORBA.WStringValueHelper;
  53: import org.omg.CORBA.portable.BoxedValueHelper;
  54: import org.omg.CORBA.portable.InputStream;
  55: import org.omg.CORBA.portable.OutputStream;
  56: import org.omg.CORBA.portable.Streamable;
  57: import org.omg.CORBA.portable.ValueFactory;
  58: 
  59: import java.io.IOException;
  60: import java.io.Serializable;
  61: import java.lang.reflect.Constructor;
  62: import java.lang.reflect.Modifier;
  63: import java.util.StringTokenizer;
  64: 
  65: import javax.rmi.CORBA.Util;
  66: import javax.rmi.CORBA.ValueHandler;
  67: 
  68: /**
  69:  * A specialised class for reading and writing the value types.
  70:  * 
  71:  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
  72:  */
  73: public abstract class Vio
  74: {
  75:   /**
  76:    * If true, wrap value type data into chunks. This decrease the performance,
  77:    * and is not required for interoperability with jdk 1.5, but is left in the
  78:    * implementation as the optional mode for solving possible interoperability
  79:    * problems with non-Sun CORBA implementations.
  80:    * 
  81:    * The current implementation would accept both single chunk or multiple
  82:    * chunks, but will always send a single chunk (if true) or unchunked data (if
  83:    * false).
  84:    */
  85:   public static boolean USE_CHUNKING = false;
  86: 
  87:   /**
  88:    * The first field in the value record. The last octet may contain additional
  89:    * flags (vf_CODEBASE, vf_ID and vf_MULTIPLE_IDS). The tag value is different
  90:    * for the indirections (vt_INDIRECTION) and nulls (vt_NULL).
  91:    */
  92:   public static final int vt_VALUE_TAG = 0x7fffff00;
  93: 
  94:   /**
  95:    * The value tag flag, indicating that the codebase URL is present in the
  96:    * value tag record.
  97:    */
  98:   public static final int vf_CODEBASE = 0x1;
  99: 
 100:   /**
 101:    * The value tag flag, indicating that a single repository id is present in
 102:    * the value tag record.
 103:    */
 104:   public static final int vf_ID = 0x2;
 105: 
 106:   /**
 107:    * The value tag flag, indicating, that there are multiple repository ids
 108:    * present in the record. If this flag is set, the flag vf_ID must also be
 109:    * set, resulting the value of the least significant byte 0x6.
 110:    */
 111:   public static final int vf_MULTIPLE_IDS = 0x4;
 112: 
 113:   /**
 114:    * The value tag flag, indicating the presence of chunking. Each chunk is
 115:    * preceeded by a positive int, indicating the number of bytes in the chunk. A
 116:    * sequence of chunks is terminated by a non positive int.
 117:    */
 118:   public static final int vf_CHUNKING = 0x8;
 119: 
 120:   /**
 121:    * The indirection tag value. Such tag must be followed by the CORBA long,
 122:    * indicating the offset in the CORBA message, where the indirected
 123:    * information is present. This offset is assumed zero at the position where
 124:    * the mentioned CORBA long starts and can refer both forward (positive
 125:    * values) and backward (negative values).
 126:    */
 127:   public static final int vt_INDIRECTION = 0xffffffff;
 128: 
 129:   /**
 130:    * This tag value means that the value object being transferred is equal to
 131:    * null.
 132:    */
 133:   public static final int vt_NULL = 0x0;
 134: 
 135:   /**
 136:    * The size of CORBA long (java int).
 137:    */
 138:   static final int INT_SIZE = 4;
 139: 
 140:   /**
 141:    * The String value helper (one instance is sufficient).
 142:    */
 143:   public static final WStringValueHelper m_StringValueHelper = new WStringValueHelper();
 144: 
 145:   /**
 146:    * An instance of the value handler.
 147:    */
 148:   static ValueHandler handler = Util.createValueHandler();
 149: 
 150:   /**
 151:    * Read the value base from the given input stream. Determines the required
 152:    * class from the repository id. This includes operations that are not
 153:    * required when an unitialised instance or at least class of the value type
 154:    * is known. Hence it may be faster to use the alternative methods,
 155:    * read(InputStream, Class) or read(InputStream, Serializable).
 156:    * 
 157:    * @param input a stream to read from.
 158:    * 
 159:    * @return the loaded value.
 160:    * 
 161:    * @throws MARSHAL if the reading has failed due any reason.
 162:    */
 163:   public static Serializable read(InputStream input)
 164:   {
 165:     return read(input, (String) null);
 166:   }
 167: 
 168:   /**
 169:    * Read the value base from the given input stream. Determines the required
 170:    * class from the repository id. This includes operations that are not
 171:    * required when an unitialised instance or at least class of the value type
 172:    * is known. Hence it may be faster to use the alternative methods,
 173:    * read(InputStream, Class) or read(InputStream, Serializable).
 174:    * 
 175:    * @param input a stream to read from.
 176:    * @param repository_id a repository id of the object being read, may be null.
 177:    * 
 178:    * @return the loaded value.
 179:    * 
 180:    * @throws MARSHAL if the reading has failed due any reason.
 181:    */
 182:   public static Serializable read(InputStream input, String repository_id)
 183:   {
 184:     try
 185:       {
 186:         final int position = getCurrentPosition(input);
 187:         // We may need to jump back if the value is read via value factory.
 188:         input.mark(512);
 189: 
 190:         int value_tag = input.read_long();
 191:         checkTag(value_tag);
 192: 
 193:         String codebase = null;
 194:         String[] ids = null;
 195:         String id = repository_id;
 196: 
 197:         // Check for the agreed null value.
 198:         if (value_tag == vt_NULL)
 199:           return null;
 200:         else if (value_tag == vt_INDIRECTION)
 201:           return readIndirection(input);
 202:         else
 203:           {
 204:             // Read the value.
 205:             if ((value_tag & vf_CODEBASE) != 0)
 206:               {
 207:                 // The codebase is present. The codebase is a space
 208:                 // separated list of URLs from where the implementing
 209:                 // code can be downloaded.
 210:                 codebase = read_string(input);
 211:               }
 212: 
 213:             if ((value_tag & vf_MULTIPLE_IDS) != 0)
 214:               {
 215:                 // Multiple supported repository ids are present.
 216:                 ids = read_string_array(input);
 217:               }
 218:             else if ((value_tag & vf_ID) != 0)
 219:               {
 220:                 // Single supported repository id is present.
 221:                 id = read_string(input);
 222:               }
 223:           }
 224: 
 225:         BoxedValueHelper helper = getHelper(null, id);
 226:         // The existing implementing object.
 227:         java.lang.Object ox = null;
 228: 
 229:         if (helper != null)
 230:           ox = null; // Helper will care about the instantiating.
 231:         else if (id.equals(WStringValueHelper.id()))
 232:           helper = m_StringValueHelper;
 233:         else
 234:           ox = createInstance(id, ids, codebase);
 235:         return (Serializable) read_instance(input, position, ox, value_tag,
 236:           helper, id, ids, codebase);
 237:       }
 238:     catch (Exception ex)
 239:       {
 240:         MARSHAL m = new MARSHAL();
 241:         m.minor = Minor.Value;        
 242:         m.initCause(ex);
 243:         throw m;
 244:       }
 245:   }
 246: 
 247:   /**
 248:    * Read the value base from the given input stream when the value base class
 249:    * is available. Hence there is no need to guess it from the repository id.
 250:    * 
 251:    * @param input a stream to read from.
 252:    * @param value_class the class of the value being read.
 253:    * 
 254:    * @return the loaded value.
 255:    * 
 256:    * @throws MARSHAL if the reading has failed due any reason.
 257:    */
 258:   public static Serializable read(InputStream input, Class value_class)
 259:   {
 260:     final int position = getCurrentPosition(input);
 261: 
 262:     String id = null;
 263:     String[] ids = null;
 264:     String codebase = null;
 265: 
 266:     try
 267:       {
 268:         int value_tag = input.read_long();
 269:         checkTag(value_tag);
 270: 
 271:         // Check for the agreed null value.
 272:         if (value_tag == vt_NULL)
 273:           return null;
 274:         else if (value_tag == vt_INDIRECTION)
 275:           return readIndirection(input);
 276:         else
 277:           {
 278:             // Read the value.
 279:             if ((value_tag & vf_CODEBASE) != 0)
 280:               {
 281:                 // The codebase is present.
 282:                 codebase = read_string(input);
 283:               }
 284: 
 285:             if ((value_tag & vf_MULTIPLE_IDS) != 0)
 286:               {
 287:                 // Multiple supported repository ids are present.
 288:                 ids = read_string_array(input);
 289:               }
 290:             else if ((value_tag & vf_ID) != 0)
 291:               {
 292:                 // Single supported repository id is present.
 293:                 id = read_string(input);
 294:               }
 295:           }
 296: 
 297:         BoxedValueHelper vHelper = id != null ? getHelper(value_class, id)
 298:           : getHelper(value_class, ids);
 299: 
 300:         java.lang.Object ox;
 301: 
 302:         if (vHelper == null)
 303:           {
 304:             try
 305:               {
 306:                 ox = createInstance(id, ids, codebase);
 307:               }
 308:             catch (Exception e)
 309:               {
 310:                 ox = null;
 311:               }
 312: 
 313:             if (ox != null)
 314:               {
 315:                 if (value_class != null
 316:                   && !value_class.isAssignableFrom(ox.getClass()))
 317:                   {
 318:                     MARSHAL m = new MARSHAL(ox.getClass() + " is not a "
 319:                     + value_class.getName());
 320:                     m.minor = Minor.ClassCast;
 321:                     throw m;
 322:                   }
 323:               }
 324:           }
 325:         else
 326:           ox = null;
 327: 
 328:         ox = read_instance(input, position, ox, value_tag, vHelper, id, ids,
 329:           codebase);
 330:         return (Serializable) ox;
 331:       }
 332:     catch (MARSHAL m)
 333:       {
 334:         throw m;
 335:       }
 336:     catch (SystemException sysEx)
 337:       {
 338:         // OK.
 339:         throw sysEx;
 340:       }
 341:     catch (Exception ex)
 342:       {
 343:         MARSHAL m = new MARSHAL("Cant read " + value_class);
 344:         m.minor = Minor.Value;
 345:         m.initCause(ex);
 346:         throw m;
 347:       }
 348:   }
 349: 
 350:   /**
 351:    * Read the value base from the given input stream when the unitialised
 352:    * instance is available. Hence there is no need to guess the class from the
 353:    * repository id and then to instantiate an instance.
 354:    * 
 355:    * @param input a stream to read from.
 356:    * 
 357:    * @param value_instance an pre-created instance of the value. If the helper
 358:    * is not null, this parameter is ignored an should be null.
 359:    * 
 360:    * @param helper a helper to create an instance and read the object- specific
 361:    * part of the record. If the value_instance is used instead, this parameter
 362:    * should be null.
 363:    * 
 364:    * @return the loaded value.
 365:    * 
 366:    * @throws MARSHAL if the reading has failed due any reason.
 367:    */
 368:   public static Object read(InputStream input, Object value_instance,
 369:     BoxedValueHelper helper)
 370:   {
 371:     final int position = getCurrentPosition(input);
 372: 
 373:     String id = null;
 374:     String[] ids = null;
 375:     String codebase = null;
 376: 
 377:     try
 378:       {
 379:         int value_tag = input.read_long();
 380:         checkTag(value_tag);
 381: 
 382:         // Check for the agreed null value.
 383:         if (value_tag == vt_NULL)
 384:           return null;
 385:         else if (value_tag == vt_INDIRECTION)
 386:           return readIndirection(input);
 387:         else
 388:           {
 389:             // Read the value.
 390:             if ((value_tag & vf_CODEBASE) != 0)
 391:               {
 392:                 // The codebase is present.
 393:                 codebase = read_string(input);
 394:               }
 395: 
 396:             if ((value_tag & vf_MULTIPLE_IDS) != 0)
 397:               {
 398:                 // Multiple supported repository ids are present.
 399:                 ids = read_string_array(input);
 400:               }
 401:             else if ((value_tag & vf_ID) != 0)
 402:               {
 403:                 // Single supported repository id is present.
 404:                 id = read_string(input);
 405:               }
 406:           }
 407: 
 408:         Class value_class = value_instance == null ? null
 409:           : value_instance.getClass();
 410: 
 411:         if (helper == null)
 412:           helper = id != null ? getHelper(value_class, id) : getHelper(
 413:             value_class, ids);
 414: 
 415:         value_instance = read_instance(input, position, value_instance,
 416:           value_tag, helper, id, ids, codebase);
 417:         return value_instance;
 418:       }
 419:     catch (Exception ex)
 420:       {
 421:         MARSHAL m = new MARSHAL();
 422:         m.minor = Minor.Value;
 423:         m.initCause(ex);
 424:         throw m;
 425:       }
 426:   }
 427: 
 428:   /**
 429:    * Read using provided boxed value helper. This method expects the full value
 430:    * type header, followed by contents, that are delegated to the provided
 431:    * helper. It handles null.
 432:    * 
 433:    * @param input the stream to read from.
 434:    * @param helper the helper that reads the type-specific part of the content.
 435:    * 
 436:    * @return the value, created by the helper, or null if the header indicates
 437:    * that null was previously written.
 438:    */
 439:   public static Serializable read(InputStream input, BoxedValueHelper helper)
 440:   {
 441:     return (Serializable) read(input, null, helper);
 442:   }
 443: 
 444:   /**
 445:    * Fill in the instance fields by the data from the input stream. The method
 446:    * assumes that the value header, if any, is already behind. The information
 447:    * from the stream is stored into the passed ox parameter.
 448:    * 
 449:    * @param input an input stream to read from.
 450:    * 
 451:    * @param value a pre-instantiated value type object, must be either
 452:    * Streamable or CustomMarshal. If the helper is used, this parameter is
 453:    * ignored and should be null.
 454:    * 
 455:    * @param value_tag the tag that must be read previously.
 456:    * @param helper the helper for read object specific part; may be null to read
 457:    * in using other methods.
 458:    * 
 459:    * @return the value that was read.
 460:    */
 461:   static Object read_instance(InputStream input, final int position,
 462:     Object value, int value_tag, BoxedValueHelper helper, String id,
 463:     String[] ids, String codebase)
 464:   {
 465:     if (helper != m_StringValueHelper && id != null)
 466:       if (id.equals(StringValueHelper.id()))
 467:         {
 468:           value = null;
 469:           helper = m_StringValueHelper;
 470:         }
 471: 
 472:     try
 473:       {
 474:         if ((value_tag & vf_CHUNKING) != 0)
 475:           {
 476:             BufferedCdrOutput output = createBuffer(input, 1024);
 477:             // Read the current (not a nested one) value in this spec case.
 478:             readNestedValue(value_tag, input, output, -1);
 479:             BufferredCdrInput ci = new BufferredCdrInput(output.buffer.getBuffer());
 480:             ci.setRunTime(output.getRunTime());
 481: 
 482:             input = new HeadlessInput(ci, input);
 483:           }
 484:         else
 485:           {
 486:             if (input instanceof BufferredCdrInput)
 487:               {
 488:                 // Highly probable case.
 489:                 input = new HeadlessInput((BufferredCdrInput) input, null);
 490:               }
 491:             else if (input instanceof HeadlessInput)
 492:               {
 493:                 // There is no need to instantiate one more HeadlessInput
 494:                 // as we can just reset.
 495:                 ((HeadlessInput) input).subsequentCalls = false;
 496:               }
 497:             else
 498:               {
 499:                 BufferedCdrOutput bout = new BufferedCdrOutput();
 500:                 int c;
 501:                 while ((c = input.read()) >= 0)
 502:                   bout.write((byte) c);
 503:                 input = new HeadlessInput(
 504:                   (BufferredCdrInput) bout.create_input_stream(), input);
 505:               }
 506:           }
 507:       }
 508:     catch (IOException ex)
 509:       {
 510:         MARSHAL m = new MARSHAL("Unable to read chunks");
 511:         m.minor = Minor.Value;
 512:         m.initCause(ex);
 513:         throw m;
 514:       }
 515: 
 516:     return readValue(input, position, value, helper, id, ids, codebase);
 517:   }
 518: 
 519:   /**
 520:    * Create a buffer, inheriting critical settings from the passed input stream.
 521:    */
 522:   private static BufferedCdrOutput createBuffer(InputStream input, int proposed_size)
 523:   {
 524:     BufferedCdrOutput bout;
 525:     bout = new BufferedCdrOutput(2 * proposed_size + 256);
 526: 
 527:     if (input instanceof BufferredCdrInput)
 528:       {
 529:         BufferredCdrInput in = (BufferredCdrInput) input;
 530:         bout.setBigEndian(in.isBigEndian());
 531:       }
 532: 
 533:     if (input instanceof gnuValueStream)
 534:       bout.setRunTime(((gnuValueStream) input).getRunTime());
 535:     else
 536:       bout.setRunTime(new gnuRuntime(null, null));
 537:     return bout;
 538:   }
 539: 
 540:   /**
 541:    * Read the chunked nested value from the given input stream, transferring the
 542:    * contents to the given output stream.
 543:    * 
 544:    * @param value_tag the value tag of the value being read.
 545:    * @param input the input stream from where the remainder of the nested value
 546:    * must be read.
 547:    * @param output the output stream where the unchunked nested value must be
 548:    * copied.
 549:    * 
 550:    * @return the tag that ended the nested value.
 551:    */
 552:   public static int readNestedValue(int value_tag, InputStream input,
 553:     BufferedCdrOutput output, int level)
 554:     throws IOException
 555:   {
 556:     String id = null;
 557:     if (level < -1)
 558:       {
 559:         // For the first level, this information is already behind.
 560:         output.write_long(value_tag - vf_CHUNKING);
 561: 
 562:         // The nested value should be aways chunked.
 563:         if ((value_tag & vf_CHUNKING) == 0)
 564:           {
 565:             MARSHAL m = new MARSHAL("readNestedValue: must be chunked");
 566:             m.minor = Minor.Chunks;
 567:             throw m;
 568:           }
 569:         else if (value_tag == vt_NULL)
 570:           {
 571:             MARSHAL m = new MARSHAL("readNestedValue: nul");
 572:             m.minor = Minor.Chunks;
 573:             throw m;
 574:           }
 575:         else if (value_tag == vt_INDIRECTION)
 576:           {
 577:             MARSHAL m = new MARSHAL("readNestedValue: indirection");
 578:             m.minor = Minor.Chunks;
 579:             throw m;
 580:           }
 581:         else
 582:           {
 583:             // Read the value.
 584:             if ((value_tag & vf_CODEBASE) != 0)
 585:               {
 586:                 String codebase = read_string(input);
 587:                 write_string(output, codebase);
 588:               }
 589: 
 590:             if ((value_tag & vf_MULTIPLE_IDS) != 0)
 591:               {
 592:                 // Multiple supported repository ids are present.
 593:                 String[] ids = read_string_array(input);
 594:                 id = ids[0];
 595:                 write_string_array(output, ids);
 596:               }
 597:             else if ((value_tag & vf_ID) != 0)
 598:               {
 599:                 id = read_string(input);
 600:                 write_string(output, id);
 601:               }
 602:           }
 603:       }
 604: 
 605:     int n = -1;
 606: 
 607:     // Read all chunks.
 608:     int chunk_size;
 609: 
 610:     byte[] r = null;
 611: 
 612:     while (true)
 613:       {
 614:         // Read the size of the next chunk or it may also be the
 615:         // header of the nested value.
 616:         chunk_size = input.read_long();
 617: 
 618:         // End of chunk terminator.
 619:         if (chunk_size < 0 && chunk_size >= level)
 620:           return chunk_size;
 621:         else if (chunk_size >= 0x7FFFFF00)
 622:           {
 623:             int onInput = getCurrentPosition(input) - 4;
 624:             int onOutput = output.getPosition();
 625:             output.getRunTime().redirect(onInput, onOutput);
 626:             // Value over 0x7FFFFF00 indicates that the nested value
 627:             // starts here. Read the nested value, storing it into the output.
 628:             // First parameter is actually the value tag.
 629:             chunk_size = readNestedValue(chunk_size, input, output, level - 1);
 630:             if (chunk_size < 0 && chunk_size >= level)
 631:               return chunk_size;
 632:           }
 633:         else
 634:           {
 635:             // The chunk follows.
 636:             if (r == null || r.length < chunk_size)
 637:               r = new byte[chunk_size + 256];
 638: 
 639:             n = 0;
 640:             reading: while (n < chunk_size)
 641:               n += input.read(r, n, chunk_size - n);
 642:             output.write(r, 0, n);
 643:           }
 644:       }
 645:   }
 646: 
 647:   /**
 648:    * Read the value (the header must be behind).
 649:    */
 650:   public static Serializable readValue(InputStream input, final int position,
 651:     Object value, BoxedValueHelper helper, String id, String[] ids,
 652:     String codebase)
 653:   {
 654:     gnuRuntime g;
 655:     gnuValueStream c = ((gnuValueStream) input);
 656:     if (c.getRunTime() == null)
 657:       {
 658:         g = new gnuRuntime(codebase, value);
 659:         c.setRunTime(g);
 660:       }
 661:     else
 662:       {
 663:         g = c.getRunTime();
 664:         g.addCodeBase(codebase);
 665:         g.target = (Serializable) value;
 666:       }
 667:     if (value != null)
 668:       g.objectWritten(value, position);
 669: 
 670:     if (input instanceof HeadlessInput)
 671:       ((HeadlessInput) input).subsequentCalls = false;
 672: 
 673:     boolean ok = true;
 674: 
 675:     // The user-defined io operations are implemented.
 676:     if (value instanceof CustomMarshal)
 677:       {
 678:         CustomMarshal marsh = (CustomMarshal) value;
 679:         marsh.unmarshal((DataInputStream) input);
 680:       }
 681:     else
 682:     // The IDL-generated io operations are implemented.
 683:     if (value instanceof Streamable)
 684:       {
 685:         ((Streamable) value)._read(input);
 686:       }
 687:     else if (helper != null)
 688:       {
 689:         // If helper is non-null the value should normally be null.
 690:         value = helper.read_value(input);
 691:         g.objectWritten(value, position);
 692:       }
 693:     else
 694:       {
 695:         ok = false;
 696:         ValueFactory factory = null;
 697:         org.omg.CORBA_2_3.ORB orb = (org.omg.CORBA_2_3.ORB) input.orb();
 698: 
 699:         if (id != null)
 700:           factory = orb.lookup_value_factory(id);
 701: 
 702:         if (factory == null && ids != null)
 703:           {
 704:             for (int i = 0; i < ids.length && factory == null; i++)
 705:               {
 706:                 factory = orb.lookup_value_factory(ids[i]);
 707:               }
 708:           }
 709: 
 710:         if (factory != null)
 711:           {
 712:             value = factory.read_value((org.omg.CORBA_2_3.portable.InputStream) input);
 713:             ok = true;
 714:           }
 715:       }
 716: 
 717:     if (!ok && value instanceof Serializable)
 718:     // Delegate to ValueHandler
 719:       {
 720:         if (ids != null && ids.length > 0)
 721:           id = ids[0];
 722: 
 723:         value = handler.readValue(input, position, value.getClass(), id, g);
 724:         ok = true;
 725:       }
 726: 
 727:     if (!ok)
 728:       {
 729:         if (value != null)
 730:           {
 731:             MARSHAL m = new MARSHAL(value.getClass().getName()
 732:             + " must be Streamable, CustomMarshal or Serializable");
 733:             m.minor = Minor.UnsupportedValue;
 734:             throw m;
 735:           }
 736:         else
 737:           {
 738:             MARSHAL m = new MARSHAL("Unable to instantiate " + id + ":" + list(ids)
 739:             + " helper " + helper);
 740:             m.minor = Minor.UnsupportedValue;
 741:             throw m;
 742:           }
 743:       }
 744:     else
 745:       return (Serializable) value;
 746:   }
 747: 
 748:   /**
 749:    * Conveniency method to list ids in exception reports.
 750:    */
 751:   static String list(String[] s)
 752:   {
 753:     if (s == null)
 754:       return "null";
 755:     else
 756:       {
 757:         StringBuffer b = new StringBuffer("{");
 758:         for (int i = 0; i < s.length; i++)
 759:           {
 760:             b.append(s[i]);
 761:             b.append(" ");
 762:           }
 763:         b.append("}");
 764:         return b.toString();
 765:       }
 766:   }
 767: 
 768:   /**
 769:    * Write the value base into the given stream.
 770:    * 
 771:    * @param output a stream to write to.
 772:    * 
 773:    * @param value a value type object, must be either Streamable or
 774:    * CustomMarshal.
 775:    * 
 776:    * @throws MARSHAL if the writing failed due any reason.
 777:    */
 778:   public static void write(OutputStream output, Serializable value)
 779:   {
 780:     // Write null if this is a null value.
 781:     if (value == null)
 782:       output.write_long(vt_NULL);
 783:     else if (value instanceof String)
 784:       write(output, value, m_StringValueHelper);
 785:     else
 786:       write(output, value, value.getClass());
 787:   }
 788: 
 789:   /**
 790:    * Write the value base into the given stream, stating that it is an instance
 791:    * of the given class.
 792:    * 
 793:    * @param output a stream to write to.
 794:    * 
 795:    * @param value a value to write.
 796:    * 
 797:    * @throws MARSHAL if the writing failed due any reason.
 798:    */
 799:   public static void write(OutputStream output, Serializable value,
 800:     Class substitute)
 801:   {
 802:     // Write null if this is a null value.
 803:     if (value == null)
 804:       output.write_long(vt_NULL);
 805:     else if (value instanceof String || substitute == String.class)
 806:       writeString(output, value);
 807:     else
 808:       {
 809:         String vId = ObjectCreator.getRepositoryId(value.getClass());
 810:         if (substitute == null || value.getClass().equals(substitute))
 811:           write_instance(output, value, vId, getHelper(value.getClass(), vId));
 812:         else
 813:           {
 814:             String vC = ObjectCreator.getRepositoryId(substitute);
 815:             String[] ids = new String[] { vId, vC };
 816:             BoxedValueHelper h = getHelper(substitute.getClass(), ids);
 817:             // If the helper is available, it is also responsible for
 818:             // providing the repository Id. Otherwise, write both
 819:             // ids.
 820:             if (h == null)
 821:               write_instance(output, value, ids, null);
 822:             else
 823:               write_instance(output, value, h.get_id(), null);
 824:           }
 825:       }
 826:   }
 827: 
 828:   /**
 829:    * Write the value base into the given stream, supplementing it with an array
 830:    * of the provided repository ids plus the repository id, derived from the
 831:    * passed value.
 832:    * 
 833:    * @param output a stream to write to.
 834:    * 
 835:    * @param value a value to write.
 836:    * 
 837:    * @throws MARSHAL if the writing failed due any reason.
 838:    */
 839:   public static void write(OutputStream output, Serializable value,
 840:     String[] multiple_ids)
 841:   {
 842:     // Write null if this is a null value.
 843:     if (value == null)
 844:       output.write_long(vt_NULL);
 845:     else
 846:       {
 847:         String[] ids = new String[multiple_ids.length + 1];
 848:         ids[0] = ObjectCreator.getRepositoryId(value.getClass());
 849:         System.arraycopy(multiple_ids, 0, ids, 1, multiple_ids.length);
 850:         BoxedValueHelper h = getHelper(value.getClass(), ids);
 851:         write_instance(output, value, ids, h);
 852:       }
 853:   }
 854: 
 855:   /**
 856:    * Write value when its repository Id is explicitly given. Only this Id is
 857:    * written, the type of value is not taken into consideration.
 858:    * 
 859:    * @param output an output stream to write into.
 860:    * @param value a value to write.
 861:    * @param id a value repository id.
 862:    */
 863:   public static void write(OutputStream output, Serializable value, String id)
 864:   {
 865:     if (value == null)
 866:       output.write_long(vt_NULL);
 867:     else
 868:       write_instance(output, value, id, getHelper(value.getClass(), id));
 869:   }
 870: 
 871:   /**
 872:    * Write standard value type header, followed by contents, produced by the
 873:    * boxed value helper.
 874:    * 
 875:    * @param output the stream to write to.
 876:    * @param value the value to write, can be null.
 877:    * @param helper the helper that writes the value content if it is not null
 878:    * (must be provided for this method).
 879:    */
 880:   public static void write(OutputStream output, Serializable value,
 881:     BoxedValueHelper helper)
 882:   {
 883:     if (helper == null)
 884:       throw new AssertionError("Helper must be provided");
 885:     if (value == null)
 886:       output.write_long(vt_NULL);
 887:     else
 888:       write_instance(output, value, helper.get_id(), helper);
 889:   }
 890: 
 891:   /**
 892:    * Write the parameter that is surely a string and not null.
 893:    */
 894:   private static void writeString(OutputStream output, Serializable string)
 895:   {
 896:     write_instance(output, string, m_StringValueHelper.get_id(),
 897:       m_StringValueHelper);
 898:   }
 899: 
 900:   /**
 901:    * Write value when its repository Id is explicitly given. Does not handle
 902:    * null.
 903:    * 
 904:    * @param output an output stream to write into.
 905:    * @param value a value to write.
 906:    * @param ids a value repository id (can be either single string or string
 907:    * array).
 908:    * @param helper a helper, writing object - specifical part. Can be null if
 909:    * the value should be written using other methods.
 910:    */
 911:   static void write_instance(OutputStream output, Serializable value,
 912:     Object ids, BoxedValueHelper helper)
 913:   {
 914:     gnuValueStream rout = null;
 915:     gnuRuntime runtime = null;
 916: 
 917:     try
 918:       {
 919:         if (output instanceof gnuValueStream)
 920:           {
 921:             int position;
 922:             rout = (gnuValueStream) output;
 923:             runtime = rout.getRunTime();
 924: 
 925:             if (runtime == null)
 926:               {
 927:                 runtime = new gnuRuntime(null, value);
 928:                 rout.setRunTime(runtime);
 929:                 rout.getRunTime().objectWritten(value,
 930:                   position = rout.getPosition());
 931:               }
 932:             else if (runtime.target == value)
 933:               {
 934:                 if (!writeSelf(output, value))
 935:                   throw new InternalError("Recursive helper call for "
 936:                     + value.getClass().getName());
 937:                 return;
 938:               }
 939:             else
 940:               {
 941:                 position = runtime.isWrittenAt(value);
 942:                 if (position >= 0)
 943:                   {
 944:                     // The object was already written.
 945:                     output.write_long(vt_INDIRECTION);
 946:                     output.write_long(position - rout.getPosition());
 947:                     // Replacing object write data by indirection reference.
 948:                     return;
 949:                   }
 950:                 else
 951:                   {
 952:                     runtime.objectWritten(value, position = rout.getPosition());
 953:                   }
 954:               }
 955:           }
 956: 
 957:         int value_tag = vt_VALUE_TAG;
 958: 
 959:         if (ids instanceof String)
 960:           value_tag |= vf_ID;
 961:         else if (ids instanceof String[])
 962:           // OMG standard requires to set both flags.
 963:           value_tag |= vf_MULTIPLE_IDS | vf_ID;
 964: 
 965:         int chunkSizeLocation;
 966: 
 967:         OutputStream outObj;
 968: 
 969:         if (USE_CHUNKING)
 970:           {
 971:             // Wrap the value being written into one chunk (makes sense only for
 972:             // compatibility reasons).
 973:             outObj = output;
 974:             value_tag |= vf_CHUNKING;
 975:           }
 976:         else
 977:           outObj = output;
 978: 
 979:         output.write_long(value_tag);
 980: 
 981:         if ((value_tag & vf_MULTIPLE_IDS) != 0)
 982:           write_string_array(output, (String[]) ids);
 983:         else if ((value_tag & vf_ID) != 0)
 984:           write_string(output, (String) ids);
 985: 
 986:         if (USE_CHUNKING)
 987:           {
 988:             // So far, write 0x55555555 instead of the chunk size (alignment may
 989:             // take place).
 990:             output.write_long(0x55555555);
 991:             // If the chunking is involved, the chunk size must be written here.
 992:             chunkSizeLocation = rout.getPosition() - INT_SIZE;
 993:           }
 994:         else
 995:           // Not in use for this case.
 996:           chunkSizeLocation = -1;
 997: 
 998:         writeValue(outObj, value, helper);
 999: 
1000:         if (USE_CHUNKING)
1001:           {
1002:             // Write the chunk size where the place for it was reserved.
1003:             int chunkSize = rout.getPosition() - chunkSizeLocation - INT_SIZE;
1004:             int current = rout.getPosition();
1005:             rout.seek(chunkSizeLocation);
1006:             output.write_long(chunkSize);
1007:             rout.seek(current);
1008: 
1009:             // The end of record marker.
1010:             output.write_long(-1);
1011:           }
1012:       }
1013:     finally
1014:       {
1015:         if (runtime != null)
1016:           runtime.target = null;
1017:       }
1018:   }
1019: 
1020:   /**
1021:    * Write value (after header).
1022:    */
1023:   static void writeValue(OutputStream output, Serializable value,
1024:     BoxedValueHelper helper)
1025:   {
1026:     ((gnuValueStream) output).getRunTime().target = value;
1027:     if (helper != null)
1028:       helper.write_value(output, value);
1029:     else if (!writeSelf(output, value))
1030:       {
1031:         // Try to find helper via class loader.
1032:         boolean ok = false;
1033: 
1034:         if (!ok)
1035:           {
1036:             if (output instanceof BufferedCdrOutput)
1037:               {
1038:                 BufferedCdrOutput b = (BufferedCdrOutput) output;
1039:                 if (b.runtime == null)
1040:                   b.runtime = new gnuRuntime(null, value);
1041:               }
1042: 
1043:             handler.writeValue(output, value);
1044:           }
1045:       }
1046:   }
1047: 
1048:   /**
1049:    * Try to write value supposing that it implements self-streamable interfaces.
1050:    * Return false if it does not or true on success.
1051:    */
1052:   static boolean writeSelf(OutputStream output, Serializable value)
1053:   {
1054:     // User defined write method is present.
1055:     if (value instanceof CustomMarshal)
1056:       {
1057:         ((CustomMarshal) value).marshal((DataOutputStream) output);
1058:         return true;
1059:       }
1060:     else if (value instanceof Streamable)
1061:       {
1062:         ((Streamable) value)._write(output);
1063:         return true;
1064:       }
1065:     return false;
1066:   }
1067: 
1068:   /**
1069:    * Read the indirection data and return the object that was already written to
1070:    * this stream.
1071:    * 
1072:    * @param an_input the input stream, must be BufferredCdrInput.
1073:    */
1074:   static Serializable readIndirection(InputStream an_input)
1075:   {
1076:     if (!(an_input instanceof gnuValueStream))
1077:       throw new NO_IMPLEMENT(gnuValueStream.class.getName()
1078:         + " expected as parameter");
1079: 
1080:     gnuValueStream in = (gnuValueStream) an_input;
1081: 
1082:     int current_pos = in.getPosition();
1083: 
1084:     int offset = an_input.read_long();
1085:     if (offset > -INT_SIZE)
1086:       {
1087:         MARSHAL m = new MARSHAL("Indirection tag refers to " + offset
1088:         + " (must be less than -" + INT_SIZE + ")");
1089:         m.minor = Minor.Offset;
1090:         throw m;
1091:       }
1092: 
1093:     int stored_at = current_pos + offset;
1094: 
1095:     if (in.getRunTime() == null)
1096:       {
1097:         MARSHAL m = new MARSHAL(stored_at + " offset " + offset + ": not written");
1098:         m.minor = Minor.Value;
1099:         throw m;
1100:       }
1101: 
1102:     return (Serializable) in.getRunTime().isObjectWrittenAt(stored_at, offset);
1103:   }
1104: 
1105:   /**
1106:    * Check the passed value tag for correctness.
1107:    * 
1108:    * @param value_tag a tag to check, must be between 0x7fffff00 and 0x7fffffff
1109:    * 
1110:    * @throws MARSHAL if the tag is outside this interval.
1111:    */
1112:   static void checkTag(int value_tag)
1113:   {
1114:     if ((value_tag < 0x7fffff00 || value_tag > 0x7fffffff)
1115:       && value_tag != vt_NULL && value_tag != vt_INDIRECTION)
1116:       {
1117:         MARSHAL m = new MARSHAL("Invalid value record, unsupported header tag: "
1118:         + value_tag + " (0x" + Integer.toHexString(value_tag) + ")");
1119:         m.minor = Minor.ValueHeaderTag;
1120:         throw m;
1121:       }
1122: 
1123:     if ((value_tag & vf_MULTIPLE_IDS) != 0 && (value_tag & vf_ID) == 0)
1124:       {
1125:         MARSHAL m = new MARSHAL("Invalid value record header flag combination (0x"
1126:         + Integer.toHexString(value_tag) + ")");
1127:         m.minor = Minor.ValueHeaderFlags;
1128:         throw m;
1129:       }
1130:   }
1131: 
1132:   /**
1133:    * Throw MARSHAL.
1134:    */
1135:   static void throwIt(String msg, String id1, String id2, Throwable e)
1136:     throws MARSHAL
1137:   {
1138:     MARSHAL m = new MARSHAL(msg + ":'" + id1 + "' versus '" + id2 + "'");
1139:     if (e != null)
1140:       m.initCause(e);
1141:     m.minor = Minor.Value;
1142:     throw m;
1143:   }
1144: 
1145:   /**
1146:    * Load class by name and create the instance.
1147:    */
1148:   static Object createInstance(String id, String[] ids, String codebase)
1149:   {
1150:     Object o = null;
1151: 
1152:     if (id != null)
1153:       o = _createInstance(id, codebase);
1154: 
1155:     if (ids != null)
1156:       for (int i = 0; i < ids.length && o == null; i++)
1157:         o = _createInstance(ids[i], codebase);
1158:     return o;
1159:   }
1160: 
1161:   static Object _createInstance(String id, String codebase)
1162:   {
1163:     if (id == null)
1164:       return null;
1165:     if (id.equals(StringValueHelper.id()))
1166:       return "";
1167:     StringTokenizer st = new StringTokenizer(id, ":");
1168: 
1169:     String prefix = st.nextToken();
1170:     if (prefix.equalsIgnoreCase("IDL"))
1171:       return ObjectCreator.Idl2Object(id);
1172:     else if (prefix.equalsIgnoreCase("RMI"))
1173:       {
1174:         String className = st.nextToken();
1175:         String hashCode = st.nextToken();
1176:         String sid = null;
1177:         if (st.hasMoreElements())
1178:           sid = st.nextToken();
1179: 
1180:         try
1181:           {
1182:             Class objectClass = Util.loadClass(className, codebase,
1183:               Vio.class.getClassLoader());
1184: 
1185:             String rid = ObjectCreator.getRepositoryId(objectClass);
1186: 
1187:             if (!rid.equals(id))
1188:               {
1189:                 // If direct string comparison fails, compare by meaning.
1190:                 StringTokenizer st2 = new StringTokenizer(rid, ":");
1191:                 if (!st2.nextToken().equals("RMI"))
1192:                   throw new InternalError("RMI format expected: '" + rid + "'");
1193:                 if (!st2.nextToken().equals(className))
1194:                   throwIt("Class name mismatch", id, rid, null);
1195: 
1196:                 try
1197:                   {
1198:                     long h1 = Long.parseLong(hashCode, 16);
1199:                     long h2 = Long.parseLong(st2.nextToken(), 16);
1200:                     if (h1 != h2)
1201:                       throwIt("Hashcode mismatch", id, rid, null);
1202: 
1203:                     if (sid != null && st2.hasMoreTokens())
1204:                       {
1205:                         long s1 = Long.parseLong(hashCode, 16);
1206:                         long s2 = Long.parseLong(st2.nextToken(), 16);
1207:                         if (s1 != s2)
1208:                           throwIt("serialVersionUID mismatch", id, rid, null);
1209:                       }
1210:                   }
1211:                 catch (NumberFormatException e)
1212:                   {
1213:                     throwIt("Invalid hashcode or svuid format: ", id, rid, e);
1214:                   }
1215:               }
1216: 
1217:             // Low - level instantiation required here.
1218:             return instantiateAnyWay(objectClass);
1219:           }
1220:         catch (Exception ex)
1221:           {
1222:             MARSHAL m = new MARSHAL("Unable to instantiate " + id);
1223:             m.minor = Minor.Instantiation;
1224:             m.initCause(ex);
1225:             throw m;
1226:           }
1227:       }
1228:     else
1229:       throw new NO_IMPLEMENT("Unsupported prefix " + prefix + ":");
1230:   }
1231: 
1232:   /**
1233:    * Read string, expecting the probable indirection.
1234:    */
1235:   static String read_string(InputStream input)
1236:   {
1237:     gnuValueStream g = (gnuValueStream) input;
1238:     int previous = g.getPosition();
1239:     int l = input.read_long();
1240:     if (l != vt_INDIRECTION)
1241:       {
1242:         g.seek(previous);
1243:         String s = input.read_string();
1244:         if (g.getRunTime() == null)
1245:           g.setRunTime(new gnuRuntime(null, null));
1246:         g.getRunTime().singleIdWritten(s, previous);
1247:         return s;
1248:       }
1249:     else
1250:       {
1251:         gnuRuntime r = g.getRunTime();
1252:         int base = g.getPosition();
1253:         int delta = input.read_long();
1254:         if (r == null)
1255:           {
1256:             previous = g.getPosition();
1257:             g.seek(base + delta);
1258:             String indir = input.read_string();
1259:             g.seek(previous);
1260:             return indir;
1261:           }
1262:         else
1263:           {
1264:             return (String) r.isObjectWrittenAt(base + delta, delta);
1265:           }
1266:       }
1267:   }
1268: 
1269:   /**
1270:    * Read string array, expecting the probable indirection.
1271:    */
1272:   static String[] read_string_array(InputStream input)
1273:   {
1274:     gnuValueStream g = (gnuValueStream) input;
1275:     int previous = g.getPosition();
1276:     int l = input.read_long();
1277:     if (l != vt_INDIRECTION)
1278:       {
1279:         g.seek(previous);
1280:         String[] s = StringSeqHelper.read(input);
1281:         if (g.getRunTime() == null)
1282:           g.setRunTime(new gnuRuntime(null, null));
1283:         g.getRunTime().objectWritten(s, previous);
1284:         return s;
1285:       }
1286:     else
1287:       {
1288:         gnuRuntime r = g.getRunTime();
1289:         int base = g.getPosition();
1290:         int delta = input.read_long();
1291:         if (r == null)
1292:           {
1293:             previous = g.getPosition();
1294:             g.seek(base + delta);
1295:             String[] indir = StringSeqHelper.read(input);
1296:             g.seek(previous);
1297:             return indir;
1298:           }
1299:         else
1300:           {
1301:             return (String[]) r.isObjectWrittenAt(base + delta, delta);
1302:           }
1303:       }
1304:   }
1305: 
1306:   /**
1307:    * Write repository Id, probably shared.
1308:    */
1309:   static void write_string(OutputStream output, String id)
1310:   {
1311:     if (output instanceof gnuValueStream)
1312:       {
1313:         gnuValueStream b = (gnuValueStream) output;
1314:         if (b != null)
1315:           {
1316:             int written = b.getRunTime().idWrittenAt(id);
1317:             if (written >= 0)
1318:               {
1319:                 // Reuse existing id record.
1320:                 output.write_long(vt_INDIRECTION);
1321:                 int p = b.getPosition();
1322:                 output.write_long(written - p);
1323:               }
1324:             else
1325:               {
1326:                 b.getRunTime().singleIdWritten(id, b.getPosition());
1327:                 output.write_string(id);
1328:               }
1329:           }
1330:       }
1331:     else
1332:       output.write_string(id);
1333:   }
1334: 
1335:   /**
1336:    * Write repository Id, probably shared.
1337:    */
1338:   static void write_string_array(OutputStream output, String[] ids)
1339:   {
1340:     if (output instanceof gnuValueStream)
1341:       {
1342:         gnuValueStream b = (gnuValueStream) output;
1343:         if (b != null)
1344:           {
1345:             int written = b.getRunTime().idWrittenAt(ids);
1346:             if (written >= 0)
1347:               {
1348:                 // Reuse existing id record.
1349:                 output.write_long(vt_INDIRECTION);
1350:                 int p = b.getPosition();
1351:                 output.write_long(written - p);
1352:               }
1353:             else
1354:               {
1355:                 b.getRunTime().multipleIdsWritten(ids, b.getPosition());
1356:                 StringSeqHelper.write(output, ids);
1357:               }
1358:           }
1359:       }
1360:     else
1361:       StringSeqHelper.write(output, ids);
1362:   }
1363: 
1364:   /**
1365:    * Get the helper that could write the given object, or null if no pre-defined
1366:    * helper available for this object.
1367:    */
1368:   public static BoxedValueHelper getHelper(Class x, Object ids)
1369:   {
1370:     if (x != null && x.equals(String.class))
1371:       return m_StringValueHelper;
1372:     else if (x != null && x.isArray())
1373:       return new ArrayValueHelper(x);
1374:     else if (ids instanceof String)
1375:       return locateHelper((String) ids);
1376:     else if (ids instanceof String[])
1377:       {
1378:         String[] ia = (String[]) ids;
1379:         BoxedValueHelper h;
1380:         for (int i = 0; i < ia.length; i++)
1381:           {
1382:             h = locateHelper(ia[i]);
1383:             if (h != null)
1384:               return h;
1385:           }
1386:         return null;
1387:       }
1388:     else
1389:       return null;
1390:   }
1391: 
1392:   /**
1393:    * Get the helper that could write the given object, or null if no pre-defined
1394:    * helper available for this object.
1395:    */
1396:   public static BoxedValueHelper getHelper(Class x, String id)
1397:   {
1398:     if (x != null && x.equals(String.class))
1399:       return m_StringValueHelper;
1400:     else if (x != null && x.isArray())
1401:       return new ArrayValueHelper(x);
1402:     else
1403:       return locateHelper(id);
1404:   }
1405: 
1406:   /**
1407:    * Try to locate helper from the repository id.
1408:    */
1409:   static BoxedValueHelper locateHelper(String id)
1410:   {
1411:     if (id != null)
1412:       {
1413:         if (id.equals(m_StringValueHelper.get_id()))
1414:           return m_StringValueHelper;
1415:         else
1416:         // Try to locate helper for IDL type.
1417:         if (id.startsWith("IDL:"))
1418:           {
1419:             try
1420:               {
1421:                 Class helperClass = ObjectCreator.findHelper(id);
1422:                 if (BoxedValueHelper.class.isAssignableFrom(helperClass))
1423:                   return (BoxedValueHelper) helperClass.newInstance();
1424:                 else if (helperClass != null)
1425:                   return new IDLTypeHelper(helperClass);
1426:                 else
1427:                   return null;
1428:               }
1429:             catch (Exception ex)
1430:               {
1431:                 return null;
1432:               }
1433:           }
1434:       }
1435:     return null;
1436:   }
1437: 
1438:   /**
1439:    * Get the current position.
1440:    */
1441:   static int getCurrentPosition(InputStream x)
1442:   {
1443:     if (x instanceof gnuValueStream)
1444:       return ((gnuValueStream) x).getPosition();
1445:     else
1446:       return 0;
1447:   }
1448: 
1449:   /**
1450:    * Instantiate an instance of this class anyway; also in the case when it has
1451:    * no parameterless or any other constructor. The fields will be assigned
1452:    * while reading the class from the stream.
1453:    * 
1454:    * @param clazz a class for that the instance should be instantiated.
1455:    */
1456:   public static Object instantiateAnyWay(Class clazz)
1457:     throws Exception
1458:   {
1459:     Class first_nonserial = clazz;
1460: 
1461:     while (Serializable.class.isAssignableFrom(first_nonserial)
1462:       || Modifier.isAbstract(first_nonserial.getModifiers()))
1463:       first_nonserial = first_nonserial.getSuperclass();
1464: 
1465:     final Class local_constructor_class = first_nonserial;
1466: 
1467:     Constructor constructor = local_constructor_class.getDeclaredConstructor(new Class[0]);
1468: 
1469:     return VMVio.allocateObject(clazz, constructor.getDeclaringClass(),
1470:       constructor);
1471:   }