Source for java.io.ObjectOutputStream

   1: /* ObjectOutputStream.java -- Class used to write serialized objects
   2:    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008
   3:    Free Software Foundation, Inc.
   4: 
   5: This file is part of GNU Classpath.
   6: 
   7: GNU Classpath is free software; you can redistribute it and/or modify
   8: it under the terms of the GNU General Public License as published by
   9: the Free Software Foundation; either version 2, or (at your option)
  10: any later version.
  11: 
  12: GNU Classpath is distributed in the hope that it will be useful, but
  13: WITHOUT ANY WARRANTY; without even the implied warranty of
  14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15: General Public License for more details.
  16: 
  17: You should have received a copy of the GNU General Public License
  18: along with GNU Classpath; see the file COPYING.  If not, write to the
  19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20: 02110-1301 USA.
  21: 
  22: Linking this library statically or dynamically with other modules is
  23: making a combined work based on this library.  Thus, the terms and
  24: conditions of the GNU General Public License cover the whole
  25: combination.
  26: 
  27: As a special exception, the copyright holders of this library give you
  28: permission to link this library with independent modules to produce an
  29: executable, regardless of the license terms of these independent
  30: modules, and to copy and distribute the resulting executable under
  31: terms of your choice, provided that you also meet, for each linked
  32: independent module, the terms and conditions of the license of that
  33: module.  An independent module is a module which is not derived from
  34: or based on this library.  If you modify this library, you may extend
  35: this exception to your version of the library, but you are not
  36: obligated to do so.  If you do not wish to do so, delete this
  37: exception statement from your version. */
  38: 
  39: 
  40: package java.io;
  41: 
  42: import gnu.java.io.ObjectIdentityMap2Int;
  43: import gnu.java.lang.reflect.TypeSignature;
  44: import gnu.java.security.action.SetAccessibleAction;
  45: 
  46: import java.lang.reflect.Array;
  47: import java.lang.reflect.Field;
  48: import java.lang.reflect.InvocationTargetException;
  49: import java.lang.reflect.Method;
  50: 
  51: 
  52: /**
  53:  * An <code>ObjectOutputStream</code> can be used to write objects
  54:  * as well as primitive data in a platform-independent manner to an
  55:  * <code>OutputStream</code>.
  56:  *
  57:  * The data produced by an <code>ObjectOutputStream</code> can be read
  58:  * and reconstituted by an <code>ObjectInputStream</code>.
  59:  *
  60:  * <code>writeObject (Object)</code> is used to write Objects, the
  61:  * <code>write&lt;type&gt;</code> methods are used to write primitive
  62:  * data (as in <code>DataOutputStream</code>). Strings can be written
  63:  * as objects or as primitive data.
  64:  *
  65:  * Not all objects can be written out using an
  66:  * <code>ObjectOutputStream</code>.  Only those objects that are an
  67:  * instance of <code>java.io.Serializable</code> can be written.
  68:  *
  69:  * Using default serialization, information about the class of an
  70:  * object is written, all of the non-transient, non-static fields of
  71:  * the object are written, if any of these fields are objects, they are
  72:  * written out in the same manner.
  73:  *
  74:  * An object is only written out the first time it is encountered.  If
  75:  * the object is encountered later, a reference to it is written to
  76:  * the underlying stream.  Thus writing circular object graphs
  77:  * does not present a problem, nor are relationships between objects
  78:  * in a graph lost.
  79:  *
  80:  * Example usage:
  81:  * <pre>
  82:  * Hashtable map = new Hashtable ();
  83:  * map.put ("one", new Integer (1));
  84:  * map.put ("two", new Integer (2));
  85:  *
  86:  * ObjectOutputStream oos =
  87:  * new ObjectOutputStream (new FileOutputStream ("numbers"));
  88:  * oos.writeObject (map);
  89:  * oos.close ();
  90:  *
  91:  * ObjectInputStream ois =
  92:  * new ObjectInputStream (new FileInputStream ("numbers"));
  93:  * Hashtable newmap = (Hashtable)ois.readObject ();
  94:  *
  95:  * System.out.println (newmap);
  96:  * </pre>
  97:  *
  98:  * The default serialization can be overriden in two ways.
  99:  *
 100:  * By defining a method <code>private void
 101:  * writeObject (ObjectOutputStream)</code>, a class can dictate exactly
 102:  * how information about itself is written.
 103:  * <code>defaultWriteObject ()</code> may be called from this method to
 104:  * carry out default serialization.  This method is not
 105:  * responsible for dealing with fields of super-classes or subclasses.
 106:  *
 107:  * By implementing <code>java.io.Externalizable</code>.  This gives
 108:  * the class complete control over the way it is written to the
 109:  * stream.  If this approach is used the burden of writing superclass
 110:  * and subclass data is transfered to the class implementing
 111:  * <code>java.io.Externalizable</code>.
 112:  *
 113:  * @see java.io.DataOutputStream
 114:  * @see java.io.Externalizable
 115:  * @see java.io.ObjectInputStream
 116:  * @see java.io.Serializable
 117:  * @author Tom Tromey (tromey@redhat.com)
 118:  * @author Jeroen Frijters (jeroen@frijters.net)
 119:  * @author Guilhem Lavaux (guilhem@kaffe.org)
 120:  * @author Michael Koch (konqueror@gmx.de)
 121:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 122:  */
 123: public class ObjectOutputStream extends OutputStream
 124:   implements ObjectOutput, ObjectStreamConstants
 125: {
 126:   /**
 127:    * Creates a new <code>ObjectOutputStream</code> that will do all of
 128:    * its writing onto <code>out</code>.  This method also initializes
 129:    * the stream by writing the header information (stream magic number
 130:    * and stream version).
 131:    *
 132:    * @exception IOException Writing stream header to underlying
 133:    * stream cannot be completed.
 134:    *
 135:    * @see #writeStreamHeader()
 136:    */
 137:   public ObjectOutputStream (OutputStream out) throws IOException
 138:   {
 139:     realOutput = new DataOutputStream(out);
 140:     blockData = new byte[ BUFFER_SIZE ];
 141:     blockDataCount = 0;
 142:     blockDataOutput = new DataOutputStream(this);
 143:     setBlockDataMode(true);
 144:     replacementEnabled = false;
 145:     isSerializing = false;
 146:     nextOID = baseWireHandle;
 147:     OIDLookupTable = new ObjectIdentityMap2Int();
 148:     protocolVersion = defaultProtocolVersion;
 149:     useSubclassMethod = false;
 150:     writeStreamHeader();
 151: 
 152:     if (DEBUG)
 153:       {
 154:     String val = System.getProperty("gcj.dumpobjects");
 155:     if (val != null && !val.equals(""))
 156:       dump = true;
 157:       }
 158:   }
 159: 
 160:   /**
 161:    * Writes a representation of <code>obj</code> to the underlying
 162:    * output stream by writing out information about its class, then
 163:    * writing out each of the objects non-transient, non-static
 164:    * fields.  If any of these fields are other objects,
 165:    * they are written out in the same manner.
 166:    *
 167:    * This method can be overriden by a class by implementing
 168:    * <code>private void writeObject (ObjectOutputStream)</code>.
 169:    *
 170:    * If an exception is thrown from this method, the stream is left in
 171:    * an undefined state.
 172:    *
 173:    * @param obj the object to serialize.
 174:    * @exception NotSerializableException An attempt was made to
 175:    * serialize an <code>Object</code> that is not serializable.
 176:    *
 177:    * @exception InvalidClassException Somebody tried to serialize
 178:    * an object which is wrongly formatted.
 179:    *
 180:    * @exception IOException Exception from underlying
 181:    * <code>OutputStream</code>.
 182:    * @see #writeUnshared(Object)
 183:    */
 184:   public final void writeObject(Object obj) throws IOException
 185:   {
 186:     writeObject(obj, true);
 187:   }
 188: 
 189:   /**
 190:    * Writes an object to the stream in the same manner as
 191:    * {@link #writeObject(Object)}, but without the use of
 192:    * references.  As a result, the object is always written
 193:    * to the stream in full.  Likewise, if an object is written
 194:    * by this method and is then later written again by
 195:    * {@link #writeObject(Object)}, both calls will write out
 196:    * the object in full, as the later call to
 197:    * {@link #writeObject(Object)} will know nothing of the
 198:    * earlier use of {@link #writeUnshared(Object)}.
 199:    *
 200:    * @param obj the object to serialize.
 201:    * @throws NotSerializableException if the object being
 202:    *                                  serialized does not implement
 203:    *                                  {@link Serializable}.
 204:    * @throws InvalidClassException if a problem occurs with
 205:    *                               the class of the object being
 206:    *                               serialized.
 207:    * @throws IOException if an I/O error occurs on the underlying
 208:    *                     <code>OutputStream</code>.
 209:    * @since 1.4
 210:    * @see #writeObject(Object)
 211:    */
 212:   public void writeUnshared(Object obj)
 213:     throws IOException
 214:   {
 215:     writeObject(obj, false);
 216:   }
 217: 
 218:   /**
 219:    * Writes a representation of <code>obj</code> to the underlying
 220:    * output stream by writing out information about its class, then
 221:    * writing out each of the objects non-transient, non-static
 222:    * fields.  If any of these fields are other objects,
 223:    * they are written out in the same manner.
 224:    *
 225:    * This method can be overriden by a class by implementing
 226:    * <code>private void writeObject (ObjectOutputStream)</code>.
 227:    *
 228:    * If an exception is thrown from this method, the stream is left in
 229:    * an undefined state.
 230:    *
 231:    * @param obj the object to serialize.
 232:    * @param shared true if the serialized object should be
 233:    *               shared with later calls.
 234:    * @exception NotSerializableException An attempt was made to
 235:    * serialize an <code>Object</code> that is not serializable.
 236:    *
 237:    * @exception InvalidClassException Somebody tried to serialize
 238:    * an object which is wrongly formatted.
 239:    *
 240:    * @exception IOException Exception from underlying
 241:    * <code>OutputStream</code>.
 242:    * @see #writeUnshared(Object)
 243:    */
 244:   private final void writeObject(Object obj, boolean shared)
 245:     throws IOException
 246:   {
 247:     if (useSubclassMethod)
 248:       {
 249:     if (dump)
 250:       dumpElementln ("WRITE OVERRIDE: " + obj);
 251:       
 252:     writeObjectOverride(obj);
 253:     return;
 254:       }
 255: 
 256:     if (dump)
 257:       dumpElementln ("WRITE: ", obj);
 258:     
 259:     depth += 2;    
 260: 
 261:     boolean was_serializing = isSerializing;
 262:     boolean old_mode = setBlockDataMode(false);
 263:     try
 264:       {
 265:     isSerializing = true;
 266:     boolean replaceDone = false;
 267:     Object replacedObject = null;
 268:     
 269:     while (true)
 270:       {
 271:         if (obj == null)
 272:           {
 273:         realOutput.writeByte(TC_NULL);
 274:         break;
 275:           }
 276: 
 277:         int handle = findHandle(obj);
 278:         if (handle >= 0 && shared)
 279:           {
 280:         realOutput.writeByte(TC_REFERENCE);
 281:         realOutput.writeInt(handle);
 282:         break;
 283:           }
 284: 
 285:         if (obj instanceof Class)
 286:           {
 287:         Class cl = (Class)obj;
 288:         ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl);
 289:         realOutput.writeByte(TC_CLASS);
 290:         if (!osc.isProxyClass)
 291:           {
 292:             writeObject (osc);
 293:           }
 294:         else
 295:           {System.err.println("1");
 296:             realOutput.writeByte(TC_PROXYCLASSDESC);
 297:             Class[] intfs = cl.getInterfaces();
 298:             realOutput.writeInt(intfs.length);
 299:             for (int i = 0; i < intfs.length; i++)
 300:               realOutput.writeUTF(intfs[i].getName());
 301:             
 302:             boolean oldmode = setBlockDataMode(true);
 303:             annotateProxyClass(cl);
 304:             setBlockDataMode(oldmode);
 305:             realOutput.writeByte(TC_ENDBLOCKDATA);
 306:             
 307:             writeObject(osc.getSuper());
 308:           }
 309:         if (shared)
 310:           assignNewHandle(obj);
 311:         break;
 312:           }
 313: 
 314:         if (obj instanceof ObjectStreamClass)
 315:           {
 316:         writeClassDescriptor((ObjectStreamClass) obj);
 317:         break;
 318:           }
 319: 
 320:         Class clazz = obj.getClass();
 321:         ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
 322:         if (osc == null)
 323:           throw new NotSerializableException(clazz.getName());
 324: 
 325:         if (osc.isEnum())
 326:           {
 327:         /* TC_ENUM classDesc newHandle enumConstantName */
 328:         realOutput.writeByte(TC_ENUM);
 329:         writeObject(osc);
 330:         if (shared)
 331:           assignNewHandle(obj);
 332:         writeObject(((Enum) obj).name());
 333:         break;
 334:           }
 335: 
 336:         if ((replacementEnabled || obj instanceof Serializable)
 337:         && ! replaceDone)
 338:           {
 339:         replacedObject = obj;
 340:         
 341:         if (obj instanceof Serializable)
 342:           {
 343:             try
 344:               {
 345:                         Method m = osc.writeReplaceMethod;
 346:                         if (m != null)
 347:                             obj = m.invoke(obj, new Object[0]);
 348:               }
 349:             catch (IllegalAccessException ignore)
 350:               {
 351:               }
 352:             catch (InvocationTargetException ignore)
 353:               {
 354:               }
 355:           }
 356:         
 357:         if (replacementEnabled)
 358:           obj = replaceObject(obj);
 359:         
 360:         replaceDone = true;
 361:         continue;
 362:           }
 363: 
 364:         if (obj instanceof String)
 365:           {
 366:                 String s = (String)obj;
 367:                 long l = realOutput.getUTFlength(s, 0, 0);
 368:                 if (l <= 65535)
 369:                   {
 370:             realOutput.writeByte(TC_STRING);
 371:             if (shared)
 372:               assignNewHandle(obj);
 373:             realOutput.writeUTFShort(s, (int)l);
 374:                   }
 375:                 else
 376:                   {
 377:             realOutput.writeByte(TC_LONGSTRING);
 378:             if (shared)
 379:               assignNewHandle(obj);
 380:             realOutput.writeUTFLong(s, l);
 381:                   }
 382:         break;
 383:           }
 384: 
 385:         if (clazz.isArray ())
 386:           {
 387:         realOutput.writeByte(TC_ARRAY);
 388:         writeObject(osc);
 389:         if (shared)
 390:           assignNewHandle(obj);
 391:         writeArraySizeAndElements(obj, clazz.getComponentType());
 392:         break;
 393:           }
 394:         
 395:         realOutput.writeByte(TC_OBJECT);
 396:         writeObject(osc);
 397: 
 398:         if (shared)
 399:           if (replaceDone)
 400:         assignNewHandle(replacedObject);
 401:           else
 402:         assignNewHandle(obj);
 403:         
 404:         if (obj instanceof Externalizable)
 405:           {
 406:         if (protocolVersion == PROTOCOL_VERSION_2)
 407:           setBlockDataMode(true);
 408:         
 409:         ((Externalizable)obj).writeExternal(this);
 410:         
 411:         if (protocolVersion == PROTOCOL_VERSION_2)
 412:           {
 413:             setBlockDataMode(false);
 414:             realOutput.writeByte(TC_ENDBLOCKDATA);
 415:           }
 416: 
 417:         break;
 418:           }
 419: 
 420:         if (obj instanceof Serializable)
 421:           {
 422:         Object prevObject = this.currentObject;
 423:         ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
 424:         currentObject = obj;
 425:         ObjectStreamClass[] hierarchy = osc.hierarchy();
 426:         
 427:         for (int i = 0; i < hierarchy.length; i++)
 428:           {
 429:             currentObjectStreamClass = hierarchy[i];
 430:             
 431:             fieldsAlreadyWritten = false;
 432:             if (currentObjectStreamClass.hasWriteMethod())
 433:               {
 434:             if (dump)
 435:               dumpElementln ("WRITE METHOD CALLED FOR: ", obj);
 436:             setBlockDataMode(true);
 437:             callWriteMethod(obj, currentObjectStreamClass);
 438:             setBlockDataMode(false);
 439:             realOutput.writeByte(TC_ENDBLOCKDATA);
 440:             if (dump)
 441:               dumpElementln ("WRITE ENDBLOCKDATA FOR: ", obj);
 442:               }
 443:             else
 444:               {
 445:             if (dump)
 446:               dumpElementln ("WRITE FIELDS CALLED FOR: ", obj);
 447:             writeFields(obj, currentObjectStreamClass);
 448:               }
 449:           }
 450: 
 451:         this.currentObject = prevObject;
 452:         this.currentObjectStreamClass = prevObjectStreamClass;
 453:         currentPutField = null;
 454:         break;
 455:           }
 456: 
 457:         throw new NotSerializableException(clazz.getName()
 458:                            + " in "
 459:                            + obj.getClass());
 460:       } // end pseudo-loop
 461:       }
 462:     catch (ObjectStreamException ose)
 463:       {
 464:     // Rethrow these are fatal.
 465:     throw ose;
 466:       }
 467:     catch (IOException e)
 468:       {
 469:     realOutput.writeByte(TC_EXCEPTION);
 470:     reset(true);
 471: 
 472:     setBlockDataMode(false);
 473:     try
 474:       {
 475:         if (DEBUG)
 476:           {
 477:         e.printStackTrace(System.out);
 478:           }
 479:         writeObject(e);
 480:       }
 481:     catch (IOException ioe)
 482:       {
 483:         StreamCorruptedException ex = 
 484:           new StreamCorruptedException
 485:           (ioe + " thrown while exception was being written to stream.");
 486:         if (DEBUG)
 487:           {
 488:         ex.printStackTrace(System.out);
 489:           }
 490:         throw ex;
 491:       }
 492: 
 493:     reset (true);
 494:     
 495:       }
 496:     finally
 497:       {
 498:     isSerializing = was_serializing;
 499:     setBlockDataMode(old_mode);
 500:     depth -= 2;
 501: 
 502:     if (dump)
 503:       dumpElementln ("END: ", obj);
 504:       }
 505:   }
 506: 
 507:   protected void writeClassDescriptor(ObjectStreamClass osc) throws IOException
 508:   {
 509:     if (osc.isProxyClass)
 510:       {
 511:         realOutput.writeByte(TC_PROXYCLASSDESC);
 512:     Class[] intfs = osc.forClass().getInterfaces();
 513:     realOutput.writeInt(intfs.length);
 514:     for (int i = 0; i < intfs.length; i++)
 515:       realOutput.writeUTF(intfs[i].getName());
 516: 
 517:         assignNewHandle(osc);
 518:     
 519:         boolean oldmode = setBlockDataMode(true);
 520:         annotateProxyClass(osc.forClass());
 521:         setBlockDataMode(oldmode);
 522:         realOutput.writeByte(TC_ENDBLOCKDATA);
 523:       }
 524:     else
 525:       {
 526:         realOutput.writeByte(TC_CLASSDESC);
 527:         realOutput.writeUTF(osc.getName());
 528:     if (osc.isEnum())
 529:       realOutput.writeLong(0L);
 530:     else
 531:       realOutput.writeLong(osc.getSerialVersionUID());
 532:         assignNewHandle(osc);
 533: 
 534:         int flags = osc.getFlags();
 535: 
 536:         if (protocolVersion == PROTOCOL_VERSION_2
 537:         && osc.isExternalizable())
 538:         flags |= SC_BLOCK_DATA;
 539: 
 540:         realOutput.writeByte(flags);
 541: 
 542:         ObjectStreamField[] fields = osc.fields;
 543: 
 544:     if (fields == ObjectStreamClass.INVALID_FIELDS)
 545:       throw new InvalidClassException
 546:           (osc.getName(), "serialPersistentFields is invalid");
 547: 
 548:         realOutput.writeShort(fields.length);
 549: 
 550:         ObjectStreamField field;
 551:         for (int i = 0; i < fields.length; i++)
 552:           {
 553:         field = fields[i];
 554:         realOutput.writeByte(field.getTypeCode ());
 555:         realOutput.writeUTF(field.getName ());
 556: 
 557:         if (! field.isPrimitive())
 558:           writeObject(field.getTypeString());
 559:           }
 560: 
 561:         boolean oldmode = setBlockDataMode(true);
 562:         annotateClass(osc.forClass());
 563:         setBlockDataMode(oldmode);
 564:         realOutput.writeByte(TC_ENDBLOCKDATA);
 565:       }
 566: 
 567:     if (osc.isSerializable() || osc.isExternalizable())
 568:       writeObject(osc.getSuper());
 569:     else
 570:       writeObject(null);
 571:   }
 572:   
 573:   /**
 574:    * Writes the current objects non-transient, non-static fields from
 575:    * the current class to the underlying output stream.
 576:    *
 577:    * This method is intended to be called from within a object's
 578:    * <code>private void writeObject (ObjectOutputStream)</code>
 579:    * method.
 580:    *
 581:    * @exception NotActiveException This method was called from a
 582:    * context other than from the current object's and current class's
 583:    * <code>private void writeObject (ObjectOutputStream)</code>
 584:    * method.
 585:    *
 586:    * @exception IOException Exception from underlying
 587:    * <code>OutputStream</code>.
 588:    */
 589:   public void defaultWriteObject()
 590:     throws IOException, NotActiveException
 591:   {
 592:     markFieldsWritten();
 593:     writeFields(currentObject, currentObjectStreamClass);
 594:   }
 595: 
 596: 
 597:   private void markFieldsWritten() throws IOException
 598:   {
 599:     if (currentObject == null || currentObjectStreamClass == null)
 600:       throw new NotActiveException
 601:     ("defaultWriteObject called by non-active class and/or object");
 602: 
 603:     if (fieldsAlreadyWritten)
 604:       throw new IOException
 605:     ("Only one of writeFields and defaultWriteObject may be called, and it may only be called once");
 606: 
 607:     fieldsAlreadyWritten = true;
 608:   }
 609: 
 610:   /**
 611:    * Resets stream to state equivalent to the state just after it was
 612:    * constructed.
 613:    *
 614:    * Causes all objects previously written to the stream to be
 615:    * forgotten.  A notification of this reset is also written to the
 616:    * underlying stream.
 617:    *
 618:    * @exception IOException Exception from underlying
 619:    * <code>OutputStream</code> or reset called while serialization is
 620:    * in progress.
 621:    */
 622:   public void reset() throws IOException
 623:   {
 624:     reset(false);
 625:   }
 626: 
 627: 
 628:   private void reset(boolean internal) throws IOException
 629:   {
 630:     if (!internal)
 631:       {
 632:     if (isSerializing)
 633:       throw new IOException("Reset called while serialization in progress");
 634: 
 635:     realOutput.writeByte(TC_RESET);
 636:       }
 637:     
 638:     clearHandles();
 639:   }
 640: 
 641: 
 642:   /**
 643:    * Informs this <code>ObjectOutputStream</code> to write data
 644:    * according to the specified protocol.  There are currently two
 645:    * different protocols, specified by <code>PROTOCOL_VERSION_1</code>
 646:    * and <code>PROTOCOL_VERSION_2</code>.  This implementation writes
 647:    * data using <code>PROTOCOL_VERSION_2</code> by default, as is done
 648:    * since the JDK 1.2.
 649:    * <p>
 650:    * For an explanation of the differences between the two protocols
 651:    * see the Java Object Serialization Specification.
 652:    * </p>
 653:    * 
 654:    * @param version the version to use.
 655:    * 
 656:    * @throws IllegalArgumentException if <code>version</code> is not a valid 
 657:    * protocol.
 658:    * @throws IllegalStateException if called after the first the first object
 659:    * was serialized.
 660:    * @throws IOException if an I/O error occurs.
 661:    * 
 662:    * @see ObjectStreamConstants#PROTOCOL_VERSION_1
 663:    * @see ObjectStreamConstants#PROTOCOL_VERSION_2
 664:    * 
 665:    * @since 1.2
 666:    */
 667:   public void useProtocolVersion(int version) throws IOException
 668:   {
 669:     if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
 670:       throw new IllegalArgumentException("Invalid protocol version requested.");
 671:     
 672:     if (nextOID != baseWireHandle)
 673:       throw new IllegalStateException("Protocol version cannot be changed " 
 674:                                       + "after serialization started.");
 675:     
 676:     protocolVersion = version;
 677:   }
 678: 
 679:   /**
 680:    * An empty hook that allows subclasses to write extra information
 681:    * about classes to the stream.  This method is called the first
 682:    * time each class is seen, and after all of the standard
 683:    * information about the class has been written.
 684:    *
 685:    * @exception IOException Exception from underlying
 686:    * <code>OutputStream</code>.
 687:    *
 688:    * @see ObjectInputStream#resolveClass(java.io.ObjectStreamClass)
 689:    */
 690:   protected void annotateClass(Class<?> cl) throws IOException
 691:   {
 692:   }
 693: 
 694:   protected void annotateProxyClass(Class<?> cl) throws IOException
 695:   {
 696:   }
 697: 
 698:   /**
 699:    * Allows subclasses to replace objects that are written to the
 700:    * stream with other objects to be written in their place.  This
 701:    * method is called the first time each object is encountered
 702:    * (modulo reseting of the stream).
 703:    *
 704:    * This method must be enabled before it will be called in the
 705:    * serialization process.
 706:    *
 707:    * @exception IOException Exception from underlying
 708:    * <code>OutputStream</code>.
 709:    *
 710:    * @see #enableReplaceObject(boolean)
 711:    */
 712:   protected Object replaceObject(Object obj) throws IOException
 713:   {
 714:     return obj;
 715:   }
 716: 
 717: 
 718:   /**
 719:    * If <code>enable</code> is <code>true</code> and this object is
 720:    * trusted, then <code>replaceObject (Object)</code> will be called
 721:    * in subsequent calls to <code>writeObject (Object)</code>.
 722:    * Otherwise, <code>replaceObject (Object)</code> will not be called.
 723:    *
 724:    * @exception SecurityException This class is not trusted.
 725:    */
 726:   protected boolean enableReplaceObject(boolean enable)
 727:     throws SecurityException
 728:   {
 729:     if (enable)
 730:       {
 731:     SecurityManager sm = System.getSecurityManager();
 732:     if (sm != null)
 733:       sm.checkPermission(new SerializablePermission("enableSubstitution"));
 734:       }
 735: 
 736:     boolean old_val = replacementEnabled;
 737:     replacementEnabled = enable;
 738:     return old_val;
 739:   }
 740: 
 741: 
 742:   /**
 743:    * Writes stream magic and stream version information to the
 744:    * underlying stream.
 745:    *
 746:    * @exception IOException Exception from underlying
 747:    * <code>OutputStream</code>.
 748:    */
 749:   protected void writeStreamHeader() throws IOException
 750:   {
 751:     realOutput.writeShort(STREAM_MAGIC);
 752:     realOutput.writeShort(STREAM_VERSION);
 753:   }
 754: 
 755:   /**
 756:    * Protected constructor that allows subclasses to override
 757:    * serialization.  This constructor should be called by subclasses
 758:    * that wish to override <code>writeObject (Object)</code>.  This
 759:    * method does a security check <i>NOTE: currently not
 760:    * implemented</i>, then sets a flag that informs
 761:    * <code>writeObject (Object)</code> to call the subclasses
 762:    * <code>writeObjectOverride (Object)</code> method.
 763:    *
 764:    * @see #writeObjectOverride(Object)
 765:    */
 766:   protected ObjectOutputStream() throws IOException, SecurityException
 767:   {
 768:     SecurityManager sec_man = System.getSecurityManager ();
 769:     if (sec_man != null)
 770:       sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
 771:     useSubclassMethod = true;
 772:   }
 773: 
 774: 
 775:   /**
 776:    * This method allows subclasses to override the default
 777:    * serialization mechanism provided by
 778:    * <code>ObjectOutputStream</code>.  To make this method be used for
 779:    * writing objects, subclasses must invoke the 0-argument
 780:    * constructor on this class from there constructor.
 781:    *
 782:    * @see #ObjectOutputStream()
 783:    *
 784:    * @exception NotActiveException Subclass has arranged for this
 785:    * method to be called, but did not implement this method.
 786:    */
 787:   protected void writeObjectOverride(Object obj) throws NotActiveException,
 788:     IOException
 789:   {
 790:     throw new NotActiveException
 791:       ("Subclass of ObjectOutputStream must implement writeObjectOverride");
 792:   }
 793: 
 794: 
 795:   /**
 796:    * @see DataOutputStream#write(int)
 797:    */
 798:   public void write (int data) throws IOException
 799:   {
 800:     if (writeDataAsBlocks)
 801:       {
 802:     if (blockDataCount == BUFFER_SIZE)
 803:       drain();
 804: 
 805:     blockData[ blockDataCount++ ] = (byte)data;
 806:       }
 807:     else
 808:       realOutput.write(data);
 809:   }
 810: 
 811: 
 812:   /**
 813:    * @see DataOutputStream#write(byte[])
 814:    */
 815:   public void write(byte[] b) throws IOException
 816:   {
 817:     write(b, 0, b.length);
 818:   }
 819: 
 820: 
 821:   /**
 822:    * @see DataOutputStream#write(byte[],int,int)
 823:    */
 824:   public void write(byte[] b, int off, int len) throws IOException
 825:   {
 826:     if (writeDataAsBlocks)
 827:       {
 828:     if (len < 0)
 829:       throw new IndexOutOfBoundsException();
 830: 
 831:     if (blockDataCount + len < BUFFER_SIZE)
 832:       {
 833:         System.arraycopy(b, off, blockData, blockDataCount, len);
 834:         blockDataCount += len;
 835:       }
 836:     else
 837:       {
 838:         drain();
 839:         writeBlockDataHeader(len);
 840:         realOutput.write(b, off, len);
 841:       }
 842:       }
 843:     else
 844:       realOutput.write(b, off, len);
 845:   }
 846: 
 847: 
 848:   /**
 849:    * @see DataOutputStream#flush()
 850:    */
 851:   public void flush () throws IOException
 852:   {
 853:     drain();
 854:     realOutput.flush();
 855:   }
 856: 
 857: 
 858:   /**
 859:    * Causes the block-data buffer to be written to the underlying
 860:    * stream, but does not flush underlying stream.
 861:    *
 862:    * @exception IOException Exception from underlying
 863:    * <code>OutputStream</code>.
 864:    */
 865:   protected void drain() throws IOException
 866:   {
 867:     if (blockDataCount == 0)
 868:       return;
 869: 
 870:     if (writeDataAsBlocks)
 871:       writeBlockDataHeader(blockDataCount);
 872:     realOutput.write(blockData, 0, blockDataCount);
 873:     blockDataCount = 0;
 874:   }
 875: 
 876: 
 877:   /**
 878:    * @see java.io.DataOutputStream#close ()
 879:    */
 880:   public void close() throws IOException
 881:   {
 882:     flush();
 883:     realOutput.close();
 884:   }
 885: 
 886: 
 887:   /**
 888:    * @see java.io.DataOutputStream#writeBoolean (boolean)
 889:    */
 890:   public void writeBoolean(boolean data) throws IOException
 891:   {
 892:     blockDataOutput.writeBoolean(data);
 893:   }
 894: 
 895: 
 896:   /**
 897:    * @see java.io.DataOutputStream#writeByte (int)
 898:    */
 899:   public void writeByte(int data) throws IOException
 900:   {
 901:     blockDataOutput.writeByte(data);
 902:   }
 903: 
 904: 
 905:   /**
 906:    * @see java.io.DataOutputStream#writeShort (int)
 907:    */
 908:   public void writeShort (int data) throws IOException
 909:   {
 910:     blockDataOutput.writeShort(data);
 911:   }
 912: 
 913: 
 914:   /**
 915:    * @see java.io.DataOutputStream#writeChar (int)
 916:    */
 917:   public void writeChar(int data) throws IOException
 918:   {
 919:     blockDataOutput.writeChar(data);
 920:   }
 921: 
 922: 
 923:   /**
 924:    * @see java.io.DataOutputStream#writeInt (int)
 925:    */
 926:   public void writeInt(int data) throws IOException
 927:   {
 928:     blockDataOutput.writeInt(data);
 929:   }
 930: 
 931: 
 932:   /**
 933:    * @see java.io.DataOutputStream#writeLong (long)
 934:    */
 935:   public void writeLong(long data) throws IOException
 936:   {
 937:     blockDataOutput.writeLong(data);
 938:   }
 939: 
 940: 
 941:   /**
 942:    * @see java.io.DataOutputStream#writeFloat (float)
 943:    */
 944:   public void writeFloat(float data) throws IOException
 945:   {
 946:     blockDataOutput.writeFloat(data);
 947:   }
 948: 
 949: 
 950:   /**
 951:    * @see java.io.DataOutputStream#writeDouble (double)
 952:    */
 953:   public void writeDouble(double data) throws IOException
 954:   {
 955:     blockDataOutput.writeDouble(data);
 956:   }
 957: 
 958: 
 959:   /**
 960:    * @see java.io.DataOutputStream#writeBytes (java.lang.String)
 961:    */
 962:   public void writeBytes(String data) throws IOException
 963:   {
 964:     blockDataOutput.writeBytes(data);
 965:   }
 966: 
 967: 
 968:   /**
 969:    * @see java.io.DataOutputStream#writeChars (java.lang.String)
 970:    */
 971:   public void writeChars(String data) throws IOException
 972:   {
 973:     dataOutput.writeChars(data);
 974:   }
 975: 
 976: 
 977:   /**
 978:    * @see java.io.DataOutputStream#writeUTF (java.lang.String)
 979:    */
 980:   public void writeUTF(String data) throws IOException
 981:   {
 982:     dataOutput.writeUTF(data);
 983:   }
 984: 
 985: 
 986:   /**
 987:    * This class allows a class to specify exactly which fields should
 988:    * be written, and what values should be written for these fields.
 989:    *
 990:    * XXX: finish up comments
 991:    */
 992:   public abstract static class PutField
 993:   {
 994:     public abstract void put (String name, boolean value);
 995:     public abstract void put (String name, byte value);
 996:     public abstract void put (String name, char value);
 997:     public abstract void put (String name, double value);
 998:     public abstract void put (String name, float value);
 999:     public abstract void put (String name, int value);
1000:     public abstract void put (String name, long value);
1001:     public abstract void put (String name, short value);
1002:     public abstract void put (String name, Object value);
1003: 
1004:     /**
1005:      * @deprecated
1006:      */
1007:     public abstract void write (ObjectOutput out) throws IOException;
1008:   }
1009: 
1010:   public PutField putFields() throws IOException
1011:   {
1012:     if (currentPutField != null)
1013:       return currentPutField;
1014: 
1015:     currentPutField = new PutField()
1016:       {
1017:     private byte[] prim_field_data
1018:       = new byte[currentObjectStreamClass.primFieldSize];
1019:     private Object[] objs
1020:       = new Object[currentObjectStreamClass.objectFieldCount];
1021: 
1022:     private ObjectStreamField getField (String name)
1023:     {
1024:       ObjectStreamField field
1025:         = currentObjectStreamClass.getField(name);
1026:       
1027:       if (field == null)
1028:         throw new IllegalArgumentException("no such serializable field " + name);
1029:       
1030:       return field;
1031:     }
1032:     
1033:     public void put(String name, boolean value)
1034:     {
1035:       ObjectStreamField field = getField(name);
1036: 
1037:       checkType(field, 'Z');
1038:       prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0);
1039:     }
1040: 
1041:     public void put(String name, byte value)
1042:     {
1043:       ObjectStreamField field = getField(name);
1044: 
1045:       checkType(field, 'B');
1046:       prim_field_data[field.getOffset()] = value;
1047:     }
1048: 
1049:     public void put(String name, char value)
1050:     {
1051:       ObjectStreamField field = getField(name);
1052: 
1053:       checkType(field, 'C');
1054:       int off = field.getOffset();
1055:       prim_field_data[off++] = (byte)(value >>> 8);
1056:       prim_field_data[off] = (byte)value;
1057:     }
1058: 
1059:     public void put(String name, double value)
1060:     {
1061:       ObjectStreamField field = getField (name);
1062: 
1063:       checkType(field, 'D');
1064:       int off = field.getOffset();
1065:       long l_value = Double.doubleToLongBits (value);
1066:       prim_field_data[off++] = (byte)(l_value >>> 52);
1067:       prim_field_data[off++] = (byte)(l_value >>> 48);
1068:       prim_field_data[off++] = (byte)(l_value >>> 40);
1069:       prim_field_data[off++] = (byte)(l_value >>> 32);
1070:       prim_field_data[off++] = (byte)(l_value >>> 24);
1071:       prim_field_data[off++] = (byte)(l_value >>> 16);
1072:       prim_field_data[off++] = (byte)(l_value >>> 8);
1073:       prim_field_data[off] = (byte)l_value;
1074:     }
1075: 
1076:     public void put(String name, float value)
1077:     {
1078:       ObjectStreamField field = getField(name);
1079: 
1080:       checkType(field, 'F');
1081:       int off = field.getOffset();
1082:       int i_value = Float.floatToIntBits(value);
1083:       prim_field_data[off++] = (byte)(i_value >>> 24);
1084:       prim_field_data[off++] = (byte)(i_value >>> 16);
1085:       prim_field_data[off++] = (byte)(i_value >>> 8);
1086:       prim_field_data[off] = (byte)i_value;
1087:     }
1088: 
1089:     public void put(String name, int value)
1090:     {
1091:       ObjectStreamField field = getField(name);
1092:       checkType(field, 'I');
1093:       int off = field.getOffset();
1094:       prim_field_data[off++] = (byte)(value >>> 24);
1095:       prim_field_data[off++] = (byte)(value >>> 16);
1096:       prim_field_data[off++] = (byte)(value >>> 8);
1097:       prim_field_data[off] = (byte)value;
1098:     }
1099: 
1100:     public void put(String name, long value)
1101:     {
1102:       ObjectStreamField field = getField(name);
1103:       checkType(field, 'J');
1104:       int off = field.getOffset();
1105:       prim_field_data[off++] = (byte)(value >>> 52);
1106:       prim_field_data[off++] = (byte)(value >>> 48);
1107:       prim_field_data[off++] = (byte)(value >>> 40);
1108:       prim_field_data[off++] = (byte)(value >>> 32);
1109:       prim_field_data[off++] = (byte)(value >>> 24);
1110:       prim_field_data[off++] = (byte)(value >>> 16);
1111:       prim_field_data[off++] = (byte)(value >>> 8);
1112:       prim_field_data[off] = (byte)value;
1113:     }
1114: 
1115:     public void put(String name, short value)
1116:     {
1117:       ObjectStreamField field = getField(name);
1118:       checkType(field, 'S');
1119:       int off = field.getOffset();
1120:       prim_field_data[off++] = (byte)(value >>> 8);
1121:       prim_field_data[off] = (byte)value;
1122:     }
1123: 
1124:     public void put(String name, Object value)
1125:     {
1126:       ObjectStreamField field = getField(name);
1127: 
1128:       if (value != null &&
1129:           ! field.getType().isAssignableFrom(value.getClass ()))        
1130:         throw new IllegalArgumentException("Class " + value.getClass() +
1131:                            " cannot be cast to " + field.getType());
1132:       objs[field.getOffset()] = value;
1133:     }
1134: 
1135:     public void write(ObjectOutput out) throws IOException
1136:     {
1137:       // Apparently Block data is not used with PutField as per
1138:       // empirical evidence against JDK 1.2.  Also see Mauve test
1139:       // java.io.ObjectInputOutput.Test.GetPutField.
1140:       boolean oldmode = setBlockDataMode(false);
1141:       out.write(prim_field_data);
1142:       for (int i = 0; i < objs.length; ++ i)
1143:         out.writeObject(objs[i]);
1144:       setBlockDataMode(oldmode);
1145:     }
1146: 
1147:     private void checkType(ObjectStreamField field, char type)
1148:       throws IllegalArgumentException
1149:     {
1150:       if (TypeSignature.getEncodingOfClass(field.getType()).charAt(0)
1151:           != type)
1152:         throw new IllegalArgumentException();
1153:     }
1154:       };
1155:     // end PutFieldImpl
1156: 
1157:     return currentPutField;
1158:   }
1159: 
1160: 
1161:   public void writeFields() throws IOException
1162:   {
1163:     if (currentPutField == null)
1164:       throw new NotActiveException("writeFields can only be called after putFields has been called");
1165: 
1166:     markFieldsWritten();
1167:     currentPutField.write(this);
1168:   }
1169: 
1170: 
1171:   // write out the block-data buffer, picking the correct header
1172:   // depending on the size of the buffer
1173:   private void writeBlockDataHeader(int size) throws IOException
1174:   {
1175:     if (size < 256)
1176:       {
1177:     realOutput.writeByte(TC_BLOCKDATA);
1178:     realOutput.write(size);
1179:       }
1180:     else
1181:       {
1182:     realOutput.writeByte(TC_BLOCKDATALONG);
1183:     realOutput.writeInt(size);
1184:       }
1185:   }
1186: 
1187: 
1188:   // lookup the handle for OBJ, return null if OBJ doesn't have a
1189:   // handle yet
1190:   private int findHandle(Object obj)
1191:   {
1192:     return OIDLookupTable.get(obj);
1193:   }
1194: 
1195: 
1196:   // assigns the next availible handle to OBJ
1197:   private int assignNewHandle(Object obj)
1198:   {
1199:     OIDLookupTable.put(obj, nextOID);
1200:     return nextOID++;
1201:   }
1202: 
1203: 
1204:   // resets mapping from objects to handles
1205:   private void clearHandles()
1206:   {
1207:     nextOID = baseWireHandle;
1208:     OIDLookupTable.clear();
1209:   }
1210: 
1211: 
1212:   // write out array size followed by each element of the array
1213:   private void writeArraySizeAndElements(Object array, Class clazz)
1214:     throws IOException
1215:   {
1216:     int length = Array.getLength(array);
1217: 
1218:     if (clazz.isPrimitive())
1219:       {
1220:     if (clazz == Boolean.TYPE)
1221:       {
1222:         boolean[] cast_array = (boolean[])array;
1223:         realOutput.writeInt (length);
1224:         for (int i = 0; i < length; i++)
1225:           realOutput.writeBoolean(cast_array[i]);
1226:         return;
1227:       }
1228:     if (clazz == Byte.TYPE)
1229:       {
1230:         byte[] cast_array = (byte[])array;
1231:         realOutput.writeInt(length);
1232:         realOutput.write(cast_array, 0, length);
1233:         return;
1234:       }
1235:     if (clazz == Character.TYPE)
1236:       {
1237:         char[] cast_array = (char[])array;
1238:         realOutput.writeInt(length);
1239:         for (int i = 0; i < length; i++)
1240:           realOutput.writeChar(cast_array[i]);
1241:         return;
1242:       }
1243:     if (clazz == Double.TYPE)
1244:       {
1245:         double[] cast_array = (double[])array;
1246:         realOutput.writeInt(length);
1247:         for (int i = 0; i < length; i++)
1248:           realOutput.writeDouble(cast_array[i]);
1249:         return;
1250:       }
1251:     if (clazz == Float.TYPE)
1252:       {
1253:         float[] cast_array = (float[])array;
1254:         realOutput.writeInt(length);
1255:         for (int i = 0; i < length; i++)
1256:           realOutput.writeFloat(cast_array[i]);
1257:         return;
1258:       }
1259:     if (clazz == Integer.TYPE)
1260:       {
1261:         int[] cast_array = (int[])array;
1262:         realOutput.writeInt(length);
1263:         for (int i = 0; i < length; i++)
1264:           realOutput.writeInt(cast_array[i]);
1265:         return;
1266:       }
1267:     if (clazz == Long.TYPE)
1268:       {
1269:         long[] cast_array = (long[])array;
1270:         realOutput.writeInt (length);
1271:         for (int i = 0; i < length; i++)
1272:           realOutput.writeLong(cast_array[i]);
1273:         return;
1274:       }
1275:     if (clazz == Short.TYPE)
1276:       {
1277:         short[] cast_array = (short[])array;
1278:         realOutput.writeInt (length);
1279:         for (int i = 0; i < length; i++)
1280:           realOutput.writeShort(cast_array[i]);
1281:         return;
1282:       }
1283:       }
1284:     else
1285:       {
1286:     Object[] cast_array = (Object[])array;
1287:     realOutput.writeInt(length);
1288:     for (int i = 0; i < length; i++)
1289:       writeObject(cast_array[i]);
1290:       }
1291:   }
1292: 
1293: 
1294:   // writes out FIELDS of OBJECT for the specified ObjectStreamClass.
1295:   // FIELDS are already in canonical order.
1296:   private void writeFields(Object obj, ObjectStreamClass osc)
1297:     throws IOException
1298:   {
1299:     ObjectStreamField[] fields = osc.fields;
1300:     boolean oldmode = setBlockDataMode(false);
1301: 
1302:     try
1303:       {
1304:         writeFields(obj,fields);
1305:       }
1306:     catch (IllegalArgumentException _)
1307:       {
1308:         InvalidClassException e = new InvalidClassException
1309:           ("writing fields of class " + osc.forClass().getName());
1310:         e.initCause(_);
1311:         throw e;
1312:       }
1313:     catch (IOException e)
1314:       {
1315:         throw e;
1316:       }
1317:     catch (Exception _)
1318:       {
1319:         IOException e = new IOException("Unexpected exception " + _);
1320:         e.initCause(_);
1321:         throw(e);
1322:       }    
1323: 
1324:     setBlockDataMode(oldmode);
1325:   }
1326:         
1327: 
1328:   /**
1329:    * Helper function for writeFields(Object,ObjectStreamClass): write
1330:    * fields from given fields array.  Pass exception on.
1331:    *
1332:    * @param obj the object to be written
1333:    *
1334:    * @param fields the fields of obj to be written.
1335:    */
1336:   private void writeFields(Object obj, ObjectStreamField[] fields)
1337:     throws
1338:       IllegalArgumentException, IllegalAccessException, IOException
1339:   {
1340:     for (int i = 0; i < fields.length; i++)
1341:       {
1342:         ObjectStreamField osf = fields[i];
1343:         Field field = osf.field;
1344:         
1345:         if (DEBUG && dump)
1346:           dumpElementln ("WRITE FIELD: " + osf.getName() + " type=" + osf.getType());
1347:         
1348:         switch (osf.getTypeCode())
1349:           {
1350:           case 'Z': realOutput.writeBoolean(field.getBoolean(obj)); break;
1351:           case 'B': realOutput.writeByte   (field.getByte   (obj)); break;
1352:           case 'S': realOutput.writeShort  (field.getShort  (obj)); break;
1353:           case 'C': realOutput.writeChar   (field.getChar   (obj)); break;
1354:           case 'I': realOutput.writeInt    (field.getInt    (obj)); break;
1355:           case 'F': realOutput.writeFloat  (field.getFloat  (obj)); break;
1356:           case 'J': realOutput.writeLong   (field.getLong   (obj)); break;
1357:           case 'D': realOutput.writeDouble (field.getDouble (obj)); break;
1358:           case 'L': 
1359:           case '[':            writeObject (field.get       (obj)); break;
1360:           default: 
1361:             throw new IOException("Unexpected type code " + osf.getTypeCode());
1362:           }
1363:       }
1364:   }
1365: 
1366: 
1367:   // Toggles writing primitive data to block-data buffer.
1368:   // Package-private to avoid a trampoline constructor.
1369:   boolean setBlockDataMode(boolean on) throws IOException
1370:   {
1371:     if (on == writeDataAsBlocks)
1372:       return on;
1373: 
1374:     drain();
1375:     boolean oldmode = writeDataAsBlocks;
1376:     writeDataAsBlocks = on;
1377: 
1378:     if (on)
1379:       dataOutput = blockDataOutput;
1380:     else
1381:       dataOutput = realOutput;
1382: 
1383:     return oldmode;
1384:   }
1385: 
1386: 
1387:   private void callWriteMethod(Object obj, ObjectStreamClass osc)
1388:     throws IOException
1389:   {
1390:     currentPutField = null;
1391:     try
1392:       {
1393:         Object args[] = {this};
1394:         osc.writeObjectMethod.invoke(obj, args);
1395:       }
1396:     catch (InvocationTargetException x)
1397:       {
1398:         /* Rethrow if possible. */
1399:     Throwable exception = x.getTargetException();
1400:     if (exception instanceof RuntimeException)
1401:       throw (RuntimeException) exception;
1402:     if (exception instanceof IOException)
1403:       throw (IOException) exception;
1404: 
1405:     IOException ioe
1406:       = new IOException("Exception thrown from writeObject() on " +
1407:                 osc.forClass().getName() + ": " +
1408:                             exception.getClass().getName());
1409:     ioe.initCause(exception);
1410:     throw ioe;
1411:       }
1412:     catch (Exception x)
1413:       {
1414:     IOException ioe
1415:       = new IOException("Failure invoking writeObject() on " +
1416:                 osc.forClass().getName() + ": " +
1417:                 x.getClass().getName());
1418:     ioe.initCause(x);
1419:     throw ioe;
1420:       }
1421:   }
1422: 
1423:   private void dumpElementln (String msg, Object obj)
1424:   {
1425:     try
1426:       {
1427:     for (int i = 0; i < depth; i++)
1428:       System.out.print (" ");
1429:     System.out.print (Thread.currentThread() + ": ");
1430:     System.out.print (msg);
1431:     if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
1432:       System.out.print (obj.getClass());
1433:     else
1434:       System.out.print (obj);
1435:       }
1436:     catch (Exception _)
1437:       {
1438:       }
1439:     finally
1440:       {
1441:     System.out.println ();
1442:       }
1443:   }
1444: 
1445:   private void dumpElementln (String msg)
1446:   {
1447:     for (int i = 0; i < depth; i++)
1448:       System.out.print (" ");
1449:     System.out.print (Thread.currentThread() + ": ");
1450:     System.out.println(msg);
1451:   }
1452: 
1453:   // this value comes from 1.2 spec, but is used in 1.1 as well
1454:   private static final int BUFFER_SIZE = 1024;
1455: 
1456:   private static int defaultProtocolVersion = PROTOCOL_VERSION_2;
1457: 
1458:   private DataOutputStream dataOutput;
1459:   private boolean writeDataAsBlocks;
1460:   private DataOutputStream realOutput;
1461:   private DataOutputStream blockDataOutput;
1462:   private byte[] blockData;
1463:   private int blockDataCount;
1464:   private Object currentObject;
1465:   // Package-private to avoid a trampoline.
1466:   ObjectStreamClass currentObjectStreamClass;
1467:   private PutField currentPutField;
1468:   private boolean fieldsAlreadyWritten;
1469:   private boolean replacementEnabled;
1470:   private boolean isSerializing;
1471:   private int nextOID;
1472:   private ObjectIdentityMap2Int OIDLookupTable;
1473:   private int protocolVersion;
1474:   private boolean useSubclassMethod;
1475:   private SetAccessibleAction setAccessible = new SetAccessibleAction();
1476: 
1477:   // The nesting depth for debugging output
1478:   private int depth = 0;
1479: 
1480:   // Set if we're generating debugging dumps
1481:   private boolean dump = false;
1482: 
1483:   private static final boolean DEBUG = false;
1484: }