You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2005/12/01 07:04:00 UTC

svn commit: r350181 [99/198] - in /incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core: ./ depends/ depends/files/ depends/jars/ depends/libs/ depends/libs/linux.IA32/ depends/libs/win.IA32/ depends/oss/ depends/oss/linux.IA32/ depends/oss/win.I...

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamClass.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamClass.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamClass.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamClass.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,1062 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.io;
+
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.util.WeakHashMap;
+
+import com.ibm.oti.util.PriviAction;
+import com.ibm.oti.util.Sorter;
+
+/**
+ * Instances of ObjectStreamClass are used to describe classes of objects used
+ * by serialization. When objects are saved, information about all its
+ * superclasses is also saved by the use of descriptors, instances of
+ * ObjectStreamClass.
+ * 
+ * These descriptors carry information about the class they represent, such as
+ *  - The name of the class - SUID of the class - Field names and types
+ * 
+ * @see ObjectOutputStream
+ * @see ObjectInputStream
+ * @see java.lang.Class
+ */
+public class ObjectStreamClass implements Serializable {
+
+	// No need to compute the SUID for ObjectStreamClass, just use the value
+	// below
+	static final long serialVersionUID = -6120832682080437368L;
+
+	// Name of the field that contains the SUID value (if present)
+	private static final String UID_FIELD_NAME = "serialVersionUID"; //$NON-NLS-1$
+
+	private static final int CLASS_MODIFIERS_MASK;
+
+	private static final Class[] READ_PARAM_TYPES;
+
+	private static final Class[] WRITE_PARAM_TYPES;
+
+	static final Class[] EMPTY_CONSTRUCTOR_PARAM_TYPES;
+
+	private static final Class VOID_CLASS;
+
+	static final Class[] UNSHARED_PARAM_TYPES;
+
+	private static native void oneTimeInitialization();
+
+	static {
+		oneTimeInitialization();
+
+		CLASS_MODIFIERS_MASK = Modifier.PUBLIC | Modifier.FINAL
+				| Modifier.INTERFACE | Modifier.ABSTRACT;
+		READ_PARAM_TYPES = new Class[1];
+		WRITE_PARAM_TYPES = new Class[1];
+		READ_PARAM_TYPES[0] = java.io.ObjectInputStream.class;
+		WRITE_PARAM_TYPES[0] = java.io.ObjectOutputStream.class;
+		EMPTY_CONSTRUCTOR_PARAM_TYPES = new Class[0];
+		VOID_CLASS = Void.TYPE;
+		UNSHARED_PARAM_TYPES = new Class[1];
+		UNSHARED_PARAM_TYPES[0] = Object.class;
+	}
+
+	/**
+	 * A value that indicates the class has no Serializable fields
+	 */
+	public static final ObjectStreamField[] NO_FIELDS = new ObjectStreamField[0];
+
+	static final Class ARRAY_OF_FIELDS; // used to fetch field
+										// serialPersistentFields and checking
+										// its type
+	static {
+		try {
+			ARRAY_OF_FIELDS = Class.forName("[Ljava.io.ObjectStreamField;"); //$NON-NLS-1$
+		} catch (ClassNotFoundException e) {
+			// This should not happen
+			throw new RuntimeException();
+		}
+	}
+
+	private static final String CLINIT_NAME = "<clinit>"; //$NON-NLS-1$
+
+	private static final int CLINIT_MODIFIERS = Modifier.STATIC;
+
+	private static final String CLINIT_SIGNATURE = "()V"; //$NON-NLS-1$
+
+	// Used to determine if an object is Serializable or Externalizable
+	private static final Class SERIALIZABLE = java.io.Serializable.class;
+
+	private static final Class EXTERNALIZABLE = java.io.Externalizable.class;
+
+	// Used to test if the object is a String or a class.
+	static final Class STRINGCLASS = java.lang.String.class;
+
+	static final Class CLASSCLASS = java.lang.Class.class;
+
+	static final Class OBJECTSTREAMCLASSCLASS = java.io.ObjectStreamClass.class;
+
+	// Table mapping instances of java.lang.Class to to corresponding instances
+	// of ObjectStreamClass
+	private static final WeakHashMap classesAndDescriptors = new WeakHashMap();
+
+	// ClassDesc
+	private String className; // Name of the class this descriptor represents
+
+	private WeakReference resolvedClass; // Corresponding loaded class with
+											// the name above
+
+	private long svUID; // Serial version UID of the class the descriptor
+						// represents
+
+	// ClassDescInfo
+	private byte flags; // Any combination of SC_WRITE_METHOD, SC_SERIALIZABLE
+						// and SC_EXTERNALIZABLE (see ObjectStreamConstants)
+
+	private ObjectStreamClass superclass; // Descriptor for the superclass of
+											// the class associated with this
+											// descriptor
+
+	private ObjectStreamField[] fields; // Array of ObjectStreamField (see
+										// below) describing the fields of this
+										// class
+
+	private ObjectStreamField[] loadFields; // Array of ObjectStreamField
+											// describing the serialized fields
+											// of this class
+
+	// If an ObjectStreamClass describes an Externalizable class, it (the
+	// descriptor) should not have
+	// field descriptors (ObjectStreamField) at all. The ObjectStreamClass that
+	// gets saved should simply
+	// have no field info. This is a footnote in page 1511 (class Serializable)
+	// of
+	// "The Java Class Libraries, Second Edition, Vol I".
+
+	/**
+	 * Constructs a new instance of this class.
+	 */
+	ObjectStreamClass() {
+		super();
+	}
+
+	/**
+	 * Add an extra entry mapping a given class <code>cl</code> to its class
+	 * descriptor, which will be computed (an ObjectStreamClass). If
+	 * <code>computeSUID</code> is true, this method will compute the SUID for
+	 * this class.
+	 * 
+	 * @param cl
+	 *            a java.langClass for which to compute the corresponding
+	 *            descriptor
+	 * @param computeSUID
+	 *            a boolean indicating if SUID should be computed or not.
+	 * @return the computer class descriptor
+	 */
+	private static ObjectStreamClass addToCache(Class cl, boolean computeSUID) {
+
+		ObjectStreamClass result = new ObjectStreamClass();
+		classesAndDescriptors.put(cl, result);
+
+		// Now we fill in the values
+		result.setName(cl.getName());
+		result.setClass(cl);
+		Class superclass = cl.getSuperclass();
+		if (superclass != null)
+			result.setSuperclass(lookup(superclass));
+
+		Field[] declaredFields = null;
+		if (computeSUID) {
+			declaredFields = cl.getDeclaredFields(); // Lazy computation, to
+														// save speed&space
+			result.setSerialVersionUID(computeSerialVersionUID(cl,
+					declaredFields));
+		}
+
+		boolean serializable = isSerializable(cl);
+		// Serializables need field descriptors
+		if (serializable && !cl.isArray()) {
+			if (declaredFields == null)
+				declaredFields = cl.getDeclaredFields(); // Lazy computation,
+															// to save
+															// speed&space
+			result.buildFieldDescriptors(declaredFields);
+		} else {
+			// Externalizables or arrays do not need FieldDesc info
+			result.setFields(new ObjectStreamField[0]);
+		}
+
+		byte flags = 0;
+		boolean externalizable = isExternalizable(cl);
+		if (externalizable)
+			flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
+		else if (serializable)
+			flags |= ObjectStreamConstants.SC_SERIALIZABLE;
+		if (getPrivateWriteObjectMethod(cl) != null)
+			flags |= ObjectStreamConstants.SC_WRITE_METHOD;
+		result.setFlags(flags);
+
+		return result;
+	}
+
+	/**
+	 * Builds the collection of field descriptors for the receiver
+	 * 
+	 * @param declaredFields
+	 *            collection of java.lang.reflect.Field for which to compute
+	 *            field descriptors
+	 */
+	void buildFieldDescriptors(Field[] declaredFields) {
+		// We could find the field ourselves in the collection, but calling
+		// reflect is easier. Optimize if needed.
+		final Field f = ObjectStreamClass.fieldSerialPersistentFields(this
+				.forClass());
+		// If we could not find the emulated fields, we'll have to compute
+		// dumpable fields from reflect fields
+		boolean useReflectFields = f == null; // Assume we will compute the
+												// fields to dump based on the
+												// reflect fields
+
+		if (!useReflectFields) {
+			// The user declared a collection of emulated fields. Use them.
+			AccessController.doPrivileged(new PriviAction(f)); // We have to be
+																// able to fetch
+																// its value,
+																// even if it is
+																// private
+			try {
+				fields = (ObjectStreamField[]) f.get(null); // static field,
+															// pass null
+			} catch (IllegalAccessException ex) {
+				// WARNING - what should we do if we have no access ? This
+				// should not happen.
+				throw new RuntimeException();
+			}
+		} else {
+			// Compute collection of dumpable fields based on reflect fields
+			java.util.Vector serializableFields = new java.util.Vector(
+					declaredFields.length);
+			// Filter, we are only interested in fields that are serializable
+			for (int i = 0; i < declaredFields.length; i++) {
+				Field declaredField = declaredFields[i];
+				int modifiers = declaredField.getModifiers();
+				boolean shouldBeSerialized = !(Modifier.isStatic(modifiers) || Modifier
+						.isTransient(modifiers));
+				if (shouldBeSerialized) {
+					ObjectStreamField field = new ObjectStreamField(
+							declaredField.getName(), declaredField.getType());
+					serializableFields.addElement(field);
+				}
+			}
+
+			if (serializableFields.size() == 0) {
+				fields = NO_FIELDS; // If no serializable fields, share the
+									// special value so that users can test
+			} else {
+				// Now convert from Vector to array
+				fields = new ObjectStreamField[serializableFields.size()];
+				serializableFields.copyInto(fields);
+			}
+		}
+		ObjectStreamField.sortFields(fields);
+		// assign offsets
+		int primOffset = 0, objectOffset = 0;
+		for (int i = 0; i < fields.length; i++) {
+			Class type = fields[i].getType();
+			if (type.isPrimitive()) {
+				fields[i].offset = primOffset;
+				primOffset += primitiveSize(type);
+			} else {
+				fields[i].offset = objectOffset++;
+			}
+		}
+	}
+
+	/**
+	 * Compute and return the Serial Version UID of the class <code>cl</code>.
+	 * The value is computed based on the class name, superclass chain, field
+	 * names, method names, modifiers, etc.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class for which to compute the SUID
+	 * @param fields
+	 *            cl.getDeclaredFields(), pre-computed by the caller
+	 * @return the value of SUID of this class
+	 * 
+	 */
+	private static long computeSerialVersionUID(Class cl, Field[] fields) {
+		// First we should try to fetch the static slot
+		// 'static final long serialVersionUID'. If it is defined,
+		// return it. If not defined, we really need to compute SUID
+		// using SHAOutputStream
+
+		for (int i = 0; i < fields.length; i++) {
+			final Field field = fields[i];
+			if (Long.TYPE == field.getType()) {
+				int modifiers = field.getModifiers();
+				if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
+					if (UID_FIELD_NAME.equals(field.getName())) {
+						// We need to be able to see it even if we have no
+						// visibility.
+						// That is why we set accessible first (new API in
+						// reflect 1.2)
+						AccessController.doPrivileged(new PriviAction(field));
+						try {
+							return field.getLong(null); // Static field,
+														// parameter is ignored
+						} catch (IllegalAccessException iae) {
+							throw new RuntimeException(com.ibm.oti.util.Msg
+									.getString("K0071", iae.toString())); //$NON-NLS-1$
+						}
+					}
+				}
+			}
+		}
+
+		java.security.MessageDigest digest;
+		try {
+			digest = java.security.MessageDigest.getInstance("SHA"); //$NON-NLS-1$
+		} catch (java.security.NoSuchAlgorithmException e) {
+			throw new Error(e.toString());
+		}
+		ByteArrayOutputStream sha = new ByteArrayOutputStream();
+		try {
+			DataOutputStream output = new DataOutputStream(sha);
+			output.writeUTF(cl.getName());
+			int classModifiers = CLASS_MODIFIERS_MASK & cl.getModifiers();
+			// Workaround for 1F9LOQO. Arrays are ABSTRACT in JDK, but that is
+			// not in the spec.
+			// Since we want to be compatible for X-loading, we have to pretend
+			// we have the same shape
+			boolean isArray = cl.isArray();
+			if (isArray) {
+				classModifiers |= Modifier.ABSTRACT;
+			}
+			// Required for JDK UID compatibility
+			if (cl.isInterface() && !Modifier.isPublic(classModifiers))
+				classModifiers &= ~Modifier.ABSTRACT;
+			output.writeInt(classModifiers);
+
+			// Workaround for 1F9LOQO. In JDK1.2 arrays implement Cloneable and
+			// Serializable
+			// but not in JDK 1.1.7. So, JDK 1.2 "pretends" arrays have no
+			// interfaces when
+			// computing SHA-1 to be compatible.
+			if (!isArray) {
+				// ------------------ Interface information
+				Class[] interfaces = cl.getInterfaces();
+				if (interfaces.length > 1) { // Only attempt to sort if
+												// really needed (saves object
+												// creation, etc)
+					// Sort them
+					Sorter.Comparator interfaceComparator = new Sorter.Comparator() {
+						public int compare(Object interface1, Object interface2) {
+							return ((Class) interface1).getName().compareTo(
+									((Class) interface2).getName());
+						}
+					};
+					Sorter.sort(interfaces, interfaceComparator);
+				}
+
+				// Dump them
+				for (int i = 0; i < interfaces.length; i++)
+					output.writeUTF(interfaces[i].getName());
+			}
+
+			// ------------------ Field information
+
+			if (fields.length > 1) {// Only attempt to sort if really needed
+									// (saves object creation, etc)
+				// Sort them
+				Sorter.Comparator fieldComparator = new Sorter.Comparator() {
+					public int compare(Object field1, Object field2) {
+						return ((Field) field1).getName().compareTo(
+								((Field) field2).getName());
+					}
+				};
+				Sorter.sort(fields, fieldComparator);
+			}
+
+			// Dump them
+			for (int i = 0; i < fields.length; i++) {
+				Field field = fields[i];
+				int modifiers = field.getModifiers();
+				boolean skip = Modifier.isPrivate(modifiers)
+						&& (Modifier.isTransient(modifiers) || Modifier
+								.isStatic(modifiers));
+				if (!skip) {
+					// write name, modifier & "descriptor" of all but private
+					// static and private transient
+					output.writeUTF(field.getName());
+					output.writeInt(modifiers);
+					output
+							.writeUTF(descriptorForFieldSignature(getFieldSignature(field)));
+				}
+			}
+
+			// Normally constructors come before methods (because <init> <
+			// anyMethodName).
+			// However, <clinit> is an exception. Besides, reflect will not let
+			// us get to it.
+			if (hasClinit(cl)) {
+				// write name, modifier & "descriptor"
+				output.writeUTF(CLINIT_NAME);
+				output.writeInt(CLINIT_MODIFIERS);
+				output.writeUTF(CLINIT_SIGNATURE);
+			}
+
+			// ------------------ Constructor information
+			Constructor[] constructors = cl.getDeclaredConstructors();
+			if (constructors.length > 1) {// Only attempt to sort if really
+											// needed (saves object creation,
+											// etc)
+				// Sort them
+				Sorter.Comparator constructorComparator = new Sorter.Comparator() {
+					public int compare(Object constructor1, Object constructor2) {
+						// All constructors have same name, so we sort based on
+						// signature
+						return (getConstructorSignature((Constructor) constructor1)
+								.compareTo(getConstructorSignature((Constructor) constructor2)));
+					}
+				};
+				Sorter.sort(constructors, constructorComparator);
+			}
+
+			// Dump them
+			for (int i = 0; i < constructors.length; i++) {
+				Constructor constructor = constructors[i];
+				int modifiers = constructor.getModifiers();
+				boolean isPrivate = Modifier.isPrivate(modifiers);
+				if (!isPrivate) {
+					// write name, modifier & "descriptor" of all but private
+					// ones
+					output.writeUTF("<init>"); // constructor.getName() returns //$NON-NLS-1$
+												// the constructor name as
+												// typed, not the VM name
+					output.writeInt(modifiers);
+					output
+							.writeUTF(descriptorForSignature(getConstructorSignature(constructor)));
+				}
+			}
+
+			// ------------------ Method information
+			Method[] methods = cl.getDeclaredMethods();
+			if (methods.length > 1) {// Only attempt to sort if really needed
+										// (saves object creation, etc)
+				// Sort them
+				Sorter.Comparator methodComparator = new Sorter.Comparator() {
+					public int compare(Object method1, Object method2) {
+						int result = ((Method) method1).getName().compareTo(
+								((Method) method2).getName());
+						if (result == 0) {
+							// same name, signature will tell which one comes
+							// first
+							return (getMethodSignature((Method) method1)
+									.compareTo(getMethodSignature((Method) method2)));
+						}
+						return result;
+					}
+				};
+				Sorter.sort(methods, methodComparator);
+			}
+
+			// Dump them
+			for (int i = 0; i < methods.length; i++) {
+				Method method = methods[i];
+				int modifiers = method.getModifiers();
+				boolean isPrivate = Modifier.isPrivate(modifiers);
+				if (!isPrivate) {
+					// write name, modifier & "descriptor" of all but private
+					// ones
+					output.writeUTF(method.getName());
+					output.writeInt(modifiers);
+					output
+							.writeUTF(descriptorForSignature(getMethodSignature(method)));
+				}
+			}
+		} catch (IOException e) {
+			throw new RuntimeException(com.ibm.oti.util.Msg.getString("K0072", //$NON-NLS-1$
+					e.toString()));
+		}
+
+		// now compute the UID based on the SHA
+		byte[] hash = digest.digest(sha.toByteArray());
+		return littleEndianLongAt(hash, 0);
+
+	}
+
+	/**
+	 * Return what the serializaton specification calls "descriptor" given a
+	 * field signature. signature.
+	 * 
+	 * @param signature
+	 *            a field signature
+	 * @return containing the descriptor
+	 * 
+	 */
+	private static String descriptorForFieldSignature(String signature) {
+		return signature.replace('.', '/');
+	}
+
+	/**
+	 * Return what the serializaton specification calls "descriptor" given a
+	 * method/constructor signature.
+	 * 
+	 * @param signature
+	 *            a method or constructor signature
+	 * @return containing the descriptor
+	 * 
+	 */
+	private static String descriptorForSignature(String signature) {
+		return signature.substring(signature.indexOf("(")); //$NON-NLS-1$
+	}
+
+	/**
+	 * Return the java.lang.reflect.Field <code>serialPersistentFields</code>
+	 * if class <code>cl</code> implements it. Return null otherwise.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class which to test
+	 * @return <code>java.lang.reflect.Field</code> if the class has
+	 *         serialPersistentFields <code>null</code> if the class does not
+	 *         have serialPersistentFields
+	 */
+	static Field fieldSerialPersistentFields(Class cl) {
+		try {
+			Field f = cl.getDeclaredField("serialPersistentFields"); //$NON-NLS-1$
+			int modifiers = f.getModifiers();
+			if (Modifier.isStatic(modifiers) && Modifier.isPrivate(modifiers)
+					&& Modifier.isFinal(modifiers))
+				if (f.getType() == ARRAY_OF_FIELDS)
+					return f;
+		} catch (NoSuchFieldException nsm) {
+		}
+		return null;
+	}
+
+	/**
+	 * Return the class (java.lang.Class) that the receiver represents
+	 * 
+	 * @return <code>null</code> if there is no corresponding class for the
+	 *         receiver <code>Class</code> The loaded class corresponding to
+	 *         the receiver
+	 */
+	public Class forClass() {
+		if (resolvedClass != null) {
+			return (Class) resolvedClass.get();
+		}
+		return null;
+	}
+
+	/**
+	 * Return a String representing the signature for a Constructor
+	 * <code>c</code>.
+	 * 
+	 * @param c
+	 *            a java.lang.reflect.Constructor for which to compute the
+	 *            signature
+	 * @return the constructor's signature
+	 * 
+	 */
+	static native String getConstructorSignature(Constructor c);
+
+	/**
+	 * Answers a given field by name.
+	 * 
+	 * @param name
+	 *            name of the desired field.
+	 * @return a given field by name.
+	 */
+
+	public ObjectStreamField getField(String name) {
+		ObjectStreamField[] allFields = fields();
+		for (int i = 0; i < allFields.length; i++) {
+			ObjectStreamField f = allFields[i];
+			if (f.getName().equals(name))
+				return f;
+		}
+		return null;
+	}
+
+	/**
+	 * Answers the collection of field descriptors for the fields of the
+	 * corresponding class
+	 * 
+	 * @return the receiver's collection of declared fields for the class it
+	 *         represents
+	 */
+
+	ObjectStreamField[] fields() {
+		if (fields == null) {
+			Class forCl = forClass();
+			if (forCl != null && isSerializable(forCl) && !forCl.isArray())
+				buildFieldDescriptors(forCl.getDeclaredFields());
+			else
+				// Externalizables or arrays do not need FieldDesc info
+				setFields(new ObjectStreamField[0]);
+		}
+		return fields;
+	}
+
+	/**
+	 * Answers the collection of field descriptors for the fields of the
+	 * corresponding class
+	 * 
+	 * @return the receiver's collection of declared fields for the class it
+	 *         represents
+	 */
+
+	public ObjectStreamField[] getFields() {
+		return (ObjectStreamField[]) fields().clone();
+	}
+
+	/**
+	 * Answers the collection of field descriptors for the input fields of the
+	 * corresponding class
+	 * 
+	 * @return the receiver's collection of input fields for the class it
+	 *         represents
+	 */
+
+	ObjectStreamField[] getLoadFields() {
+		return loadFields;
+	}
+
+	/**
+	 * Return a String representing the signature for a field <code>f</code>.
+	 * 
+	 * @param f
+	 *            a java.lang.reflect.Field for which to compute the signature
+	 * @return the field's signature
+	 * 
+	 */
+	private static native String getFieldSignature(Field f);
+
+	/**
+	 * Answers the flags for this descriptor, where possible combined values are
+	 * 
+	 * ObjectStreamConstants.SC_WRITE_METHOD
+	 * ObjectStreamConstants.SC_SERIALIZABLE
+	 * ObjectStreamConstants.SC_EXTERNALIZABLE
+	 * 
+	 * @return byte the receiver's flags for the class it represents
+	 */
+	byte getFlags() {
+		return flags;
+	}
+
+	/**
+	 * Return a String representing the signature for a method <code>m</code>.
+	 * 
+	 * @param m
+	 *            a java.lang.reflect.Method for which to compute the signature
+	 * @return the method's signature
+	 * 
+	 */
+	static native String getMethodSignature(Method m);
+
+	/**
+	 * Answers the name of the class represented by the receiver
+	 * 
+	 * @return fully qualified name of the class the receiver represents
+	 */
+	public String getName() {
+		return className;
+	}
+
+	/**
+	 * Answers the Serial Version User ID of the class represented by the
+	 * receiver
+	 * 
+	 * @return SUID for the class represented by the receiver
+	 */
+	public long getSerialVersionUID() {
+		return svUID;
+	}
+
+	/**
+	 * Answers the descriptor (ObjectStreamClass) of the superclass of the class
+	 * represented by the receiver.
+	 * 
+	 * @return an ObjectStreamClass representing the superclass of the class
+	 *         represented by the receiver.
+	 */
+	ObjectStreamClass getSuperclass() {
+		return superclass;
+	}
+
+	/**
+	 * Return true if the given class <code>cl</code> has the
+	 * compiler-generated method <code>clinit</code>. Even though it is
+	 * compiler-generated, it is used by the serialization code to compute SUID.
+	 * This is unfortunate, since it may depend on compiler optimizations in
+	 * some cases.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class which to test
+	 * @return <code>true</code> if the class has <clinit> <code>false</code>
+	 *         if the class does not have <clinit>
+	 */
+	private static native boolean hasClinit(Class cl);
+
+	/**
+	 * Return true if the given class <code>cl</code> implements private
+	 * method <code>readObject()</code>.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class which to test
+	 * @return <code>true</code> if the class implements readObject
+	 *         <code>false</code> if the class does not implement readObject
+	 */
+	static Method getPrivateReadObjectMethod(Class cl) {
+		try {
+			Method method = cl
+					.getDeclaredMethod("readObject", READ_PARAM_TYPES); //$NON-NLS-1$
+			if (Modifier.isPrivate(method.getModifiers())
+					&& method.getReturnType() == VOID_CLASS) {
+				return method;
+			}
+		} catch (NoSuchMethodException nsm) {
+		}
+		return null;
+	}
+
+	/**
+	 * Return true if the given class <code>cl</code> implements private
+	 * method <code>readObject()</code>.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class which to test
+	 * @return <code>true</code> if the class implements readObject
+	 *         <code>false</code> if the class does not implement readObject
+	 */
+	static Method getPrivateReadObjectNoDataMethod(Class cl) {
+		try {
+			Method method = cl.getDeclaredMethod("readObjectNoData", //$NON-NLS-1$
+					EMPTY_CONSTRUCTOR_PARAM_TYPES);
+			if (Modifier.isPrivate(method.getModifiers())
+					&& method.getReturnType() == VOID_CLASS) {
+				return method;
+			}
+		} catch (NoSuchMethodException nsm) {
+		}
+		return null;
+	}
+
+	/**
+	 * Return true if the given class <code>cl</code> implements private
+	 * method <code>writeObject()</code>.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class which to test
+	 * @return <code>true</code> if the class implements writeObject
+	 *         <code>false</code> if the class does not implement writeObject
+	 */
+	static Method getPrivateWriteObjectMethod(Class cl) {
+		try {
+			Method method = cl.getDeclaredMethod("writeObject", //$NON-NLS-1$
+					WRITE_PARAM_TYPES);
+			if (Modifier.isPrivate(method.getModifiers())
+					&& method.getReturnType() == VOID_CLASS) {
+				return method;
+			}
+		} catch (NoSuchMethodException nsm) {
+		}
+		return null;
+	}
+
+	/**
+	 * Return true if instances of class <code>cl</code> are Externalizable,
+	 * false otherwise.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class which to test
+	 * @return <code>true</code> if instances of the class are Externalizable
+	 *         <code>false</code> if instances of the class are not
+	 *         Externalizable
+	 * 
+	 * @see Object#hashCode
+	 */
+	static boolean isExternalizable(Class cl) {
+		return EXTERNALIZABLE.isAssignableFrom(cl);
+	}
+
+	/**
+	 * Return true if the typecode
+	 * <code>typecode<code> describes a primitive type
+	 *
+	 * @param		typecode	a char describing the typecode
+	 * @return		<code>true</code> if the typecode represents a primitive type
+	 *				<code>false</code> if the typecode represents an Object type (including arrays)
+	 *
+	 * @see			Object#hashCode
+	 */
+	static boolean isPrimitiveType(char typecode) {
+		return !(typecode == '[' || typecode == 'L');
+	}
+
+	/**
+	 * Return true if instances of class <code>cl</code> are Serializable,
+	 * false otherwise.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class which to test
+	 * @return <code>true</code> if instances of the class are Serializable
+	 *         <code>false</code> if instances of the class are not
+	 *         Serializable
+	 * 
+	 * @see Object#hashCode
+	 */
+	static boolean isSerializable(Class cl) {
+		return SERIALIZABLE.isAssignableFrom(cl);
+	}
+
+	/**
+	 * Return a little endian long stored in a given position of the buffer
+	 * 
+	 * @param buffer
+	 *            a byte array with the byte representation of the number
+	 * @param position
+	 *            index where the number starts in the byte array
+	 * @return the number that was stored in little endian format
+	 */
+	private static long littleEndianLongAt(byte[] buffer, int position) {
+		long result = 0;
+		for (int i = position + 7; i >= position; i--)
+			result = (result << 8) + (buffer[i] & 0xff);
+		return result;
+	}
+
+	/**
+	 * Return the descriptor (ObjectStreamClass) corresponding to the class
+	 * <code>cl</code>. If the class is not Serializable or Externalizable,
+	 * null is returned.
+	 * 
+	 * @param cl
+	 *            a java.langClass for which to obtain the corresponding
+	 *            descriptor
+	 * @return <code>null</code> if instances of the class <code>cl</code>
+	 *         are not Serializable or Externalizable
+	 *         <code>ObjectStreamClass</code> The corresponding descriptor if
+	 *         the class <code>cl</code> is Serializable or Externalizable
+	 */
+	public static ObjectStreamClass lookup(Class cl) {
+		boolean serializable = isSerializable(cl);
+		boolean externalizable = isExternalizable(cl);
+
+		// Has to be either Serializable or Externalizable
+		if (!serializable && !externalizable)
+			return null;
+
+		return lookupStreamClass(cl, true);
+	}
+
+	/**
+	 * Return the descriptor (ObjectStreamClass) corresponding to the class
+	 * <code>cl</code>. Returns an ObjectStreamClass even if instances of the
+	 * class cannot be serialized
+	 * 
+	 * @param cl
+	 *            a java.langClass for which to obtain the corresponding
+	 *            descriptor
+	 * @return the corresponding descriptor
+	 */
+	static ObjectStreamClass lookupStreamClass(Class cl) {
+		return lookupStreamClass(cl, isSerializable(cl) || isExternalizable(cl));
+	}
+
+	/**
+	 * Return the descriptor (ObjectStreamClass) corresponding to the class
+	 * <code>cl</code>. Returns an ObjectStreamClass even if instances of the
+	 * class cannot be serialized
+	 * 
+	 * @param cl
+	 *            a <code>java.langClass</code> for which to obtain the
+	 *            corresponding descriptor
+	 * @param computeSUID
+	 *            a boolean indicating if SUID should be computed or not.
+	 * @return the corresponding descriptor
+	 */
+	private static synchronized ObjectStreamClass lookupStreamClass(Class cl,
+			boolean computeSUID) {
+		// Synchronized because of the lookup table 'classesAndDescriptors'
+		ObjectStreamClass cachedValue = (ObjectStreamClass) classesAndDescriptors
+				.get(cl);
+		if (cachedValue != null)
+			return cachedValue;
+		return addToCache(cl, computeSUID);
+	}
+
+	/**
+	 * Return the java.lang.reflect.Method <code>readResolve</code> if class
+	 * <code>cl</code> implements it. Return null otherwise.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class which to test
+	 * @return <code>java.lang.reflect.Method</code> if the class implements
+	 *         readResolve <code>null</code> if the class does not implement
+	 *         readResolve
+	 */
+	static Method methodReadResolve(Class cl) {
+		Class search = cl;
+		while (search != null) {
+			try {
+				Method method = search.getDeclaredMethod("readResolve", null); //$NON-NLS-1$
+				if (search == cl
+						|| (method.getModifiers() & Modifier.PRIVATE) == 0)
+					return method;
+				return null;
+			} catch (NoSuchMethodException nsm) {
+			}
+			search = search.getSuperclass();
+		}
+		return null;
+	}
+
+	/**
+	 * Return the java.lang.reflect.Method <code>writeReplace</code> if class
+	 * <code>cl</code> implements it. Return null otherwise.
+	 * 
+	 * @param cl
+	 *            a java.lang.Class which to test
+	 * @return <code>java.lang.reflect.Method</code> if the class implements
+	 *         writeReplace <code>null</code> if the class does not implement
+	 *         writeReplace
+	 */
+	static Method methodWriteReplace(Class cl) {
+		Class search = cl;
+		while (search != null) {
+			try {
+				Method method = search.getDeclaredMethod("writeReplace", null); //$NON-NLS-1$
+				if (search == cl
+						|| (method.getModifiers() & Modifier.PRIVATE) == 0)
+					return method;
+				return null;
+			} catch (NoSuchMethodException nsm) {
+			}
+			search = search.getSuperclass();
+		}
+		return null;
+	}
+
+	/**
+	 * Set the class (java.lang.Class) that the receiver represents
+	 * 
+	 * @param c
+	 *            aClass, the new class that the receiver describes
+	 */
+	void setClass(Class c) {
+		resolvedClass = new WeakReference(c);
+	}
+
+	/**
+	 * Set the collection of field descriptors for the fields of the
+	 * corresponding class
+	 * 
+	 * @param f
+	 *            ObjectStreamField[], the receiver's new collection of declared
+	 *            fields for the class it represents
+	 */
+	void setFields(ObjectStreamField[] f) {
+		fields = f;
+	}
+
+	/**
+	 * Set the collection of field descriptors for the input fields of the
+	 * corresponding class
+	 * 
+	 * @param f
+	 *            ObjectStreamField[], the receiver's new collection of input
+	 *            fields for the class it represents
+	 */
+	void setLoadFields(ObjectStreamField[] f) {
+		loadFields = f;
+	}
+
+	/**
+	 * Set the flags for this descriptor, where possible combined values are
+	 * 
+	 * ObjectStreamConstants.SC_WRITE_METHOD
+	 * ObjectStreamConstants.SC_SERIALIZABLE
+	 * ObjectStreamConstants.SC_EXTERNALIZABLE
+	 * 
+	 * @param b
+	 *            byte, the receiver's new flags for the class it represents
+	 */
+	void setFlags(byte b) {
+		flags = b;
+	}
+
+	/**
+	 * Set the name of the class represented by the receiver
+	 * 
+	 * @param newName
+	 *            a String, the new fully qualified name of the class the
+	 *            receiver represents
+	 */
+	void setName(String newName) {
+		className = newName;
+	}
+
+	/**
+	 * Set the Serial Version User ID of the class represented by the receiver
+	 * 
+	 * @param l
+	 *            a long, the new SUID for the class represented by the receiver
+	 */
+	void setSerialVersionUID(long l) {
+		svUID = l;
+	}
+
+	/**
+	 * Set the descriptor for the superclass of the class described by the
+	 * receiver
+	 * 
+	 * @param c
+	 *            an ObjectStreamClass, the new ObjectStreamClass for the
+	 *            superclass of the class represented by the receiver
+	 */
+	void setSuperclass(ObjectStreamClass c) {
+		superclass = c;
+	}
+
+	private int primitiveSize(Class type) {
+		if (type == Byte.TYPE || type == Boolean.TYPE)
+			return 1;
+		if (type == Short.TYPE || type == Character.TYPE)
+			return 2;
+		if (type == Integer.TYPE || type == Float.TYPE)
+			return 4;
+		if (type == Long.TYPE || type == Double.TYPE)
+			return 8;
+		return 0;
+	}
+
+	/**
+	 * Answers a string containing a concise, human-readable description of the
+	 * receiver.
+	 * 
+	 * @return a printable representation for the receiver.
+	 */
+	public String toString() {
+		return getName() + ": static final long serialVersionUID =" //$NON-NLS-1$
+				+ getSerialVersionUID() + "L;"; //$NON-NLS-1$
+	}
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamConstants.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamConstants.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamConstants.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamConstants.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,94 @@
+/* Copyright 1998, 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.io;
+
+
+/**
+ * Helper interface with constants used by the serialization implementation.
+ * 
+ */
+
+public abstract interface ObjectStreamConstants {
+
+	/**
+	 * Used for the stream header
+	 */
+	public static final short STREAM_MAGIC = (short) 0xaced;
+
+	/**
+	 * Used for the stream header
+	 */
+	public static final short STREAM_VERSION = 5;
+
+	// These are tags to indicate the stream contents
+	public static final byte TC_BASE = 0x70;
+
+	public static final byte TC_NULL = (byte) 0x70;
+
+	public static final byte TC_REFERENCE = (byte) 0x71;
+
+	public static final byte TC_CLASSDESC = (byte) 0x72;
+
+	public static final byte TC_OBJECT = (byte) 0x73;
+
+	public static final byte TC_STRING = (byte) 0x74;
+
+	public static final byte TC_ARRAY = (byte) 0x75;
+
+	public static final byte TC_CLASS = (byte) 0x76;
+
+	public static final byte TC_BLOCKDATA = (byte) 0x77;
+
+	public static final byte TC_ENDBLOCKDATA = (byte) 0x78;
+
+	public static final byte TC_RESET = (byte) 0x79;
+
+	public static final byte TC_BLOCKDATALONG = (byte) 0x7A;
+
+	public static final byte TC_EXCEPTION = (byte) 0x7B;
+
+	public static final byte TC_LONGSTRING = (byte) 0x7C;
+
+	public static final byte TC_PROXYCLASSDESC = (byte) 0x7D;
+
+	public static final byte TC_MAX = 0x7D;
+
+	/**
+	 * The first object dumped gets assigned this handle/ID
+	 */
+	public static final int baseWireHandle = 0x007e0000;
+
+	public static final int PROTOCOL_VERSION_1 = 1;
+
+	public static final int PROTOCOL_VERSION_2 = 2;
+
+	public static final SerializablePermission SUBCLASS_IMPLEMENTATION_PERMISSION = new SerializablePermission(
+			"enableSubclassImplementation"); //$NON-NLS-1$
+
+	public static final SerializablePermission SUBSTITUTION_PERMISSION = new SerializablePermission(
+			"enableSubstitution"); //$NON-NLS-1$
+
+	// Flags that indicate if the object was serializable, externalizable
+	// and had a writeObject method when dumped.
+	public static final byte SC_WRITE_METHOD = 0x01; // If SC_SERIALIZABLE
+
+	public static final byte SC_SERIALIZABLE = 0x02;
+
+	public static final byte SC_EXTERNALIZABLE = 0x04;
+
+	public static final byte SC_BLOCK_DATA = 0x08; // If SC_EXTERNALIZABLE
+
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamException.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamException.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamException.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamException.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,55 @@
+/* Copyright 1998, 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.io;
+
+
+/**
+ * This is the superclass of all exceptions that can happen when serializing or
+ * deserialing objects. The state of the stream is unknown when one of these
+ * serialization-related exceptions are thrown.
+ * 
+ * @see InvalidObjectException
+ * @see NotActiveException
+ * @see NotSerializableException
+ * @see OptionalDataException
+ * @see StreamCorruptedException
+ * @see WriteAbortedException
+ * 
+ */
+public abstract class ObjectStreamException extends IOException {
+
+	static final long serialVersionUID = 7260898174833392607L;
+
+	/**
+	 * Constructs a new instance of this class with its walkback filled in.
+	 * 
+	 */
+	protected ObjectStreamException() {
+		super();
+	}
+
+	/**
+	 * Constructs a new instance of this class with its walkback and message
+	 * filled in.
+	 * 
+	 * @param detailMessage
+	 *            The detail message for the exception.
+	 */
+	protected ObjectStreamException(String detailMessage) {
+		super(detailMessage);
+	}
+
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamField.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamField.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamField.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/ObjectStreamField.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,339 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.io;
+
+
+import java.lang.ref.WeakReference;
+
+import com.ibm.oti.util.Sorter;
+
+/**
+ * This class represents object fields that are saved to the stream, by
+ * serialization. Classes can define the collection of fields to be dumped,
+ * which can differ from the actual object's declared fields.
+ * 
+ * @see ObjectOutputStream#writeFields()
+ * @see ObjectInputStream#readFields()
+ * 
+ */
+public class ObjectStreamField extends Object implements Comparable {
+	private String name; // Declared name of the field
+
+	private Object type; // Declared type of the field
+
+	int offset; // offset of this field in the object
+
+	private String typeString; // Cached version of intern'ed type String.
+
+	private boolean unshared = false;
+
+	/**
+	 * Constructs an ObjectStreamField with the given name and the given type
+	 * 
+	 * @param name
+	 *            a String, the name of the field
+	 * @param cl
+	 *            A Class object representing the type of the field
+	 */
+	public ObjectStreamField(String name, Class cl) {
+		if (name != null && cl != null) {
+			this.name = name;
+			this.type = new WeakReference(cl);
+		} else
+			throw new NullPointerException();
+	}
+
+	/**
+	 * Constructs an ObjectStreamField with the given name and the given type
+	 * 
+	 * @param name
+	 *            a String, the name of the field
+	 * @param cl
+	 *            A Class object representing the type of the field
+	 * @param unshared
+	 *            write and read the field unshared
+	 */
+	public ObjectStreamField(String name, Class cl, boolean unshared) {
+		if (name != null && cl != null) {
+			this.name = name;
+			if (cl.getClassLoader() == null) {
+				this.type = cl;
+			} else {
+				this.type = new WeakReference(cl);
+			}
+			this.unshared = unshared;
+		} else
+			throw new NullPointerException();
+	}
+
+	/**
+	 * Constructs an ObjectStreamField with the given name and the given type.
+	 * The type may be null.
+	 * 
+	 * @param signature
+	 *            A String representing the type of the field
+	 * @param name
+	 *            a String, the name of the field, or null
+	 */
+	ObjectStreamField(String signature, String name) {
+		if (name != null) {
+			this.name = name;
+			this.typeString = signature.replace('.', '/');
+		} else
+			throw new NullPointerException();
+	}
+
+	/**
+	 * Comparing the receiver to the parameter, according to the Comparable
+	 * interface.
+	 * 
+	 * @param o
+	 *            The object to compare against
+	 * 
+	 * @return -1 if the receiver is "smaller" than the parameter. 0 if the
+	 *         receiver is "equal" to the parameter. 1 if the receiver is
+	 *         "greater" than the parameter.
+	 * 
+	 */
+	public int compareTo(Object o) {
+		ObjectStreamField f = (ObjectStreamField) o;
+		boolean thisPrimitive = this.isPrimitive();
+		boolean fPrimitive = f.isPrimitive();
+
+		// If one is primitive and the other isn't, we have enough info to
+		// compare
+		if (thisPrimitive != fPrimitive)
+			return thisPrimitive ? -1 : 1;
+
+		// Either both primitives or both not primitives. Compare based on name.
+		return this.getName().compareTo(f.getName());
+	}
+
+	/**
+	 * Return the name of the field the receiver represents
+	 * 
+	 * @return a String, the name of the field
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Return the offset of this field in the object
+	 * 
+	 * @return an int, the offset
+	 */
+	public int getOffset() {
+		return offset;
+	}
+
+	/**
+	 * Return the type of the field the receiver represents
+	 * 
+	 * @return A Class object representing the type of the field
+	 */
+	public Class getType() {
+		if (type instanceof WeakReference) {
+			return (Class) ((WeakReference) type).get();
+		}
+		return (Class) type;
+	}
+
+	/**
+	 * Return the type code that corresponds to the class the receiver
+	 * represents
+	 * 
+	 * @return A char, the typecode of the class
+	 */
+	public char getTypeCode() {
+		Class t = getType();
+		if (t == Integer.TYPE)
+			return 'I';
+		if (t == Byte.TYPE)
+			return 'B';
+		if (t == Character.TYPE)
+			return 'C';
+		if (t == Short.TYPE)
+			return 'S';
+		if (t == Boolean.TYPE)
+			return 'Z';
+		if (t == Long.TYPE)
+			return 'J';
+		if (t == Float.TYPE)
+			return 'F';
+		if (t == Double.TYPE)
+			return 'D';
+		if (t.isArray())
+			return '[';
+		return 'L';
+	}
+
+	/**
+	 * Return the type signature used by the VM to represent the type for this
+	 * field.
+	 * 
+	 * @return A String, the signature for the class of this field.
+	 */
+	public String getTypeString() {
+		if (typeString == null)
+			typeString = computeTypeString().intern();
+		return typeString;
+	}
+
+	/**
+	 * Return the type signature used by the VM to represent the type for this
+	 * field.
+	 * 
+	 * @return A String, the signature for the class of this field.
+	 */
+	private String computeTypeString() {
+		// NOTE: this is very similar to Class.getSignature(). Unfortunately
+		// we can't call that due to visibility restrictions.
+
+		Class t = getType();
+		if (t.isArray())
+			return t.getName().replace('.', '/');
+
+		if (isPrimitive()) {
+			// Special cases for each base type.
+			// NOTE: In how many places do we find this same pattern in java ?
+			// getTypeCode() return character, here we return String.
+			if (t == Integer.TYPE)
+				return "I"; //$NON-NLS-1$
+			if (t == Byte.TYPE)
+				return "B"; //$NON-NLS-1$
+			if (t == Character.TYPE)
+				return "C"; //$NON-NLS-1$
+			if (t == Short.TYPE)
+				return "S"; //$NON-NLS-1$
+			if (t == Boolean.TYPE)
+				return "Z"; //$NON-NLS-1$
+			if (t == Long.TYPE)
+				return "J"; //$NON-NLS-1$
+			if (t == Float.TYPE)
+				return "F"; //$NON-NLS-1$
+			if (t == Double.TYPE)
+				return "D"; //$NON-NLS-1$
+			throw new RuntimeException();
+		}
+
+		// General case.
+		return ("L" + t.getName() + ';').replace('.', '/'); //$NON-NLS-1$
+	}
+
+	/**
+	 * Return a boolean indicating whether the class of this field is a
+	 * primitive type or not
+	 * 
+	 * @return true if the type of this field is a primitive type false if the
+	 *         type of this field is a regular class.
+	 */
+	public boolean isPrimitive() {
+		Class t = getType();
+		return t != null && t.isPrimitive();
+	}
+
+	/**
+	 * Set the offset this field represents in the object
+	 * 
+	 * @param newValue
+	 *            an int, the offset
+	 */
+	protected void setOffset(int newValue) {
+		this.offset = newValue;
+	}
+
+	/**
+	 * Answers a string containing a concise, human-readable description of the
+	 * receiver.
+	 * 
+	 * @return a printable representation for the receiver.
+	 */
+	public String toString() {
+		return this.getClass().getName() + '(' + getName() + ':' + getType()
+				+ ')';
+	}
+
+	/**
+	 * Sorts the fields for dumping. Primitive types come first, then regular
+	 * types.
+	 * 
+	 * @param fields
+	 *            ObjectStreamField[] fields to be sorted
+	 */
+	static void sortFields(ObjectStreamField[] fields) {
+		// Sort if necessary
+		if (fields.length > 1) {
+			Sorter.Comparator fieldDescComparator = new Sorter.Comparator() {
+				public int compare(Object o1, Object o2) {
+					ObjectStreamField f1 = (ObjectStreamField) o1;
+					ObjectStreamField f2 = (ObjectStreamField) o2;
+					return f1.compareTo(f2);
+				}
+			};
+			Sorter.sort(fields, fieldDescComparator);
+		}
+	}
+
+	void resolve(ClassLoader loader) {
+		if (typeString.length() == 1) {
+			switch (typeString.charAt(0)) {
+			case 'I':
+				type = Integer.TYPE;
+				return;
+			case 'B':
+				type = Byte.TYPE;
+				return;
+			case 'C':
+				type = Character.TYPE;
+				return;
+			case 'S':
+				type = Short.TYPE;
+				return;
+			case 'Z':
+				type = Boolean.TYPE;
+				return;
+			case 'J':
+				type = Long.TYPE;
+				return;
+			case 'F':
+				type = Float.TYPE;
+				return;
+			case 'D':
+				type = Double.TYPE;
+				return;
+			}
+		}
+		String className = typeString.replace('/', '.');
+		if (className.charAt(0) == 'L') {
+			// remove L and ;
+			className = className.substring(1, className.length() - 1);
+		}
+		try {
+			Class cl = Class.forName(className, false, loader);
+			if (cl.getClassLoader() == null) {
+				type = cl;
+			} else {
+				type = new WeakReference(cl);
+			}
+		} catch (ClassNotFoundException e) {
+		}
+	}
+
+	boolean getUnshared() {
+		return unshared;
+	}
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OptionalDataException.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OptionalDataException.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OptionalDataException.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OptionalDataException.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,57 @@
+/* Copyright 1998, 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.io;
+/**
+ * When readObject() encounters primitive types (int, char, etc) instead of an
+ * object instance in the input stream, this type of exception will be thrown.
+ * 
+ * @see ObjectInputStream#available()
+ * @see ObjectInputStream#readObject()
+ * @see ObjectInputStream#skipBytes(int)
+ */
+public class OptionalDataException extends ObjectStreamException {
+
+	static final long serialVersionUID = -8011121865681257820L;
+
+	/**
+	 * If true it means there is no more primitive data available.
+	 */
+	public boolean eof;
+
+	/**
+	 * Number of bytes of primitive data (int, char, long, etc).
+	 */
+	public int length;
+
+	/**
+	 * Constructs a new instance of this class with its walkback filled in.
+	 */
+	OptionalDataException() {
+		super();
+	}
+
+	/**
+	 * Constructs a new instance of this class with its walkback and message
+	 * filled in.
+	 * 
+	 * @param detailMessage
+	 *            String The detail message for the exception.
+	 */
+	OptionalDataException(String detailMessage) {
+		super(detailMessage);
+	}
+
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OutputStream.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OutputStream.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OutputStream.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OutputStream.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,118 @@
+/* Copyright 1998, 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.io;
+
+
+/**
+ * OutputStream is an abstract class for all byte output streams. It provides
+ * basic method implementations for writing bytes to a stream.
+ * 
+ * @see InputStream
+ */
+
+public abstract class OutputStream {
+	/**
+	 * This constructor does nothing interesting. Provided for signature
+	 * compatibility.
+	 * 
+	 */
+
+	public OutputStream() {
+		/*empty*/
+	}
+
+	/**
+	 * Close this OutputStream. Concrete implementations of this class should
+	 * free any resources during close. This implementation does nothing.
+	 * 
+	 * @throws IOException
+	 *             If an error occurs attempting to close this OutputStream.
+	 */
+
+	public void close() throws IOException {
+		/*empty*/
+	}
+
+	/**
+	 * Flush this OutputStream. Concrete implementations of this class should
+	 * ensure any pending writes to the underlying stream are written out when
+	 * this method is envoked. This implementation does nothing.
+	 * 
+	 * @throws IOException
+	 *             If an error occurs attempting to flush this OutputStream.
+	 */
+
+	public void flush() throws IOException {
+		/*empty */
+	}
+
+	/**
+	 * Writes the entire contents of the byte array <code>buffer</code> to
+	 * this OutputStream.
+	 * 
+	 * @param buffer
+	 *            the buffer to be written
+	 * 
+	 * @throws IOException
+	 *             If an error occurs attempting to write to this OutputStream.
+	 */
+
+	public void write(byte buffer[]) throws IOException {
+		write(buffer, 0, buffer.length);
+	}
+
+	/**
+	 * Writes <code>count</code> <code>bytes</code> from the byte array
+	 * <code>buffer</code> starting at <code>offset</code> to this
+	 * OutputStream.
+	 * 
+	 * @param buffer
+	 *            the buffer to be written
+	 * @param offset
+	 *            offset in buffer to get bytes
+	 * @param count
+	 *            number of bytes in buffer to write
+	 * 
+	 * @throws IOException
+	 *             If an error occurs attempting to write to this OutputStream.
+	 * @throws IndexOutOfBoundsException
+	 *             If offset or count are outside of bounds.
+	 */
+
+	public void write(byte buffer[], int offset, int count) throws IOException {
+		// avoid int overflow, check null buffer
+		if (offset <= buffer.length && 0 <= offset && 0 <= count
+				&& count <= buffer.length - offset) {
+			for (int i = offset; i < offset + count; i++)
+				write(buffer[i]);
+		} else
+			throw new ArrayIndexOutOfBoundsException(com.ibm.oti.util.Msg
+					.getString("K002f")); //$NON-NLS-1$
+	}
+
+	/**
+	 * Writes the specified byte <code>oneByte</code> to this OutputStream.
+	 * Only the low order byte of <code>oneByte</code> is written.
+	 * 
+	 * @param oneByte
+	 *            the byte to be written
+	 * 
+	 * @throws IOException
+	 *             If an error occurs attempting to write to this OutputStream.
+	 */
+
+	public abstract void write(int oneByte) throws IOException;
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OutputStreamWriter.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OutputStreamWriter.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OutputStreamWriter.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/OutputStreamWriter.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,294 @@
+/* Copyright 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.io; 
+
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.security.AccessController;
+
+import com.ibm.oti.util.PriviAction;
+
+/**
+ * OutputStreamWriter is a class for turning a character output stream into a
+ * byte output stream. The conversion of Unicode characters to their byte
+ * equivalents is determinded by the converter used. By default, the encoding is
+ * ISO8859_1 (ISO-Latin-1) but can be changed by calling the constructor which
+ * takes an encoding.
+ * 
+ * 
+ * @see InputStreamReader
+ */
+
+public class OutputStreamWriter extends Writer {
+	private OutputStream out;
+
+	private CharsetEncoder encoder;
+
+	private ByteBuffer bytes = ByteBuffer.allocate(8192);
+
+	/**
+	 * Constructs a new OutputStreamWriter using <code>out</code> as the
+	 * OutputStream to write converted characters to. The default character
+	 * encoding is used (see class description).
+	 * 
+	 * @param out
+	 *            the non-null OutputStream to write converted bytes to.
+	 */
+
+	public OutputStreamWriter(OutputStream out) {
+		super(out);
+		this.out = out;
+		String encoding = (String) AccessController
+				.doPrivileged(new PriviAction("file.encoding", "ISO8859_1")); //$NON-NLS-1$ //$NON-NLS-2$
+		encoder = Charset.forName(encoding).newEncoder();
+		encoder.onMalformedInput(CodingErrorAction.REPLACE);
+		encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+	}
+
+	/**
+	 * Constructs a new OutputStreamWriter using <code>out</code> as the
+	 * OutputStream to write converted characters to and <code>end</code> as
+	 * the character encoding. If the encoding cannot be found, an
+	 * UnsupportedEncodingException error is thrown.
+	 * 
+	 * @param out
+	 *            the non-null OutputStream to write converted bytes to.
+	 * @param enc
+	 *            the non-null String describing the desired character encoding.
+	 * 
+	 * @throws UnsupportedEncodingException
+	 *             if the encoding cannot be found.
+	 */
+
+	public OutputStreamWriter(OutputStream out, final String enc)
+			throws UnsupportedEncodingException {
+		super(out);
+		enc.length();
+		this.out = out;
+		try {
+			encoder = Charset.forName(enc).newEncoder();
+		} catch (Exception e) {
+			throw new UnsupportedEncodingException(enc);
+		}
+		encoder.onMalformedInput(CodingErrorAction.REPLACE);
+		encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+	}
+
+	/**
+	 * Constructs a new OutputStreamWriter using <code>out</code> as the
+	 * OutputStream to write converted characters to and <code>cs</code> as
+	 * the character encoding.
+	 * 
+	 * 
+	 * @param out
+	 *            the non-null OutputStream to write converted bytes to.
+	 * @param cs
+	 *            the non-null Charset which specify the character encoding.
+	 */
+	public OutputStreamWriter(OutputStream out, Charset cs) {
+		super(out);
+		this.out = out;
+		encoder = cs.newEncoder();
+		encoder.onMalformedInput(CodingErrorAction.REPLACE);
+		encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+	}
+
+	/**
+	 * Constructs a new OutputStreamWriter using <code>out</code> as the
+	 * OutputStream to write converted characters to and <code>enc</code> as
+	 * the character encoding.
+	 * 
+	 * 
+	 * @param out
+	 *            the non-null OutputStream to write converted bytes to.
+	 * @param enc
+	 *            the non-null CharsetEncoder which used to character encoding.
+	 */
+	public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
+		super(out);
+		enc.charset();
+		this.out = out;
+		encoder = enc;
+	}
+
+	/**
+	 * Close this OutputStreamWriter. This implementation first flushes the
+	 * buffer and the target OutputStream. The OutputStream is then closed and
+	 * the resources for the buffer and converter are freed.
+	 * <p>
+	 * Only the first invocation of this method has any effect. Subsequent calls
+	 * do no work.
+	 * 
+	 * @throws IOException
+	 *             If an error occurs attempting to close this
+	 *             OutputStreamWriter.
+	 */
+	public void close() throws IOException {
+		synchronized (lock) {
+			if (encoder != null) {
+				flush();
+				out.flush();
+				out.close();
+				encoder = null;
+				bytes = null;
+			}
+		}
+	}
+
+	/**
+	 * Flush this OutputStreamWriter. This implementation ensures all buffered
+	 * bytes are written to the target OutputStream. After writing the bytes,
+	 * the target OutputStream is then flushed.
+	 * 
+	 * @throws IOException
+	 *             If an error occurs attempting to flush this
+	 *             OutputStreamWriter.
+	 */
+
+	public void flush() throws IOException {
+		synchronized (lock) {
+			checkStatus();
+			int position;
+			if ((position = bytes.position()) > 0) {
+				bytes.flip();
+				out.write(bytes.array(), 0, position);
+				bytes.clear();
+			}
+			out.flush();
+		}
+	}
+
+	private void checkStatus() throws IOException {
+		if (encoder == null) {
+			throw new IOException("This writer has been closed!"); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Answer the String which identifies the encoding used to convert
+	 * characters to bytes. The value <code>null</code> is returned if this
+	 * Writer has been closed.
+	 * 
+	 * @return the String describing the converter or null if this Writer is
+	 *         closed.
+	 */
+
+	public String getEncoding() {
+		return encoder.charset().name();
+	}
+
+	/**
+	 * Writes <code>count</code> characters starting at <code>offset</code>
+	 * in <code>buf</code> to this Writer. The characters are immediately
+	 * converted to bytes by the character converter and stored in a local
+	 * buffer. If the buffer becomes full as a result of this write, this Writer
+	 * is flushed.
+	 * 
+	 * @param buf
+	 *            the non-null array containing characters to write.
+	 * @param offset
+	 *            offset in buf to retrieve characters
+	 * @param count
+	 *            maximum number of characters to write
+	 * 
+	 * @throws IOException
+	 *             If this OuputStreamWriter has already been closed or some
+	 *             other IOException occurs.
+	 * @throws ArrayIndexOutOfBoundsException
+	 *             If offset or count are outside of bounds.
+	 */
+	public void write(char[] buf, int offset, int count) throws IOException {
+		if (offset < 0 || count < 0 || offset + count > buf.length) {
+			throw new ArrayIndexOutOfBoundsException();
+		}
+		CharBuffer chars = CharBuffer.wrap(buf, offset, count);
+		convert(chars);
+	}
+
+	private void convert(CharBuffer chars) throws IOException {
+		synchronized (lock) {
+			checkStatus();
+            CoderResult result = encoder.encode(chars, bytes, true);
+			while (true) {
+				if (result.isError()) {
+					throw new IOException(result.toString());
+				} else if (result.isOverflow()) {
+					//flush the output buffer
+					flush();
+					result = encoder.encode(chars, bytes, true);
+                    continue;
+				}
+				break;
+			}
+		}
+	}
+
+	/**
+	 * Writes out the character <code>oneChar</code> to this Writer. The
+	 * low-order 2 bytes are immediately converted to bytes by the character
+	 * converter and stored in a local buffer. If the buffer becomes full as a
+	 * result of this write, this Writer is flushed.
+	 * 
+	 * @param oneChar
+	 *            the character to write
+	 * 
+	 * @throws IOException
+	 *             If this OuputStreamWriter has already been closed or some
+	 *             other IOException occurs.
+	 */
+	public void write(int oneChar) throws IOException {
+		synchronized (lock) {
+			checkStatus();
+			CharBuffer chars = CharBuffer.wrap(new char[] { (char) oneChar });
+			convert(chars);
+		}
+	}
+
+	/**
+	 * Writes <code>count</code> characters starting at <code>offset</code>
+	 * in <code>str</code> to this Writer. The characters are immediately
+	 * converted to bytes by the character converter and stored in a local
+	 * buffer. If the buffer becomes full as a result of this write, this Writer
+	 * is flushed.
+	 * 
+	 * @param str
+	 *            the non-null String containing characters to write.
+	 * @param offset
+	 *            offset in str to retrieve characters
+	 * @param count
+	 *            maximum number of characters to write
+	 * 
+	 * @throws IOException
+	 *             If this OuputStreamWriter has already been closed or some
+	 *             other IOException occurs.
+	 * @throws StringIndexOutOfBoundsException
+	 *             If offset or count are outside of bounds.
+	 */
+	public void write(String str, int offset, int count) throws IOException {
+		// avoid int overflow
+		if (offset < 0 || count < 0 || offset + count > str.length()) {
+			throw new StringIndexOutOfBoundsException();
+		}
+		CharBuffer chars = CharBuffer.wrap(str, offset, count + offset);
+		convert(chars);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/PipedInputStream.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/PipedInputStream.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/PipedInputStream.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/PipedInputStream.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,337 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.io;
+
+
+/**
+ * PipedInputStream is a class which receives information on a communications
+ * pipe. When two threads want to pass data back and forth, one creates a piped
+ * output stream and the other creates a piped input stream.
+ * 
+ * @see PipedOutputStream
+ */
+public class PipedInputStream extends InputStream {
+	private Thread lastReader, lastWriter;
+
+	private boolean isClosed = false;
+
+	/**
+	 * The circular buffer through which data is passed.
+	 */
+	protected byte buffer[];
+
+	/**
+	 * The index in <code>buffer</code> where the next byte will be written.
+	 */
+	protected int in = -1;
+
+	/**
+	 * The index in <code>buffer</code> where the next byte will be read.
+	 */
+	protected int out = 0;
+
+	/**
+	 * The size of the default pipe in bytes
+	 */
+	protected static final int PIPE_SIZE = 1024;
+
+	/**
+	 * Indicates if this pipe is connected
+	 */
+	boolean isConnected = false;
+
+	/**
+	 * Constructs a new unconnected PipedInputStream. The resulting Stream must
+	 * be connected to a PipedOutputStream before data may be read from it.
+	 * 
+	 */
+	public PipedInputStream() {
+		/*empty*/
+	}
+
+	/**
+	 * Constructs a new PipedInputStream connected to the PipedOutputStream
+	 * <code>out</code>. Any data written to the output stream can be read
+	 * from the this input stream.
+	 * 
+	 * @param out
+	 *            the PipedOutputStream to connect to.
+	 * 
+	 * @throws IOException
+	 *             if this or <code>out</code> are already connected.
+	 */
+	public PipedInputStream(PipedOutputStream out) throws IOException {
+		connect(out);
+	}
+
+	/**
+	 * Answers a int representing the number of bytes that are available before
+	 * this PipedInputStream will block. This method returns the number of bytes
+	 * written to the pipe but not read yet up to the size of the pipe.
+	 * 
+	 * @return int the number of bytes available before blocking.
+	 * 
+	 * @throws IOException
+	 *             If an error occurs in this stream.
+	 */
+	public synchronized int available() throws IOException {
+		if (buffer == null || in == -1)
+			return 0;
+		return in <= out ? buffer.length - out + in : in - out;
+	}
+
+	/**
+	 * Close this PipedInputStream. This implementation releases the buffer used
+	 * for the pipe and notifies all threads waiting to read or write.
+	 * 
+	 * @throws IOException
+	 *             If an error occurs attempting to close this stream.
+	 */
+	public void close() throws IOException {
+		synchronized (this) {
+			/* No exception thrown if already closed */
+			if (buffer != null) {
+				/* Release buffer to indicate closed. */
+				buffer = null;
+			}
+		}
+	}
+
+	/**
+	 * Connects this PipedInputStream to a PipedOutputStream. Any data written
+	 * to the OutputStream becomes readable in this InputStream.
+	 * 
+	 * @param src
+	 *            the source PipedOutputStream.
+	 * 
+	 * @throws IOException
+	 *             If either stream is already connected.
+	 */
+	public void connect(PipedOutputStream src) throws IOException {
+		src.connect(this);
+	}
+
+	/**
+	 * Reads a single byte from this PipedInputStream and returns the result as
+	 * an int. The low-order byte is returned or -1 of the end of stream was
+	 * encountered. If there is no data in the pipe, this method blocks until
+	 * there is data available. Separate threads should be used for the reader
+	 * of the PipedInputStream and the PipedOutputStream. There may be
+	 * undesirable results if more than one Thread interacts a input or output
+	 * pipe.
+	 * 
+	 * @return int The byte read or -1 if end of stream.
+	 * 
+	 * @throws IOException
+	 *             If the stream is already closed or another IOException
+	 *             occurs.
+	 */
+	public synchronized int read() throws IOException {
+		if (isConnected) {
+			if (buffer != null) {
+				/**
+				 * Set the last thread to be reading on this PipedInputStream.
+				 * If lastReader dies while someone is waiting to write an
+				 * IOException of "Pipe broken" will be thrown in receive()
+				 */
+				lastReader = Thread.currentThread();
+				try {
+					boolean first = true;
+					while (in == -1) {
+						// Are we at end of stream?
+						if (isClosed)
+							return -1;
+						if (!first && lastWriter != null
+								&& !lastWriter.isAlive())
+							throw new IOException(com.ibm.oti.util.Msg
+									.getString("K0076")); //$NON-NLS-1$
+						first = false;
+						// Notify callers of receive()
+						notifyAll();
+						wait(1000);
+					}
+				} catch (InterruptedException e) {
+					throw new InterruptedIOException();
+				}
+
+				byte result = buffer[out++];
+				if (out == buffer.length)
+					out = 0;
+				if (out == in) {
+					// empty buffer
+					in = -1;
+					out = 0;
+				}
+				return result & 0xff;
+			}
+			throw new IOException(com.ibm.oti.util.Msg.getString("K0075")); //$NON-NLS-1$
+		}
+		throw new IOException(com.ibm.oti.util.Msg.getString("K0074")); //$NON-NLS-1$
+	}
+
+	/**
+	 * Reads at most <code>count</code> bytes from this PipedInputStream and
+	 * stores them in byte array <code>buffer</code> starting at
+	 * <code>offset</code>. Answer the number of bytes actually read or -1 if
+	 * no bytes were read and end of stream was encountered. Separate threads
+	 * should be used for the reader of the PipedInputStream and the
+	 * PipedOutputStream. There may be undesirable results if more than one
+	 * Thread interacts a input or output pipe.
+	 * 
+	 * @param bytes
+	 *            the byte array in which to store the read bytes.
+	 * @param offset
+	 *            the offset in <code>buffer</code> to store the read bytes.
+	 * @param count
+	 *            the maximum number of bytes to store in <code>buffer</code>.
+	 * @return the number of bytes actually read or -1 if end of stream.
+	 * 
+	 * @throws IOException
+	 *             If the stream is already closed or another IOException
+	 *             occurs.
+	 */
+	public synchronized int read(byte[] bytes, int offset, int count)
+			throws IOException {
+		if (bytes != null && 0 <= offset && offset <= bytes.length
+				&& 0 <= count && count <= bytes.length - offset) {
+			if (count == 0)
+				return 0;
+			if (isConnected && buffer != null) {
+				/**
+				 * Set the last thread to be reading on this PipedInputStream.
+				 * If lastReader dies while someone is waiting to write an
+				 * IOException of "Pipe broken" will be thrown in receive()
+				 */
+				lastReader = Thread.currentThread();
+				try {
+					boolean first = true;
+					while (in == -1) {
+						// Are we at end of stream?
+						if (isClosed)
+							return -1;
+						if (!first && lastWriter != null
+								&& !lastWriter.isAlive())
+							throw new IOException(com.ibm.oti.util.Msg
+									.getString("K0076")); //$NON-NLS-1$
+						first = false;
+						// Notify callers of receive()
+						notifyAll();
+						wait(1000);
+					}
+				} catch (InterruptedException e) {
+					throw new InterruptedIOException();
+				}
+
+				int copyLength = 0;
+				/* Copy bytes from out to end of buffer first */
+				if (out >= in) {
+					copyLength = count > (buffer.length - out) ? buffer.length
+							- out : count;
+					System.arraycopy(buffer, out, bytes, offset, copyLength);
+					out += copyLength;
+					if (out == buffer.length)
+						out = 0;
+					if (out == in) {
+						// empty buffer
+						in = -1;
+						out = 0;
+					}
+				}
+
+				/*
+				 * Did the read fully succeed in the previous copy or is the
+				 * buffer empty?
+				 */
+				if (copyLength == count || in == -1)
+					return copyLength;
+
+				int bytesCopied = copyLength;
+				/* Copy bytes from 0 to the number of available bytes */
+				copyLength = in - out > (count - bytesCopied) ? count
+						- bytesCopied : in - out;
+				System.arraycopy(buffer, out, bytes, offset + bytesCopied,
+						copyLength);
+				out += copyLength;
+				if (out == in) {
+					// empty buffer
+					in = -1;
+					out = 0;
+				}
+				return bytesCopied + copyLength;
+			}
+			if (!isConnected) {
+				throw new IOException(com.ibm.oti.util.Msg.getString("K0074")); //$NON-NLS-1$
+			}
+			throw new IOException(com.ibm.oti.util.Msg.getString("K0075")); //$NON-NLS-1$
+		}
+		if (bytes == null) {
+			throw new NullPointerException();
+		}
+		throw new ArrayIndexOutOfBoundsException();
+	}
+
+	/**
+	 * Receives a byte and stores it into the PipedInputStream. This called by
+	 * PipedOutputStream.write() when writes occur. The lowest-order byte is
+	 * stored at index <code>in</code> in the <code>buffer</code>.
+	 * <P>
+	 * If the buffer is full and the thread sending #receive is interrupted, the
+	 * InterruptedIOException will be thrown.
+	 * 
+	 * @param oneByte
+	 *            the byte to store into the pipe.
+	 * 
+	 * @throws IOException
+	 *             If the stream is already closed or another IOException
+	 *             occurs.
+	 */
+	protected synchronized void receive(int oneByte) throws IOException {
+		if (buffer != null) {
+			/**
+			 * Set the last thread to be writing on this PipedInputStream. If
+			 * lastWriter dies while someone is waiting to read an IOException
+			 * of "Pipe broken" will be thrown in read()
+			 */
+			lastWriter = Thread.currentThread();
+			try {
+				while (buffer != null && out == in) {
+					notifyAll();
+					wait(1000);
+					if (lastReader != null && !lastReader.isAlive())
+						throw new IOException(com.ibm.oti.util.Msg
+								.getString("K0076")); //$NON-NLS-1$
+				}
+			} catch (InterruptedException e) {
+				throw new InterruptedIOException();
+			}
+			if (buffer != null) {
+				if (in == -1)
+					in = 0;
+				buffer[in++] = (byte) oneByte;
+				if (in == buffer.length)
+					in = 0;
+				return;
+			}
+		}
+		throw new IOException(com.ibm.oti.util.Msg.getString("K0078")); //$NON-NLS-1$
+	}
+
+	synchronized void done() {
+		isClosed = true;
+		notifyAll();
+	}
+
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/PipedOutputStream.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/PipedOutputStream.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/PipedOutputStream.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/io/PipedOutputStream.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,168 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.io;
+
+
+/**
+ * PipedOutputStream is a class which places information on a communications
+ * pipe. When two threads want to pass data back and forth, one creates a piped
+ * output stream and the other creates a piped input stream.
+ * 
+ * @see PipedInputStream
+ */
+public class PipedOutputStream extends OutputStream {
+
+	/**
+	 * The destination PipedInputStream
+	 */
+	private PipedInputStream dest;
+
+	/**
+	 * Constructs a new unconnected PipedOutputStream. The resulting Stream must
+	 * be connected to a PipedInputStream before data may be written to it.
+	 */
+	public PipedOutputStream() {
+		super();
+	}
+
+	/**
+	 * Constructs a new PipedOutputStream connected to the PipedInputStream
+	 * <code>dest</code>. Any data written to this stream can be read from
+	 * the <code>dest</code>.
+	 * 
+	 * @param dest
+	 *            the PipedInputStream to connect to.
+	 * 
+	 * @throws IOException
+	 *             if <code>dest</code> is already connected.
+	 */
+	public PipedOutputStream(PipedInputStream dest) throws IOException {
+		super();
+		connect(dest);
+	}
+
+	/**
+	 * Close this PipedOutputStream. Any data buffered in the corresponding
+	 * PipedInputStream can be read, then -1 will be returned to the reader. If
+	 * this OutputStream is not connected, this method does nothing.
+	 * 
+	 * @throws IOException
+	 *             If an error occurs attempting to close this
+	 *             PipedOutputStream.
+	 */
+	public void close() throws IOException {
+		if (dest != null) { // Is the pipe connected?
+			dest.done();
+			dest = null;
+		}
+	}
+
+	/**
+	 * Connects this PipedOutputStream to a PipedInputStream. Any data written
+	 * to this OutputStream becomes readable in the InputStream.
+	 * 
+	 * @param stream
+	 *            the destination PipedInputStream.
+	 * 
+	 * @throws IOException
+	 *             If this Stream or the dest is already connected.
+	 */
+	public void connect(PipedInputStream stream) throws IOException {
+		if (this.dest == null) {
+			if (!stream.isConnected) {
+				stream.buffer = new byte[PipedInputStream.PIPE_SIZE];
+				stream.isConnected = true;
+				this.dest = stream;
+			} else
+				throw new IOException(com.ibm.oti.util.Msg.getString("K007a")); //$NON-NLS-1$
+		} else
+			throw new IOException(com.ibm.oti.util.Msg.getString("K0079")); //$NON-NLS-1$
+	}
+
+	/**
+	 * Notifies the readers on the PipedInputStream that bytes can be read. This
+	 * method does nothing if this Stream is not connected.
+	 * 
+	 * @throws IOException
+	 *             If an IO error occurs during the flush.
+	 */
+	public void flush() throws IOException {
+		if (dest != null) {
+			synchronized (dest) {
+				dest.notifyAll();
+			}
+		}
+	}
+
+	/**
+	 * Writes <code>count</code> <code>bytes</code> from this byte array
+	 * <code>buffer</code> starting at offset <code>index</code> to this
+	 * PipedOutputStream. The written data can now be read from the destination
+	 * PipedInputStream. Separate threads should be used for the reader of the
+	 * PipedInputStream and the PipedOutputStream. There may be undesirable
+	 * results if more than one Thread interacts a input or output pipe.
+	 * 
+	 * @param buffer
+	 *            the buffer to be written
+	 * @param offset
+	 *            offset in buffer to get bytes
+	 * @param count
+	 *            number of bytes in buffer to write
+	 * 
+	 * @throws IOException
+	 *             If the receiving thread was terminated without closing the
+	 *             pipe. This case is not currently handled correctly.
+	 * @throws InterruptedIOException
+	 *             If the pipe is full and the current thread is interrupted
+	 *             waiting for space to write data. This case is not currently
+	 *             handled correctly.
+	 * @throws NullPointerException
+	 *             If the receiver has not been connected yet.
+	 * @throws IllegalArgumentException
+	 *             If any of the arguments are out of bounds.
+	 */
+	public void write(byte buffer[], int offset, int count) throws IOException {
+		super.write(buffer, offset, count);
+	}
+
+	/**
+	 * Writes the specified byte <code>oneByte</code> to this
+	 * PipedOutputStream. Only the low order byte of <code>oneByte</code> is
+	 * written. The data can now be read from the destination PipedInputStream.
+	 * Separate threads should be used for the reader of the PipedInputStream
+	 * and the PipedOutputStream. There may be undesirable results if more than
+	 * one Thread interacts a input or output pipe.
+	 * 
+	 * @param oneByte
+	 *            the byte to be written
+	 * 
+	 * @throws IOException
+	 *             If the receiving thread was terminated without closing the
+	 *             pipe. This case is not currently handled correctly.
+	 * @throws InterruptedIOException
+	 *             If the pipe is full and the current thread is interrupted
+	 *             waiting for space to write data. This case is not currently
+	 *             handled correctly.
+	 * @throws NullPointerException
+	 *             If the receiver has not been connected yet.
+	 */
+	public void write(int oneByte) throws IOException {
+		if (dest != null)
+			dest.receive(oneByte);
+		else
+			throw new IOException();
+	}
+}