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