/*
 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
/*
 * Licensed Materials - Property of IBM
 * RMI-IIOP v1.0
 * Copyright IBM Corp. 1998 1999  All Rights Reserved
 *
 */

package com.sun.corba.se.impl.io;

import org.omg.CORBA.portable.OutputStream;

import java.security.AccessController ;
import java.security.PrivilegedAction ;

import java.io.IOException;
import java.io.InvalidClassException;
import java.io.Externalizable;
import java.io.NotSerializableException;
import java.io.NotActiveException;

import java.lang.reflect.InvocationTargetException;

import javax.rmi.CORBA.Util;

import sun.corba.Bridge ;

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
Since: JDK1.1.6
/** * IIOPOutputStream is ... * * @author Stephen Lewallen * @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()); } } final void setOrbStream(org.omg.CORBA_2_3.portable.OutputStream os) { orbStream = os; } final org.omg.CORBA_2_3.portable.OutputStream getOrbStream() { return orbStream; } final void increaseRecursionDepth(){ recursionDepth++; } final int decreaseRecursionDepth(){ return --recursionDepth; }
Override the actions of the final method "writeObject()" in ObjectOutputStream.
Since: JDK1.1.6
/** * 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
/** * 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
/** * 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
/** * 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
/** * 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.
/** * 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. */ if (currentClassDesc.forClass().getName().equals("java.lang.String")) { this.writeUTF((String)obj); return; } 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.invokeWriteObject( obj, this ) ; 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); } } 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 { for (int i = 0; i < fields.length; i++) { if (fields[i].getField() == null) throw new InvalidClassException(cl.getName(), "Nonexistent field " + fields[i].getName()); switch (fields[i].getTypeCode()) { case 'B': byte byteValue = bridge.getByte(o, fields[i].getFieldID()) ; orbStream.write_octet(byteValue); break; case 'C': char charValue = bridge.getChar(o, fields[i].getFieldID()) ; orbStream.write_wchar(charValue); break; case 'F': float floatValue = bridge.getFloat(o, fields[i].getFieldID()) ; orbStream.write_float(floatValue); break; case 'D' : double doubleValue = bridge.getDouble(o, fields[i].getFieldID()) ; orbStream.write_double(doubleValue); break; case 'I': int intValue = bridge.getInt(o, fields[i].getFieldID()) ; orbStream.write_long(intValue); break; case 'J': long longValue = bridge.getLong(o, fields[i].getFieldID()) ; orbStream.write_longlong(longValue); break; case 'S': short shortValue = bridge.getShort(o, fields[i].getFieldID()) ; orbStream.write_short(shortValue); break; case 'Z': boolean booleanValue = bridge.getBoolean(o, fields[i].getFieldID()) ; orbStream.write_boolean(booleanValue); break; case '[': case 'L': Object objectValue = bridge.getObject(o, fields[i].getFieldID()) ; writeObjectField(fields[i], objectValue); break; default: throw new InvalidClassException(cl.getName()); } } } }