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.lang.reflect.Array;
0031: import java.lang.reflect.Modifier;
0032: import java.lang.reflect.Proxy;
0033: import java.security.AccessControlContext;
0034: import java.security.AccessController;
0035: import java.security.PrivilegedAction;
0036: import java.security.PrivilegedActionException;
0037: import java.security.PrivilegedExceptionAction;
0038: import java.util.Arrays;
0039: import java.util.HashMap;
0040: import java.util.concurrent.ConcurrentHashMap;
0041: import java.util.concurrent.ConcurrentMap;
0042: import java.util.concurrent.atomic.AtomicBoolean;
0043: import static java.io.ObjectStreamClass.processQueue;
0044:
0045: /**
0046: * An ObjectInputStream deserializes primitive data and objects previously
0047: * written using an ObjectOutputStream.
0048: *
0049: * <p>ObjectOutputStream and ObjectInputStream can provide an application with
0050: * persistent storage for graphs of objects when used with a FileOutputStream
0051: * and FileInputStream respectively. ObjectInputStream is used to recover
0052: * those objects previously serialized. Other uses include passing objects
0053: * between hosts using a socket stream or for marshaling and unmarshaling
0054: * arguments and parameters in a remote communication system.
0055: *
0056: * <p>ObjectInputStream ensures that the types of all objects in the graph
0057: * created from the stream match the classes present in the Java Virtual
0058: * Machine. Classes are loaded as required using the standard mechanisms.
0059: *
0060: * <p>Only objects that support the java.io.Serializable or
0061: * java.io.Externalizable interface can be read from streams.
0062: *
0063: * <p>The method <code>readObject</code> is used to read an object from the
0064: * stream. Java's safe casting should be used to get the desired type. In
0065: * Java, strings and arrays are objects and are treated as objects during
0066: * serialization. When read they need to be cast to the expected type.
0067: *
0068: * <p>Primitive data types can be read from the stream using the appropriate
0069: * method on DataInput.
0070: *
0071: * <p>The default deserialization mechanism for objects restores the contents
0072: * of each field to the value and type it had when it was written. Fields
0073: * declared as transient or static are ignored by the deserialization process.
0074: * References to other objects cause those objects to be read from the stream
0075: * as necessary. Graphs of objects are restored correctly using a reference
0076: * sharing mechanism. New objects are always allocated when deserializing,
0077: * which prevents existing objects from being overwritten.
0078: *
0079: * <p>Reading an object is analogous to running the constructors of a new
0080: * object. Memory is allocated for the object and initialized to zero (NULL).
0081: * No-arg constructors are invoked for the non-serializable classes and then
0082: * the fields of the serializable classes are restored from the stream starting
0083: * with the serializable class closest to java.lang.object and finishing with
0084: * the object's most specific class.
0085: *
0086: * <p>For example to read from a stream as written by the example in
0087: * ObjectOutputStream:
0088: * <br>
0089: * <pre>
0090: * FileInputStream fis = new FileInputStream("t.tmp");
0091: * ObjectInputStream ois = new ObjectInputStream(fis);
0092: *
0093: * int i = ois.readInt();
0094: * String today = (String) ois.readObject();
0095: * Date date = (Date) ois.readObject();
0096: *
0097: * ois.close();
0098: * </pre>
0099: *
0100: * <p>Classes control how they are serialized by implementing either the
0101: * java.io.Serializable or java.io.Externalizable interfaces.
0102: *
0103: * <p>Implementing the Serializable interface allows object serialization to
0104: * save and restore the entire state of the object and it allows classes to
0105: * evolve between the time the stream is written and the time it is read. It
0106: * automatically traverses references between objects, saving and restoring
0107: * entire graphs.
0108: *
0109: * <p>Serializable classes that require special handling during the
0110: * serialization and deserialization process should implement the following
0111: * methods:<p>
0112: *
0113: * <pre>
0114: * private void writeObject(java.io.ObjectOutputStream stream)
0115: * throws IOException;
0116: * private void readObject(java.io.ObjectInputStream stream)
0117: * throws IOException, ClassNotFoundException;
0118: * private void readObjectNoData()
0119: * throws ObjectStreamException;
0120: * </pre>
0121: *
0122: * <p>The readObject method is responsible for reading and restoring the state
0123: * of the object for its particular class using data written to the stream by
0124: * the corresponding writeObject method. The method does not need to concern
0125: * itself with the state belonging to its superclasses or subclasses. State is
0126: * restored by reading data from the ObjectInputStream for the individual
0127: * fields and making assignments to the appropriate fields of the object.
0128: * Reading primitive data types is supported by DataInput.
0129: *
0130: * <p>Any attempt to read object data which exceeds the boundaries of the
0131: * custom data written by the corresponding writeObject method will cause an
0132: * OptionalDataException to be thrown with an eof field value of true.
0133: * Non-object reads which exceed the end of the allotted data will reflect the
0134: * end of data in the same way that they would indicate the end of the stream:
0135: * bytewise reads will return -1 as the byte read or number of bytes read, and
0136: * primitive reads will throw EOFExceptions. If there is no corresponding
0137: * writeObject method, then the end of default serialized data marks the end of
0138: * the allotted data.
0139: *
0140: * <p>Primitive and object read calls issued from within a readExternal method
0141: * behave in the same manner--if the stream is already positioned at the end of
0142: * data written by the corresponding writeExternal method, object reads will
0143: * throw OptionalDataExceptions with eof set to true, bytewise reads will
0144: * return -1, and primitive reads will throw EOFExceptions. Note that this
0145: * behavior does not hold for streams written with the old
0146: * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the
0147: * end of data written by writeExternal methods is not demarcated, and hence
0148: * cannot be detected.
0149: *
0150: * <p>The readObjectNoData method is responsible for initializing the state of
0151: * the object for its particular class in the event that the serialization
0152: * stream does not list the given class as a superclass of the object being
0153: * deserialized. This may occur in cases where the receiving party uses a
0154: * different version of the deserialized instance's class than the sending
0155: * party, and the receiver's version extends classes that are not extended by
0156: * the sender's version. This may also occur if the serialization stream has
0157: * been tampered; hence, readObjectNoData is useful for initializing
0158: * deserialized objects properly despite a "hostile" or incomplete source
0159: * stream.
0160: *
0161: * <p>Serialization does not read or assign values to the fields of any object
0162: * that does not implement the java.io.Serializable interface. Subclasses of
0163: * Objects that are not serializable can be serializable. In this case the
0164: * non-serializable class must have a no-arg constructor to allow its fields to
0165: * be initialized. In this case it is the responsibility of the subclass to
0166: * save and restore the state of the non-serializable class. It is frequently
0167: * the case that the fields of that class are accessible (public, package, or
0168: * protected) or that there are get and set methods that can be used to restore
0169: * the state.
0170: *
0171: * <p>Any exception that occurs while deserializing an object will be caught by
0172: * the ObjectInputStream and abort the reading process.
0173: *
0174: * <p>Implementing the Externalizable interface allows the object to assume
0175: * complete control over the contents and format of the object's serialized
0176: * form. The methods of the Externalizable interface, writeExternal and
0177: * readExternal, are called to save and restore the objects state. When
0178: * implemented by a class they can write and read their own state using all of
0179: * the methods of ObjectOutput and ObjectInput. It is the responsibility of
0180: * the objects to handle any versioning that occurs.
0181: *
0182: * <p>Enum constants are deserialized differently than ordinary serializable or
0183: * externalizable objects. The serialized form of an enum constant consists
0184: * solely of its name; field values of the constant are not transmitted. To
0185: * deserialize an enum constant, ObjectInputStream reads the constant name from
0186: * the stream; the deserialized constant is then obtained by calling the static
0187: * method <code>Enum.valueOf(Class, String)</code> with the enum constant's
0188: * base type and the received constant name as arguments. Like other
0189: * serializable or externalizable objects, enum constants can function as the
0190: * targets of back references appearing subsequently in the serialization
0191: * stream. The process by which enum constants are deserialized cannot be
0192: * customized: any class-specific readObject, readObjectNoData, and readResolve
0193: * methods defined by enum types are ignored during deserialization.
0194: * Similarly, any serialPersistentFields or serialVersionUID field declarations
0195: * are also ignored--all enum types have a fixed serialVersionUID of 0L.
0196: *
0197: * @author Mike Warres
0198: * @author Roger Riggs
0199: * @version 1.182, 07/06/09
0200: * @see java.io.DataInput
0201: * @see java.io.ObjectOutputStream
0202: * @see java.io.Serializable
0203: * @see <a href="../../../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
0204: * @since JDK1.1
0205: */
0206: public class ObjectInputStream extends InputStream implements
0207: ObjectInput, ObjectStreamConstants {
0208: /** handle value representing null */
0209: private static final int NULL_HANDLE = -1;
0210:
0211: /** marker for unshared objects in internal handle table */
0212: private static final Object unsharedMarker = new Object();
0213:
0214: /** table mapping primitive type names to corresponding class objects */
0215: private static final HashMap primClasses = new HashMap(8, 1.0F);
0216: static {
0217: primClasses.put("boolean", boolean.class);
0218: primClasses.put("byte", byte.class);
0219: primClasses.put("char", char.class);
0220: primClasses.put("short", short.class);
0221: primClasses.put("int", int.class);
0222: primClasses.put("long", long.class);
0223: primClasses.put("float", float.class);
0224: primClasses.put("double", double.class);
0225: primClasses.put("void", void.class);
0226: }
0227:
0228: private static class Caches {
0229: /** cache of subclass security audit results */
0230: static final ConcurrentMap<WeakClassKey, Boolean> subclassAudits = new ConcurrentHashMap<WeakClassKey, Boolean>();
0231:
0232: /** queue for WeakReferences to audited subclasses */
0233: static final ReferenceQueue<Class<?>> subclassAuditsQueue = new ReferenceQueue<Class<?>>();
0234: }
0235:
0236: /** filter stream for handling block data conversion */
0237: private final BlockDataInputStream bin;
0238: /** validation callback list */
0239: private final ValidationList vlist;
0240: /** recursion depth */
0241: private int depth;
0242: /** whether stream is closed */
0243: private boolean closed;
0244:
0245: /** wire handle -> obj/exception map */
0246: private final HandleTable handles;
0247: /** scratch field for passing handle values up/down call stack */
0248: private int passHandle = NULL_HANDLE;
0249: /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
0250: private boolean defaultDataEnd = false;
0251:
0252: /** buffer for reading primitive field values */
0253: private byte[] primVals;
0254:
0255: /** if true, invoke readObjectOverride() instead of readObject() */
0256: private final boolean enableOverride;
0257: /** if true, invoke resolveObject() */
0258: private boolean enableResolve;
0259:
0260: /**
0261: * Context during upcalls to class-defined readObject methods; holds
0262: * object currently being deserialized and descriptor for current class.
0263: * Null when not during readObject upcall.
0264: */
0265: private CallbackContext curContext;
0266:
0267: /**
0268: * Creates an ObjectInputStream that reads from the specified InputStream.
0269: * A serialization stream header is read from the stream and verified.
0270: * This constructor will block until the corresponding ObjectOutputStream
0271: * has written and flushed the header.
0272: *
0273: * <p>If a security manager is installed, this constructor will check for
0274: * the "enableSubclassImplementation" SerializablePermission when invoked
0275: * directly or indirectly by the constructor of a subclass which overrides
0276: * the ObjectInputStream.readFields or ObjectInputStream.readUnshared
0277: * methods.
0278: *
0279: * @param in input stream to read from
0280: * @throws StreamCorruptedException if the stream header is incorrect
0281: * @throws IOException if an I/O error occurs while reading stream header
0282: * @throws SecurityException if untrusted subclass illegally overrides
0283: * security-sensitive methods
0284: * @throws NullPointerException if <code>in</code> is <code>null</code>
0285: * @see ObjectInputStream#ObjectInputStream()
0286: * @see ObjectInputStream#readFields()
0287: * @see ObjectOutputStream#ObjectOutputStream(OutputStream)
0288: */
0289: public ObjectInputStream(InputStream in) throws IOException {
0290: verifySubclass();
0291: bin = new BlockDataInputStream(in);
0292: handles = new HandleTable(10);
0293: vlist = new ValidationList();
0294: enableOverride = false;
0295: readStreamHeader();
0296: bin.setBlockDataMode(true);
0297: }
0298:
0299: /**
0300: * Provide a way for subclasses that are completely reimplementing
0301: * ObjectInputStream to not have to allocate private data just used by this
0302: * implementation of ObjectInputStream.
0303: *
0304: * <p>If there is a security manager installed, this method first calls the
0305: * security manager's <code>checkPermission</code> method with the
0306: * <code>SerializablePermission("enableSubclassImplementation")</code>
0307: * permission to ensure it's ok to enable subclassing.
0308: *
0309: * @throws SecurityException if a security manager exists and its
0310: * <code>checkPermission</code> method denies enabling
0311: * subclassing.
0312: * @see SecurityManager#checkPermission
0313: * @see java.io.SerializablePermission
0314: */
0315: protected ObjectInputStream() throws IOException, SecurityException {
0316: SecurityManager sm = System.getSecurityManager();
0317: if (sm != null) {
0318: sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
0319: }
0320: bin = null;
0321: handles = null;
0322: vlist = null;
0323: enableOverride = true;
0324: }
0325:
0326: /**
0327: * Read an object from the ObjectInputStream. The class of the object, the
0328: * signature of the class, and the values of the non-transient and
0329: * non-static fields of the class and all of its supertypes are read.
0330: * Default deserializing for a class can be overriden using the writeObject
0331: * and readObject methods. Objects referenced by this object are read
0332: * transitively so that a complete equivalent graph of objects is
0333: * reconstructed by readObject.
0334: *
0335: * <p>The root object is completely restored when all of its fields and the
0336: * objects it references are completely restored. At this point the object
0337: * validation callbacks are executed in order based on their registered
0338: * priorities. The callbacks are registered by objects (in the readObject
0339: * special methods) as they are individually restored.
0340: *
0341: * <p>Exceptions are thrown for problems with the InputStream and for
0342: * classes that should not be deserialized. All exceptions are fatal to
0343: * the InputStream and leave it in an indeterminate state; it is up to the
0344: * caller to ignore or recover the stream state.
0345: *
0346: * @throws ClassNotFoundException Class of a serialized object cannot be
0347: * found.
0348: * @throws InvalidClassException Something is wrong with a class used by
0349: * serialization.
0350: * @throws StreamCorruptedException Control information in the
0351: * stream is inconsistent.
0352: * @throws OptionalDataException Primitive data was found in the
0353: * stream instead of objects.
0354: * @throws IOException Any of the usual Input/Output related exceptions.
0355: */
0356: public final Object readObject() throws IOException,
0357: ClassNotFoundException {
0358: if (enableOverride) {
0359: return readObjectOverride();
0360: }
0361:
0362: // if nested read, passHandle contains handle of enclosing object
0363: int outerHandle = passHandle;
0364: try {
0365: Object obj = readObject0(false);
0366: handles.markDependency(outerHandle, passHandle);
0367: ClassNotFoundException ex = handles
0368: .lookupException(passHandle);
0369: if (ex != null) {
0370: throw ex;
0371: }
0372: if (depth == 0) {
0373: vlist.doCallbacks();
0374: }
0375: return obj;
0376: } finally {
0377: passHandle = outerHandle;
0378: if (closed && depth == 0) {
0379: clear();
0380: }
0381: }
0382: }
0383:
0384: /**
0385: * This method is called by trusted subclasses of ObjectOutputStream that
0386: * constructed ObjectOutputStream using the protected no-arg constructor.
0387: * The subclass is expected to provide an override method with the modifier
0388: * "final".
0389: *
0390: * @return the Object read from the stream.
0391: * @throws ClassNotFoundException Class definition of a serialized object
0392: * cannot be found.
0393: * @throws OptionalDataException Primitive data was found in the stream
0394: * instead of objects.
0395: * @throws IOException if I/O errors occurred while reading from the
0396: * underlying stream
0397: * @see #ObjectInputStream()
0398: * @see #readObject()
0399: * @since 1.2
0400: */
0401: protected Object readObjectOverride() throws IOException,
0402: ClassNotFoundException {
0403: return null;
0404: }
0405:
0406: /**
0407: * Reads an "unshared" object from the ObjectInputStream. This method is
0408: * identical to readObject, except that it prevents subsequent calls to
0409: * readObject and readUnshared from returning additional references to the
0410: * deserialized instance obtained via this call. Specifically:
0411: * <ul>
0412: * <li>If readUnshared is called to deserialize a back-reference (the
0413: * stream representation of an object which has been written
0414: * previously to the stream), an ObjectStreamException will be
0415: * thrown.
0416: *
0417: * <li>If readUnshared returns successfully, then any subsequent attempts
0418: * to deserialize back-references to the stream handle deserialized
0419: * by readUnshared will cause an ObjectStreamException to be thrown.
0420: * </ul>
0421: * Deserializing an object via readUnshared invalidates the stream handle
0422: * associated with the returned object. Note that this in itself does not
0423: * always guarantee that the reference returned by readUnshared is unique;
0424: * the deserialized object may define a readResolve method which returns an
0425: * object visible to other parties, or readUnshared may return a Class
0426: * object or enum constant obtainable elsewhere in the stream or through
0427: * external means. If the deserialized object defines a readResolve method
0428: * and the invocation of that method returns an array, then readUnshared
0429: * returns a shallow clone of that array; this guarantees that the returned
0430: * array object is unique and cannot be obtained a second time from an
0431: * invocation of readObject or readUnshared on the ObjectInputStream,
0432: * even if the underlying data stream has been manipulated.
0433: *
0434: * <p>ObjectInputStream subclasses which override this method can only be
0435: * constructed in security contexts possessing the
0436: * "enableSubclassImplementation" SerializablePermission; any attempt to
0437: * instantiate such a subclass without this permission will cause a
0438: * SecurityException to be thrown.
0439: *
0440: * @return reference to deserialized object
0441: * @throws ClassNotFoundException if class of an object to deserialize
0442: * cannot be found
0443: * @throws StreamCorruptedException if control information in the stream
0444: * is inconsistent
0445: * @throws ObjectStreamException if object to deserialize has already
0446: * appeared in stream
0447: * @throws OptionalDataException if primitive data is next in stream
0448: * @throws IOException if an I/O error occurs during deserialization
0449: * @since 1.4
0450: */
0451: public Object readUnshared() throws IOException,
0452: ClassNotFoundException {
0453: // if nested read, passHandle contains handle of enclosing object
0454: int outerHandle = passHandle;
0455: try {
0456: Object obj = readObject0(true);
0457: handles.markDependency(outerHandle, passHandle);
0458: ClassNotFoundException ex = handles
0459: .lookupException(passHandle);
0460: if (ex != null) {
0461: throw ex;
0462: }
0463: if (depth == 0) {
0464: vlist.doCallbacks();
0465: }
0466: return obj;
0467: } finally {
0468: passHandle = outerHandle;
0469: if (closed && depth == 0) {
0470: clear();
0471: }
0472: }
0473: }
0474:
0475: /**
0476: * Read the non-static and non-transient fields of the current class from
0477: * this stream. This may only be called from the readObject method of the
0478: * class being deserialized. It will throw the NotActiveException if it is
0479: * called otherwise.
0480: *
0481: * @throws ClassNotFoundException if the class of a serialized object
0482: * could not be found.
0483: * @throws IOException if an I/O error occurs.
0484: * @throws NotActiveException if the stream is not currently reading
0485: * objects.
0486: */
0487: public void defaultReadObject() throws IOException,
0488: ClassNotFoundException {
0489: if (curContext == null) {
0490: throw new NotActiveException("not in call to readObject");
0491: }
0492: Object curObj = curContext.getObj();
0493: ObjectStreamClass curDesc = curContext.getDesc();
0494: bin.setBlockDataMode(false);
0495: defaultReadFields(curObj, curDesc);
0496: bin.setBlockDataMode(true);
0497: if (!curDesc.hasWriteObjectData()) {
0498: /*
0499: * Fix for 4360508: since stream does not contain terminating
0500: * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
0501: * knows to simulate end-of-custom-data behavior.
0502: */
0503: defaultDataEnd = true;
0504: }
0505: ClassNotFoundException ex = handles.lookupException(passHandle);
0506: if (ex != null) {
0507: throw ex;
0508: }
0509: }
0510:
0511: /**
0512: * Reads the persistent fields from the stream and makes them available by
0513: * name.
0514: *
0515: * @return the <code>GetField</code> object representing the persistent
0516: * fields of the object being deserialized
0517: * @throws ClassNotFoundException if the class of a serialized object
0518: * could not be found.
0519: * @throws IOException if an I/O error occurs.
0520: * @throws NotActiveException if the stream is not currently reading
0521: * objects.
0522: * @since 1.2
0523: */
0524: public ObjectInputStream.GetField readFields() throws IOException,
0525: ClassNotFoundException {
0526: if (curContext == null) {
0527: throw new NotActiveException("not in call to readObject");
0528: }
0529: Object curObj = curContext.getObj();
0530: ObjectStreamClass curDesc = curContext.getDesc();
0531: bin.setBlockDataMode(false);
0532: GetFieldImpl getField = new GetFieldImpl(curDesc);
0533: getField.readFields();
0534: bin.setBlockDataMode(true);
0535: if (!curDesc.hasWriteObjectData()) {
0536: /*
0537: * Fix for 4360508: since stream does not contain terminating
0538: * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
0539: * knows to simulate end-of-custom-data behavior.
0540: */
0541: defaultDataEnd = true;
0542: }
0543:
0544: return getField;
0545: }
0546:
0547: /**
0548: * Register an object to be validated before the graph is returned. While
0549: * similar to resolveObject these validations are called after the entire
0550: * graph has been reconstituted. Typically, a readObject method will
0551: * register the object with the stream so that when all of the objects are
0552: * restored a final set of validations can be performed.
0553: *
0554: * @param obj the object to receive the validation callback.
0555: * @param prio controls the order of callbacks;zero is a good default.
0556: * Use higher numbers to be called back earlier, lower numbers for
0557: * later callbacks. Within a priority, callbacks are processed in
0558: * no particular order.
0559: * @throws NotActiveException The stream is not currently reading objects
0560: * so it is invalid to register a callback.
0561: * @throws InvalidObjectException The validation object is null.
0562: */
0563: public void registerValidation(ObjectInputValidation obj, int prio)
0564: throws NotActiveException, InvalidObjectException {
0565: if (depth == 0) {
0566: throw new NotActiveException("stream inactive");
0567: }
0568: vlist.register(obj, prio);
0569: }
0570:
0571: /**
0572: * Load the local class equivalent of the specified stream class
0573: * description. Subclasses may implement this method to allow classes to
0574: * be fetched from an alternate source.
0575: *
0576: * <p>The corresponding method in <code>ObjectOutputStream</code> is
0577: * <code>annotateClass</code>. This method will be invoked only once for
0578: * each unique class in the stream. This method can be implemented by
0579: * subclasses to use an alternate loading mechanism but must return a
0580: * <code>Class</code> object. Once returned, if the class is not an array
0581: * class, its serialVersionUID is compared to the serialVersionUID of the
0582: * serialized class, and if there is a mismatch, the deserialization fails
0583: * and an {@link InvalidClassException} is thrown.
0584: *
0585: * <p>The default implementation of this method in
0586: * <code>ObjectInputStream</code> returns the result of calling
0587: * <pre>
0588: * Class.forName(desc.getName(), false, loader)
0589: * </pre>
0590: * where <code>loader</code> is determined as follows: if there is a
0591: * method on the current thread's stack whose declaring class was
0592: * defined by a user-defined class loader (and was not a generated to
0593: * implement reflective invocations), then <code>loader</code> is class
0594: * loader corresponding to the closest such method to the currently
0595: * executing frame; otherwise, <code>loader</code> is
0596: * <code>null</code>. If this call results in a
0597: * <code>ClassNotFoundException</code> and the name of the passed
0598: * <code>ObjectStreamClass</code> instance is the Java language keyword
0599: * for a primitive type or void, then the <code>Class</code> object
0600: * representing that primitive type or void will be returned
0601: * (e.g., an <code>ObjectStreamClass</code> with the name
0602: * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>).
0603: * Otherwise, the <code>ClassNotFoundException</code> will be thrown to
0604: * the caller of this method.
0605: *
0606: * @param desc an instance of class <code>ObjectStreamClass</code>
0607: * @return a <code>Class</code> object corresponding to <code>desc</code>
0608: * @throws IOException any of the usual Input/Output exceptions.
0609: * @throws ClassNotFoundException if class of a serialized object cannot
0610: * be found.
0611: */
0612: protected Class<?> resolveClass(ObjectStreamClass desc)
0613: throws IOException, ClassNotFoundException {
0614: String name = desc.getName();
0615: try {
0616: return Class
0617: .forName(name, false, latestUserDefinedLoader());
0618: } catch (ClassNotFoundException ex) {
0619: Class cl = (Class) primClasses.get(name);
0620: if (cl != null) {
0621: return cl;
0622: } else {
0623: throw ex;
0624: }
0625: }
0626: }
0627:
0628: /**
0629: * Returns a proxy class that implements the interfaces named in a proxy
0630: * class descriptor; subclasses may implement this method to read custom
0631: * data from the stream along with the descriptors for dynamic proxy
0632: * classes, allowing them to use an alternate loading mechanism for the
0633: * interfaces and the proxy class.
0634: *
0635: * <p>This method is called exactly once for each unique proxy class
0636: * descriptor in the stream.
0637: *
0638: * <p>The corresponding method in <code>ObjectOutputStream</code> is
0639: * <code>annotateProxyClass</code>. For a given subclass of
0640: * <code>ObjectInputStream</code> that overrides this method, the
0641: * <code>annotateProxyClass</code> method in the corresponding subclass of
0642: * <code>ObjectOutputStream</code> must write any data or objects read by
0643: * this method.
0644: *
0645: * <p>The default implementation of this method in
0646: * <code>ObjectInputStream</code> returns the result of calling
0647: * <code>Proxy.getProxyClass</code> with the list of <code>Class</code>
0648: * objects for the interfaces that are named in the <code>interfaces</code>
0649: * parameter. The <code>Class</code> object for each interface name
0650: * <code>i</code> is the value returned by calling
0651: * <pre>
0652: * Class.forName(i, false, loader)
0653: * </pre>
0654: * where <code>loader</code> is that of the first non-<code>null</code>
0655: * class loader up the execution stack, or <code>null</code> if no
0656: * non-<code>null</code> class loaders are on the stack (the same class
0657: * loader choice used by the <code>resolveClass</code> method). Unless any
0658: * of the resolved interfaces are non-public, this same value of
0659: * <code>loader</code> is also the class loader passed to
0660: * <code>Proxy.getProxyClass</code>; if non-public interfaces are present,
0661: * their class loader is passed instead (if more than one non-public
0662: * interface class loader is encountered, an
0663: * <code>IllegalAccessError</code> is thrown).
0664: * If <code>Proxy.getProxyClass</code> throws an
0665: * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code>
0666: * will throw a <code>ClassNotFoundException</code> containing the
0667: * <code>IllegalArgumentException</code>.
0668: *
0669: * @param interfaces the list of interface names that were
0670: * deserialized in the proxy class descriptor
0671: * @return a proxy class for the specified interfaces
0672: * @throws IOException any exception thrown by the underlying
0673: * <code>InputStream</code>
0674: * @throws ClassNotFoundException if the proxy class or any of the
0675: * named interfaces could not be found
0676: * @see ObjectOutputStream#annotateProxyClass(Class)
0677: * @since 1.3
0678: */
0679: protected Class<?> resolveProxyClass(String[] interfaces)
0680: throws IOException, ClassNotFoundException {
0681: ClassLoader latestLoader = latestUserDefinedLoader();
0682: ClassLoader nonPublicLoader = null;
0683: boolean hasNonPublicInterface = false;
0684:
0685: // define proxy in class loader of non-public interface(s), if any
0686: Class[] classObjs = new Class[interfaces.length];
0687: for (int i = 0; i < interfaces.length; i++) {
0688: Class cl = Class
0689: .forName(interfaces[i], false, latestLoader);
0690: if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
0691: if (hasNonPublicInterface) {
0692: if (nonPublicLoader != cl.getClassLoader()) {
0693: throw new IllegalAccessError(
0694: "conflicting non-public interface class loaders");
0695: }
0696: } else {
0697: nonPublicLoader = cl.getClassLoader();
0698: hasNonPublicInterface = true;
0699: }
0700: }
0701: classObjs[i] = cl;
0702: }
0703: try {
0704: return Proxy.getProxyClass(
0705: hasNonPublicInterface ? nonPublicLoader
0706: : latestLoader, classObjs);
0707: } catch (IllegalArgumentException e) {
0708: throw new ClassNotFoundException(null, e);
0709: }
0710: }
0711:
0712: /**
0713: * This method will allow trusted subclasses of ObjectInputStream to
0714: * substitute one object for another during deserialization. Replacing
0715: * objects is disabled until enableResolveObject is called. The
0716: * enableResolveObject method checks that the stream requesting to resolve
0717: * object can be trusted. Every reference to serializable objects is passed
0718: * to resolveObject. To insure that the private state of objects is not
0719: * unintentionally exposed only trusted streams may use resolveObject.
0720: *
0721: * <p>This method is called after an object has been read but before it is
0722: * returned from readObject. The default resolveObject method just returns
0723: * the same object.
0724: *
0725: * <p>When a subclass is replacing objects it must insure that the
0726: * substituted object is compatible with every field where the reference
0727: * will be stored. Objects whose type is not a subclass of the type of the
0728: * field or array element abort the serialization by raising an exception
0729: * and the object is not be stored.
0730: *
0731: * <p>This method is called only once when each object is first
0732: * encountered. All subsequent references to the object will be redirected
0733: * to the new object.
0734: *
0735: * @param obj object to be substituted
0736: * @return the substituted object
0737: * @throws IOException Any of the usual Input/Output exceptions.
0738: */
0739: protected Object resolveObject(Object obj) throws IOException {
0740: return obj;
0741: }
0742:
0743: /**
0744: * Enable the stream to allow objects read from the stream to be replaced.
0745: * When enabled, the resolveObject method is called for every object being
0746: * deserialized.
0747: *
0748: * <p>If <i>enable</i> is true, and there is a security manager installed,
0749: * this method first calls the security manager's
0750: * <code>checkPermission</code> method with the
0751: * <code>SerializablePermission("enableSubstitution")</code> permission to
0752: * ensure it's ok to enable the stream to allow objects read from the
0753: * stream to be replaced.
0754: *
0755: * @param enable true for enabling use of <code>resolveObject</code> for
0756: * every object being deserialized
0757: * @return the previous setting before this method was invoked
0758: * @throws SecurityException if a security manager exists and its
0759: * <code>checkPermission</code> method denies enabling the stream
0760: * to allow objects read from the stream to be replaced.
0761: * @see SecurityManager#checkPermission
0762: * @see java.io.SerializablePermission
0763: */
0764: protected boolean enableResolveObject(boolean enable)
0765: throws SecurityException {
0766: if (enable == enableResolve) {
0767: return enable;
0768: }
0769: if (enable) {
0770: SecurityManager sm = System.getSecurityManager();
0771: if (sm != null) {
0772: sm.checkPermission(SUBSTITUTION_PERMISSION);
0773: }
0774: }
0775: enableResolve = enable;
0776: return !enableResolve;
0777: }
0778:
0779: /**
0780: * The readStreamHeader method is provided to allow subclasses to read and
0781: * verify their own stream headers. It reads and verifies the magic number
0782: * and version number.
0783: *
0784: * @throws IOException if there are I/O errors while reading from the
0785: * underlying <code>InputStream</code>
0786: * @throws StreamCorruptedException if control information in the stream
0787: * is inconsistent
0788: */
0789: protected void readStreamHeader() throws IOException,
0790: StreamCorruptedException {
0791: short s0 = bin.readShort();
0792: short s1 = bin.readShort();
0793: if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
0794: throw new StreamCorruptedException(String.format(
0795: "invalid stream header: %04X%04X", s0, s1));
0796: }
0797: }
0798:
0799: /**
0800: * Read a class descriptor from the serialization stream. This method is
0801: * called when the ObjectInputStream expects a class descriptor as the next
0802: * item in the serialization stream. Subclasses of ObjectInputStream may
0803: * override this method to read in class descriptors that have been written
0804: * in non-standard formats (by subclasses of ObjectOutputStream which have
0805: * overridden the <code>writeClassDescriptor</code> method). By default,
0806: * this method reads class descriptors according to the format defined in
0807: * the Object Serialization specification.
0808: *
0809: * @return the class descriptor read
0810: * @throws IOException If an I/O error has occurred.
0811: * @throws ClassNotFoundException If the Class of a serialized object used
0812: * in the class descriptor representation cannot be found
0813: * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
0814: * @since 1.3
0815: */
0816: protected ObjectStreamClass readClassDescriptor()
0817: throws IOException, ClassNotFoundException {
0818: ObjectStreamClass desc = new ObjectStreamClass();
0819: desc.readNonProxy(this );
0820: return desc;
0821: }
0822:
0823: /**
0824: * Reads a byte of data. This method will block if no input is available.
0825: *
0826: * @return the byte read, or -1 if the end of the stream is reached.
0827: * @throws IOException If an I/O error has occurred.
0828: */
0829: public int read() throws IOException {
0830: return bin.read();
0831: }
0832:
0833: /**
0834: * Reads into an array of bytes. This method will block until some input
0835: * is available. Consider using java.io.DataInputStream.readFully to read
0836: * exactly 'length' bytes.
0837: *
0838: * @param buf the buffer into which the data is read
0839: * @param off the start offset of the data
0840: * @param len the maximum number of bytes read
0841: * @return the actual number of bytes read, -1 is returned when the end of
0842: * the stream is reached.
0843: * @throws IOException If an I/O error has occurred.
0844: * @see java.io.DataInputStream#readFully(byte[],int,int)
0845: */
0846: public int read(byte[] buf, int off, int len) throws IOException {
0847: if (buf == null) {
0848: throw new NullPointerException();
0849: }
0850: int endoff = off + len;
0851: if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
0852: throw new IndexOutOfBoundsException();
0853: }
0854: return bin.read(buf, off, len, false);
0855: }
0856:
0857: /**
0858: * Returns the number of bytes that can be read without blocking.
0859: *
0860: * @return the number of available bytes.
0861: * @throws IOException if there are I/O errors while reading from the
0862: * underlying <code>InputStream</code>
0863: */
0864: public int available() throws IOException {
0865: return bin.available();
0866: }
0867:
0868: /**
0869: * Closes the input stream. Must be called to release any resources
0870: * associated with the stream.
0871: *
0872: * @throws IOException If an I/O error has occurred.
0873: */
0874: public void close() throws IOException {
0875: /*
0876: * Even if stream already closed, propagate redundant close to
0877: * underlying stream to stay consistent with previous implementations.
0878: */
0879: closed = true;
0880: if (depth == 0) {
0881: clear();
0882: }
0883: bin.close();
0884: }
0885:
0886: /**
0887: * Reads in a boolean.
0888: *
0889: * @return the boolean read.
0890: * @throws EOFException If end of file is reached.
0891: * @throws IOException If other I/O error has occurred.
0892: */
0893: public boolean readBoolean() throws IOException {
0894: return bin.readBoolean();
0895: }
0896:
0897: /**
0898: * Reads an 8 bit byte.
0899: *
0900: * @return the 8 bit byte read.
0901: * @throws EOFException If end of file is reached.
0902: * @throws IOException If other I/O error has occurred.
0903: */
0904: public byte readByte() throws IOException {
0905: return bin.readByte();
0906: }
0907:
0908: /**
0909: * Reads an unsigned 8 bit byte.
0910: *
0911: * @return the 8 bit byte read.
0912: * @throws EOFException If end of file is reached.
0913: * @throws IOException If other I/O error has occurred.
0914: */
0915: public int readUnsignedByte() throws IOException {
0916: return bin.readUnsignedByte();
0917: }
0918:
0919: /**
0920: * Reads a 16 bit char.
0921: *
0922: * @return the 16 bit char read.
0923: * @throws EOFException If end of file is reached.
0924: * @throws IOException If other I/O error has occurred.
0925: */
0926: public char readChar() throws IOException {
0927: return bin.readChar();
0928: }
0929:
0930: /**
0931: * Reads a 16 bit short.
0932: *
0933: * @return the 16 bit short read.
0934: * @throws EOFException If end of file is reached.
0935: * @throws IOException If other I/O error has occurred.
0936: */
0937: public short readShort() throws IOException {
0938: return bin.readShort();
0939: }
0940:
0941: /**
0942: * Reads an unsigned 16 bit short.
0943: *
0944: * @return the 16 bit short read.
0945: * @throws EOFException If end of file is reached.
0946: * @throws IOException If other I/O error has occurred.
0947: */
0948: public int readUnsignedShort() throws IOException {
0949: return bin.readUnsignedShort();
0950: }
0951:
0952: /**
0953: * Reads a 32 bit int.
0954: *
0955: * @return the 32 bit integer read.
0956: * @throws EOFException If end of file is reached.
0957: * @throws IOException If other I/O error has occurred.
0958: */
0959: public int readInt() throws IOException {
0960: return bin.readInt();
0961: }
0962:
0963: /**
0964: * Reads a 64 bit long.
0965: *
0966: * @return the read 64 bit long.
0967: * @throws EOFException If end of file is reached.
0968: * @throws IOException If other I/O error has occurred.
0969: */
0970: public long readLong() throws IOException {
0971: return bin.readLong();
0972: }
0973:
0974: /**
0975: * Reads a 32 bit float.
0976: *
0977: * @return the 32 bit float read.
0978: * @throws EOFException If end of file is reached.
0979: * @throws IOException If other I/O error has occurred.
0980: */
0981: public float readFloat() throws IOException {
0982: return bin.readFloat();
0983: }
0984:
0985: /**
0986: * Reads a 64 bit double.
0987: *
0988: * @return the 64 bit double read.
0989: * @throws EOFException If end of file is reached.
0990: * @throws IOException If other I/O error has occurred.
0991: */
0992: public double readDouble() throws IOException {
0993: return bin.readDouble();
0994: }
0995:
0996: /**
0997: * Reads bytes, blocking until all bytes are read.
0998: *
0999: * @param buf the buffer into which the data is read
1000: * @throws EOFException If end of file is reached.
1001: * @throws IOException If other I/O error has occurred.
1002: */
1003: public void readFully(byte[] buf) throws IOException {
1004: bin.readFully(buf, 0, buf.length, false);
1005: }
1006:
1007: /**
1008: * Reads bytes, blocking until all bytes are read.
1009: *
1010: * @param buf the buffer into which the data is read
1011: * @param off the start offset of the data
1012: * @param len the maximum number of bytes to read
1013: * @throws EOFException If end of file is reached.
1014: * @throws IOException If other I/O error has occurred.
1015: */
1016: public void readFully(byte[] buf, int off, int len)
1017: throws IOException {
1018: int endoff = off + len;
1019: if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
1020: throw new IndexOutOfBoundsException();
1021: }
1022: bin.readFully(buf, off, len, false);
1023: }
1024:
1025: /**
1026: * Skips bytes.
1027: *
1028: * @param len the number of bytes to be skipped
1029: * @return the actual number of bytes skipped.
1030: * @throws IOException If an I/O error has occurred.
1031: */
1032: public int skipBytes(int len) throws IOException {
1033: return bin.skipBytes(len);
1034: }
1035:
1036: /**
1037: * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
1038: *
1039: * @return a String copy of the line.
1040: * @throws IOException if there are I/O errors while reading from the
1041: * underlying <code>InputStream</code>
1042: * @deprecated This method does not properly convert bytes to characters.
1043: * see DataInputStream for the details and alternatives.
1044: */
1045: @Deprecated
1046: public String readLine() throws IOException {
1047: return bin.readLine();
1048: }
1049:
1050: /**
1051: * Reads a String in
1052: * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
1053: * format.
1054: *
1055: * @return the String.
1056: * @throws IOException if there are I/O errors while reading from the
1057: * underlying <code>InputStream</code>
1058: * @throws UTFDataFormatException if read bytes do not represent a valid
1059: * modified UTF-8 encoding of a string
1060: */
1061: public String readUTF() throws IOException {
1062: return bin.readUTF();
1063: }
1064:
1065: /**
1066: * Provide access to the persistent fields read from the input stream.
1067: */
1068: public static abstract class GetField {
1069:
1070: /**
1071: * Get the ObjectStreamClass that describes the fields in the stream.
1072: *
1073: * @return the descriptor class that describes the serializable fields
1074: */
1075: public abstract ObjectStreamClass getObjectStreamClass();
1076:
1077: /**
1078: * Return true if the named field is defaulted and has no value in this
1079: * stream.
1080: *
1081: * @param name the name of the field
1082: * @return true, if and only if the named field is defaulted
1083: * @throws IOException if there are I/O errors while reading from
1084: * the underlying <code>InputStream</code>
1085: * @throws IllegalArgumentException if <code>name</code> does not
1086: * correspond to a serializable field
1087: */
1088: public abstract boolean defaulted(String name)
1089: throws IOException;
1090:
1091: /**
1092: * Get the value of the named boolean field from the persistent field.
1093: *
1094: * @param name the name of the field
1095: * @param val the default value to use if <code>name</code> does not
1096: * have a value
1097: * @return the value of the named <code>boolean</code> field
1098: * @throws IOException if there are I/O errors while reading from the
1099: * underlying <code>InputStream</code>
1100: * @throws IllegalArgumentException if type of <code>name</code> is
1101: * not serializable or if the field type is incorrect
1102: */
1103: public abstract boolean get(String name, boolean val)
1104: throws IOException;
1105:
1106: /**
1107: * Get the value of the named byte field from the persistent field.
1108: *
1109: * @param name the name of the field
1110: * @param val the default value to use if <code>name</code> does not
1111: * have a value
1112: * @return the value of the named <code>byte</code> field
1113: * @throws IOException if there are I/O errors while reading from the
1114: * underlying <code>InputStream</code>
1115: * @throws IllegalArgumentException if type of <code>name</code> is
1116: * not serializable or if the field type is incorrect
1117: */
1118: public abstract byte get(String name, byte val)
1119: throws IOException;
1120:
1121: /**
1122: * Get the value of the named char field from the persistent field.
1123: *
1124: * @param name the name of the field
1125: * @param val the default value to use if <code>name</code> does not
1126: * have a value
1127: * @return the value of the named <code>char</code> field
1128: * @throws IOException if there are I/O errors while reading from the
1129: * underlying <code>InputStream</code>
1130: * @throws IllegalArgumentException if type of <code>name</code> is
1131: * not serializable or if the field type is incorrect
1132: */
1133: public abstract char get(String name, char val)
1134: throws IOException;
1135:
1136: /**
1137: * Get the value of the named short field from the persistent field.
1138: *
1139: * @param name the name of the field
1140: * @param val the default value to use if <code>name</code> does not
1141: * have a value
1142: * @return the value of the named <code>short</code> field
1143: * @throws IOException if there are I/O errors while reading from the
1144: * underlying <code>InputStream</code>
1145: * @throws IllegalArgumentException if type of <code>name</code> is
1146: * not serializable or if the field type is incorrect
1147: */
1148: public abstract short get(String name, short val)
1149: throws IOException;
1150:
1151: /**
1152: * Get the value of the named int field from the persistent field.
1153: *
1154: * @param name the name of the field
1155: * @param val the default value to use if <code>name</code> does not
1156: * have a value
1157: * @return the value of the named <code>int</code> field
1158: * @throws IOException if there are I/O errors while reading from the
1159: * underlying <code>InputStream</code>
1160: * @throws IllegalArgumentException if type of <code>name</code> is
1161: * not serializable or if the field type is incorrect
1162: */
1163: public abstract int get(String name, int val)
1164: throws IOException;
1165:
1166: /**
1167: * Get the value of the named long field from the persistent field.
1168: *
1169: * @param name the name of the field
1170: * @param val the default value to use if <code>name</code> does not
1171: * have a value
1172: * @return the value of the named <code>long</code> field
1173: * @throws IOException if there are I/O errors while reading from the
1174: * underlying <code>InputStream</code>
1175: * @throws IllegalArgumentException if type of <code>name</code> is
1176: * not serializable or if the field type is incorrect
1177: */
1178: public abstract long get(String name, long val)
1179: throws IOException;
1180:
1181: /**
1182: * Get the value of the named float field from the persistent field.
1183: *
1184: * @param name the name of the field
1185: * @param val the default value to use if <code>name</code> does not
1186: * have a value
1187: * @return the value of the named <code>float</code> field
1188: * @throws IOException if there are I/O errors while reading from the
1189: * underlying <code>InputStream</code>
1190: * @throws IllegalArgumentException if type of <code>name</code> is
1191: * not serializable or if the field type is incorrect
1192: */
1193: public abstract float get(String name, float val)
1194: throws IOException;
1195:
1196: /**
1197: * Get the value of the named double field from the persistent field.
1198: *
1199: * @param name the name of the field
1200: * @param val the default value to use if <code>name</code> does not
1201: * have a value
1202: * @return the value of the named <code>double</code> field
1203: * @throws IOException if there are I/O errors while reading from the
1204: * underlying <code>InputStream</code>
1205: * @throws IllegalArgumentException if type of <code>name</code> is
1206: * not serializable or if the field type is incorrect
1207: */
1208: public abstract double get(String name, double val)
1209: throws IOException;
1210:
1211: /**
1212: * Get the value of the named Object field from the persistent field.
1213: *
1214: * @param name the name of the field
1215: * @param val the default value to use if <code>name</code> does not
1216: * have a value
1217: * @return the value of the named <code>Object</code> field
1218: * @throws IOException if there are I/O errors while reading from the
1219: * underlying <code>InputStream</code>
1220: * @throws IllegalArgumentException if type of <code>name</code> is
1221: * not serializable or if the field type is incorrect
1222: */
1223: public abstract Object get(String name, Object val)
1224: throws IOException;
1225: }
1226:
1227: /**
1228: * Verifies that this (possibly subclass) instance can be constructed
1229: * without violating security constraints: the subclass must not override
1230: * security-sensitive non-final methods, or else the
1231: * "enableSubclassImplementation" SerializablePermission is checked.
1232: */
1233: private void verifySubclass() {
1234: Class cl = getClass();
1235: if (cl == ObjectInputStream.class) {
1236: return;
1237: }
1238: SecurityManager sm = System.getSecurityManager();
1239: if (sm == null) {
1240: return;
1241: }
1242: processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
1243: WeakClassKey key = new WeakClassKey(cl,
1244: Caches.subclassAuditsQueue);
1245: Boolean result = Caches.subclassAudits.get(key);
1246: if (result == null) {
1247: result = Boolean.valueOf(auditSubclass(cl));
1248: Caches.subclassAudits.putIfAbsent(key, result);
1249: }
1250: if (result.booleanValue()) {
1251: return;
1252: }
1253: sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1254: }
1255:
1256: /**
1257: * Performs reflective checks on given subclass to verify that it doesn't
1258: * override security-sensitive non-final methods. Returns true if subclass
1259: * is "safe", false otherwise.
1260: */
1261: private static boolean auditSubclass(final Class subcl) {
1262: Boolean result = (Boolean) AccessController
1263: .doPrivileged(new PrivilegedAction() {
1264: public Object run() {
1265: for (Class cl = subcl; cl != ObjectInputStream.class; cl = cl
1266: .getSuperclass()) {
1267: try {
1268: cl.getDeclaredMethod("readUnshared",
1269: (Class[]) null);
1270: return Boolean.FALSE;
1271: } catch (NoSuchMethodException ex) {
1272: }
1273: try {
1274: cl.getDeclaredMethod("readFields",
1275: (Class[]) null);
1276: return Boolean.FALSE;
1277: } catch (NoSuchMethodException ex) {
1278: }
1279: }
1280: return Boolean.TRUE;
1281: }
1282: });
1283: return result.booleanValue();
1284: }
1285:
1286: /**
1287: * Clears internal data structures.
1288: */
1289: private void clear() {
1290: handles.clear();
1291: vlist.clear();
1292: }
1293:
1294: /**
1295: * Underlying readObject implementation.
1296: */
1297: private Object readObject0(boolean unshared) throws IOException {
1298: boolean oldMode = bin.getBlockDataMode();
1299: if (oldMode) {
1300: int remain = bin.currentBlockRemaining();
1301: if (remain > 0) {
1302: throw new OptionalDataException(remain);
1303: } else if (defaultDataEnd) {
1304: /*
1305: * Fix for 4360508: stream is currently at the end of a field
1306: * value block written via default serialization; since there
1307: * is no terminating TC_ENDBLOCKDATA tag, simulate
1308: * end-of-custom-data behavior explicitly.
1309: */
1310: throw new OptionalDataException(true);
1311: }
1312: bin.setBlockDataMode(false);
1313: }
1314:
1315: byte tc;
1316: while ((tc = bin.peekByte()) == TC_RESET) {
1317: bin.readByte();
1318: handleReset();
1319: }
1320:
1321: depth++;
1322: try {
1323: switch (tc) {
1324: case TC_NULL:
1325: return readNull();
1326:
1327: case TC_REFERENCE:
1328: return readHandle(unshared);
1329:
1330: case TC_CLASS:
1331: return readClass(unshared);
1332:
1333: case TC_CLASSDESC:
1334: case TC_PROXYCLASSDESC:
1335: return readClassDesc(unshared);
1336:
1337: case TC_STRING:
1338: case TC_LONGSTRING:
1339: return checkResolve(readString(unshared));
1340:
1341: case TC_ARRAY:
1342: return checkResolve(readArray(unshared));
1343:
1344: case TC_ENUM:
1345: return checkResolve(readEnum(unshared));
1346:
1347: case TC_OBJECT:
1348: return checkResolve(readOrdinaryObject(unshared));
1349:
1350: case TC_EXCEPTION:
1351: IOException ex = readFatalException();
1352: throw new WriteAbortedException("writing aborted", ex);
1353:
1354: case TC_BLOCKDATA:
1355: case TC_BLOCKDATALONG:
1356: if (oldMode) {
1357: bin.setBlockDataMode(true);
1358: bin.peek(); // force header read
1359: throw new OptionalDataException(bin
1360: .currentBlockRemaining());
1361: } else {
1362: throw new StreamCorruptedException(
1363: "unexpected block data");
1364: }
1365:
1366: case TC_ENDBLOCKDATA:
1367: if (oldMode) {
1368: throw new OptionalDataException(true);
1369: } else {
1370: throw new StreamCorruptedException(
1371: "unexpected end of block data");
1372: }
1373:
1374: default:
1375: throw new StreamCorruptedException(String.format(
1376: "invalid type code: %02X", tc));
1377: }
1378: } finally {
1379: depth--;
1380: bin.setBlockDataMode(oldMode);
1381: }
1382: }
1383:
1384: /**
1385: * If resolveObject has been enabled and given object does not have an
1386: * exception associated with it, calls resolveObject to determine
1387: * replacement for object, and updates handle table accordingly. Returns
1388: * replacement object, or echoes provided object if no replacement
1389: * occurred. Expects that passHandle is set to given object's handle prior
1390: * to calling this method.
1391: */
1392: private Object checkResolve(Object obj) throws IOException {
1393: if (!enableResolve
1394: || handles.lookupException(passHandle) != null) {
1395: return obj;
1396: }
1397: Object rep = resolveObject(obj);
1398: if (rep != obj) {
1399: handles.setObject(passHandle, rep);
1400: }
1401: return rep;
1402: }
1403:
1404: /**
1405: * Reads string without allowing it to be replaced in stream. Called from
1406: * within ObjectStreamClass.read().
1407: */
1408: String readTypeString() throws IOException {
1409: int oldHandle = passHandle;
1410: try {
1411: byte tc = bin.peekByte();
1412: switch (tc) {
1413: case TC_NULL:
1414: return (String) readNull();
1415:
1416: case TC_REFERENCE:
1417: return (String) readHandle(false);
1418:
1419: case TC_STRING:
1420: case TC_LONGSTRING:
1421: return readString(false);
1422:
1423: default:
1424: throw new StreamCorruptedException(String.format(
1425: "invalid type code: %02X", tc));
1426: }
1427: } finally {
1428: passHandle = oldHandle;
1429: }
1430: }
1431:
1432: /**
1433: * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
1434: */
1435: private Object readNull() throws IOException {
1436: if (bin.readByte() != TC_NULL) {
1437: throw new InternalError();
1438: }
1439: passHandle = NULL_HANDLE;
1440: return null;
1441: }
1442:
1443: /**
1444: * Reads in object handle, sets passHandle to the read handle, and returns
1445: * object associated with the handle.
1446: */
1447: private Object readHandle(boolean unshared) throws IOException {
1448: if (bin.readByte() != TC_REFERENCE) {
1449: throw new InternalError();
1450: }
1451: passHandle = bin.readInt() - baseWireHandle;
1452: if (passHandle < 0 || passHandle >= handles.size()) {
1453: throw new StreamCorruptedException(String.format(
1454: "invalid handle value: %08X", passHandle
1455: + baseWireHandle));
1456: }
1457: if (unshared) {
1458: // REMIND: what type of exception to throw here?
1459: throw new InvalidObjectException(
1460: "cannot read back reference as unshared");
1461: }
1462:
1463: Object obj = handles.lookupObject(passHandle);
1464: if (obj == unsharedMarker) {
1465: // REMIND: what type of exception to throw here?
1466: throw new InvalidObjectException(
1467: "cannot read back reference to unshared object");
1468: }
1469: return obj;
1470: }
1471:
1472: /**
1473: * Reads in and returns class object. Sets passHandle to class object's
1474: * assigned handle. Returns null if class is unresolvable (in which case a
1475: * ClassNotFoundException will be associated with the class' handle in the
1476: * handle table).
1477: */
1478: private Class readClass(boolean unshared) throws IOException {
1479: if (bin.readByte() != TC_CLASS) {
1480: throw new InternalError();
1481: }
1482: ObjectStreamClass desc = readClassDesc(false);
1483: Class cl = desc.forClass();
1484: passHandle = handles.assign(unshared ? unsharedMarker : cl);
1485:
1486: ClassNotFoundException resolveEx = desc.getResolveException();
1487: if (resolveEx != null) {
1488: handles.markException(passHandle, resolveEx);
1489: }
1490:
1491: handles.finish(passHandle);
1492: return cl;
1493: }
1494:
1495: /**
1496: * Reads in and returns (possibly null) class descriptor. Sets passHandle
1497: * to class descriptor's assigned handle. If class descriptor cannot be
1498: * resolved to a class in the local VM, a ClassNotFoundException is
1499: * associated with the class descriptor's handle.
1500: */
1501: private ObjectStreamClass readClassDesc(boolean unshared)
1502: throws IOException {
1503: byte tc = bin.peekByte();
1504: switch (tc) {
1505: case TC_NULL:
1506: return (ObjectStreamClass) readNull();
1507:
1508: case TC_REFERENCE:
1509: return (ObjectStreamClass) readHandle(unshared);
1510:
1511: case TC_PROXYCLASSDESC:
1512: return readProxyDesc(unshared);
1513:
1514: case TC_CLASSDESC:
1515: return readNonProxyDesc(unshared);
1516:
1517: default:
1518: throw new StreamCorruptedException(String.format(
1519: "invalid type code: %02X", tc));
1520: }
1521: }
1522:
1523: /**
1524: * Reads in and returns class descriptor for a dynamic proxy class. Sets
1525: * passHandle to proxy class descriptor's assigned handle. If proxy class
1526: * descriptor cannot be resolved to a class in the local VM, a
1527: * ClassNotFoundException is associated with the descriptor's handle.
1528: */
1529: private ObjectStreamClass readProxyDesc(boolean unshared)
1530: throws IOException {
1531: if (bin.readByte() != TC_PROXYCLASSDESC) {
1532: throw new InternalError();
1533: }
1534:
1535: ObjectStreamClass desc = new ObjectStreamClass();
1536: int descHandle = handles.assign(unshared ? unsharedMarker
1537: : desc);
1538: passHandle = NULL_HANDLE;
1539:
1540: int numIfaces = bin.readInt();
1541: String[] ifaces = new String[numIfaces];
1542: for (int i = 0; i < numIfaces; i++) {
1543: ifaces[i] = bin.readUTF();
1544: }
1545:
1546: Class cl = null;
1547: ClassNotFoundException resolveEx = null;
1548: bin.setBlockDataMode(true);
1549: try {
1550: if ((cl = resolveProxyClass(ifaces)) == null) {
1551: resolveEx = new ClassNotFoundException("null class");
1552: }
1553: } catch (ClassNotFoundException ex) {
1554: resolveEx = ex;
1555: }
1556: skipCustomData();
1557:
1558: desc.initProxy(cl, resolveEx, readClassDesc(false));
1559:
1560: handles.finish(descHandle);
1561: passHandle = descHandle;
1562: return desc;
1563: }
1564:
1565: /**
1566: * Reads in and returns class descriptor for a class that is not a dynamic
1567: * proxy class. Sets passHandle to class descriptor's assigned handle. If
1568: * class descriptor cannot be resolved to a class in the local VM, a
1569: * ClassNotFoundException is associated with the descriptor's handle.
1570: */
1571: private ObjectStreamClass readNonProxyDesc(boolean unshared)
1572: throws IOException {
1573: if (bin.readByte() != TC_CLASSDESC) {
1574: throw new InternalError();
1575: }
1576:
1577: ObjectStreamClass desc = new ObjectStreamClass();
1578: int descHandle = handles.assign(unshared ? unsharedMarker
1579: : desc);
1580: passHandle = NULL_HANDLE;
1581:
1582: ObjectStreamClass readDesc = null;
1583: try {
1584: readDesc = readClassDescriptor();
1585: } catch (ClassNotFoundException ex) {
1586: throw (IOException) new InvalidClassException(
1587: "failed to read class descriptor").initCause(ex);
1588: }
1589:
1590: Class cl = null;
1591: ClassNotFoundException resolveEx = null;
1592: bin.setBlockDataMode(true);
1593: try {
1594: if ((cl = resolveClass(readDesc)) == null) {
1595: resolveEx = new ClassNotFoundException("null class");
1596: }
1597: } catch (ClassNotFoundException ex) {
1598: resolveEx = ex;
1599: }
1600: skipCustomData();
1601:
1602: desc
1603: .initNonProxy(readDesc, cl, resolveEx,
1604: readClassDesc(false));
1605:
1606: handles.finish(descHandle);
1607: passHandle = descHandle;
1608: return desc;
1609: }
1610:
1611: /**
1612: * Reads in and returns new string. Sets passHandle to new string's
1613: * assigned handle.
1614: */
1615: private String readString(boolean unshared) throws IOException {
1616: String str;
1617: byte tc = bin.readByte();
1618: switch (tc) {
1619: case TC_STRING:
1620: str = bin.readUTF();
1621: break;
1622:
1623: case TC_LONGSTRING:
1624: str = bin.readLongUTF();
1625: break;
1626:
1627: default:
1628: throw new StreamCorruptedException(String.format(
1629: "invalid type code: %02X", tc));
1630: }
1631: passHandle = handles.assign(unshared ? unsharedMarker : str);
1632: handles.finish(passHandle);
1633: return str;
1634: }
1635:
1636: /**
1637: * Reads in and returns array object, or null if array class is
1638: * unresolvable. Sets passHandle to array's assigned handle.
1639: */
1640: private Object readArray(boolean unshared) throws IOException {
1641: if (bin.readByte() != TC_ARRAY) {
1642: throw new InternalError();
1643: }
1644:
1645: ObjectStreamClass desc = readClassDesc(false);
1646: int len = bin.readInt();
1647:
1648: Object array = null;
1649: Class cl, ccl = null;
1650: if ((cl = desc.forClass()) != null) {
1651: ccl = cl.getComponentType();
1652: array = Array.newInstance(ccl, len);
1653: }
1654:
1655: int arrayHandle = handles.assign(unshared ? unsharedMarker
1656: : array);
1657: ClassNotFoundException resolveEx = desc.getResolveException();
1658: if (resolveEx != null) {
1659: handles.markException(arrayHandle, resolveEx);
1660: }
1661:
1662: if (ccl == null) {
1663: for (int i = 0; i < len; i++) {
1664: readObject0(false);
1665: }
1666: } else if (ccl.isPrimitive()) {
1667: if (ccl == Integer.TYPE) {
1668: bin.readInts((int[]) array, 0, len);
1669: } else if (ccl == Byte.TYPE) {
1670: bin.readFully((byte[]) array, 0, len, true);
1671: } else if (ccl == Long.TYPE) {
1672: bin.readLongs((long[]) array, 0, len);
1673: } else if (ccl == Float.TYPE) {
1674: bin.readFloats((float[]) array, 0, len);
1675: } else if (ccl == Double.TYPE) {
1676: bin.readDoubles((double[]) array, 0, len);
1677: } else if (ccl == Short.TYPE) {
1678: bin.readShorts((short[]) array, 0, len);
1679: } else if (ccl == Character.TYPE) {
1680: bin.readChars((char[]) array, 0, len);
1681: } else if (ccl == Boolean.TYPE) {
1682: bin.readBooleans((boolean[]) array, 0, len);
1683: } else {
1684: throw new InternalError();
1685: }
1686: } else {
1687: Object[] oa = (Object[]) array;
1688: for (int i = 0; i < len; i++) {
1689: oa[i] = readObject0(false);
1690: handles.markDependency(arrayHandle, passHandle);
1691: }
1692: }
1693:
1694: handles.finish(arrayHandle);
1695: passHandle = arrayHandle;
1696: return array;
1697: }
1698:
1699: /**
1700: * Reads in and returns enum constant, or null if enum type is
1701: * unresolvable. Sets passHandle to enum constant's assigned handle.
1702: */
1703: private Enum readEnum(boolean unshared) throws IOException {
1704: if (bin.readByte() != TC_ENUM) {
1705: throw new InternalError();
1706: }
1707:
1708: ObjectStreamClass desc = readClassDesc(false);
1709: if (!desc.isEnum()) {
1710: throw new InvalidClassException("non-enum class: " + desc);
1711: }
1712:
1713: int enumHandle = handles.assign(unshared ? unsharedMarker
1714: : null);
1715: ClassNotFoundException resolveEx = desc.getResolveException();
1716: if (resolveEx != null) {
1717: handles.markException(enumHandle, resolveEx);
1718: }
1719:
1720: String name = readString(false);
1721: Enum en = null;
1722: Class cl = desc.forClass();
1723: if (cl != null) {
1724: try {
1725: en = Enum.valueOf(cl, name);
1726: } catch (IllegalArgumentException ex) {
1727: throw (IOException) new InvalidObjectException(
1728: "enum constant " + name + " does not exist in "
1729: + cl).initCause(ex);
1730: }
1731: if (!unshared) {
1732: handles.setObject(enumHandle, en);
1733: }
1734: }
1735:
1736: handles.finish(enumHandle);
1737: passHandle = enumHandle;
1738: return en;
1739: }
1740:
1741: /**
1742: * Reads and returns "ordinary" (i.e., not a String, Class,
1743: * ObjectStreamClass, array, or enum constant) object, or null if object's
1744: * class is unresolvable (in which case a ClassNotFoundException will be
1745: * associated with object's handle). Sets passHandle to object's assigned
1746: * handle.
1747: */
1748: private Object readOrdinaryObject(boolean unshared)
1749: throws IOException {
1750: if (bin.readByte() != TC_OBJECT) {
1751: throw new InternalError();
1752: }
1753:
1754: ObjectStreamClass desc = readClassDesc(false);
1755: desc.checkDeserialize();
1756:
1757: Object obj;
1758: try {
1759: obj = desc.isInstantiable() ? desc.newInstance() : null;
1760: } catch (Exception ex) {
1761: throw (IOException) new InvalidClassException(desc
1762: .forClass().getName(), "unable to create instance")
1763: .initCause(ex);
1764: }
1765:
1766: passHandle = handles.assign(unshared ? unsharedMarker : obj);
1767: ClassNotFoundException resolveEx = desc.getResolveException();
1768: if (resolveEx != null) {
1769: handles.markException(passHandle, resolveEx);
1770: }
1771:
1772: if (desc.isExternalizable()) {
1773: readExternalData((Externalizable) obj, desc);
1774: } else {
1775: readSerialData(obj, desc);
1776: }
1777:
1778: handles.finish(passHandle);
1779:
1780: if (obj != null && handles.lookupException(passHandle) == null
1781: && desc.hasReadResolveMethod()) {
1782: Object rep = desc.invokeReadResolve(obj);
1783: if (unshared && rep.getClass().isArray()) {
1784: rep = cloneArray(rep);
1785: }
1786: if (rep != obj) {
1787: handles.setObject(passHandle, obj = rep);
1788: }
1789: }
1790:
1791: return obj;
1792: }
1793:
1794: /**
1795: * If obj is non-null, reads externalizable data by invoking readExternal()
1796: * method of obj; otherwise, attempts to skip over externalizable data.
1797: * Expects that passHandle is set to obj's handle before this method is
1798: * called.
1799: */
1800: private void readExternalData(Externalizable obj,
1801: ObjectStreamClass desc) throws IOException {
1802: CallbackContext oldContext = curContext;
1803: curContext = null;
1804: try {
1805: boolean blocked = desc.hasBlockExternalData();
1806: if (blocked) {
1807: bin.setBlockDataMode(true);
1808: }
1809: if (obj != null) {
1810: try {
1811: obj.readExternal(this );
1812: } catch (ClassNotFoundException ex) {
1813: /*
1814: * In most cases, the handle table has already propagated
1815: * a CNFException to passHandle at this point; this mark
1816: * call is included to address cases where the readExternal
1817: * method has cons'ed and thrown a new CNFException of its
1818: * own.
1819: */
1820: handles.markException(passHandle, ex);
1821: }
1822: }
1823: if (blocked) {
1824: skipCustomData();
1825: }
1826: } finally {
1827: curContext = oldContext;
1828: }
1829: /*
1830: * At this point, if the externalizable data was not written in
1831: * block-data form and either the externalizable class doesn't exist
1832: * locally (i.e., obj == null) or readExternal() just threw a
1833: * CNFException, then the stream is probably in an inconsistent state,
1834: * since some (or all) of the externalizable data may not have been
1835: * consumed. Since there's no "correct" action to take in this case,
1836: * we mimic the behavior of past serialization implementations and
1837: * blindly hope that the stream is in sync; if it isn't and additional
1838: * externalizable data remains in the stream, a subsequent read will
1839: * most likely throw a StreamCorruptedException.
1840: */
1841: }
1842:
1843: /**
1844: * Reads (or attempts to skip, if obj is null or is tagged with a
1845: * ClassNotFoundException) instance data for each serializable class of
1846: * object in stream, from superclass to subclass. Expects that passHandle
1847: * is set to obj's handle before this method is called.
1848: */
1849: private void readSerialData(Object obj, ObjectStreamClass desc)
1850: throws IOException {
1851: ObjectStreamClass.ClassDataSlot[] slots = desc
1852: .getClassDataLayout();
1853: for (int i = 0; i < slots.length; i++) {
1854: ObjectStreamClass slotDesc = slots[i].desc;
1855:
1856: if (slots[i].hasData) {
1857: if (obj != null && slotDesc.hasReadObjectMethod()
1858: && handles.lookupException(passHandle) == null) {
1859: CallbackContext oldContext = curContext;
1860:
1861: try {
1862: curContext = new CallbackContext(obj, slotDesc);
1863:
1864: bin.setBlockDataMode(true);
1865: slotDesc.invokeReadObject(obj, this );
1866: } catch (ClassNotFoundException ex) {
1867: /*
1868: * In most cases, the handle table has already
1869: * propagated a CNFException to passHandle at this
1870: * point; this mark call is included to address cases
1871: * where the custom readObject method has cons'ed and
1872: * thrown a new CNFException of its own.
1873: */
1874: handles.markException(passHandle, ex);
1875: } finally {
1876: curContext.setUsed();
1877: curContext = oldContext;
1878: }
1879:
1880: /*
1881: * defaultDataEnd may have been set indirectly by custom
1882: * readObject() method when calling defaultReadObject() or
1883: * readFields(); clear it to restore normal read behavior.
1884: */
1885: defaultDataEnd = false;
1886: } else {
1887: defaultReadFields(obj, slotDesc);
1888: }
1889: if (slotDesc.hasWriteObjectData()) {
1890: skipCustomData();
1891: } else {
1892: bin.setBlockDataMode(false);
1893: }
1894: } else {
1895: if (obj != null && slotDesc.hasReadObjectNoDataMethod()
1896: && handles.lookupException(passHandle) == null) {
1897: slotDesc.invokeReadObjectNoData(obj);
1898: }
1899: }
1900: }
1901: }
1902:
1903: /**
1904: * Skips over all block data and objects until TC_ENDBLOCKDATA is
1905: * encountered.
1906: */
1907: private void skipCustomData() throws IOException {
1908: int oldHandle = passHandle;
1909: for (;;) {
1910: if (bin.getBlockDataMode()) {
1911: bin.skipBlockData();
1912: bin.setBlockDataMode(false);
1913: }
1914: switch (bin.peekByte()) {
1915: case TC_BLOCKDATA:
1916: case TC_BLOCKDATALONG:
1917: bin.setBlockDataMode(true);
1918: break;
1919:
1920: case TC_ENDBLOCKDATA:
1921: bin.readByte();
1922: passHandle = oldHandle;
1923: return;
1924:
1925: default:
1926: readObject0(false);
1927: break;
1928: }
1929: }
1930: }
1931:
1932: /**
1933: * Reads in values of serializable fields declared by given class
1934: * descriptor. If obj is non-null, sets field values in obj. Expects that
1935: * passHandle is set to obj's handle before this method is called.
1936: */
1937: private void defaultReadFields(Object obj, ObjectStreamClass desc)
1938: throws IOException {
1939: // REMIND: is isInstance check necessary?
1940: Class cl = desc.forClass();
1941: if (cl != null && obj != null && !cl.isInstance(obj)) {
1942: throw new ClassCastException();
1943: }
1944:
1945: int primDataSize = desc.getPrimDataSize();
1946: if (primVals == null || primVals.length < primDataSize) {
1947: primVals = new byte[primDataSize];
1948: }
1949: bin.readFully(primVals, 0, primDataSize, false);
1950: if (obj != null) {
1951: desc.setPrimFieldValues(obj, primVals);
1952: }
1953:
1954: int objHandle = passHandle;
1955: ObjectStreamField[] fields = desc.getFields(false);
1956: Object[] objVals = new Object[desc.getNumObjFields()];
1957: int numPrimFields = fields.length - objVals.length;
1958: for (int i = 0; i < objVals.length; i++) {
1959: ObjectStreamField f = fields[numPrimFields + i];
1960: objVals[i] = readObject0(f.isUnshared());
1961: if (f.getField() != null) {
1962: handles.markDependency(objHandle, passHandle);
1963: }
1964: }
1965: if (obj != null) {
1966: desc.setObjFieldValues(obj, objVals);
1967: }
1968: passHandle = objHandle;
1969: }
1970:
1971: /**
1972: * Reads in and returns IOException that caused serialization to abort.
1973: * All stream state is discarded prior to reading in fatal exception. Sets
1974: * passHandle to fatal exception's handle.
1975: */
1976: private IOException readFatalException() throws IOException {
1977: if (bin.readByte() != TC_EXCEPTION) {
1978: throw new InternalError();
1979: }
1980: clear();
1981: return (IOException) readObject0(false);
1982: }
1983:
1984: /**
1985: * If recursion depth is 0, clears internal data structures; otherwise,
1986: * throws a StreamCorruptedException. This method is called when a
1987: * TC_RESET typecode is encountered.
1988: */
1989: private void handleReset() throws StreamCorruptedException {
1990: if (depth > 0) {
1991: throw new StreamCorruptedException(
1992: "unexpected reset; recursion depth: " + depth);
1993: }
1994: clear();
1995: }
1996:
1997: /**
1998: * Converts specified span of bytes into float values.
1999: */
2000: // REMIND: remove once hotspot inlines Float.intBitsToFloat
2001: private static native void bytesToFloats(byte[] src, int srcpos,
2002: float[] dst, int dstpos, int nfloats);
2003:
2004: /**
2005: * Converts specified span of bytes into double values.
2006: */
2007: // REMIND: remove once hotspot inlines Double.longBitsToDouble
2008: private static native void bytesToDoubles(byte[] src, int srcpos,
2009: double[] dst, int dstpos, int ndoubles);
2010:
2011: /**
2012: * Returns the first non-null class loader (not counting class loaders of
2013: * generated reflection implementation classes) up the execution stack, or
2014: * null if only code from the null class loader is on the stack. This
2015: * method is also called via reflection by the following RMI-IIOP class:
2016: *
2017: * com.sun.corba.se.internal.util.JDKClassLoader
2018: *
2019: * This method should not be removed or its signature changed without
2020: * corresponding modifications to the above class.
2021: */
2022: // REMIND: change name to something more accurate?
2023: private static native ClassLoader latestUserDefinedLoader();
2024:
2025: /**
2026: * Default GetField implementation.
2027: */
2028: private class GetFieldImpl extends GetField {
2029:
2030: /** class descriptor describing serializable fields */
2031: private final ObjectStreamClass desc;
2032: /** primitive field values */
2033: private final byte[] primVals;
2034: /** object field values */
2035: private final Object[] objVals;
2036: /** object field value handles */
2037: private final int[] objHandles;
2038:
2039: /**
2040: * Creates GetFieldImpl object for reading fields defined in given
2041: * class descriptor.
2042: */
2043: GetFieldImpl(ObjectStreamClass desc) {
2044: this .desc = desc;
2045: primVals = new byte[desc.getPrimDataSize()];
2046: objVals = new Object[desc.getNumObjFields()];
2047: objHandles = new int[objVals.length];
2048: }
2049:
2050: public ObjectStreamClass getObjectStreamClass() {
2051: return desc;
2052: }
2053:
2054: public boolean defaulted(String name) throws IOException {
2055: return (getFieldOffset(name, null) < 0);
2056: }
2057:
2058: public boolean get(String name, boolean val) throws IOException {
2059: int off = getFieldOffset(name, Boolean.TYPE);
2060: return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
2061: }
2062:
2063: public byte get(String name, byte val) throws IOException {
2064: int off = getFieldOffset(name, Byte.TYPE);
2065: return (off >= 0) ? primVals[off] : val;
2066: }
2067:
2068: public char get(String name, char val) throws IOException {
2069: int off = getFieldOffset(name, Character.TYPE);
2070: return (off >= 0) ? Bits.getChar(primVals, off) : val;
2071: }
2072:
2073: public short get(String name, short val) throws IOException {
2074: int off = getFieldOffset(name, Short.TYPE);
2075: return (off >= 0) ? Bits.getShort(primVals, off) : val;
2076: }
2077:
2078: public int get(String name, int val) throws IOException {
2079: int off = getFieldOffset(name, Integer.TYPE);
2080: return (off >= 0) ? Bits.getInt(primVals, off) : val;
2081: }
2082:
2083: public float get(String name, float val) throws IOException {
2084: int off = getFieldOffset(name, Float.TYPE);
2085: return (off >= 0) ? Bits.getFloat(primVals, off) : val;
2086: }
2087:
2088: public long get(String name, long val) throws IOException {
2089: int off = getFieldOffset(name, Long.TYPE);
2090: return (off >= 0) ? Bits.getLong(primVals, off) : val;
2091: }
2092:
2093: public double get(String name, double val) throws IOException {
2094: int off = getFieldOffset(name, Double.TYPE);
2095: return (off >= 0) ? Bits.getDouble(primVals, off) : val;
2096: }
2097:
2098: public Object get(String name, Object val) throws IOException {
2099: int off = getFieldOffset(name, Object.class);
2100: if (off >= 0) {
2101: int objHandle = objHandles[off];
2102: handles.markDependency(passHandle, objHandle);
2103: return (handles.lookupException(objHandle) == null) ? objVals[off]
2104: : null;
2105: } else {
2106: return val;
2107: }
2108: }
2109:
2110: /**
2111: * Reads primitive and object field values from stream.
2112: */
2113: void readFields() throws IOException {
2114: bin.readFully(primVals, 0, primVals.length, false);
2115:
2116: int oldHandle = passHandle;
2117: ObjectStreamField[] fields = desc.getFields(false);
2118: int numPrimFields = fields.length - objVals.length;
2119: for (int i = 0; i < objVals.length; i++) {
2120: objVals[i] = readObject0(fields[numPrimFields + i]
2121: .isUnshared());
2122: objHandles[i] = passHandle;
2123: }
2124: passHandle = oldHandle;
2125: }
2126:
2127: /**
2128: * Returns offset of field with given name and type. A specified type
2129: * of null matches all types, Object.class matches all non-primitive
2130: * types, and any other non-null type matches assignable types only.
2131: * If no matching field is found in the (incoming) class
2132: * descriptor but a matching field is present in the associated local
2133: * class descriptor, returns -1. Throws IllegalArgumentException if
2134: * neither incoming nor local class descriptor contains a match.
2135: */
2136: private int getFieldOffset(String name, Class type) {
2137: ObjectStreamField field = desc.getField(name, type);
2138: if (field != null) {
2139: return field.getOffset();
2140: } else if (desc.getLocalDesc().getField(name, type) != null) {
2141: return -1;
2142: } else {
2143: throw new IllegalArgumentException("no such field "
2144: + name + " with type " + type);
2145: }
2146: }
2147: }
2148:
2149: /**
2150: * Prioritized list of callbacks to be performed once object graph has been
2151: * completely deserialized.
2152: */
2153: private static class ValidationList {
2154:
2155: private static class Callback {
2156: final ObjectInputValidation obj;
2157: final int priority;
2158: Callback next;
2159: final AccessControlContext acc;
2160:
2161: Callback(ObjectInputValidation obj, int priority,
2162: Callback next, AccessControlContext acc) {
2163: this .obj = obj;
2164: this .priority = priority;
2165: this .next = next;
2166: this .acc = acc;
2167: }
2168: }
2169:
2170: /** linked list of callbacks */
2171: private Callback list;
2172:
2173: /**
2174: * Creates new (empty) ValidationList.
2175: */
2176: ValidationList() {
2177: }
2178:
2179: /**
2180: * Registers callback. Throws InvalidObjectException if callback
2181: * object is null.
2182: */
2183: void register(ObjectInputValidation obj, int priority)
2184: throws InvalidObjectException {
2185: if (obj == null) {
2186: throw new InvalidObjectException("null callback");
2187: }
2188:
2189: Callback prev = null, cur = list;
2190: while (cur != null && priority < cur.priority) {
2191: prev = cur;
2192: cur = cur.next;
2193: }
2194: AccessControlContext acc = AccessController.getContext();
2195: if (prev != null) {
2196: prev.next = new Callback(obj, priority, cur, acc);
2197: } else {
2198: list = new Callback(obj, priority, list, acc);
2199: }
2200: }
2201:
2202: /**
2203: * Invokes all registered callbacks and clears the callback list.
2204: * Callbacks with higher priorities are called first; those with equal
2205: * priorities may be called in any order. If any of the callbacks
2206: * throws an InvalidObjectException, the callback process is terminated
2207: * and the exception propagated upwards.
2208: */
2209: void doCallbacks() throws InvalidObjectException {
2210: try {
2211: while (list != null) {
2212: AccessController.doPrivileged(
2213: new PrivilegedExceptionAction() {
2214: public Object run()
2215: throws InvalidObjectException {
2216: list.obj.validateObject();
2217: return null;
2218: }
2219: }, list.acc);
2220: list = list.next;
2221: }
2222: } catch (PrivilegedActionException ex) {
2223: list = null;
2224: throw (InvalidObjectException) ex.getException();
2225: }
2226: }
2227:
2228: /**
2229: * Resets the callback list to its initial (empty) state.
2230: */
2231: public void clear() {
2232: list = null;
2233: }
2234: }
2235:
2236: /**
2237: * Input stream supporting single-byte peek operations.
2238: */
2239: private static class PeekInputStream extends InputStream {
2240:
2241: /** underlying stream */
2242: private final InputStream in;
2243: /** peeked byte */
2244: private int peekb = -1;
2245:
2246: /**
2247: * Creates new PeekInputStream on top of given underlying stream.
2248: */
2249: PeekInputStream(InputStream in) {
2250: this .in = in;
2251: }
2252:
2253: /**
2254: * Peeks at next byte value in stream. Similar to read(), except
2255: * that it does not consume the read value.
2256: */
2257: int peek() throws IOException {
2258: return (peekb >= 0) ? peekb : (peekb = in.read());
2259: }
2260:
2261: public int read() throws IOException {
2262: if (peekb >= 0) {
2263: int v = peekb;
2264: peekb = -1;
2265: return v;
2266: } else {
2267: return in.read();
2268: }
2269: }
2270:
2271: public int read(byte[] b, int off, int len) throws IOException {
2272: if (len == 0) {
2273: return 0;
2274: } else if (peekb < 0) {
2275: return in.read(b, off, len);
2276: } else {
2277: b[off++] = (byte) peekb;
2278: len--;
2279: peekb = -1;
2280: int n = in.read(b, off, len);
2281: return (n >= 0) ? (n + 1) : 1;
2282: }
2283: }
2284:
2285: void readFully(byte[] b, int off, int len) throws IOException {
2286: int n = 0;
2287: while (n < len) {
2288: int count = read(b, off + n, len - n);
2289: if (count < 0) {
2290: throw new EOFException();
2291: }
2292: n += count;
2293: }
2294: }
2295:
2296: public long skip(long n) throws IOException {
2297: if (n <= 0) {
2298: return 0;
2299: }
2300: int skipped = 0;
2301: if (peekb >= 0) {
2302: peekb = -1;
2303: skipped++;
2304: n--;
2305: }
2306: return skipped + skip(n);
2307: }
2308:
2309: public int available() throws IOException {
2310: return in.available() + ((peekb >= 0) ? 1 : 0);
2311: }
2312:
2313: public void close() throws IOException {
2314: in.close();
2315: }
2316: }
2317:
2318: /**
2319: * Input stream with two modes: in default mode, inputs data written in the
2320: * same format as DataOutputStream; in "block data" mode, inputs data
2321: * bracketed by block data markers (see object serialization specification
2322: * for details). Buffering depends on block data mode: when in default
2323: * mode, no data is buffered in advance; when in block data mode, all data
2324: * for the current data block is read in at once (and buffered).
2325: */
2326: private class BlockDataInputStream extends InputStream implements
2327: DataInput {
2328: /** maximum data block length */
2329: private static final int MAX_BLOCK_SIZE = 1024;
2330: /** maximum data block header length */
2331: private static final int MAX_HEADER_SIZE = 5;
2332: /** (tunable) length of char buffer (for reading strings) */
2333: private static final int CHAR_BUF_SIZE = 256;
2334: /** readBlockHeader() return value indicating header read may block */
2335: private static final int HEADER_BLOCKED = -2;
2336:
2337: /** buffer for reading general/block data */
2338: private final byte[] buf = new byte[MAX_BLOCK_SIZE];
2339: /** buffer for reading block data headers */
2340: private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
2341: /** char buffer for fast string reads */
2342: private final char[] cbuf = new char[CHAR_BUF_SIZE];
2343:
2344: /** block data mode */
2345: private boolean blkmode = false;
2346:
2347: // block data state fields; values meaningful only when blkmode true
2348: /** current offset into buf */
2349: private int pos = 0;
2350: /** end offset of valid data in buf, or -1 if no more block data */
2351: private int end = -1;
2352: /** number of bytes in current block yet to be read from stream */
2353: private int unread = 0;
2354:
2355: /** underlying stream (wrapped in peekable filter stream) */
2356: private final PeekInputStream in;
2357: /** loopback stream (for data reads that span data blocks) */
2358: private final DataInputStream din;
2359:
2360: /**
2361: * Creates new BlockDataInputStream on top of given underlying stream.
2362: * Block data mode is turned off by default.
2363: */
2364: BlockDataInputStream(InputStream in) {
2365: this .in = new PeekInputStream(in);
2366: din = new DataInputStream(this );
2367: }
2368:
2369: /**
2370: * Sets block data mode to the given mode (true == on, false == off)
2371: * and returns the previous mode value. If the new mode is the same as
2372: * the old mode, no action is taken. Throws IllegalStateException if
2373: * block data mode is being switched from on to off while unconsumed
2374: * block data is still present in the stream.
2375: */
2376: boolean setBlockDataMode(boolean newmode) throws IOException {
2377: if (blkmode == newmode) {
2378: return blkmode;
2379: }
2380: if (newmode) {
2381: pos = 0;
2382: end = 0;
2383: unread = 0;
2384: } else if (pos < end) {
2385: throw new IllegalStateException("unread block data");
2386: }
2387: blkmode = newmode;
2388: return !blkmode;
2389: }
2390:
2391: /**
2392: * Returns true if the stream is currently in block data mode, false
2393: * otherwise.
2394: */
2395: boolean getBlockDataMode() {
2396: return blkmode;
2397: }
2398:
2399: /**
2400: * If in block data mode, skips to the end of the current group of data
2401: * blocks (but does not unset block data mode). If not in block data
2402: * mode, throws an IllegalStateException.
2403: */
2404: void skipBlockData() throws IOException {
2405: if (!blkmode) {
2406: throw new IllegalStateException(
2407: "not in block data mode");
2408: }
2409: while (end >= 0) {
2410: refill();
2411: }
2412: }
2413:
2414: /**
2415: * Attempts to read in the next block data header (if any). If
2416: * canBlock is false and a full header cannot be read without possibly
2417: * blocking, returns HEADER_BLOCKED, else if the next element in the
2418: * stream is a block data header, returns the block data length
2419: * specified by the header, else returns -1.
2420: */
2421: private int readBlockHeader(boolean canBlock)
2422: throws IOException {
2423: if (defaultDataEnd) {
2424: /*
2425: * Fix for 4360508: stream is currently at the end of a field
2426: * value block written via default serialization; since there
2427: * is no terminating TC_ENDBLOCKDATA tag, simulate
2428: * end-of-custom-data behavior explicitly.
2429: */
2430: return -1;
2431: }
2432: try {
2433: for (;;) {
2434: int avail = canBlock ? Integer.MAX_VALUE : in
2435: .available();
2436: if (avail == 0) {
2437: return HEADER_BLOCKED;
2438: }
2439:
2440: int tc = in.peek();
2441: switch (tc) {
2442: case TC_BLOCKDATA:
2443: if (avail < 2) {
2444: return HEADER_BLOCKED;
2445: }
2446: in.readFully(hbuf, 0, 2);
2447: return hbuf[1] & 0xFF;
2448:
2449: case TC_BLOCKDATALONG:
2450: if (avail < 5) {
2451: return HEADER_BLOCKED;
2452: }
2453: in.readFully(hbuf, 0, 5);
2454: int len = Bits.getInt(hbuf, 1);
2455: if (len < 0) {
2456: throw new StreamCorruptedException(
2457: "illegal block data header length: "
2458: + len);
2459: }
2460: return len;
2461:
2462: /*
2463: * TC_RESETs may occur in between data blocks.
2464: * Unfortunately, this case must be parsed at a lower
2465: * level than other typecodes, since primitive data
2466: * reads may span data blocks separated by a TC_RESET.
2467: */
2468: case TC_RESET:
2469: in.read();
2470: handleReset();
2471: break;
2472:
2473: default:
2474: if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
2475: throw new StreamCorruptedException(String
2476: .format("invalid type code: %02X",
2477: tc));
2478: }
2479: return -1;
2480: }
2481: }
2482: } catch (EOFException ex) {
2483: throw new StreamCorruptedException(
2484: "unexpected EOF while reading block data header");
2485: }
2486: }
2487:
2488: /**
2489: * Refills internal buffer buf with block data. Any data in buf at the
2490: * time of the call is considered consumed. Sets the pos, end, and
2491: * unread fields to reflect the new amount of available block data; if
2492: * the next element in the stream is not a data block, sets pos and
2493: * unread to 0 and end to -1.
2494: */
2495: private void refill() throws IOException {
2496: try {
2497: do {
2498: pos = 0;
2499: if (unread > 0) {
2500: int n = in.read(buf, 0, Math.min(unread,
2501: MAX_BLOCK_SIZE));
2502: if (n >= 0) {
2503: end = n;
2504: unread -= n;
2505: } else {
2506: throw new StreamCorruptedException(
2507: "unexpected EOF in middle of data block");
2508: }
2509: } else {
2510: int n = readBlockHeader(true);
2511: if (n >= 0) {
2512: end = 0;
2513: unread = n;
2514: } else {
2515: end = -1;
2516: unread = 0;
2517: }
2518: }
2519: } while (pos == end);
2520: } catch (IOException ex) {
2521: pos = 0;
2522: end = -1;
2523: unread = 0;
2524: throw ex;
2525: }
2526: }
2527:
2528: /**
2529: * If in block data mode, returns the number of unconsumed bytes
2530: * remaining in the current data block. If not in block data mode,
2531: * throws an IllegalStateException.
2532: */
2533: int currentBlockRemaining() {
2534: if (blkmode) {
2535: return (end >= 0) ? (end - pos) + unread : 0;
2536: } else {
2537: throw new IllegalStateException();
2538: }
2539: }
2540:
2541: /**
2542: * Peeks at (but does not consume) and returns the next byte value in
2543: * the stream, or -1 if the end of the stream/block data (if in block
2544: * data mode) has been reached.
2545: */
2546: int peek() throws IOException {
2547: if (blkmode) {
2548: if (pos == end) {
2549: refill();
2550: }
2551: return (end >= 0) ? (buf[pos] & 0xFF) : -1;
2552: } else {
2553: return in.peek();
2554: }
2555: }
2556:
2557: /**
2558: * Peeks at (but does not consume) and returns the next byte value in
2559: * the stream, or throws EOFException if end of stream/block data has
2560: * been reached.
2561: */
2562: byte peekByte() throws IOException {
2563: int val = peek();
2564: if (val < 0) {
2565: throw new EOFException();
2566: }
2567: return (byte) val;
2568: }
2569:
2570: /* ----------------- generic input stream methods ------------------ */
2571: /*
2572: * The following methods are equivalent to their counterparts in
2573: * InputStream, except that they interpret data block boundaries and
2574: * read the requested data from within data blocks when in block data
2575: * mode.
2576: */
2577:
2578: public int read() throws IOException {
2579: if (blkmode) {
2580: if (pos == end) {
2581: refill();
2582: }
2583: return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
2584: } else {
2585: return in.read();
2586: }
2587: }
2588:
2589: public int read(byte[] b, int off, int len) throws IOException {
2590: return read(b, off, len, false);
2591: }
2592:
2593: public long skip(long len) throws IOException {
2594: long remain = len;
2595: while (remain > 0) {
2596: if (blkmode) {
2597: if (pos == end) {
2598: refill();
2599: }
2600: if (end < 0) {
2601: break;
2602: }
2603: int nread = (int) Math.min(remain, end - pos);
2604: remain -= nread;
2605: pos += nread;
2606: } else {
2607: int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
2608: if ((nread = in.read(buf, 0, nread)) < 0) {
2609: break;
2610: }
2611: remain -= nread;
2612: }
2613: }
2614: return len - remain;
2615: }
2616:
2617: public int available() throws IOException {
2618: if (blkmode) {
2619: if ((pos == end) && (unread == 0)) {
2620: int n;
2621: while ((n = readBlockHeader(false)) == 0)
2622: ;
2623: switch (n) {
2624: case HEADER_BLOCKED:
2625: break;
2626:
2627: case -1:
2628: pos = 0;
2629: end = -1;
2630: break;
2631:
2632: default:
2633: pos = 0;
2634: end = 0;
2635: unread = n;
2636: break;
2637: }
2638: }
2639: // avoid unnecessary call to in.available() if possible
2640: int unreadAvail = (unread > 0) ? Math.min(in
2641: .available(), unread) : 0;
2642: return (end >= 0) ? (end - pos) + unreadAvail : 0;
2643: } else {
2644: return in.available();
2645: }
2646: }
2647:
2648: public void close() throws IOException {
2649: if (blkmode) {
2650: pos = 0;
2651: end = -1;
2652: unread = 0;
2653: }
2654: in.close();
2655: }
2656:
2657: /**
2658: * Attempts to read len bytes into byte array b at offset off. Returns
2659: * the number of bytes read, or -1 if the end of stream/block data has
2660: * been reached. If copy is true, reads values into an intermediate
2661: * buffer before copying them to b (to avoid exposing a reference to
2662: * b).
2663: */
2664: int read(byte[] b, int off, int len, boolean copy)
2665: throws IOException {
2666: if (len == 0) {
2667: return 0;
2668: } else if (blkmode) {
2669: if (pos == end) {
2670: refill();
2671: }
2672: if (end < 0) {
2673: return -1;
2674: }
2675: int nread = Math.min(len, end - pos);
2676: System.arraycopy(buf, pos, b, off, nread);
2677: pos += nread;
2678: return nread;
2679: } else if (copy) {
2680: int nread = in.read(buf, 0, Math.min(len,
2681: MAX_BLOCK_SIZE));
2682: if (nread > 0) {
2683: System.arraycopy(buf, 0, b, off, nread);
2684: }
2685: return nread;
2686: } else {
2687: return in.read(b, off, len);
2688: }
2689: }
2690:
2691: /* ----------------- primitive data input methods ------------------ */
2692: /*
2693: * The following methods are equivalent to their counterparts in
2694: * DataInputStream, except that they interpret data block boundaries
2695: * and read the requested data from within data blocks when in block
2696: * data mode.
2697: */
2698:
2699: public void readFully(byte[] b) throws IOException {
2700: readFully(b, 0, b.length, false);
2701: }
2702:
2703: public void readFully(byte[] b, int off, int len)
2704: throws IOException {
2705: readFully(b, off, len, false);
2706: }
2707:
2708: public void readFully(byte[] b, int off, int len, boolean copy)
2709: throws IOException {
2710: while (len > 0) {
2711: int n = read(b, off, len, copy);
2712: if (n < 0) {
2713: throw new EOFException();
2714: }
2715: off += n;
2716: len -= n;
2717: }
2718: }
2719:
2720: public int skipBytes(int n) throws IOException {
2721: return din.skipBytes(n);
2722: }
2723:
2724: public boolean readBoolean() throws IOException {
2725: int v = read();
2726: if (v < 0) {
2727: throw new EOFException();
2728: }
2729: return (v != 0);
2730: }
2731:
2732: public byte readByte() throws IOException {
2733: int v = read();
2734: if (v < 0) {
2735: throw new EOFException();
2736: }
2737: return (byte) v;
2738: }
2739:
2740: public int readUnsignedByte() throws IOException {
2741: int v = read();
2742: if (v < 0) {
2743: throw new EOFException();
2744: }
2745: return v;
2746: }
2747:
2748: public char readChar() throws IOException {
2749: if (!blkmode) {
2750: pos = 0;
2751: in.readFully(buf, 0, 2);
2752: } else if (end - pos < 2) {
2753: return din.readChar();
2754: }
2755: char v = Bits.getChar(buf, pos);
2756: pos += 2;
2757: return v;
2758: }
2759:
2760: public short readShort() throws IOException {
2761: if (!blkmode) {
2762: pos = 0;
2763: in.readFully(buf, 0, 2);
2764: } else if (end - pos < 2) {
2765: return din.readShort();
2766: }
2767: short v = Bits.getShort(buf, pos);
2768: pos += 2;
2769: return v;
2770: }
2771:
2772: public int readUnsignedShort() throws IOException {
2773: if (!blkmode) {
2774: pos = 0;
2775: in.readFully(buf, 0, 2);
2776: } else if (end - pos < 2) {
2777: return din.readUnsignedShort();
2778: }
2779: int v = Bits.getShort(buf, pos) & 0xFFFF;
2780: pos += 2;
2781: return v;
2782: }
2783:
2784: public int readInt() throws IOException {
2785: if (!blkmode) {
2786: pos = 0;
2787: in.readFully(buf, 0, 4);
2788: } else if (end - pos < 4) {
2789: return din.readInt();
2790: }
2791: int v = Bits.getInt(buf, pos);
2792: pos += 4;
2793: return v;
2794: }
2795:
2796: public float readFloat() throws IOException {
2797: if (!blkmode) {
2798: pos = 0;
2799: in.readFully(buf, 0, 4);
2800: } else if (end - pos < 4) {
2801: return din.readFloat();
2802: }
2803: float v = Bits.getFloat(buf, pos);
2804: pos += 4;
2805: return v;
2806: }
2807:
2808: public long readLong() throws IOException {
2809: if (!blkmode) {
2810: pos = 0;
2811: in.readFully(buf, 0, 8);
2812: } else if (end - pos < 8) {
2813: return din.readLong();
2814: }
2815: long v = Bits.getLong(buf, pos);
2816: pos += 8;
2817: return v;
2818: }
2819:
2820: public double readDouble() throws IOException {
2821: if (!blkmode) {
2822: pos = 0;
2823: in.readFully(buf, 0, 8);
2824: } else if (end - pos < 8) {
2825: return din.readDouble();
2826: }
2827: double v = Bits.getDouble(buf, pos);
2828: pos += 8;
2829: return v;
2830: }
2831:
2832: public String readUTF() throws IOException {
2833: return readUTFBody(readUnsignedShort());
2834: }
2835:
2836: public String readLine() throws IOException {
2837: return din.readLine(); // deprecated, not worth optimizing
2838: }
2839:
2840: /* -------------- primitive data array input methods --------------- */
2841: /*
2842: * The following methods read in spans of primitive data values.
2843: * Though equivalent to calling the corresponding primitive read
2844: * methods repeatedly, these methods are optimized for reading groups
2845: * of primitive data values more efficiently.
2846: */
2847:
2848: void readBooleans(boolean[] v, int off, int len)
2849: throws IOException {
2850: int stop, endoff = off + len;
2851: while (off < endoff) {
2852: if (!blkmode) {
2853: int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
2854: in.readFully(buf, 0, span);
2855: stop = off + span;
2856: pos = 0;
2857: } else if (end - pos < 1) {
2858: v[off++] = din.readBoolean();
2859: continue;
2860: } else {
2861: stop = Math.min(endoff, off + end - pos);
2862: }
2863:
2864: while (off < stop) {
2865: v[off++] = Bits.getBoolean(buf, pos++);
2866: }
2867: }
2868: }
2869:
2870: void readChars(char[] v, int off, int len) throws IOException {
2871: int stop, endoff = off + len;
2872: while (off < endoff) {
2873: if (!blkmode) {
2874: int span = Math.min(endoff - off,
2875: MAX_BLOCK_SIZE >> 1);
2876: in.readFully(buf, 0, span << 1);
2877: stop = off + span;
2878: pos = 0;
2879: } else if (end - pos < 2) {
2880: v[off++] = din.readChar();
2881: continue;
2882: } else {
2883: stop = Math.min(endoff, off + ((end - pos) >> 1));
2884: }
2885:
2886: while (off < stop) {
2887: v[off++] = Bits.getChar(buf, pos);
2888: pos += 2;
2889: }
2890: }
2891: }
2892:
2893: void readShorts(short[] v, int off, int len) throws IOException {
2894: int stop, endoff = off + len;
2895: while (off < endoff) {
2896: if (!blkmode) {
2897: int span = Math.min(endoff - off,
2898: MAX_BLOCK_SIZE >> 1);
2899: in.readFully(buf, 0, span << 1);
2900: stop = off + span;
2901: pos = 0;
2902: } else if (end - pos < 2) {
2903: v[off++] = din.readShort();
2904: continue;
2905: } else {
2906: stop = Math.min(endoff, off + ((end - pos) >> 1));
2907: }
2908:
2909: while (off < stop) {
2910: v[off++] = Bits.getShort(buf, pos);
2911: pos += 2;
2912: }
2913: }
2914: }
2915:
2916: void readInts(int[] v, int off, int len) throws IOException {
2917: int stop, endoff = off + len;
2918: while (off < endoff) {
2919: if (!blkmode) {
2920: int span = Math.min(endoff - off,
2921: MAX_BLOCK_SIZE >> 2);
2922: in.readFully(buf, 0, span << 2);
2923: stop = off + span;
2924: pos = 0;
2925: } else if (end - pos < 4) {
2926: v[off++] = din.readInt();
2927: continue;
2928: } else {
2929: stop = Math.min(endoff, off + ((end - pos) >> 2));
2930: }
2931:
2932: while (off < stop) {
2933: v[off++] = Bits.getInt(buf, pos);
2934: pos += 4;
2935: }
2936: }
2937: }
2938:
2939: void readFloats(float[] v, int off, int len) throws IOException {
2940: int span, endoff = off + len;
2941: while (off < endoff) {
2942: if (!blkmode) {
2943: span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
2944: in.readFully(buf, 0, span << 2);
2945: pos = 0;
2946: } else if (end - pos < 4) {
2947: v[off++] = din.readFloat();
2948: continue;
2949: } else {
2950: span = Math.min(endoff - off, ((end - pos) >> 2));
2951: }
2952:
2953: bytesToFloats(buf, pos, v, off, span);
2954: off += span;
2955: pos += span << 2;
2956: }
2957: }
2958:
2959: void readLongs(long[] v, int off, int len) throws IOException {
2960: int stop, endoff = off + len;
2961: while (off < endoff) {
2962: if (!blkmode) {
2963: int span = Math.min(endoff - off,
2964: MAX_BLOCK_SIZE >> 3);
2965: in.readFully(buf, 0, span << 3);
2966: stop = off + span;
2967: pos = 0;
2968: } else if (end - pos < 8) {
2969: v[off++] = din.readLong();
2970: continue;
2971: } else {
2972: stop = Math.min(endoff, off + ((end - pos) >> 3));
2973: }
2974:
2975: while (off < stop) {
2976: v[off++] = Bits.getLong(buf, pos);
2977: pos += 8;
2978: }
2979: }
2980: }
2981:
2982: void readDoubles(double[] v, int off, int len)
2983: throws IOException {
2984: int span, endoff = off + len;
2985: while (off < endoff) {
2986: if (!blkmode) {
2987: span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
2988: in.readFully(buf, 0, span << 3);
2989: pos = 0;
2990: } else if (end - pos < 8) {
2991: v[off++] = din.readDouble();
2992: continue;
2993: } else {
2994: span = Math.min(endoff - off, ((end - pos) >> 3));
2995: }
2996:
2997: bytesToDoubles(buf, pos, v, off, span);
2998: off += span;
2999: pos += span << 3;
3000: }
3001: }
3002:
3003: /**
3004: * Reads in string written in "long" UTF format. "Long" UTF format is
3005: * identical to standard UTF, except that it uses an 8 byte header
3006: * (instead of the standard 2 bytes) to convey the UTF encoding length.
3007: */
3008: String readLongUTF() throws IOException {
3009: return readUTFBody(readLong());
3010: }
3011:
3012: /**
3013: * Reads in the "body" (i.e., the UTF representation minus the 2-byte
3014: * or 8-byte length header) of a UTF encoding, which occupies the next
3015: * utflen bytes.
3016: */
3017: private String readUTFBody(long utflen) throws IOException {
3018: StringBuilder sbuf = new StringBuilder();
3019: if (!blkmode) {
3020: end = pos = 0;
3021: }
3022:
3023: while (utflen > 0) {
3024: int avail = end - pos;
3025: if (avail >= 3 || (long) avail == utflen) {
3026: utflen -= readUTFSpan(sbuf, utflen);
3027: } else {
3028: if (blkmode) {
3029: // near block boundary, read one byte at a time
3030: utflen -= readUTFChar(sbuf, utflen);
3031: } else {
3032: // shift and refill buffer manually
3033: if (avail > 0) {
3034: System.arraycopy(buf, pos, buf, 0, avail);
3035: }
3036: pos = 0;
3037: end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
3038: in.readFully(buf, avail, end - avail);
3039: }
3040: }
3041: }
3042:
3043: return sbuf.toString();
3044: }
3045:
3046: /**
3047: * Reads span of UTF-encoded characters out of internal buffer
3048: * (starting at offset pos and ending at or before offset end),
3049: * consuming no more than utflen bytes. Appends read characters to
3050: * sbuf. Returns the number of bytes consumed.
3051: */
3052: private long readUTFSpan(StringBuilder sbuf, long utflen)
3053: throws IOException {
3054: int cpos = 0;
3055: int start = pos;
3056: int avail = Math.min(end - pos, CHAR_BUF_SIZE);
3057: // stop short of last char unless all of utf bytes in buffer
3058: int stop = pos
3059: + ((utflen > avail) ? avail - 2 : (int) utflen);
3060: boolean outOfBounds = false;
3061:
3062: try {
3063: while (pos < stop) {
3064: int b1, b2, b3;
3065: b1 = buf[pos++] & 0xFF;
3066: switch (b1 >> 4) {
3067: case 0:
3068: case 1:
3069: case 2:
3070: case 3:
3071: case 4:
3072: case 5:
3073: case 6:
3074: case 7: // 1 byte format: 0xxxxxxx
3075: cbuf[cpos++] = (char) b1;
3076: break;
3077:
3078: case 12:
3079: case 13: // 2 byte format: 110xxxxx 10xxxxxx
3080: b2 = buf[pos++];
3081: if ((b2 & 0xC0) != 0x80) {
3082: throw new UTFDataFormatException();
3083: }
3084: cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) | ((b2 & 0x3F) << 0));
3085: break;
3086:
3087: case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3088: b3 = buf[pos + 1];
3089: b2 = buf[pos + 0];
3090: pos += 2;
3091: if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3092: throw new UTFDataFormatException();
3093: }
3094: cbuf[cpos++] = (char) (((b1 & 0x0F) << 12)
3095: | ((b2 & 0x3F) << 6) | ((b3 & 0x3F) << 0));
3096: break;
3097:
3098: default: // 10xx xxxx, 1111 xxxx
3099: throw new UTFDataFormatException();
3100: }
3101: }
3102: } catch (ArrayIndexOutOfBoundsException ex) {
3103: outOfBounds = true;
3104: } finally {
3105: if (outOfBounds || (pos - start) > utflen) {
3106: /*
3107: * Fix for 4450867: if a malformed utf char causes the
3108: * conversion loop to scan past the expected end of the utf
3109: * string, only consume the expected number of utf bytes.
3110: */
3111: pos = start + (int) utflen;
3112: throw new UTFDataFormatException();
3113: }
3114: }
3115:
3116: sbuf.append(cbuf, 0, cpos);
3117: return pos - start;
3118: }
3119:
3120: /**
3121: * Reads in single UTF-encoded character one byte at a time, appends
3122: * the character to sbuf, and returns the number of bytes consumed.
3123: * This method is used when reading in UTF strings written in block
3124: * data mode to handle UTF-encoded characters which (potentially)
3125: * straddle block-data boundaries.
3126: */
3127: private int readUTFChar(StringBuilder sbuf, long utflen)
3128: throws IOException {
3129: int b1, b2, b3;
3130: b1 = readByte() & 0xFF;
3131: switch (b1 >> 4) {
3132: case 0:
3133: case 1:
3134: case 2:
3135: case 3:
3136: case 4:
3137: case 5:
3138: case 6:
3139: case 7: // 1 byte format: 0xxxxxxx
3140: sbuf.append((char) b1);
3141: return 1;
3142:
3143: case 12:
3144: case 13: // 2 byte format: 110xxxxx 10xxxxxx
3145: if (utflen < 2) {
3146: throw new UTFDataFormatException();
3147: }
3148: b2 = readByte();
3149: if ((b2 & 0xC0) != 0x80) {
3150: throw new UTFDataFormatException();
3151: }
3152: sbuf
3153: .append((char) (((b1 & 0x1F) << 6) | ((b2 & 0x3F) << 0)));
3154: return 2;
3155:
3156: case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3157: if (utflen < 3) {
3158: if (utflen == 2) {
3159: readByte(); // consume remaining byte
3160: }
3161: throw new UTFDataFormatException();
3162: }
3163: b2 = readByte();
3164: b3 = readByte();
3165: if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3166: throw new UTFDataFormatException();
3167: }
3168: sbuf.append((char) (((b1 & 0x0F) << 12)
3169: | ((b2 & 0x3F) << 6) | ((b3 & 0x3F) << 0)));
3170: return 3;
3171:
3172: default: // 10xx xxxx, 1111 xxxx
3173: throw new UTFDataFormatException();
3174: }
3175: }
3176: }
3177:
3178: /**
3179: * Unsynchronized table which tracks wire handle to object mappings, as
3180: * well as ClassNotFoundExceptions associated with deserialized objects.
3181: * This class implements an exception-propagation algorithm for
3182: * determining which objects should have ClassNotFoundExceptions associated
3183: * with them, taking into account cycles and discontinuities (e.g., skipped
3184: * fields) in the object graph.
3185: *
3186: * <p>General use of the table is as follows: during deserialization, a
3187: * given object is first assigned a handle by calling the assign method.
3188: * This method leaves the assigned handle in an "open" state, wherein
3189: * dependencies on the exception status of other handles can be registered
3190: * by calling the markDependency method, or an exception can be directly
3191: * associated with the handle by calling markException. When a handle is
3192: * tagged with an exception, the HandleTable assumes responsibility for
3193: * propagating the exception to any other objects which depend
3194: * (transitively) on the exception-tagged object.
3195: *
3196: * <p>Once all exception information/dependencies for the handle have been
3197: * registered, the handle should be "closed" by calling the finish method
3198: * on it. The act of finishing a handle allows the exception propagation
3199: * algorithm to aggressively prune dependency links, lessening the
3200: * performance/memory impact of exception tracking.
3201: *
3202: * <p>Note that the exception propagation algorithm used depends on handles
3203: * being assigned/finished in LIFO order; however, for simplicity as well
3204: * as memory conservation, it does not enforce this constraint.
3205: */
3206: // REMIND: add full description of exception propagation algorithm?
3207: private static class HandleTable {
3208:
3209: /* status codes indicating whether object has associated exception */
3210: private static final byte STATUS_OK = 1;
3211: private static final byte STATUS_UNKNOWN = 2;
3212: private static final byte STATUS_EXCEPTION = 3;
3213:
3214: /** array mapping handle -> object status */
3215: byte[] status;
3216: /** array mapping handle -> object/exception (depending on status) */
3217: Object[] entries;
3218: /** array mapping handle -> list of dependent handles (if any) */
3219: HandleList[] deps;
3220: /** lowest unresolved dependency */
3221: int lowDep = -1;
3222: /** number of handles in table */
3223: int size = 0;
3224:
3225: /**
3226: * Creates handle table with the given initial capacity.
3227: */
3228: HandleTable(int initialCapacity) {
3229: status = new byte[initialCapacity];
3230: entries = new Object[initialCapacity];
3231: deps = new HandleList[initialCapacity];
3232: }
3233:
3234: /**
3235: * Assigns next available handle to given object, and returns assigned
3236: * handle. Once object has been completely deserialized (and all
3237: * dependencies on other objects identified), the handle should be
3238: * "closed" by passing it to finish().
3239: */
3240: int assign(Object obj) {
3241: if (size >= entries.length) {
3242: grow();
3243: }
3244: status[size] = STATUS_UNKNOWN;
3245: entries[size] = obj;
3246: return size++;
3247: }
3248:
3249: /**
3250: * Registers a dependency (in exception status) of one handle on
3251: * another. The dependent handle must be "open" (i.e., assigned, but
3252: * not finished yet). No action is taken if either dependent or target
3253: * handle is NULL_HANDLE.
3254: */
3255: void markDependency(int dependent, int target) {
3256: if (dependent == NULL_HANDLE || target == NULL_HANDLE) {
3257: return;
3258: }
3259: switch (status[dependent]) {
3260:
3261: case STATUS_UNKNOWN:
3262: switch (status[target]) {
3263: case STATUS_OK:
3264: // ignore dependencies on objs with no exception
3265: break;
3266:
3267: case STATUS_EXCEPTION:
3268: // eagerly propagate exception
3269: markException(dependent,
3270: (ClassNotFoundException) entries[target]);
3271: break;
3272:
3273: case STATUS_UNKNOWN:
3274: // add to dependency list of target
3275: if (deps[target] == null) {
3276: deps[target] = new HandleList();
3277: }
3278: deps[target].add(dependent);
3279:
3280: // remember lowest unresolved target seen
3281: if (lowDep < 0 || lowDep > target) {
3282: lowDep = target;
3283: }
3284: break;
3285:
3286: default:
3287: throw new InternalError();
3288: }
3289: break;
3290:
3291: case STATUS_EXCEPTION:
3292: break;
3293:
3294: default:
3295: throw new InternalError();
3296: }
3297: }
3298:
3299: /**
3300: * Associates a ClassNotFoundException (if one not already associated)
3301: * with the currently active handle and propagates it to other
3302: * referencing objects as appropriate. The specified handle must be
3303: * "open" (i.e., assigned, but not finished yet).
3304: */
3305: void markException(int handle, ClassNotFoundException ex) {
3306: switch (status[handle]) {
3307: case STATUS_UNKNOWN:
3308: status[handle] = STATUS_EXCEPTION;
3309: entries[handle] = ex;
3310:
3311: // propagate exception to dependents
3312: HandleList dlist = deps[handle];
3313: if (dlist != null) {
3314: int ndeps = dlist.size();
3315: for (int i = 0; i < ndeps; i++) {
3316: markException(dlist.get(i), ex);
3317: }
3318: deps[handle] = null;
3319: }
3320: break;
3321:
3322: case STATUS_EXCEPTION:
3323: break;
3324:
3325: default:
3326: throw new InternalError();
3327: }
3328: }
3329:
3330: /**
3331: * Marks given handle as finished, meaning that no new dependencies
3332: * will be marked for handle. Calls to the assign and finish methods
3333: * must occur in LIFO order.
3334: */
3335: void finish(int handle) {
3336: int end;
3337: if (lowDep < 0) {
3338: // no pending unknowns, only resolve current handle
3339: end = handle + 1;
3340: } else if (lowDep >= handle) {
3341: // pending unknowns now clearable, resolve all upward handles
3342: end = size;
3343: lowDep = -1;
3344: } else {
3345: // unresolved backrefs present, can't resolve anything yet
3346: return;
3347: }
3348:
3349: // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
3350: for (int i = handle; i < end; i++) {
3351: switch (status[i]) {
3352: case STATUS_UNKNOWN:
3353: status[i] = STATUS_OK;
3354: deps[i] = null;
3355: break;
3356:
3357: case STATUS_OK:
3358: case STATUS_EXCEPTION:
3359: break;
3360:
3361: default:
3362: throw new InternalError();
3363: }
3364: }
3365: }
3366:
3367: /**
3368: * Assigns a new object to the given handle. The object previously
3369: * associated with the handle is forgotten. This method has no effect
3370: * if the given handle already has an exception associated with it.
3371: * This method may be called at any time after the handle is assigned.
3372: */
3373: void setObject(int handle, Object obj) {
3374: switch (status[handle]) {
3375: case STATUS_UNKNOWN:
3376: case STATUS_OK:
3377: entries[handle] = obj;
3378: break;
3379:
3380: case STATUS_EXCEPTION:
3381: break;
3382:
3383: default:
3384: throw new InternalError();
3385: }
3386: }
3387:
3388: /**
3389: * Looks up and returns object associated with the given handle.
3390: * Returns null if the given handle is NULL_HANDLE, or if it has an
3391: * associated ClassNotFoundException.
3392: */
3393: Object lookupObject(int handle) {
3394: return (handle != NULL_HANDLE && status[handle] != STATUS_EXCEPTION) ? entries[handle]
3395: : null;
3396: }
3397:
3398: /**
3399: * Looks up and returns ClassNotFoundException associated with the
3400: * given handle. Returns null if the given handle is NULL_HANDLE, or
3401: * if there is no ClassNotFoundException associated with the handle.
3402: */
3403: ClassNotFoundException lookupException(int handle) {
3404: return (handle != NULL_HANDLE && status[handle] == STATUS_EXCEPTION) ? (ClassNotFoundException) entries[handle]
3405: : null;
3406: }
3407:
3408: /**
3409: * Resets table to its initial state.
3410: */
3411: void clear() {
3412: Arrays.fill(status, 0, size, (byte) 0);
3413: Arrays.fill(entries, 0, size, null);
3414: Arrays.fill(deps, 0, size, null);
3415: lowDep = -1;
3416: size = 0;
3417: }
3418:
3419: /**
3420: * Returns number of handles registered in table.
3421: */
3422: int size() {
3423: return size;
3424: }
3425:
3426: /**
3427: * Expands capacity of internal arrays.
3428: */
3429: private void grow() {
3430: int newCapacity = (entries.length << 1) + 1;
3431:
3432: byte[] newStatus = new byte[newCapacity];
3433: Object[] newEntries = new Object[newCapacity];
3434: HandleList[] newDeps = new HandleList[newCapacity];
3435:
3436: System.arraycopy(status, 0, newStatus, 0, size);
3437: System.arraycopy(entries, 0, newEntries, 0, size);
3438: System.arraycopy(deps, 0, newDeps, 0, size);
3439:
3440: status = newStatus;
3441: entries = newEntries;
3442: deps = newDeps;
3443: }
3444:
3445: /**
3446: * Simple growable list of (integer) handles.
3447: */
3448: private static class HandleList {
3449: private int[] list = new int[4];
3450: private int size = 0;
3451:
3452: public HandleList() {
3453: }
3454:
3455: public void add(int handle) {
3456: if (size >= list.length) {
3457: int[] newList = new int[list.length << 1];
3458: System.arraycopy(list, 0, newList, 0, list.length);
3459: list = newList;
3460: }
3461: list[size++] = handle;
3462: }
3463:
3464: public int get(int index) {
3465: if (index >= size) {
3466: throw new ArrayIndexOutOfBoundsException();
3467: }
3468: return list[index];
3469: }
3470:
3471: public int size() {
3472: return size;
3473: }
3474: }
3475: }
3476:
3477: /**
3478: * Method for cloning arrays in case of using unsharing reading
3479: */
3480: private static Object cloneArray(Object array) {
3481: if (array instanceof Object[]) {
3482: return ((Object[]) array).clone();
3483: } else if (array instanceof boolean[]) {
3484: return ((boolean[]) array).clone();
3485: } else if (array instanceof byte[]) {
3486: return ((byte[]) array).clone();
3487: } else if (array instanceof char[]) {
3488: return ((char[]) array).clone();
3489: } else if (array instanceof double[]) {
3490: return ((double[]) array).clone();
3491: } else if (array instanceof float[]) {
3492: return ((float[]) array).clone();
3493: } else if (array instanceof int[]) {
3494: return ((int[]) array).clone();
3495: } else if (array instanceof long[]) {
3496: return ((long[]) array).clone();
3497: } else if (array instanceof double[]) {
3498: return ((double[]) array).clone();
3499: } else {
3500: throw new AssertionError();
3501: }
3502: }
3503:
3504: /**
3505: * Context that during upcalls to class-defined readObject methods; holds
3506: * object currently being deserialized and descriptor for current class.
3507: * This context keeps a boolean state to indicate that defaultReadObject
3508: * or readFields has already been invoked with this context or the class's
3509: * readObject method has returned; if true, the getObj method throws
3510: * NotActiveException.
3511: */
3512: private static class CallbackContext {
3513: private final Object obj;
3514: private final ObjectStreamClass desc;
3515: private final AtomicBoolean used = new AtomicBoolean();
3516:
3517: public CallbackContext(Object obj, ObjectStreamClass desc) {
3518: this .obj = obj;
3519: this .desc = desc;
3520: }
3521:
3522: public Object getObj() throws NotActiveException {
3523: checkAndSetUsed();
3524: return obj;
3525: }
3526:
3527: public ObjectStreamClass getDesc() {
3528: return desc;
3529: }
3530:
3531: private void checkAndSetUsed() throws NotActiveException {
3532: if (!used.compareAndSet(false, true)) {
3533: throw new NotActiveException(
3534: "not in readObject invocation or fields already read");
3535: }
3536: }
3537:
3538: public void setUsed() {
3539: used.set(true);
3540: }
3541: }
3542: }
|