- /*
- * @(#)IIOPOutputStream.java 1.51 04/05/05
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- /*
- * Licensed Materials - Property of IBM
- * RMI-IIOP v1.0
- * Copyright IBM Corp. 1998 1999 All Rights Reserved
- *
- * US Government Users Restricted Rights - Use, duplication or
- * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
- */
-
- package com.sun.corba.se.impl.io;
-
- import org.omg.CORBA.INTERNAL;
- import org.omg.CORBA.portable.OutputStream;
-
- import java.security.AccessController ;
- import java.security.PrivilegedAction ;
-
- import java.io.IOException;
- import java.io.DataOutputStream;
- import java.io.Serializable;
- import java.io.InvalidClassException;
- import java.io.StreamCorruptedException;
- import java.io.Externalizable;
- import java.io.ObjectStreamException;
- import java.io.NotSerializableException;
- import java.io.NotActiveException;
-
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Field;
-
- import java.util.Stack;
-
- import javax.rmi.CORBA.Util;
- import javax.rmi.CORBA.ValueHandlerMultiFormat;
-
- import sun.corba.Bridge ;
-
- import com.sun.corba.se.impl.io.ObjectStreamClass;
- import com.sun.corba.se.impl.util.Utility;
- import com.sun.corba.se.impl.util.RepositoryId;
-
- import com.sun.corba.se.spi.logging.CORBALogDomains ;
- import com.sun.corba.se.impl.logging.UtilSystemException ;
-
- /**
- * IIOPOutputStream is ...
- *
- * @author Stephen Lewallen
- * @version 0.01, 4/6/98
- * @since JDK1.1.6
- */
-
- public class IIOPOutputStream
- extends com.sun.corba.se.impl.io.OutputStreamHook
- {
- private UtilSystemException wrapper = UtilSystemException.get(
- CORBALogDomains.RPC_ENCODING ) ;
-
- private static Bridge bridge =
- (Bridge)AccessController.doPrivileged(
- new PrivilegedAction() {
- public Object run() {
- return Bridge.get() ;
- }
- }
- ) ;
-
- private org.omg.CORBA_2_3.portable.OutputStream orbStream;
-
- private Object currentObject = null;
-
- private ObjectStreamClass currentClassDesc = null;
-
- private int recursionDepth = 0;
-
- private int simpleWriteDepth = 0;
-
- private IOException abortIOException = null;
-
- private java.util.Stack classDescStack = new java.util.Stack();
-
- // Used when calling an object's writeObject method
- private Object[] writeObjectArgList = {this};
-
- public IIOPOutputStream()
- throws java.io.IOException
- {
- super();
- }
-
- // If using RMI-IIOP stream format version 2, this tells
- // the ORB stream (which must be a ValueOutputStream) to
- // begin a new valuetype to contain the optional data
- // of the writeObject method.
- protected void beginOptionalCustomData() {
-
- if (streamFormatVersion == 2) {
-
- org.omg.CORBA.portable.ValueOutputStream vout
- = (org.omg.CORBA.portable.ValueOutputStream)orbStream;
-
- vout.start_value(currentClassDesc.getRMIIIOPOptionalDataRepId());
- }
- }
-
- public final void setOrbStream(org.omg.CORBA_2_3.portable.OutputStream os) {
- orbStream = os;
- }
-
- public final org.omg.CORBA_2_3.portable.OutputStream getOrbStream() {
- return orbStream;
- }
-
- public final void increaseRecursionDepth(){
- recursionDepth++;
- }
-
- public final int decreaseRecursionDepth(){
- return --recursionDepth;
- }
-
- /**
- * Override the actions of the final method "writeObject()"
- * in ObjectOutputStream.
- * @since JDK1.1.6
- */
- public final void writeObjectOverride(Object obj)
- throws IOException
- {
- writeObjectState.writeData(this);
-
- Util.writeAbstractObject((OutputStream)orbStream, obj);
- }
-
- /**
- * Override the actions of the final method "writeObject()"
- * in ObjectOutputStream.
- * @since JDK1.1.6
- */
- public final void simpleWriteObject(Object obj, byte formatVersion)
- /* throws IOException */
- {
- byte oldStreamFormatVersion = streamFormatVersion;
-
- streamFormatVersion = formatVersion;
-
- Object prevObject = currentObject;
- ObjectStreamClass prevClassDesc = currentClassDesc;
- simpleWriteDepth++;
-
- try {
- // if (!checkSpecialClasses(obj) && !checkSubstitutableSpecialClasses(obj))
- outputObject(obj);
-
- } catch (IOException ee) {
- if (abortIOException == null)
- abortIOException = ee;
- } finally {
- /* Restore state of previous call incase this is a nested call */
- streamFormatVersion = oldStreamFormatVersion;
- simpleWriteDepth--;
- currentObject = prevObject;
- currentClassDesc = prevClassDesc;
- }
-
- /* If the recursion depth is 0, test for and clear the pending exception.
- * If there is a pending exception throw it.
- */
- IOException pending = abortIOException;
- if (simpleWriteDepth == 0)
- abortIOException = null;
- if (pending != null) {
- bridge.throwException( pending ) ;
- }
- }
-
- // Required by the superclass.
- ObjectStreamField[] getFieldsNoCopy() {
- return currentClassDesc.getFieldsNoCopy();
- }
-
- /**
- * Override the actions of the final method "defaultWriteObject()"
- * in ObjectOutputStream.
- * @since JDK1.1.6
- */
- public final void defaultWriteObjectDelegate()
- /* throws IOException */
- {
- try {
- if (currentObject == null || currentClassDesc == null)
- // XXX I18N, Logging needed.
- throw new NotActiveException("defaultWriteObjectDelegate");
-
- ObjectStreamField[] fields =
- currentClassDesc.getFieldsNoCopy();
- if (fields.length > 0) {
- outputClassFields(currentObject, currentClassDesc.forClass(),
- fields);
- }
- } catch(IOException ioe) {
- bridge.throwException(ioe);
- }
- }
-
- /**
- * Override the actions of the final method "enableReplaceObject()"
- * in ObjectOutputStream.
- * @since JDK1.1.6
- */
- public final boolean enableReplaceObjectDelegate(boolean enable)
- /* throws SecurityException */
- {
- return false;
-
- }
-
-
- protected final void annotateClass(Class<?> cl) throws IOException{
- // XXX I18N, Logging needed.
- throw new IOException("Method annotateClass not supported");
- }
-
- public final void close() throws IOException{
- // no op
- }
-
- protected final void drain() throws IOException{
- // no op
- }
-
- public final void flush() throws IOException{
- try{
- orbStream.flush();
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- protected final Object replaceObject(Object obj) throws IOException{
- // XXX I18N, Logging needed.
- throw new IOException("Method replaceObject not supported");
- }
-
- /**
- * Reset will disregard the state of any objects already written
- * to the stream. The state is reset to be the same as a new
- * ObjectOutputStream. The current point in the stream is marked
- * as reset so the corresponding ObjectInputStream will be reset
- * at the same point. Objects previously written to the stream
- * will not be refered to as already being in the stream. They
- * will be written to the stream again.
- * @since JDK1.1
- */
- public final void reset() throws IOException{
- try{
- //orbStream.reset();
-
- if (currentObject != null || currentClassDesc != null)
- // XXX I18N, Logging needed.
- throw new IOException("Illegal call to reset");
-
- abortIOException = null;
-
- if (classDescStack == null)
- classDescStack = new java.util.Stack();
- else
- classDescStack.setSize(0);
-
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void write(byte b[]) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_octet_array(b, 0, b.length);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void write(byte b[], int off, int len) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_octet_array(b, off, len);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void write(int data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_octet((byte)(data & 0xFF));
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeBoolean(boolean data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_boolean(data);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeByte(int data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_octet((byte)data);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeBytes(String data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- byte buf[] = data.getBytes();
- orbStream.write_octet_array(buf, 0, buf.length);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeChar(int data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_wchar((char)data);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeChars(String data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- char buf[] = data.toCharArray();
- orbStream.write_wchar_array(buf, 0, buf.length);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeDouble(double data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_double(data);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeFloat(float data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_float(data);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeInt(int data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_long(data);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeLong(long data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_longlong(data);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- public final void writeShort(int data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- orbStream.write_short((short)data);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- protected final void writeStreamHeader() throws IOException{
- // no op
- }
-
- /**
- * Helper method for correcting the Kestrel bug 4367783 (dealing
- * with larger than 8-bit chars). The old behavior is preserved
- * in orbutil.IIOPInputStream_1_3 in order to interoperate with
- * our legacy ORBs.
- */
- protected void internalWriteUTF(org.omg.CORBA.portable.OutputStream stream,
- String data)
- {
- stream.write_wstring(data);
- }
-
- public final void writeUTF(String data) throws IOException{
- try{
- writeObjectState.writeData(this);
-
- internalWriteUTF(orbStream, data);
- } catch(Error e) {
- IOException ioexc = new IOException(e.getMessage());
- ioexc.initCause(e) ;
- throw ioexc ;
- }
- }
-
- // INTERNAL UTILITY METHODS
- /*
- * Check for special cases of serializing objects.
- * These objects are not subject to replacement.
- */
- private boolean checkSpecialClasses(Object obj) throws IOException {
-
- /*
- * If this is a class, don't allow substitution
- */
- //if (obj instanceof Class) {
- // throw new IOException("Serialization of Class not supported");
- //}
-
- if (obj instanceof ObjectStreamClass) {
- // XXX I18N, Logging needed.
- throw new IOException("Serialization of ObjectStreamClass not supported");
- }
-
- return false;
- }
-
- /*
- * Check for special cases of substitutable serializing objects.
- * These classes are replaceable.
- */
- private boolean checkSubstitutableSpecialClasses(Object obj)
- throws IOException
- {
- if (obj instanceof String) {
- orbStream.write_value((java.io.Serializable)obj);
- return true;
- }
-
- //if (obj.getClass().isArray()) {
- // outputArray(obj);
- // return true;
- //}
-
- return false;
- }
-
- /*
- * Write out the object
- */
- private void outputObject(final Object obj) throws IOException{
-
- currentObject = obj;
- Class currclass = obj.getClass();
-
- /* Get the Class descriptor for this class,
- * Throw a NotSerializableException if there is none.
- */
- currentClassDesc = ObjectStreamClass.lookup(currclass);
- if (currentClassDesc == null) {
- // XXX I18N, Logging needed.
- throw new NotSerializableException(currclass.getName());
- }
-
- /* If the object is externalizable,
- * call writeExternal.
- * else do Serializable processing.
- */
- if (currentClassDesc.isExternalizable()) {
- // Write format version
- orbStream.write_octet(streamFormatVersion);
-
- Externalizable ext = (Externalizable)obj;
- ext.writeExternal(this);
-
- } else {
-
- /* The object's classes should be processed from supertype to subtype
- * Push all the clases of the current object onto a stack.
- * Remember the stack pointer where this set of classes is being pushed.
- */
- int stackMark = classDescStack.size();
- try {
- ObjectStreamClass next;
- while ((next = currentClassDesc.getSuperclass()) != null) {
- classDescStack.push(currentClassDesc);
- currentClassDesc = next;
- }
-
- /*
- * For currentClassDesc and all the pushed class descriptors
- * If the class is writing its own data
- * set blockData = true; call the class writeObject method
- * If not
- * invoke either the defaultWriteObject method.
- */
- do {
-
- WriteObjectState oldState = writeObjectState;
-
- try {
-
- setState(NOT_IN_WRITE_OBJECT);
-
- if (currentClassDesc.hasWriteObject()) {
- invokeObjectWriter(currentClassDesc, obj );
- } else {
- defaultWriteObjectDelegate();
- }
- } finally {
- setState(oldState);
- }
-
- } while (classDescStack.size() > stackMark &&
- (currentClassDesc = (ObjectStreamClass)classDescStack.pop()) != null);
- } finally {
- classDescStack.setSize(stackMark);
- }
- }
- }
-
- /*
- * Invoke writer.
- * _REVISIT_ invokeObjectWriter and invokeObjectReader behave inconsistently with each other since
- * the reader returns a boolean...fix later
- */
- private void invokeObjectWriter(ObjectStreamClass osc, Object obj)
- throws IOException
- {
- Class c = osc.forClass() ;
-
- try {
-
- // Write format version
- orbStream.write_octet(streamFormatVersion);
-
- writeObjectState.enterWriteObject(this);
-
- // writeObject(obj, c, this);
- osc.writeObjectMethod.invoke( obj, writeObjectArgList ) ;
-
- writeObjectState.exitWriteObject(this);
-
- } catch (InvocationTargetException e) {
- Throwable t = e.getTargetException();
- if (t instanceof IOException)
- throw (IOException)t;
- else if (t instanceof RuntimeException)
- throw (RuntimeException) t;
- else if (t instanceof Error)
- throw (Error) t;
- else
- // XXX I18N, Logging needed.
- throw new Error("invokeObjectWriter internal error",e);
- } catch (IllegalAccessException e) {
- // cannot happen
- }
- }
-
- void writeField(ObjectStreamField field, Object value) throws IOException {
- switch (field.getTypeCode()) {
- case 'B':
- if (value == null)
- orbStream.write_octet((byte)0);
- else
- orbStream.write_octet(((Byte)value).byteValue());
- break;
- case 'C':
- if (value == null)
- orbStream.write_wchar((char)0);
- else
- orbStream.write_wchar(((Character)value).charValue());
- break;
- case 'F':
- if (value == null)
- orbStream.write_float((float)0);
- else
- orbStream.write_float(((Float)value).floatValue());
- break;
- case 'D':
- if (value == null)
- orbStream.write_double((double)0);
- else
- orbStream.write_double(((Double)value).doubleValue());
- break;
- case 'I':
- if (value == null)
- orbStream.write_long((int)0);
- else
- orbStream.write_long(((Integer)value).intValue());
- break;
- case 'J':
- if (value == null)
- orbStream.write_longlong((long)0);
- else
- orbStream.write_longlong(((Long)value).longValue());
- break;
- case 'S':
- if (value == null)
- orbStream.write_short((short)0);
- else
- orbStream.write_short(((Short)value).shortValue());
- break;
- case 'Z':
- if (value == null)
- orbStream.write_boolean(false);
- else
- orbStream.write_boolean(((Boolean)value).booleanValue());
- break;
- case '[':
- case 'L':
- // What to do if it's null?
- writeObjectField(field, value);
- break;
- default:
- // XXX I18N, Logging needed.
- throw new InvalidClassException(currentClassDesc.getName());
- }
- }
-
- private void writeObjectField(ObjectStreamField field,
- Object objectValue) throws IOException {
-
- if (ObjectStreamClassCorbaExt.isAny(field.getTypeString())) {
- javax.rmi.CORBA.Util.writeAny(orbStream, objectValue);
- }
- else {
- Class type = field.getType();
- int callType = ValueHandlerImpl.kValueType;
-
- if (type.isInterface()) {
- String className = type.getName();
-
- if (java.rmi.Remote.class.isAssignableFrom(type)) {
-
- // RMI Object reference...
-
- callType = ValueHandlerImpl.kRemoteType;
-
-
- } else if (org.omg.CORBA.Object.class.isAssignableFrom(type)){
-
- // IDL Object reference...
- callType = ValueHandlerImpl.kRemoteType;
-
- } else if (RepositoryId.isAbstractBase(type)) {
- // IDL Abstract Object reference...
- callType = ValueHandlerImpl.kAbstractType;
- } else if (ObjectStreamClassCorbaExt.isAbstractInterface(type)) {
- callType = ValueHandlerImpl.kAbstractType;
- }
- }
-
- switch (callType) {
- case ValueHandlerImpl.kRemoteType:
- Util.writeRemoteObject(orbStream, objectValue);
- break;
- case ValueHandlerImpl.kAbstractType:
- Util.writeAbstractObject(orbStream, objectValue);
- break;
- case ValueHandlerImpl.kValueType:
- try{
- orbStream.write_value((java.io.Serializable)objectValue, type);
- }
- catch(ClassCastException cce){
- if (objectValue instanceof java.io.Serializable)
- throw cce;
- else
- Utility.throwNotSerializableForCorba(objectValue.getClass().getName());
- }
- }
- }
- }
-
- /* Write the fields of the specified class by invoking the appropriate
- * write* method on this class.
- */
- private void outputClassFields(Object o, Class cl,
- ObjectStreamField[] fields)
- throws IOException, InvalidClassException {
-
- for (int i = 0; i < fields.length; i++) {
- if (fields[i].getField() == null)
- // XXX I18N, Logging needed.
- throw new InvalidClassException(cl.getName(),
- "Nonexistent field " + fields[i].getName());
-
- try {
- switch (fields[i].getTypeCode()) {
- case 'B':
- byte byteValue = fields[i].getField().getByte( o ) ;
- orbStream.write_octet(byteValue);
- break;
- case 'C':
- char charValue = fields[i].getField().getChar( o ) ;
- orbStream.write_wchar(charValue);
- break;
- case 'F':
- float floatValue = fields[i].getField().getFloat( o ) ;
- orbStream.write_float(floatValue);
- break;
- case 'D' :
- double doubleValue = fields[i].getField().getDouble( o ) ;
- orbStream.write_double(doubleValue);
- break;
- case 'I':
- int intValue = fields[i].getField().getInt( o ) ;
- orbStream.write_long(intValue);
- break;
- case 'J':
- long longValue = fields[i].getField().getLong( o ) ;
- orbStream.write_longlong(longValue);
- break;
- case 'S':
- short shortValue = fields[i].getField().getShort( o ) ;
- orbStream.write_short(shortValue);
- break;
- case 'Z':
- boolean booleanValue = fields[i].getField().getBoolean( o ) ;
- orbStream.write_boolean(booleanValue);
- break;
- case '[':
- case 'L':
- Object objectValue = fields[i].getField().get( o ) ;
- writeObjectField(fields[i], objectValue);
- break;
- default:
- // XXX I18N, Logging needed.
- throw new InvalidClassException(cl.getName());
- }
- } catch (IllegalAccessException exc) {
- throw wrapper.illegalFieldAccess( exc, fields[i].getName() ) ;
- }
- }
- }
- }
-