Source Code Cross Referenced for ObjectOutputStream.java in  » 6.0-JDK-Core » io-nio » java » io » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » io nio » java.io 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1996-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025
0026        package java.io;
0027
0028        import java.io.ObjectStreamClass.WeakClassKey;
0029        import java.lang.ref.ReferenceQueue;
0030        import java.security.AccessController;
0031        import java.security.PrivilegedAction;
0032        import java.util.ArrayList;
0033        import java.util.Arrays;
0034        import java.util.List;
0035        import java.util.concurrent.ConcurrentHashMap;
0036        import java.util.concurrent.ConcurrentMap;
0037        import static java.io.ObjectStreamClass.processQueue;
0038
0039        /**
0040         * An ObjectOutputStream writes primitive data types and graphs of Java objects
0041         * to an OutputStream.  The objects can be read (reconstituted) using an
0042         * ObjectInputStream.  Persistent storage of objects can be accomplished by
0043         * using a file for the stream.  If the stream is a network socket stream, the
0044         * objects can be reconstituted on another host or in another process.
0045         *
0046         * <p>Only objects that support the java.io.Serializable interface can be
0047         * written to streams.  The class of each serializable object is encoded
0048         * including the class name and signature of the class, the values of the
0049         * object's fields and arrays, and the closure of any other objects referenced
0050         * from the initial objects.
0051         *
0052         * <p>The method writeObject is used to write an object to the stream.  Any
0053         * object, including Strings and arrays, is written with writeObject. Multiple
0054         * objects or primitives can be written to the stream.  The objects must be
0055         * read back from the corresponding ObjectInputstream with the same types and
0056         * in the same order as they were written.
0057         *
0058         * <p>Primitive data types can also be written to the stream using the
0059         * appropriate methods from DataOutput. Strings can also be written using the
0060         * writeUTF method.
0061         *
0062         * <p>The default serialization mechanism for an object writes the class of the
0063         * object, the class signature, and the values of all non-transient and
0064         * non-static fields.  References to other objects (except in transient or
0065         * static fields) cause those objects to be written also. Multiple references
0066         * to a single object are encoded using a reference sharing mechanism so that
0067         * graphs of objects can be restored to the same shape as when the original was
0068         * written.
0069         *
0070         * <p>For example to write an object that can be read by the example in
0071         * ObjectInputStream:
0072         * <br>
0073         * <pre>
0074         *	FileOutputStream fos = new FileOutputStream("t.tmp");
0075         *	ObjectOutputStream oos = new ObjectOutputStream(fos);
0076         *
0077         *	oos.writeInt(12345);
0078         *	oos.writeObject("Today");
0079         *	oos.writeObject(new Date());
0080         *
0081         *	oos.close();
0082         * </pre>
0083         *
0084         * <p>Classes that require special handling during the serialization and
0085         * deserialization process must implement special methods with these exact
0086         * signatures:
0087         * <br>
0088         * <pre>
0089         * private void readObject(java.io.ObjectInputStream stream)
0090         *     throws IOException, ClassNotFoundException;
0091         * private void writeObject(java.io.ObjectOutputStream stream)
0092         *     throws IOException
0093         * private void readObjectNoData() 
0094         *     throws ObjectStreamException;
0095         * </pre>
0096         * 
0097         * <p>The writeObject method is responsible for writing the state of the object
0098         * for its particular class so that the corresponding readObject method can
0099         * restore it.  The method does not need to concern itself with the state
0100         * belonging to the object's superclasses or subclasses.  State is saved by
0101         * writing the individual fields to the ObjectOutputStream using the
0102         * writeObject method or by using the methods for primitive data types
0103         * supported by DataOutput.
0104         *
0105         * <p>Serialization does not write out the fields of any object that does not
0106         * implement the java.io.Serializable interface.  Subclasses of Objects that
0107         * are not serializable can be serializable. In this case the non-serializable
0108         * class must have a no-arg constructor to allow its fields to be initialized.
0109         * In this case it is the responsibility of the subclass to save and restore
0110         * the state of the non-serializable class. It is frequently the case that the
0111         * fields of that class are accessible (public, package, or protected) or that
0112         * there are get and set methods that can be used to restore the state.
0113         *
0114         * <p>Serialization of an object can be prevented by implementing writeObject
0115         * and readObject methods that throw the NotSerializableException.  The
0116         * exception will be caught by the ObjectOutputStream and abort the
0117         * serialization process.
0118         *
0119         * <p>Implementing the Externalizable interface allows the object to assume
0120         * complete control over the contents and format of the object's serialized
0121         * form.  The methods of the Externalizable interface, writeExternal and
0122         * readExternal, are called to save and restore the objects state.  When
0123         * implemented by a class they can write and read their own state using all of
0124         * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
0125         * the objects to handle any versioning that occurs.
0126         *
0127         * <p>Enum constants are serialized differently than ordinary serializable or
0128         * externalizable objects.  The serialized form of an enum constant consists
0129         * solely of its name; field values of the constant are not transmitted.  To
0130         * serialize an enum constant, ObjectOutputStream writes the string returned by
0131         * the constant's name method.  Like other serializable or externalizable
0132         * objects, enum constants can function as the targets of back references
0133         * appearing subsequently in the serialization stream.  The process by which
0134         * enum constants are serialized cannot be customized; any class-specific
0135         * writeObject and writeReplace methods defined by enum types are ignored
0136         * during serialization.  Similarly, any serialPersistentFields or
0137         * serialVersionUID field declarations are also ignored--all enum types have a
0138         * fixed serialVersionUID of 0L.
0139         *
0140         * <p>Primitive data, excluding serializable fields and externalizable data, is
0141         * written to the ObjectOutputStream in block-data records. A block data record
0142         * is composed of a header and data. The block data header consists of a marker
0143         * and the number of bytes to follow the header.  Consecutive primitive data
0144         * writes are merged into one block-data record.  The blocking factor used for
0145         * a block-data record will be 1024 bytes.  Each block-data record will be
0146         * filled up to 1024 bytes, or be written whenever there is a termination of
0147         * block-data mode.  Calls to the ObjectOutputStream methods writeObject,
0148         * defaultWriteObject and writeFields initially terminate any existing
0149         * block-data record.
0150         *
0151         * @author	Mike Warres
0152         * @author	Roger Riggs
0153         * @version     1.165, 07/05/05
0154         * @see java.io.DataOutput
0155         * @see java.io.ObjectInputStream
0156         * @see java.io.Serializable
0157         * @see java.io.Externalizable
0158         * @see <a href="../../../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a>
0159         * @since       JDK1.1
0160         */
0161        public class ObjectOutputStream extends OutputStream implements 
0162                ObjectOutput, ObjectStreamConstants {
0163
0164            private static class Caches {
0165                /** cache of subclass security audit results */
0166                static final ConcurrentMap<WeakClassKey, Boolean> subclassAudits = new ConcurrentHashMap<WeakClassKey, Boolean>();
0167
0168                /** queue for WeakReferences to audited subclasses */
0169                static final ReferenceQueue<Class<?>> subclassAuditsQueue = new ReferenceQueue<Class<?>>();
0170            }
0171
0172            /** filter stream for handling block data conversion */
0173            private final BlockDataOutputStream bout;
0174            /** obj -> wire handle map */
0175            private final HandleTable handles;
0176            /** obj -> replacement obj map */
0177            private final ReplaceTable subs;
0178            /** stream protocol version */
0179            private int protocol = PROTOCOL_VERSION_2;
0180            /** recursion depth */
0181            private int depth;
0182
0183            /** buffer for writing primitive field values */
0184            private byte[] primVals;
0185
0186            /** if true, invoke writeObjectOverride() instead of writeObject() */
0187            private final boolean enableOverride;
0188            /** if true, invoke replaceObject() */
0189            private boolean enableReplace;
0190
0191            // values below valid only during upcalls to writeObject()/writeExternal()
0192            /** object currently being serialized */
0193            private Object curObj;
0194            /** descriptor for current class (null if in writeExternal()) */
0195            private ObjectStreamClass curDesc;
0196            /** current PutField object */
0197            private PutFieldImpl curPut;
0198
0199            /** custom storage for debug trace info */
0200            private final DebugTraceInfoStack debugInfoStack;
0201
0202            /**
0203             * value of "sun.io.serialization.extendedDebugInfo" property,
0204             * as true or false for extended information about exception's place
0205             */
0206            private static final boolean extendedDebugInfo = ((Boolean) java.security.AccessController
0207                    .doPrivileged(new sun.security.action.GetBooleanAction(
0208                            "sun.io.serialization.extendedDebugInfo")))
0209                    .booleanValue();
0210
0211            /**
0212             * Creates an ObjectOutputStream that writes to the specified OutputStream.
0213             * This constructor writes the serialization stream header to the
0214             * underlying stream; callers may wish to flush the stream immediately to
0215             * ensure that constructors for receiving ObjectInputStreams will not block
0216             * when reading the header.
0217             *
0218             * <p>If a security manager is installed, this constructor will check for
0219             * the "enableSubclassImplementation" SerializablePermission when invoked
0220             * directly or indirectly by the constructor of a subclass which overrides
0221             * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared
0222             * methods.
0223             *
0224             * @param	out output stream to write to
0225             * @throws	IOException if an I/O error occurs while writing stream header
0226             * @throws	SecurityException if untrusted subclass illegally overrides
0227             * 		security-sensitive methods
0228             * @throws	NullPointerException if <code>out</code> is <code>null</code>
0229             * @since	1.4
0230             * @see	ObjectOutputStream#ObjectOutputStream()
0231             * @see	ObjectOutputStream#putFields()
0232             * @see	ObjectInputStream#ObjectInputStream(InputStream)
0233             */
0234            public ObjectOutputStream(OutputStream out) throws IOException {
0235                verifySubclass();
0236                bout = new BlockDataOutputStream(out);
0237                handles = new HandleTable(10, (float) 3.00);
0238                subs = new ReplaceTable(10, (float) 3.00);
0239                enableOverride = false;
0240                writeStreamHeader();
0241                bout.setBlockDataMode(true);
0242                if (extendedDebugInfo) {
0243                    debugInfoStack = new DebugTraceInfoStack();
0244                } else {
0245                    debugInfoStack = null;
0246                }
0247            }
0248
0249            /**
0250             * Provide a way for subclasses that are completely reimplementing
0251             * ObjectOutputStream to not have to allocate private data just used by
0252             * this implementation of ObjectOutputStream.
0253             *
0254             * <p>If there is a security manager installed, this method first calls the
0255             * security manager's <code>checkPermission</code> method with a
0256             * <code>SerializablePermission("enableSubclassImplementation")</code>
0257             * permission to ensure it's ok to enable subclassing.
0258             *
0259             * @throws	SecurityException if a security manager exists and its
0260             * 		<code>checkPermission</code> method denies enabling
0261             * 		subclassing.
0262             * @see SecurityManager#checkPermission
0263             * @see java.io.SerializablePermission
0264             */
0265            protected ObjectOutputStream() throws IOException,
0266                    SecurityException {
0267                SecurityManager sm = System.getSecurityManager();
0268                if (sm != null) {
0269                    sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
0270                }
0271                bout = null;
0272                handles = null;
0273                subs = null;
0274                enableOverride = true;
0275                debugInfoStack = null;
0276            }
0277
0278            /**
0279             * Specify stream protocol version to use when writing the stream.
0280             *
0281             * <p>This routine provides a hook to enable the current version of
0282             * Serialization to write in a format that is backwards compatible to a
0283             * previous version of the stream format.
0284             *
0285             * <p>Every effort will be made to avoid introducing additional
0286             * backwards incompatibilities; however, sometimes there is no
0287             * other alternative.
0288             *
0289             * @param	version use ProtocolVersion from java.io.ObjectStreamConstants.
0290             * @throws	IllegalStateException if called after any objects
0291             * 		have been serialized.
0292             * @throws	IllegalArgumentException if invalid version is passed in.
0293             * @throws	IOException if I/O errors occur
0294             * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
0295             * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2
0296             * @since	1.2
0297             */
0298            public void useProtocolVersion(int version) throws IOException {
0299                if (handles.size() != 0) {
0300                    // REMIND: implement better check for pristine stream?
0301                    throw new IllegalStateException("stream non-empty");
0302                }
0303                switch (version) {
0304                case PROTOCOL_VERSION_1:
0305                case PROTOCOL_VERSION_2:
0306                    protocol = version;
0307                    break;
0308
0309                default:
0310                    throw new IllegalArgumentException("unknown version: "
0311                            + version);
0312                }
0313            }
0314
0315            /**
0316             * Write the specified object to the ObjectOutputStream.  The class of the
0317             * object, the signature of the class, and the values of the non-transient
0318             * and non-static fields of the class and all of its supertypes are
0319             * written.  Default serialization for a class can be overridden using the
0320             * writeObject and the readObject methods.  Objects referenced by this
0321             * object are written transitively so that a complete equivalent graph of
0322             * objects can be reconstructed by an ObjectInputStream.
0323             *
0324             * <p>Exceptions are thrown for problems with the OutputStream and for
0325             * classes that should not be serialized.  All exceptions are fatal to the
0326             * OutputStream, which is left in an indeterminate state, and it is up to
0327             * the caller to ignore or recover the stream state.
0328             *
0329             * @throws	InvalidClassException Something is wrong with a class used by
0330             *		serialization.
0331             * @throws	NotSerializableException Some object to be serialized does not
0332             *		implement the java.io.Serializable interface.
0333             * @throws	IOException Any exception thrown by the underlying
0334             * 		OutputStream.
0335             */
0336            public final void writeObject(Object obj) throws IOException {
0337                if (enableOverride) {
0338                    writeObjectOverride(obj);
0339                    return;
0340                }
0341                try {
0342                    writeObject0(obj, false);
0343                } catch (IOException ex) {
0344                    if (depth == 0) {
0345                        writeFatalException(ex);
0346                    }
0347                    throw ex;
0348                }
0349            }
0350
0351            /**
0352             * Method used by subclasses to override the default writeObject method.
0353             * This method is called by trusted subclasses of ObjectInputStream that
0354             * constructed ObjectInputStream using the protected no-arg constructor.
0355             * The subclass is expected to provide an override method with the modifier
0356             * "final".
0357             *
0358             * @param	obj object to be written to the underlying stream
0359             * @throws	IOException if there are I/O errors while writing to the
0360             * 		underlying stream
0361             * @see #ObjectOutputStream()
0362             * @see #writeObject(Object)
0363             * @since 1.2
0364             */
0365            protected void writeObjectOverride(Object obj) throws IOException {
0366            }
0367
0368            /**
0369             * Writes an "unshared" object to the ObjectOutputStream.  This method is
0370             * identical to writeObject, except that it always writes the given object
0371             * as a new, unique object in the stream (as opposed to a back-reference
0372             * pointing to a previously serialized instance).  Specifically:
0373             * <ul>
0374             *   <li>An object written via writeUnshared is always serialized in the
0375             *       same manner as a newly appearing object (an object that has not
0376             *       been written to the stream yet), regardless of whether or not the
0377             *       object has been written previously.
0378             *
0379             *   <li>If writeObject is used to write an object that has been previously
0380             *       written with writeUnshared, the previous writeUnshared operation
0381             *       is treated as if it were a write of a separate object.  In other
0382             *       words, ObjectOutputStream will never generate back-references to
0383             *       object data written by calls to writeUnshared.
0384             * </ul>
0385             * While writing an object via writeUnshared does not in itself guarantee a
0386             * unique reference to the object when it is deserialized, it allows a
0387             * single object to be defined multiple times in a stream, so that multiple
0388             * calls to readUnshared by the receiver will not conflict.  Note that the
0389             * rules described above only apply to the base-level object written with
0390             * writeUnshared, and not to any transitively referenced sub-objects in the
0391             * object graph to be serialized.
0392             *
0393             * <p>ObjectOutputStream subclasses which override this method can only be
0394             * constructed in security contexts possessing the
0395             * "enableSubclassImplementation" SerializablePermission; any attempt to
0396             * instantiate such a subclass without this permission will cause a
0397             * SecurityException to be thrown.
0398             *
0399             * @param   obj object to write to stream
0400             * @throws  NotSerializableException if an object in the graph to be
0401             *          serialized does not implement the Serializable interface
0402             * @throws  InvalidClassException if a problem exists with the class of an
0403             *          object to be serialized
0404             * @throws  IOException if an I/O error occurs during serialization
0405             * @since 1.4
0406             */
0407            public void writeUnshared(Object obj) throws IOException {
0408                try {
0409                    writeObject0(obj, true);
0410                } catch (IOException ex) {
0411                    if (depth == 0) {
0412                        writeFatalException(ex);
0413                    }
0414                    throw ex;
0415                }
0416            }
0417
0418            /**
0419             * Write the non-static and non-transient fields of the current class to
0420             * this stream.  This may only be called from the writeObject method of the
0421             * class being serialized. It will throw the NotActiveException if it is
0422             * called otherwise.
0423             *
0424             * @throws	IOException if I/O errors occur while writing to the underlying
0425             * 		<code>OutputStream</code>
0426             */
0427            public void defaultWriteObject() throws IOException {
0428                if (curObj == null || curDesc == null) {
0429                    throw new NotActiveException("not in call to writeObject");
0430                }
0431                bout.setBlockDataMode(false);
0432                defaultWriteFields(curObj, curDesc);
0433                bout.setBlockDataMode(true);
0434            }
0435
0436            /**
0437             * Retrieve the object used to buffer persistent fields to be written to
0438             * the stream.  The fields will be written to the stream when writeFields
0439             * method is called.
0440             * 
0441             * @return	an instance of the class Putfield that holds the serializable
0442             * 		fields
0443             * @throws	IOException if I/O errors occur
0444             * @since 1.2
0445             */
0446            public ObjectOutputStream.PutField putFields() throws IOException {
0447                if (curPut == null) {
0448                    if (curObj == null || curDesc == null) {
0449                        throw new NotActiveException(
0450                                "not in call to writeObject");
0451                    }
0452                    curPut = new PutFieldImpl(curDesc);
0453                }
0454                return curPut;
0455            }
0456
0457            /**
0458             * Write the buffered fields to the stream.
0459             *
0460             * @throws	IOException if I/O errors occur while writing to the underlying
0461             * 		stream
0462             * @throws	NotActiveException Called when a classes writeObject method was
0463             * 		not called to write the state of the object.
0464             * @since 1.2
0465             */
0466            public void writeFields() throws IOException {
0467                if (curPut == null) {
0468                    throw new NotActiveException("no current PutField object");
0469                }
0470                bout.setBlockDataMode(false);
0471                curPut.writeFields();
0472                bout.setBlockDataMode(true);
0473            }
0474
0475            /**
0476             * Reset will disregard the state of any objects already written to the
0477             * stream.  The state is reset to be the same as a new ObjectOutputStream.
0478             * The current point in the stream is marked as reset so the corresponding
0479             * ObjectInputStream will be reset at the same point.  Objects previously
0480             * written to the stream will not be refered to as already being in the
0481             * stream.  They will be written to the stream again.
0482             * 
0483             * @throws	IOException if reset() is invoked while serializing an object.
0484             */
0485            public void reset() throws IOException {
0486                if (depth != 0) {
0487                    throw new IOException("stream active");
0488                }
0489                bout.setBlockDataMode(false);
0490                bout.writeByte(TC_RESET);
0491                clear();
0492                bout.setBlockDataMode(true);
0493            }
0494
0495            /**
0496             * Subclasses may implement this method to allow class data to be stored in
0497             * the stream. By default this method does nothing.  The corresponding
0498             * method in ObjectInputStream is resolveClass.  This method is called
0499             * exactly once for each unique class in the stream.  The class name and
0500             * signature will have already been written to the stream.  This method may
0501             * make free use of the ObjectOutputStream to save any representation of
0502             * the class it deems suitable (for example, the bytes of the class file).
0503             * The resolveClass method in the corresponding subclass of
0504             * ObjectInputStream must read and use any data or objects written by
0505             * annotateClass.
0506             *
0507             * @param	cl the class to annotate custom data for
0508             * @throws	IOException Any exception thrown by the underlying
0509             * 		OutputStream.
0510             */
0511            protected void annotateClass(Class<?> cl) throws IOException {
0512            }
0513
0514            /**
0515             * Subclasses may implement this method to store custom data in the stream
0516             * along with descriptors for dynamic proxy classes.
0517             *
0518             * <p>This method is called exactly once for each unique proxy class
0519             * descriptor in the stream.  The default implementation of this method in
0520             * <code>ObjectOutputStream</code> does nothing.
0521             *
0522             * <p>The corresponding method in <code>ObjectInputStream</code> is
0523             * <code>resolveProxyClass</code>.  For a given subclass of
0524             * <code>ObjectOutputStream</code> that overrides this method, the
0525             * <code>resolveProxyClass</code> method in the corresponding subclass of
0526             * <code>ObjectInputStream</code> must read any data or objects written by
0527             * <code>annotateProxyClass</code>.
0528             *
0529             * @param	cl the proxy class to annotate custom data for
0530             * @throws	IOException any exception thrown by the underlying
0531             *		<code>OutputStream</code>
0532             * @see ObjectInputStream#resolveProxyClass(String[])
0533             * @since	1.3
0534             */
0535            protected void annotateProxyClass(Class<?> cl) throws IOException {
0536            }
0537
0538            /** 
0539             * This method will allow trusted subclasses of ObjectOutputStream to
0540             * substitute one object for another during serialization. Replacing
0541             * objects is disabled until enableReplaceObject is called. The
0542             * enableReplaceObject method checks that the stream requesting to do
0543             * replacement can be trusted.  The first occurrence of each object written
0544             * into the serialization stream is passed to replaceObject.  Subsequent
0545             * references to the object are replaced by the object returned by the
0546             * original call to replaceObject.  To ensure that the private state of
0547             * objects is not unintentionally exposed, only trusted streams may use
0548             * replaceObject.
0549             * 
0550             * <p>The ObjectOutputStream.writeObject method takes a parameter of type
0551             * Object (as opposed to type Serializable) to allow for cases where
0552             * non-serializable objects are replaced by serializable ones.
0553             * 
0554             * <p>When a subclass is replacing objects it must insure that either a
0555             * complementary substitution must be made during deserialization or that
0556             * the substituted object is compatible with every field where the
0557             * reference will be stored.  Objects whose type is not a subclass of the
0558             * type of the field or array element abort the serialization by raising an
0559             * exception and the object is not be stored.
0560             *
0561             * <p>This method is called only once when each object is first
0562             * encountered.  All subsequent references to the object will be redirected
0563             * to the new object. This method should return the object to be
0564             * substituted or the original object.
0565             *
0566             * <p>Null can be returned as the object to be substituted, but may cause
0567             * NullReferenceException in classes that contain references to the
0568             * original object since they may be expecting an object instead of
0569             * null.
0570             *
0571             * @param	obj the object to be replaced
0572             * @return	the alternate object that replaced the specified one
0573             * @throws	IOException Any exception thrown by the underlying
0574             * 		OutputStream.
0575             */
0576            protected Object replaceObject(Object obj) throws IOException {
0577                return obj;
0578            }
0579
0580            /**
0581             * Enable the stream to do replacement of objects in the stream.  When
0582             * enabled, the replaceObject method is called for every object being
0583             * serialized.
0584             *
0585             * <p>If <code>enable</code> is true, and there is a security manager
0586             * installed, this method first calls the security manager's
0587             * <code>checkPermission</code> method with a
0588             * <code>SerializablePermission("enableSubstitution")</code> permission to
0589             * ensure it's ok to enable the stream to do replacement of objects in the
0590             * stream.
0591             *
0592             * @param	enable boolean parameter to enable replacement of objects
0593             * @return	the previous setting before this method was invoked
0594             * @throws	SecurityException if a security manager exists and its
0595             * 		<code>checkPermission</code> method denies enabling the stream
0596             * 		to do replacement of objects in the stream.
0597             * @see SecurityManager#checkPermission
0598             * @see java.io.SerializablePermission
0599             */
0600            protected boolean enableReplaceObject(boolean enable)
0601                    throws SecurityException {
0602                if (enable == enableReplace) {
0603                    return enable;
0604                }
0605                if (enable) {
0606                    SecurityManager sm = System.getSecurityManager();
0607                    if (sm != null) {
0608                        sm.checkPermission(SUBSTITUTION_PERMISSION);
0609                    }
0610                }
0611                enableReplace = enable;
0612                return !enableReplace;
0613            }
0614
0615            /**
0616             * The writeStreamHeader method is provided so subclasses can append or
0617             * prepend their own header to the stream.  It writes the magic number and
0618             * version to the stream.
0619             *
0620             * @throws	IOException if I/O errors occur while writing to the underlying
0621             * 		stream
0622             */
0623            protected void writeStreamHeader() throws IOException {
0624                bout.writeShort(STREAM_MAGIC);
0625                bout.writeShort(STREAM_VERSION);
0626            }
0627
0628            /**
0629             * Write the specified class descriptor to the ObjectOutputStream.  Class
0630             * descriptors are used to identify the classes of objects written to the
0631             * stream.  Subclasses of ObjectOutputStream may override this method to
0632             * customize the way in which class descriptors are written to the
0633             * serialization stream.  The corresponding method in ObjectInputStream,
0634             * <code>readClassDescriptor</code>, should then be overridden to
0635             * reconstitute the class descriptor from its custom stream representation.
0636             * By default, this method writes class descriptors according to the format
0637             * defined in the Object Serialization specification.
0638             * 
0639             * <p>Note that this method will only be called if the ObjectOutputStream
0640             * is not using the old serialization stream format (set by calling
0641             * ObjectOutputStream's <code>useProtocolVersion</code> method).  If this
0642             * serialization stream is using the old format
0643             * (<code>PROTOCOL_VERSION_1</code>), the class descriptor will be written
0644             * internally in a manner that cannot be overridden or customized.
0645             *
0646             * @param	desc class descriptor to write to the stream
0647             * @throws	IOException If an I/O error has occurred.
0648             * @see java.io.ObjectInputStream#readClassDescriptor()
0649             * @see #useProtocolVersion(int)
0650             * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
0651             * @since 1.3
0652             */
0653            protected void writeClassDescriptor(ObjectStreamClass desc)
0654                    throws IOException {
0655                desc.writeNonProxy(this );
0656            }
0657
0658            /**
0659             * Writes a byte. This method will block until the byte is actually
0660             * written.
0661             *
0662             * @param	val the byte to be written to the stream
0663             * @throws	IOException If an I/O error has occurred.
0664             */
0665            public void write(int val) throws IOException {
0666                bout.write(val);
0667            }
0668
0669            /**
0670             * Writes an array of bytes. This method will block until the bytes are
0671             * actually written.
0672             *
0673             * @param	buf the data to be written
0674             * @throws	IOException If an I/O error has occurred.
0675             */
0676            public void write(byte[] buf) throws IOException {
0677                bout.write(buf, 0, buf.length, false);
0678            }
0679
0680            /**
0681             * Writes a sub array of bytes.
0682             *
0683             * @param	buf the data to be written
0684             * @param	off the start offset in the data
0685             * @param	len the number of bytes that are written
0686             * @throws	IOException If an I/O error has occurred.
0687             */
0688            public void write(byte[] buf, int off, int len) throws IOException {
0689                if (buf == null) {
0690                    throw new NullPointerException();
0691                }
0692                int endoff = off + len;
0693                if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
0694                    throw new IndexOutOfBoundsException();
0695                }
0696                bout.write(buf, off, len, false);
0697            }
0698
0699            /**
0700             * Flushes the stream. This will write any buffered output bytes and flush
0701             * through to the underlying stream.
0702             *
0703             * @throws	IOException If an I/O error has occurred.
0704             */
0705            public void flush() throws IOException {
0706                bout.flush();
0707            }
0708
0709            /**
0710             * Drain any buffered data in ObjectOutputStream.  Similar to flush but
0711             * does not propagate the flush to the underlying stream.
0712             *
0713             * @throws	IOException if I/O errors occur while writing to the underlying
0714             * 		stream
0715             */
0716            protected void drain() throws IOException {
0717                bout.drain();
0718            }
0719
0720            /**
0721             * Closes the stream. This method must be called to release any resources
0722             * associated with the stream.
0723             *
0724             * @throws	IOException If an I/O error has occurred.
0725             */
0726            public void close() throws IOException {
0727                flush();
0728                clear();
0729                bout.close();
0730            }
0731
0732            /**
0733             * Writes a boolean.
0734             *
0735             * @param	val the boolean to be written
0736             * @throws	IOException if I/O errors occur while writing to the underlying
0737             * 		stream
0738             */
0739            public void writeBoolean(boolean val) throws IOException {
0740                bout.writeBoolean(val);
0741            }
0742
0743            /**
0744             * Writes an 8 bit byte.
0745             *
0746             * @param	val the byte value to be written
0747             * @throws	IOException if I/O errors occur while writing to the underlying
0748             * 		stream
0749             */
0750            public void writeByte(int val) throws IOException {
0751                bout.writeByte(val);
0752            }
0753
0754            /**
0755             * Writes a 16 bit short.
0756             *
0757             * @param	val the short value to be written
0758             * @throws	IOException if I/O errors occur while writing to the underlying
0759             * 		stream
0760             */
0761            public void writeShort(int val) throws IOException {
0762                bout.writeShort(val);
0763            }
0764
0765            /**
0766             * Writes a 16 bit char.
0767             *
0768             * @param	val the char value to be written
0769             * @throws	IOException if I/O errors occur while writing to the underlying
0770             * 		stream
0771             */
0772            public void writeChar(int val) throws IOException {
0773                bout.writeChar(val);
0774            }
0775
0776            /**
0777             * Writes a 32 bit int.
0778             *
0779             * @param	val the integer value to be written
0780             * @throws	IOException if I/O errors occur while writing to the underlying
0781             * 		stream
0782             */
0783            public void writeInt(int val) throws IOException {
0784                bout.writeInt(val);
0785            }
0786
0787            /**
0788             * Writes a 64 bit long.
0789             *
0790             * @param	val the long value to be written
0791             * @throws	IOException if I/O errors occur while writing to the underlying
0792             * 		stream
0793             */
0794            public void writeLong(long val) throws IOException {
0795                bout.writeLong(val);
0796            }
0797
0798            /**
0799             * Writes a 32 bit float.
0800             *
0801             * @param	val the float value to be written
0802             * @throws	IOException if I/O errors occur while writing to the underlying
0803             * 		stream
0804             */
0805            public void writeFloat(float val) throws IOException {
0806                bout.writeFloat(val);
0807            }
0808
0809            /**
0810             * Writes a 64 bit double.
0811             *
0812             * @param	val the double value to be written
0813             * @throws	IOException if I/O errors occur while writing to the underlying
0814             * 		stream
0815             */
0816            public void writeDouble(double val) throws IOException {
0817                bout.writeDouble(val);
0818            }
0819
0820            /**
0821             * Writes a String as a sequence of bytes.
0822             *
0823             * @param	str the String of bytes to be written
0824             * @throws	IOException if I/O errors occur while writing to the underlying
0825             * 		stream
0826             */
0827            public void writeBytes(String str) throws IOException {
0828                bout.writeBytes(str);
0829            }
0830
0831            /**
0832             * Writes a String as a sequence of chars.
0833             *
0834             * @param	str the String of chars to be written
0835             * @throws	IOException if I/O errors occur while writing to the underlying
0836             * 		stream
0837             */
0838            public void writeChars(String str) throws IOException {
0839                bout.writeChars(str);
0840            }
0841
0842            /**
0843             * Primitive data write of this String in 
0844             * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
0845             * format.  Note that there is a
0846             * significant difference between writing a String into the stream as
0847             * primitive data or as an Object. A String instance written by writeObject
0848             * is written into the stream as a String initially. Future writeObject()
0849             * calls write references to the string into the stream.
0850             *
0851             * @param	str the String to be written
0852             * @throws	IOException if I/O errors occur while writing to the underlying
0853             * 		stream
0854             */
0855            public void writeUTF(String str) throws IOException {
0856                bout.writeUTF(str);
0857            }
0858
0859            /**
0860             * Provide programmatic access to the persistent fields to be written
0861             * to ObjectOutput.
0862             *
0863             * @since 1.2
0864             */
0865            public static abstract class PutField {
0866
0867                /**
0868                 * Put the value of the named boolean field into the persistent field.
0869                 *
0870                 * @param  name the name of the serializable field
0871                 * @param  val the value to assign to the field
0872                 * @throws IllegalArgumentException if <code>name</code> does not
0873                 * match the name of a serializable field for the class whose fields
0874                 * are being written, or if the type of the named field is not
0875                 * <code>boolean</code>
0876                 */
0877                public abstract void put(String name, boolean val);
0878
0879                /**
0880                 * Put the value of the named byte field into the persistent field.
0881                 *
0882                 * @param  name the name of the serializable field
0883                 * @param  val the value to assign to the field
0884                 * @throws IllegalArgumentException if <code>name</code> does not
0885                 * match the name of a serializable field for the class whose fields
0886                 * are being written, or if the type of the named field is not
0887                 * <code>byte</code>
0888                 */
0889                public abstract void put(String name, byte val);
0890
0891                /**
0892                 * Put the value of the named char field into the persistent field.
0893                 *
0894                 * @param  name the name of the serializable field
0895                 * @param  val the value to assign to the field
0896                 * @throws IllegalArgumentException if <code>name</code> does not
0897                 * match the name of a serializable field for the class whose fields
0898                 * are being written, or if the type of the named field is not
0899                 * <code>char</code>
0900                 */
0901                public abstract void put(String name, char val);
0902
0903                /**
0904                 * Put the value of the named short field into the persistent field.
0905                 *
0906                 * @param  name the name of the serializable field
0907                 * @param  val the value to assign to the field
0908                 * @throws IllegalArgumentException if <code>name</code> does not
0909                 * match the name of a serializable field for the class whose fields
0910                 * are being written, or if the type of the named field is not
0911                 * <code>short</code>
0912                 */
0913                public abstract void put(String name, short val);
0914
0915                /**
0916                 * Put the value of the named int field into the persistent field.
0917                 *
0918                 * @param  name the name of the serializable field
0919                 * @param  val the value to assign to the field
0920                 * @throws IllegalArgumentException if <code>name</code> does not
0921                 * match the name of a serializable field for the class whose fields
0922                 * are being written, or if the type of the named field is not
0923                 * <code>int</code>
0924                 */
0925                public abstract void put(String name, int val);
0926
0927                /**
0928                 * Put the value of the named long field into the persistent field.
0929                 *
0930                 * @param  name the name of the serializable field
0931                 * @param  val the value to assign to the field
0932                 * @throws IllegalArgumentException if <code>name</code> does not
0933                 * match the name of a serializable field for the class whose fields
0934                 * are being written, or if the type of the named field is not
0935                 * <code>long</code>
0936                 */
0937                public abstract void put(String name, long val);
0938
0939                /**
0940                 * Put the value of the named float field into the persistent field.
0941                 *
0942                 * @param  name the name of the serializable field
0943                 * @param  val the value to assign to the field
0944                 * @throws IllegalArgumentException if <code>name</code> does not
0945                 * match the name of a serializable field for the class whose fields
0946                 * are being written, or if the type of the named field is not
0947                 * <code>float</code>
0948                 */
0949                public abstract void put(String name, float val);
0950
0951                /**
0952                 * Put the value of the named double field into the persistent field.
0953                 *
0954                 * @param  name the name of the serializable field
0955                 * @param  val the value to assign to the field
0956                 * @throws IllegalArgumentException if <code>name</code> does not
0957                 * match the name of a serializable field for the class whose fields
0958                 * are being written, or if the type of the named field is not
0959                 * <code>double</code>
0960                 */
0961                public abstract void put(String name, double val);
0962
0963                /**
0964                 * Put the value of the named Object field into the persistent field.
0965                 *
0966                 * @param  name the name of the serializable field
0967                 * @param  val the value to assign to the field
0968                 *         (which may be <code>null</code>)
0969                 * @throws IllegalArgumentException if <code>name</code> does not
0970                 * match the name of a serializable field for the class whose fields
0971                 * are being written, or if the type of the named field is not a
0972                 * reference type
0973                 */
0974                public abstract void put(String name, Object val);
0975
0976                /**
0977                 * Write the data and fields to the specified ObjectOutput stream, 
0978                 * which must be the same stream that produced this  
0979                 * <code>PutField</code> object.
0980                 * 
0981                 * @param  out the stream to write the data and fields to
0982                 * @throws IOException if I/O errors occur while writing to the
0983                 * 	   underlying stream
0984                 * @throws IllegalArgumentException if the specified stream is not 
0985                 *         the same stream that produced this <code>PutField</code> 
0986                 *         object
0987                 * @deprecated This method does not write the values contained by this
0988                 * 	   <code>PutField</code> object in a proper format, and may
0989                 * 	   result in corruption of the serialization stream.  The
0990                 * 	   correct way to write <code>PutField</code> data is by
0991                 * 	   calling the {@link java.io.ObjectOutputStream#writeFields()}
0992                 * 	   method.
0993                 */
0994                @Deprecated
0995                public abstract void write(ObjectOutput out) throws IOException;
0996            }
0997
0998            /**
0999             * Returns protocol version in use.
1000             */
1001            int getProtocolVersion() {
1002                return protocol;
1003            }
1004
1005            /**
1006             * Writes string without allowing it to be replaced in stream.  Used by
1007             * ObjectStreamClass to write class descriptor type strings.
1008             */
1009            void writeTypeString(String str) throws IOException {
1010                int handle;
1011                if (str == null) {
1012                    writeNull();
1013                } else if ((handle = handles.lookup(str)) != -1) {
1014                    writeHandle(handle);
1015                } else {
1016                    writeString(str, false);
1017                }
1018            }
1019
1020            /**
1021             * Verifies that this (possibly subclass) instance can be constructed
1022             * without violating security constraints: the subclass must not override
1023             * security-sensitive non-final methods, or else the
1024             * "enableSubclassImplementation" SerializablePermission is checked.
1025             */
1026            private void verifySubclass() {
1027                Class cl = getClass();
1028                if (cl == ObjectOutputStream.class) {
1029                    return;
1030                }
1031                SecurityManager sm = System.getSecurityManager();
1032                if (sm == null) {
1033                    return;
1034                }
1035                processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
1036                WeakClassKey key = new WeakClassKey(cl,
1037                        Caches.subclassAuditsQueue);
1038                Boolean result = Caches.subclassAudits.get(key);
1039                if (result == null) {
1040                    result = Boolean.valueOf(auditSubclass(cl));
1041                    Caches.subclassAudits.putIfAbsent(key, result);
1042                }
1043                if (result.booleanValue()) {
1044                    return;
1045                }
1046                sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1047            }
1048
1049            /**
1050             * Performs reflective checks on given subclass to verify that it doesn't
1051             * override security-sensitive non-final methods.  Returns true if subclass
1052             * is "safe", false otherwise.
1053             */
1054            private static boolean auditSubclass(final Class subcl) {
1055                Boolean result = (Boolean) AccessController
1056                        .doPrivileged(new PrivilegedAction() {
1057                            public Object run() {
1058                                for (Class cl = subcl; cl != ObjectOutputStream.class; cl = cl
1059                                        .getSuperclass()) {
1060                                    try {
1061                                        cl.getDeclaredMethod("writeUnshared",
1062                                                new Class[] { Object.class });
1063                                        return Boolean.FALSE;
1064                                    } catch (NoSuchMethodException ex) {
1065                                    }
1066                                    try {
1067                                        cl.getDeclaredMethod("putFields",
1068                                                (Class[]) null);
1069                                        return Boolean.FALSE;
1070                                    } catch (NoSuchMethodException ex) {
1071                                    }
1072                                }
1073                                return Boolean.TRUE;
1074                            }
1075                        });
1076                return result.booleanValue();
1077            }
1078
1079            /**
1080             * Clears internal data structures.
1081             */
1082            private void clear() {
1083                subs.clear();
1084                handles.clear();
1085            }
1086
1087            /**
1088             * Underlying writeObject/writeUnshared implementation.
1089             */
1090            private void writeObject0(Object obj, boolean unshared)
1091                    throws IOException {
1092                boolean oldMode = bout.setBlockDataMode(false);
1093                depth++;
1094                try {
1095                    // handle previously written and non-replaceable objects
1096                    int h;
1097                    if ((obj = subs.lookup(obj)) == null) {
1098                        writeNull();
1099                        return;
1100                    } else if (!unshared && (h = handles.lookup(obj)) != -1) {
1101                        writeHandle(h);
1102                        return;
1103                    } else if (obj instanceof  Class) {
1104                        writeClass((Class) obj, unshared);
1105                        return;
1106                    } else if (obj instanceof  ObjectStreamClass) {
1107                        writeClassDesc((ObjectStreamClass) obj, unshared);
1108                        return;
1109                    }
1110
1111                    // check for replacement object
1112                    Object orig = obj;
1113                    Class cl = obj.getClass();
1114                    ObjectStreamClass desc;
1115                    for (;;) {
1116                        // REMIND: skip this check for strings/arrays?
1117                        Class repCl;
1118                        desc = ObjectStreamClass.lookup(cl, true);
1119                        if (!desc.hasWriteReplaceMethod()
1120                                || (obj = desc.invokeWriteReplace(obj)) == null
1121                                || (repCl = obj.getClass()) == cl) {
1122                            break;
1123                        }
1124                        cl = repCl;
1125                    }
1126                    if (enableReplace) {
1127                        Object rep = replaceObject(obj);
1128                        if (rep != obj && rep != null) {
1129                            cl = rep.getClass();
1130                            desc = ObjectStreamClass.lookup(cl, true);
1131                        }
1132                        obj = rep;
1133                    }
1134
1135                    // if object replaced, run through original checks a second time
1136                    if (obj != orig) {
1137                        subs.assign(orig, obj);
1138                        if (obj == null) {
1139                            writeNull();
1140                            return;
1141                        } else if (!unshared && (h = handles.lookup(obj)) != -1) {
1142                            writeHandle(h);
1143                            return;
1144                        } else if (obj instanceof  Class) {
1145                            writeClass((Class) obj, unshared);
1146                            return;
1147                        } else if (obj instanceof  ObjectStreamClass) {
1148                            writeClassDesc((ObjectStreamClass) obj, unshared);
1149                            return;
1150                        }
1151                    }
1152
1153                    // remaining cases
1154                    if (obj instanceof  String) {
1155                        writeString((String) obj, unshared);
1156                    } else if (cl.isArray()) {
1157                        writeArray(obj, desc, unshared);
1158                    } else if (obj instanceof  Enum) {
1159                        writeEnum((Enum) obj, desc, unshared);
1160                    } else if (obj instanceof  Serializable) {
1161                        writeOrdinaryObject(obj, desc, unshared);
1162                    } else {
1163                        if (extendedDebugInfo) {
1164                            throw new NotSerializableException(cl.getName()
1165                                    + "\n" + debugInfoStack.toString());
1166                        } else {
1167                            throw new NotSerializableException(cl.getName());
1168                        }
1169                    }
1170                } finally {
1171                    depth--;
1172                    bout.setBlockDataMode(oldMode);
1173                }
1174            }
1175
1176            /**
1177             * Writes null code to stream.
1178             */
1179            private void writeNull() throws IOException {
1180                bout.writeByte(TC_NULL);
1181            }
1182
1183            /**
1184             * Writes given object handle to stream.
1185             */
1186            private void writeHandle(int handle) throws IOException {
1187                bout.writeByte(TC_REFERENCE);
1188                bout.writeInt(baseWireHandle + handle);
1189            }
1190
1191            /**
1192             * Writes representation of given class to stream.
1193             */
1194            private void writeClass(Class cl, boolean unshared)
1195                    throws IOException {
1196                bout.writeByte(TC_CLASS);
1197                writeClassDesc(ObjectStreamClass.lookup(cl, true), false);
1198                handles.assign(unshared ? null : cl);
1199            }
1200
1201            /**
1202             * Writes representation of given class descriptor to stream.
1203             */
1204            private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
1205                    throws IOException {
1206                int handle;
1207                if (desc == null) {
1208                    writeNull();
1209                } else if (!unshared && (handle = handles.lookup(desc)) != -1) {
1210                    writeHandle(handle);
1211                } else if (desc.isProxy()) {
1212                    writeProxyDesc(desc, unshared);
1213                } else {
1214                    writeNonProxyDesc(desc, unshared);
1215                }
1216            }
1217
1218            /**
1219             * Writes class descriptor representing a dynamic proxy class to stream.
1220             */
1221            private void writeProxyDesc(ObjectStreamClass desc, boolean unshared)
1222                    throws IOException {
1223                bout.writeByte(TC_PROXYCLASSDESC);
1224                handles.assign(unshared ? null : desc);
1225
1226                Class cl = desc.forClass();
1227                Class[] ifaces = cl.getInterfaces();
1228                bout.writeInt(ifaces.length);
1229                for (int i = 0; i < ifaces.length; i++) {
1230                    bout.writeUTF(ifaces[i].getName());
1231                }
1232
1233                bout.setBlockDataMode(true);
1234                annotateProxyClass(cl);
1235                bout.setBlockDataMode(false);
1236                bout.writeByte(TC_ENDBLOCKDATA);
1237
1238                writeClassDesc(desc.getSuperDesc(), false);
1239            }
1240
1241            /**
1242             * Writes class descriptor representing a standard (i.e., not a dynamic
1243             * proxy) class to stream.
1244             */
1245            private void writeNonProxyDesc(ObjectStreamClass desc,
1246                    boolean unshared) throws IOException {
1247                bout.writeByte(TC_CLASSDESC);
1248                handles.assign(unshared ? null : desc);
1249
1250                if (protocol == PROTOCOL_VERSION_1) {
1251                    // do not invoke class descriptor write hook with old protocol
1252                    desc.writeNonProxy(this );
1253                } else {
1254                    writeClassDescriptor(desc);
1255                }
1256
1257                Class cl = desc.forClass();
1258                bout.setBlockDataMode(true);
1259                annotateClass(cl);
1260                bout.setBlockDataMode(false);
1261                bout.writeByte(TC_ENDBLOCKDATA);
1262
1263                writeClassDesc(desc.getSuperDesc(), false);
1264            }
1265
1266            /**
1267             * Writes given string to stream, using standard or long UTF format
1268             * depending on string length.
1269             */
1270            private void writeString(String str, boolean unshared)
1271                    throws IOException {
1272                handles.assign(unshared ? null : str);
1273                long utflen = bout.getUTFLength(str);
1274                if (utflen <= 0xFFFF) {
1275                    bout.writeByte(TC_STRING);
1276                    bout.writeUTF(str, utflen);
1277                } else {
1278                    bout.writeByte(TC_LONGSTRING);
1279                    bout.writeLongUTF(str, utflen);
1280                }
1281            }
1282
1283            /**
1284             * Writes given array object to stream.
1285             */
1286            private void writeArray(Object array, ObjectStreamClass desc,
1287                    boolean unshared) throws IOException {
1288                bout.writeByte(TC_ARRAY);
1289                writeClassDesc(desc, false);
1290                handles.assign(unshared ? null : array);
1291
1292                Class ccl = desc.forClass().getComponentType();
1293                if (ccl.isPrimitive()) {
1294                    if (ccl == Integer.TYPE) {
1295                        int[] ia = (int[]) array;
1296                        bout.writeInt(ia.length);
1297                        bout.writeInts(ia, 0, ia.length);
1298                    } else if (ccl == Byte.TYPE) {
1299                        byte[] ba = (byte[]) array;
1300                        bout.writeInt(ba.length);
1301                        bout.write(ba, 0, ba.length, true);
1302                    } else if (ccl == Long.TYPE) {
1303                        long[] ja = (long[]) array;
1304                        bout.writeInt(ja.length);
1305                        bout.writeLongs(ja, 0, ja.length);
1306                    } else if (ccl == Float.TYPE) {
1307                        float[] fa = (float[]) array;
1308                        bout.writeInt(fa.length);
1309                        bout.writeFloats(fa, 0, fa.length);
1310                    } else if (ccl == Double.TYPE) {
1311                        double[] da = (double[]) array;
1312                        bout.writeInt(da.length);
1313                        bout.writeDoubles(da, 0, da.length);
1314                    } else if (ccl == Short.TYPE) {
1315                        short[] sa = (short[]) array;
1316                        bout.writeInt(sa.length);
1317                        bout.writeShorts(sa, 0, sa.length);
1318                    } else if (ccl == Character.TYPE) {
1319                        char[] ca = (char[]) array;
1320                        bout.writeInt(ca.length);
1321                        bout.writeChars(ca, 0, ca.length);
1322                    } else if (ccl == Boolean.TYPE) {
1323                        boolean[] za = (boolean[]) array;
1324                        bout.writeInt(za.length);
1325                        bout.writeBooleans(za, 0, za.length);
1326                    } else {
1327                        throw new InternalError();
1328                    }
1329                } else {
1330                    Object[] objs = (Object[]) array;
1331                    int len = objs.length;
1332                    bout.writeInt(len);
1333                    if (extendedDebugInfo) {
1334                        debugInfoStack.push("array (class \""
1335                                + array.getClass().getName() + "\", size: "
1336                                + len + ")");
1337                    }
1338                    try {
1339                        for (int i = 0; i < len; i++) {
1340                            if (extendedDebugInfo) {
1341                                debugInfoStack.push("element of array (index: "
1342                                        + i + ")");
1343                            }
1344                            try {
1345                                writeObject0(objs[i], false);
1346                            } finally {
1347                                if (extendedDebugInfo) {
1348                                    debugInfoStack.pop();
1349                                }
1350                            }
1351                        }
1352                    } finally {
1353                        if (extendedDebugInfo) {
1354                            debugInfoStack.pop();
1355                        }
1356                    }
1357                }
1358            }
1359
1360            /**
1361             * Writes given enum constant to stream.
1362             */
1363            private void writeEnum(Enum en, ObjectStreamClass desc,
1364                    boolean unshared) throws IOException {
1365                bout.writeByte(TC_ENUM);
1366                ObjectStreamClass sdesc = desc.getSuperDesc();
1367                writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc,
1368                        false);
1369                handles.assign(unshared ? null : en);
1370                writeString(en.name(), false);
1371            }
1372
1373            /**
1374             * Writes representation of a "ordinary" (i.e., not a String, Class,
1375             * ObjectStreamClass, array, or enum constant) serializable object to the
1376             * stream.
1377             */
1378            private void writeOrdinaryObject(Object obj,
1379                    ObjectStreamClass desc, boolean unshared)
1380                    throws IOException {
1381                if (extendedDebugInfo) {
1382                    debugInfoStack.push((depth == 1 ? "root " : "")
1383                            + "object (class \"" + obj.getClass().getName()
1384                            + "\", " + obj.toString() + ")");
1385                }
1386                try {
1387                    desc.checkSerialize();
1388
1389                    bout.writeByte(TC_OBJECT);
1390                    writeClassDesc(desc, false);
1391                    handles.assign(unshared ? null : obj);
1392                    if (desc.isExternalizable() && !desc.isProxy()) {
1393                        writeExternalData((Externalizable) obj);
1394                    } else {
1395                        writeSerialData(obj, desc);
1396                    }
1397                } finally {
1398                    if (extendedDebugInfo) {
1399                        debugInfoStack.pop();
1400                    }
1401                }
1402            }
1403
1404            /**
1405             * Writes externalizable data of given object by invoking its
1406             * writeExternal() method.
1407             */
1408            private void writeExternalData(Externalizable obj)
1409                    throws IOException {
1410                Object oldObj = curObj;
1411                ObjectStreamClass oldDesc = curDesc;
1412                PutFieldImpl oldPut = curPut;
1413                curObj = obj;
1414                curDesc = null;
1415                curPut = null;
1416
1417                if (extendedDebugInfo) {
1418                    debugInfoStack.push("writeExternal data");
1419                }
1420                try {
1421                    if (protocol == PROTOCOL_VERSION_1) {
1422                        obj.writeExternal(this );
1423                    } else {
1424                        bout.setBlockDataMode(true);
1425                        obj.writeExternal(this );
1426                        bout.setBlockDataMode(false);
1427                        bout.writeByte(TC_ENDBLOCKDATA);
1428                    }
1429                } finally {
1430                    if (extendedDebugInfo) {
1431                        debugInfoStack.pop();
1432                    }
1433                }
1434
1435                curObj = oldObj;
1436                curDesc = oldDesc;
1437                curPut = oldPut;
1438            }
1439
1440            /**
1441             * Writes instance data for each serializable class of given object, from
1442             * superclass to subclass.
1443             */
1444            private void writeSerialData(Object obj, ObjectStreamClass desc)
1445                    throws IOException {
1446                ObjectStreamClass.ClassDataSlot[] slots = desc
1447                        .getClassDataLayout();
1448                for (int i = 0; i < slots.length; i++) {
1449                    ObjectStreamClass slotDesc = slots[i].desc;
1450                    if (slotDesc.hasWriteObjectMethod()) {
1451                        Object oldObj = curObj;
1452                        ObjectStreamClass oldDesc = curDesc;
1453                        PutFieldImpl oldPut = curPut;
1454                        curObj = obj;
1455                        curDesc = slotDesc;
1456                        curPut = null;
1457
1458                        if (extendedDebugInfo) {
1459                            debugInfoStack
1460                                    .push("custom writeObject data (class \""
1461                                            + slotDesc.getName() + "\")");
1462                        }
1463                        try {
1464                            bout.setBlockDataMode(true);
1465                            slotDesc.invokeWriteObject(obj, this );
1466                            bout.setBlockDataMode(false);
1467                            bout.writeByte(TC_ENDBLOCKDATA);
1468                        } finally {
1469                            if (extendedDebugInfo) {
1470                                debugInfoStack.pop();
1471                            }
1472                        }
1473
1474                        curObj = oldObj;
1475                        curDesc = oldDesc;
1476                        curPut = oldPut;
1477                    } else {
1478                        defaultWriteFields(obj, slotDesc);
1479                    }
1480                }
1481            }
1482
1483            /**
1484             * Fetches and writes values of serializable fields of given object to
1485             * stream.  The given class descriptor specifies which field values to
1486             * write, and in which order they should be written.
1487             */
1488            private void defaultWriteFields(Object obj, ObjectStreamClass desc)
1489                    throws IOException {
1490                // REMIND: perform conservative isInstance check here?
1491                desc.checkDefaultSerialize();
1492
1493                int primDataSize = desc.getPrimDataSize();
1494                if (primVals == null || primVals.length < primDataSize) {
1495                    primVals = new byte[primDataSize];
1496                }
1497                desc.getPrimFieldValues(obj, primVals);
1498                bout.write(primVals, 0, primDataSize, false);
1499
1500                ObjectStreamField[] fields = desc.getFields(false);
1501                Object[] objVals = new Object[desc.getNumObjFields()];
1502                int numPrimFields = fields.length - objVals.length;
1503                desc.getObjFieldValues(obj, objVals);
1504                for (int i = 0; i < objVals.length; i++) {
1505                    if (extendedDebugInfo) {
1506                        debugInfoStack.push("field (class \"" + desc.getName()
1507                                + "\", name: \""
1508                                + fields[numPrimFields + i].getName()
1509                                + "\", type: \""
1510                                + fields[numPrimFields + i].getType() + "\")");
1511                    }
1512                    try {
1513                        writeObject0(objVals[i], fields[numPrimFields + i]
1514                                .isUnshared());
1515                    } finally {
1516                        if (extendedDebugInfo) {
1517                            debugInfoStack.pop();
1518                        }
1519                    }
1520                }
1521            }
1522
1523            /**
1524             * Attempts to write to stream fatal IOException that has caused
1525             * serialization to abort.
1526             */
1527            private void writeFatalException(IOException ex) throws IOException {
1528                /*
1529                 * Note: the serialization specification states that if a second
1530                 * IOException occurs while attempting to serialize the original fatal
1531                 * exception to the stream, then a StreamCorruptedException should be
1532                 * thrown (section 2.1).  However, due to a bug in previous
1533                 * implementations of serialization, StreamCorruptedExceptions were
1534                 * rarely (if ever) actually thrown--the "root" exceptions from
1535                 * underlying streams were thrown instead.  This historical behavior is
1536                 * followed here for consistency.
1537                 */
1538                clear();
1539                boolean oldMode = bout.setBlockDataMode(false);
1540                try {
1541                    bout.writeByte(TC_EXCEPTION);
1542                    writeObject0(ex, false);
1543                    clear();
1544                } finally {
1545                    bout.setBlockDataMode(oldMode);
1546                }
1547            }
1548
1549            /**
1550             * Converts specified span of float values into byte values.
1551             */
1552            // REMIND: remove once hotspot inlines Float.floatToIntBits
1553            private static native void floatsToBytes(float[] src, int srcpos,
1554                    byte[] dst, int dstpos, int nfloats);
1555
1556            /**
1557             * Converts specified span of double values into byte values.
1558             */
1559            // REMIND: remove once hotspot inlines Double.doubleToLongBits
1560            private static native void doublesToBytes(double[] src, int srcpos,
1561                    byte[] dst, int dstpos, int ndoubles);
1562
1563            /**
1564             * Default PutField implementation.
1565             */
1566            private class PutFieldImpl extends PutField {
1567
1568                /** class descriptor describing serializable fields */
1569                private final ObjectStreamClass desc;
1570                /** primitive field values */
1571                private final byte[] primVals;
1572                /** object field values */
1573                private final Object[] objVals;
1574
1575                /**
1576                 * Creates PutFieldImpl object for writing fields defined in given
1577                 * class descriptor.
1578                 */
1579                PutFieldImpl(ObjectStreamClass desc) {
1580                    this .desc = desc;
1581                    primVals = new byte[desc.getPrimDataSize()];
1582                    objVals = new Object[desc.getNumObjFields()];
1583                }
1584
1585                public void put(String name, boolean val) {
1586                    Bits.putBoolean(primVals,
1587                            getFieldOffset(name, Boolean.TYPE), val);
1588                }
1589
1590                public void put(String name, byte val) {
1591                    primVals[getFieldOffset(name, Byte.TYPE)] = val;
1592                }
1593
1594                public void put(String name, char val) {
1595                    Bits.putChar(primVals,
1596                            getFieldOffset(name, Character.TYPE), val);
1597                }
1598
1599                public void put(String name, short val) {
1600                    Bits.putShort(primVals, getFieldOffset(name, Short.TYPE),
1601                            val);
1602                }
1603
1604                public void put(String name, int val) {
1605                    Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE),
1606                            val);
1607                }
1608
1609                public void put(String name, float val) {
1610                    Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE),
1611                            val);
1612                }
1613
1614                public void put(String name, long val) {
1615                    Bits
1616                            .putLong(primVals, getFieldOffset(name, Long.TYPE),
1617                                    val);
1618                }
1619
1620                public void put(String name, double val) {
1621                    Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE),
1622                            val);
1623                }
1624
1625                public void put(String name, Object val) {
1626                    objVals[getFieldOffset(name, Object.class)] = val;
1627                }
1628
1629                // deprecated in ObjectOutputStream.PutField
1630                public void write(ObjectOutput out) throws IOException {
1631                    /*
1632                     * Applications should *not* use this method to write PutField
1633                     * data, as it will lead to stream corruption if the PutField
1634                     * object writes any primitive data (since block data mode is not
1635                     * unset/set properly, as is done in OOS.writeFields()).  This
1636                     * broken implementation is being retained solely for behavioral
1637                     * compatibility, in order to support applications which use
1638                     * OOS.PutField.write() for writing only non-primitive data.
1639                     * 
1640                     * Serialization of unshared objects is not implemented here since
1641                     * it is not necessary for backwards compatibility; also, unshared
1642                     * semantics may not be supported by the given ObjectOutput
1643                     * instance.  Applications which write unshared objects using the
1644                     * PutField API must use OOS.writeFields().
1645                     */
1646                    if (ObjectOutputStream.this  != out) {
1647                        throw new IllegalArgumentException("wrong stream");
1648                    }
1649                    out.write(primVals, 0, primVals.length);
1650
1651                    ObjectStreamField[] fields = desc.getFields(false);
1652                    int numPrimFields = fields.length - objVals.length;
1653                    // REMIND: warn if numPrimFields > 0?
1654                    for (int i = 0; i < objVals.length; i++) {
1655                        if (fields[numPrimFields + i].isUnshared()) {
1656                            throw new IOException(
1657                                    "cannot write unshared object");
1658                        }
1659                        out.writeObject(objVals[i]);
1660                    }
1661                }
1662
1663                /**
1664                 * Writes buffered primitive data and object fields to stream.
1665                 */
1666                void writeFields() throws IOException {
1667                    bout.write(primVals, 0, primVals.length, false);
1668
1669                    ObjectStreamField[] fields = desc.getFields(false);
1670                    int numPrimFields = fields.length - objVals.length;
1671                    for (int i = 0; i < objVals.length; i++) {
1672                        if (extendedDebugInfo) {
1673                            debugInfoStack.push("field (class \""
1674                                    + desc.getName() + "\", name: \""
1675                                    + fields[numPrimFields + i].getName()
1676                                    + "\", type: \""
1677                                    + fields[numPrimFields + i].getType()
1678                                    + "\")");
1679                        }
1680                        try {
1681                            writeObject0(objVals[i], fields[numPrimFields + i]
1682                                    .isUnshared());
1683                        } finally {
1684                            if (extendedDebugInfo) {
1685                                debugInfoStack.pop();
1686                            }
1687                        }
1688                    }
1689                }
1690
1691                /**
1692                 * Returns offset of field with given name and type.  A specified type
1693                 * of null matches all types, Object.class matches all non-primitive
1694                 * types, and any other non-null type matches assignable types only.
1695                 * Throws IllegalArgumentException if no matching field found.
1696                 */
1697                private int getFieldOffset(String name, Class type) {
1698                    ObjectStreamField field = desc.getField(name, type);
1699                    if (field == null) {
1700                        throw new IllegalArgumentException("no such field "
1701                                + name + " with type " + type);
1702                    }
1703                    return field.getOffset();
1704                }
1705            }
1706
1707            /**
1708             * Buffered output stream with two modes: in default mode, outputs data in
1709             * same format as DataOutputStream; in "block data" mode, outputs data
1710             * bracketed by block data markers (see object serialization specification
1711             * for details).
1712             */
1713            private static class BlockDataOutputStream extends OutputStream
1714                    implements  DataOutput {
1715                /** maximum data block length */
1716                private static final int MAX_BLOCK_SIZE = 1024;
1717                /** maximum data block header length */
1718                private static final int MAX_HEADER_SIZE = 5;
1719                /** (tunable) length of char buffer (for writing strings) */
1720                private static final int CHAR_BUF_SIZE = 256;
1721
1722                /** buffer for writing general/block data */
1723                private final byte[] buf = new byte[MAX_BLOCK_SIZE];
1724                /** buffer for writing block data headers */
1725                private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
1726                /** char buffer for fast string writes */
1727                private final char[] cbuf = new char[CHAR_BUF_SIZE];
1728
1729                /** block data mode */
1730                private boolean blkmode = false;
1731                /** current offset into buf */
1732                private int pos = 0;
1733
1734                /** underlying output stream */
1735                private final OutputStream out;
1736                /** loopback stream (for data writes that span data blocks) */
1737                private final DataOutputStream dout;
1738
1739                /**
1740                 * Creates new BlockDataOutputStream on top of given underlying stream.
1741                 * Block data mode is turned off by default.
1742                 */
1743                BlockDataOutputStream(OutputStream out) {
1744                    this .out = out;
1745                    dout = new DataOutputStream(this );
1746                }
1747
1748                /**
1749                 * Sets block data mode to the given mode (true == on, false == off)
1750                 * and returns the previous mode value.  If the new mode is the same as
1751                 * the old mode, no action is taken.  If the new mode differs from the
1752                 * old mode, any buffered data is flushed before switching to the new
1753                 * mode.
1754                 */
1755                boolean setBlockDataMode(boolean mode) throws IOException {
1756                    if (blkmode == mode) {
1757                        return blkmode;
1758                    }
1759                    drain();
1760                    blkmode = mode;
1761                    return !blkmode;
1762                }
1763
1764                /**
1765                 * Returns true if the stream is currently in block data mode, false
1766                 * otherwise.
1767                 */
1768                boolean getBlockDataMode() {
1769                    return blkmode;
1770                }
1771
1772                /* ----------------- generic output stream methods ----------------- */
1773                /*
1774                 * The following methods are equivalent to their counterparts in
1775                 * OutputStream, except that they partition written data into data
1776                 * blocks when in block data mode.
1777                 */
1778
1779                public void write(int b) throws IOException {
1780                    if (pos >= MAX_BLOCK_SIZE) {
1781                        drain();
1782                    }
1783                    buf[pos++] = (byte) b;
1784                }
1785
1786                public void write(byte[] b) throws IOException {
1787                    write(b, 0, b.length, false);
1788                }
1789
1790                public void write(byte[] b, int off, int len)
1791                        throws IOException {
1792                    write(b, off, len, false);
1793                }
1794
1795                public void flush() throws IOException {
1796                    drain();
1797                    out.flush();
1798                }
1799
1800                public void close() throws IOException {
1801                    flush();
1802                    out.close();
1803                }
1804
1805                /**
1806                 * Writes specified span of byte values from given array.  If copy is
1807                 * true, copies the values to an intermediate buffer before writing
1808                 * them to underlying stream (to avoid exposing a reference to the
1809                 * original byte array).
1810                 */
1811                void write(byte[] b, int off, int len, boolean copy)
1812                        throws IOException {
1813                    if (!(copy || blkmode)) { // write directly
1814                        drain();
1815                        out.write(b, off, len);
1816                        return;
1817                    }
1818
1819                    while (len > 0) {
1820                        if (pos >= MAX_BLOCK_SIZE) {
1821                            drain();
1822                        }
1823                        if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) {
1824                            // avoid unnecessary copy
1825                            writeBlockHeader(MAX_BLOCK_SIZE);
1826                            out.write(b, off, MAX_BLOCK_SIZE);
1827                            off += MAX_BLOCK_SIZE;
1828                            len -= MAX_BLOCK_SIZE;
1829                        } else {
1830                            int wlen = Math.min(len, MAX_BLOCK_SIZE - pos);
1831                            System.arraycopy(b, off, buf, pos, wlen);
1832                            pos += wlen;
1833                            off += wlen;
1834                            len -= wlen;
1835                        }
1836                    }
1837                }
1838
1839                /**
1840                 * Writes all buffered data from this stream to the underlying stream,
1841                 * but does not flush underlying stream.
1842                 */
1843                void drain() throws IOException {
1844                    if (pos == 0) {
1845                        return;
1846                    }
1847                    if (blkmode) {
1848                        writeBlockHeader(pos);
1849                    }
1850                    out.write(buf, 0, pos);
1851                    pos = 0;
1852                }
1853
1854                /**
1855                 * Writes block data header.  Data blocks shorter than 256 bytes are
1856                 * prefixed with a 2-byte header; all others start with a 5-byte
1857                 * header.
1858                 */
1859                private void writeBlockHeader(int len) throws IOException {
1860                    if (len <= 0xFF) {
1861                        hbuf[0] = TC_BLOCKDATA;
1862                        hbuf[1] = (byte) len;
1863                        out.write(hbuf, 0, 2);
1864                    } else {
1865                        hbuf[0] = TC_BLOCKDATALONG;
1866                        Bits.putInt(hbuf, 1, len);
1867                        out.write(hbuf, 0, 5);
1868                    }
1869                }
1870
1871                /* ----------------- primitive data output methods ----------------- */
1872                /*
1873                 * The following methods are equivalent to their counterparts in
1874                 * DataOutputStream, except that they partition written data into data
1875                 * blocks when in block data mode.
1876                 */
1877
1878                public void writeBoolean(boolean v) throws IOException {
1879                    if (pos >= MAX_BLOCK_SIZE) {
1880                        drain();
1881                    }
1882                    Bits.putBoolean(buf, pos++, v);
1883                }
1884
1885                public void writeByte(int v) throws IOException {
1886                    if (pos >= MAX_BLOCK_SIZE) {
1887                        drain();
1888                    }
1889                    buf[pos++] = (byte) v;
1890                }
1891
1892                public void writeChar(int v) throws IOException {
1893                    if (pos + 2 <= MAX_BLOCK_SIZE) {
1894                        Bits.putChar(buf, pos, (char) v);
1895                        pos += 2;
1896                    } else {
1897                        dout.writeChar(v);
1898                    }
1899                }
1900
1901                public void writeShort(int v) throws IOException {
1902                    if (pos + 2 <= MAX_BLOCK_SIZE) {
1903                        Bits.putShort(buf, pos, (short) v);
1904                        pos += 2;
1905                    } else {
1906                        dout.writeShort(v);
1907                    }
1908                }
1909
1910                public void writeInt(int v) throws IOException {
1911                    if (pos + 4 <= MAX_BLOCK_SIZE) {
1912                        Bits.putInt(buf, pos, v);
1913                        pos += 4;
1914                    } else {
1915                        dout.writeInt(v);
1916                    }
1917                }
1918
1919                public void writeFloat(float v) throws IOException {
1920                    if (pos + 4 <= MAX_BLOCK_SIZE) {
1921                        Bits.putFloat(buf, pos, v);
1922                        pos += 4;
1923                    } else {
1924                        dout.writeFloat(v);
1925                    }
1926                }
1927
1928                public void writeLong(long v) throws IOException {
1929                    if (pos + 8 <= MAX_BLOCK_SIZE) {
1930                        Bits.putLong(buf, pos, v);
1931                        pos += 8;
1932                    } else {
1933                        dout.writeLong(v);
1934                    }
1935                }
1936
1937                public void writeDouble(double v) throws IOException {
1938                    if (pos + 8 <= MAX_BLOCK_SIZE) {
1939                        Bits.putDouble(buf, pos, v);
1940                        pos += 8;
1941                    } else {
1942                        dout.writeDouble(v);
1943                    }
1944                }
1945
1946                public void writeBytes(String s) throws IOException {
1947                    int endoff = s.length();
1948                    int cpos = 0;
1949                    int csize = 0;
1950                    for (int off = 0; off < endoff;) {
1951                        if (cpos >= csize) {
1952                            cpos = 0;
1953                            csize = Math.min(endoff - off, CHAR_BUF_SIZE);
1954                            s.getChars(off, off + csize, cbuf, 0);
1955                        }
1956                        if (pos >= MAX_BLOCK_SIZE) {
1957                            drain();
1958                        }
1959                        int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos);
1960                        int stop = pos + n;
1961                        while (pos < stop) {
1962                            buf[pos++] = (byte) cbuf[cpos++];
1963                        }
1964                        off += n;
1965                    }
1966                }
1967
1968                public void writeChars(String s) throws IOException {
1969                    int endoff = s.length();
1970                    for (int off = 0; off < endoff;) {
1971                        int csize = Math.min(endoff - off, CHAR_BUF_SIZE);
1972                        s.getChars(off, off + csize, cbuf, 0);
1973                        writeChars(cbuf, 0, csize);
1974                        off += csize;
1975                    }
1976                }
1977
1978                public void writeUTF(String s) throws IOException {
1979                    writeUTF(s, getUTFLength(s));
1980                }
1981
1982                /* -------------- primitive data array output methods -------------- */
1983                /*
1984                 * The following methods write out spans of primitive data values.
1985                 * Though equivalent to calling the corresponding primitive write
1986                 * methods repeatedly, these methods are optimized for writing groups
1987                 * of primitive data values more efficiently.
1988                 */
1989
1990                void writeBooleans(boolean[] v, int off, int len)
1991                        throws IOException {
1992                    int endoff = off + len;
1993                    while (off < endoff) {
1994                        if (pos >= MAX_BLOCK_SIZE) {
1995                            drain();
1996                        }
1997                        int stop = Math.min(endoff, off
1998                                + (MAX_BLOCK_SIZE - pos));
1999                        while (off < stop) {
2000                            Bits.putBoolean(buf, pos++, v[off++]);
2001                        }
2002                    }
2003                }
2004
2005                void writeChars(char[] v, int off, int len) throws IOException {
2006                    int limit = MAX_BLOCK_SIZE - 2;
2007                    int endoff = off + len;
2008                    while (off < endoff) {
2009                        if (pos <= limit) {
2010                            int avail = (MAX_BLOCK_SIZE - pos) >> 1;
2011                            int stop = Math.min(endoff, off + avail);
2012                            while (off < stop) {
2013                                Bits.putChar(buf, pos, v[off++]);
2014                                pos += 2;
2015                            }
2016                        } else {
2017                            dout.writeChar(v[off++]);
2018                        }
2019                    }
2020                }
2021
2022                void writeShorts(short[] v, int off, int len)
2023                        throws IOException {
2024                    int limit = MAX_BLOCK_SIZE - 2;
2025                    int endoff = off + len;
2026                    while (off < endoff) {
2027                        if (pos <= limit) {
2028                            int avail = (MAX_BLOCK_SIZE - pos) >> 1;
2029                            int stop = Math.min(endoff, off + avail);
2030                            while (off < stop) {
2031                                Bits.putShort(buf, pos, v[off++]);
2032                                pos += 2;
2033                            }
2034                        } else {
2035                            dout.writeShort(v[off++]);
2036                        }
2037                    }
2038                }
2039
2040                void writeInts(int[] v, int off, int len) throws IOException {
2041                    int limit = MAX_BLOCK_SIZE - 4;
2042                    int endoff = off + len;
2043                    while (off < endoff) {
2044                        if (pos <= limit) {
2045                            int avail = (MAX_BLOCK_SIZE - pos) >> 2;
2046                            int stop = Math.min(endoff, off + avail);
2047                            while (off < stop) {
2048                                Bits.putInt(buf, pos, v[off++]);
2049                                pos += 4;
2050                            }
2051                        } else {
2052                            dout.writeInt(v[off++]);
2053                        }
2054                    }
2055                }
2056
2057                void writeFloats(float[] v, int off, int len)
2058                        throws IOException {
2059                    int limit = MAX_BLOCK_SIZE - 4;
2060                    int endoff = off + len;
2061                    while (off < endoff) {
2062                        if (pos <= limit) {
2063                            int avail = (MAX_BLOCK_SIZE - pos) >> 2;
2064                            int chunklen = Math.min(endoff - off, avail);
2065                            floatsToBytes(v, off, buf, pos, chunklen);
2066                            off += chunklen;
2067                            pos += chunklen << 2;
2068                        } else {
2069                            dout.writeFloat(v[off++]);
2070                        }
2071                    }
2072                }
2073
2074                void writeLongs(long[] v, int off, int len) throws IOException {
2075                    int limit = MAX_BLOCK_SIZE - 8;
2076                    int endoff = off + len;
2077                    while (off < endoff) {
2078                        if (pos <= limit) {
2079                            int avail = (MAX_BLOCK_SIZE - pos) >> 3;
2080                            int stop = Math.min(endoff, off + avail);
2081                            while (off < stop) {
2082                                Bits.putLong(buf, pos, v[off++]);
2083                                pos += 8;
2084                            }
2085                        } else {
2086                            dout.writeLong(v[off++]);
2087                        }
2088                    }
2089                }
2090
2091                void writeDoubles(double[] v, int off, int len)
2092                        throws IOException {
2093                    int limit = MAX_BLOCK_SIZE - 8;
2094                    int endoff = off + len;
2095                    while (off < endoff) {
2096                        if (pos <= limit) {
2097                            int avail = (MAX_BLOCK_SIZE - pos) >> 3;
2098                            int chunklen = Math.min(endoff - off, avail);
2099                            doublesToBytes(v, off, buf, pos, chunklen);
2100                            off += chunklen;
2101                            pos += chunklen << 3;
2102                        } else {
2103                            dout.writeDouble(v[off++]);
2104                        }
2105                    }
2106                }
2107
2108                /**
2109                 * Returns the length in bytes of the UTF encoding of the given string.
2110                 */
2111                long getUTFLength(String s) {
2112                    int len = s.length();
2113                    long utflen = 0;
2114                    for (int off = 0; off < len;) {
2115                        int csize = Math.min(len - off, CHAR_BUF_SIZE);
2116                        s.getChars(off, off + csize, cbuf, 0);
2117                        for (int cpos = 0; cpos < csize; cpos++) {
2118                            char c = cbuf[cpos];
2119                            if (c >= 0x0001 && c <= 0x007F) {
2120                                utflen++;
2121                            } else if (c > 0x07FF) {
2122                                utflen += 3;
2123                            } else {
2124                                utflen += 2;
2125                            }
2126                        }
2127                        off += csize;
2128                    }
2129                    return utflen;
2130                }
2131
2132                /**
2133                 * Writes the given string in UTF format.  This method is used in
2134                 * situations where the UTF encoding length of the string is already
2135                 * known; specifying it explicitly avoids a prescan of the string to
2136                 * determine its UTF length.
2137                 */
2138                void writeUTF(String s, long utflen) throws IOException {
2139                    if (utflen > 0xFFFFL) {
2140                        throw new UTFDataFormatException();
2141                    }
2142                    writeShort((int) utflen);
2143                    if (utflen == (long) s.length()) {
2144                        writeBytes(s);
2145                    } else {
2146                        writeUTFBody(s);
2147                    }
2148                }
2149
2150                /**
2151                 * Writes given string in "long" UTF format.  "Long" UTF format is
2152                 * identical to standard UTF, except that it uses an 8 byte header
2153                 * (instead of the standard 2 bytes) to convey the UTF encoding length.
2154                 */
2155                void writeLongUTF(String s) throws IOException {
2156                    writeLongUTF(s, getUTFLength(s));
2157                }
2158
2159                /**
2160                 * Writes given string in "long" UTF format, where the UTF encoding
2161                 * length of the string is already known.
2162                 */
2163                void writeLongUTF(String s, long utflen) throws IOException {
2164                    writeLong(utflen);
2165                    if (utflen == (long) s.length()) {
2166                        writeBytes(s);
2167                    } else {
2168                        writeUTFBody(s);
2169                    }
2170                }
2171
2172                /**
2173                 * Writes the "body" (i.e., the UTF representation minus the 2-byte or
2174                 * 8-byte length header) of the UTF encoding for the given string.
2175                 */
2176                private void writeUTFBody(String s) throws IOException {
2177                    int limit = MAX_BLOCK_SIZE - 3;
2178                    int len = s.length();
2179                    for (int off = 0; off < len;) {
2180                        int csize = Math.min(len - off, CHAR_BUF_SIZE);
2181                        s.getChars(off, off + csize, cbuf, 0);
2182                        for (int cpos = 0; cpos < csize; cpos++) {
2183                            char c = cbuf[cpos];
2184                            if (pos <= limit) {
2185                                if (c <= 0x007F && c != 0) {
2186                                    buf[pos++] = (byte) c;
2187                                } else if (c > 0x07FF) {
2188                                    buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));
2189                                    buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));
2190                                    buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));
2191                                    pos += 3;
2192                                } else {
2193                                    buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));
2194                                    buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));
2195                                    pos += 2;
2196                                }
2197                            } else { // write one byte at a time to normalize block
2198                                if (c <= 0x007F && c != 0) {
2199                                    write(c);
2200                                } else if (c > 0x07FF) {
2201                                    write(0xE0 | ((c >> 12) & 0x0F));
2202                                    write(0x80 | ((c >> 6) & 0x3F));
2203                                    write(0x80 | ((c >> 0) & 0x3F));
2204                                } else {
2205                                    write(0xC0 | ((c >> 6) & 0x1F));
2206                                    write(0x80 | ((c >> 0) & 0x3F));
2207                                }
2208                            }
2209                        }
2210                        off += csize;
2211                    }
2212                }
2213            }
2214
2215            /**
2216             * Lightweight identity hash table which maps objects to integer handles,
2217             * assigned in ascending order.
2218             */
2219            private static class HandleTable {
2220
2221                /* number of mappings in table/next available handle */
2222                private int size;
2223                /* size threshold determining when to expand hash spine */
2224                private int threshold;
2225                /* factor for computing size threshold */
2226                private final float loadFactor;
2227                /* maps hash value -> candidate handle value */
2228                private int[] spine;
2229                /* maps handle value -> next candidate handle value */
2230                private int[] next;
2231                /* maps handle value -> associated object */
2232                private Object[] objs;
2233
2234                /**
2235                 * Creates new HandleTable with given capacity and load factor.
2236                 */
2237                HandleTable(int initialCapacity, float loadFactor) {
2238                    this .loadFactor = loadFactor;
2239                    spine = new int[initialCapacity];
2240                    next = new int[initialCapacity];
2241                    objs = new Object[initialCapacity];
2242                    threshold = (int) (initialCapacity * loadFactor);
2243                    clear();
2244                }
2245
2246                /**
2247                 * Assigns next available handle to given object, and returns handle
2248                 * value.  Handles are assigned in ascending order starting at 0.
2249                 */
2250                int assign(Object obj) {
2251                    if (size >= next.length) {
2252                        growEntries();
2253                    }
2254                    if (size >= threshold) {
2255                        growSpine();
2256                    }
2257                    insert(obj, size);
2258                    return size++;
2259                }
2260
2261                /**
2262                 * Looks up and returns handle associated with given object, or -1 if
2263                 * no mapping found.
2264                 */
2265                int lookup(Object obj) {
2266                    if (size == 0) {
2267                        return -1;
2268                    }
2269                    int index = hash(obj) % spine.length;
2270                    for (int i = spine[index]; i >= 0; i = next[i]) {
2271                        if (objs[i] == obj) {
2272                            return i;
2273                        }
2274                    }
2275                    return -1;
2276                }
2277
2278                /**
2279                 * Resets table to its initial (empty) state.
2280                 */
2281                void clear() {
2282                    Arrays.fill(spine, -1);
2283                    Arrays.fill(objs, 0, size, null);
2284                    size = 0;
2285                }
2286
2287                /**
2288                 * Returns the number of mappings currently in table.
2289                 */
2290                int size() {
2291                    return size;
2292                }
2293
2294                /**
2295                 * Inserts mapping object -> handle mapping into table.  Assumes table
2296                 * is large enough to accommodate new mapping.
2297                 */
2298                private void insert(Object obj, int handle) {
2299                    int index = hash(obj) % spine.length;
2300                    objs[handle] = obj;
2301                    next[handle] = spine[index];
2302                    spine[index] = handle;
2303                }
2304
2305                /**
2306                 * Expands the hash "spine" -- equivalent to increasing the number of
2307                 * buckets in a conventional hash table.
2308                 */
2309                private void growSpine() {
2310                    spine = new int[(spine.length << 1) + 1];
2311                    threshold = (int) (spine.length * loadFactor);
2312                    Arrays.fill(spine, -1);
2313                    for (int i = 0; i < size; i++) {
2314                        insert(objs[i], i);
2315                    }
2316                }
2317
2318                /**
2319                 * Increases hash table capacity by lengthening entry arrays.
2320                 */
2321                private void growEntries() {
2322                    int newLength = (next.length << 1) + 1;
2323                    int[] newNext = new int[newLength];
2324                    System.arraycopy(next, 0, newNext, 0, size);
2325                    next = newNext;
2326
2327                    Object[] newObjs = new Object[newLength];
2328                    System.arraycopy(objs, 0, newObjs, 0, size);
2329                    objs = newObjs;
2330                }
2331
2332                /**
2333                 * Returns hash value for given object.
2334                 */
2335                private int hash(Object obj) {
2336                    return System.identityHashCode(obj) & 0x7FFFFFFF;
2337                }
2338            }
2339
2340            /**
2341             * Lightweight identity hash table which maps objects to replacement
2342             * objects.
2343             */
2344            private static class ReplaceTable {
2345
2346                /* maps object -> index */
2347                private final HandleTable htab;
2348                /* maps index -> replacement object */
2349                private Object[] reps;
2350
2351                /**
2352                 * Creates new ReplaceTable with given capacity and load factor.
2353                 */
2354                ReplaceTable(int initialCapacity, float loadFactor) {
2355                    htab = new HandleTable(initialCapacity, loadFactor);
2356                    reps = new Object[initialCapacity];
2357                }
2358
2359                /**
2360                 * Enters mapping from object to replacement object.
2361                 */
2362                void assign(Object obj, Object rep) {
2363                    int index = htab.assign(obj);
2364                    while (index >= reps.length) {
2365                        grow();
2366                    }
2367                    reps[index] = rep;
2368                }
2369
2370                /**
2371                 * Looks up and returns replacement for given object.  If no
2372                 * replacement is found, returns the lookup object itself.
2373                 */
2374                Object lookup(Object obj) {
2375                    int index = htab.lookup(obj);
2376                    return (index >= 0) ? reps[index] : obj;
2377                }
2378
2379                /**
2380                 * Resets table to its initial (empty) state.
2381                 */
2382                void clear() {
2383                    Arrays.fill(reps, 0, htab.size(), null);
2384                    htab.clear();
2385                }
2386
2387                /**
2388                 * Returns the number of mappings currently in table.
2389                 */
2390                int size() {
2391                    return htab.size();
2392                }
2393
2394                /**
2395                 * Increases table capacity.
2396                 */
2397                private void grow() {
2398                    Object[] newReps = new Object[(reps.length << 1) + 1];
2399                    System.arraycopy(reps, 0, newReps, 0, reps.length);
2400                    reps = newReps;
2401                }
2402            }
2403
2404            /**
2405             * Stack to keep debug information about the state of the
2406             * serialization process, for embedding in exception messages.
2407             */
2408            private static class DebugTraceInfoStack {
2409                private final List<String> stack;
2410
2411                DebugTraceInfoStack() {
2412                    stack = new ArrayList<String>();
2413                }
2414
2415                /**
2416                 * Removes all of the elements from enclosed list. 
2417                 */
2418                void clear() {
2419                    stack.clear();
2420                }
2421
2422                /**
2423                 * Removes the object at the top of enclosed list.
2424                 */
2425                void pop() {
2426                    stack.remove(stack.size() - 1);
2427                }
2428
2429                /**
2430                 * Pushes a String onto the top of enclosed list.
2431                 */
2432                void push(String entry) {
2433                    stack.add("\t- " + entry);
2434                }
2435
2436                /**
2437                 * Returns a string representation of this object
2438                 */
2439                public String toString() {
2440                    StringBuilder buffer = new StringBuilder();
2441                    if (!stack.isEmpty()) {
2442                        for (int i = stack.size(); i > 0; i--) {
2443                            buffer.append(stack.get(i - 1)
2444                                    + ((i != 1) ? "\n" : ""));
2445                        }
2446                    }
2447                    return buffer.toString();
2448                }
2449            }
2450
2451        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.