/*
 * Copyright (c) 2004, 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.
 */
package com.sun.corba.se.impl.encoding;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ByteArrayOutputStream;

import java.nio.ByteBuffer;

import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.ior.IOR;
import com.sun.corba.se.spi.ior.IORFactories;
import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.spi.presentation.rmi.StubAdapter;

import com.sun.corba.se.impl.util.Utility;
import com.sun.corba.se.impl.orbutil.ORBConstants;
import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.corba.TypeCodeImpl;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;
import com.sun.corba.se.impl.protocol.giopmsgheaders.Message;

import org.omg.CORBA.Any;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.Principal;
import org.omg.CORBA.CompletionStatus;

Implementation class that uses Java serialization for output streams. This assumes a GIOP version 1.2 message format. This class uses a ByteArrayOutputStream as the underlying buffer. The first 16 bytes are direct writes into the underlying buffer. This allows [GIOPHeader (12 bytes) + requestID (4 bytes)] to be written as bytes. Subsequent write operations on this output stream object uses ObjectOutputStream class to write into the buffer. This allows marshaling complex types and graphs using the ObjectOutputStream implementation. Note, this class assumes a GIOP 1.2 style header. Note, we expect that the first 16 bytes are written only using the write_octet, write_long or write_ulong method calls.
Author:Ram Jeyaraman
/** * Implementation class that uses Java serialization for output streams. * This assumes a GIOP version 1.2 message format. * * This class uses a ByteArrayOutputStream as the underlying buffer. The * first 16 bytes are direct writes into the underlying buffer. This allows * [GIOPHeader (12 bytes) + requestID (4 bytes)] to be written as bytes. * Subsequent write operations on this output stream object uses * ObjectOutputStream class to write into the buffer. This allows marshaling * complex types and graphs using the ObjectOutputStream implementation. * * Note, this class assumes a GIOP 1.2 style header. Note, we expect that the * first 16 bytes are written only using the write_octet, write_long or * write_ulong method calls. * * @author Ram Jeyaraman */
final class IDLJavaSerializationOutputStream extends CDROutputStreamBase { private ORB orb; private byte encodingVersion; private ObjectOutputStream os; private _ByteArrayOutputStream bos; private BufferManagerWrite bufferManager; // [GIOPHeader(12) + requestID(4)] bytes private final int directWriteLength = Message.GIOPMessageHeaderLength + 4; protected ORBUtilSystemException wrapper; class _ByteArrayOutputStream extends ByteArrayOutputStream { _ByteArrayOutputStream(int initialSize) { super(initialSize); } byte[] getByteArray() { return this.buf; } } class MarshalObjectOutputStream extends ObjectOutputStream { ORB orb; MarshalObjectOutputStream(java.io.OutputStream out, ORB orb) throws IOException { super(out); this.orb = orb; java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Object run() { // needs SerializablePermission("enableSubstitution") enableReplaceObject(true); return null; } } ); }
Checks for objects that are instances of java.rmi.Remote that need to be serialized as proxy (Stub) objects.
/** * Checks for objects that are instances of java.rmi.Remote * that need to be serialized as proxy (Stub) objects. */
protected final Object replaceObject(Object obj) throws IOException { try { if ((obj instanceof java.rmi.Remote) && !(StubAdapter.isStub(obj))) { return Utility.autoConnect(obj, orb, true); } } catch (Exception e) { IOException ie = new IOException("replaceObject failed"); ie.initCause(e); throw ie; } return obj; } } public IDLJavaSerializationOutputStream(byte encodingVersion) { super(); this.encodingVersion = encodingVersion; } public void init(org.omg.CORBA.ORB orb, boolean littleEndian, BufferManagerWrite bufferManager, byte streamFormatVersion, boolean usePooledByteBuffers) { this.orb = (ORB) orb; this.bufferManager = bufferManager; wrapper = ORBUtilSystemException.get((ORB) orb, CORBALogDomains.RPC_ENCODING); bos = new _ByteArrayOutputStream(ORBConstants.GIOP_DEFAULT_BUFFER_SIZE); } // Called from read_octet or read_long or read_ulong method. private void initObjectOutputStream() { //System.out.print(" os "); if (os != null) { throw wrapper.javaStreamInitFailed(); } try { os = new MarshalObjectOutputStream(bos, orb); } catch (Exception e) { throw wrapper.javaStreamInitFailed(e); } } // org.omg.CORBA.portable.OutputStream // Primitive types. public final void write_boolean(boolean value) { try { os.writeBoolean(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_boolean"); } } public final void write_char(char value) { try { os.writeChar(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_char"); } } public final void write_wchar(char value) { this.write_char(value); } public final void write_octet(byte value) { // check if size < [ GIOPHeader(12) + requestID(4)] bytes if (bos.size() < directWriteLength) { bos.write(value); // direct write. if (bos.size() == directWriteLength) { initObjectOutputStream(); } return; } try { os.writeByte(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_octet"); } } public final void write_short(short value) { try { os.writeShort(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_short"); } } public final void write_ushort(short value) { this.write_short(value); } public final void write_long(int value) { // check if size < [ GIOPHeader(12) + requestID(4)] bytes if (bos.size() < directWriteLength) { // Use big endian (network byte order). This is fixed. // Both the writer and reader use the same byte order. bos.write((byte)((value >>> 24) & 0xFF)); bos.write((byte)((value >>> 16) & 0xFF)); bos.write((byte)((value >>> 8) & 0xFF)); bos.write((byte)((value >>> 0) & 0xFF)); if (bos.size() == directWriteLength) { initObjectOutputStream(); } else if (bos.size() > directWriteLength) { // Cannot happen. All direct writes are contained // within the first 16 bytes. wrapper.javaSerializationException("write_long"); } return; } try { os.writeInt(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_long"); } } public final void write_ulong(int value) { this.write_long(value); } public final void write_longlong(long value) { try { os.writeLong(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_longlong"); } } public final void write_ulonglong(long value) { this.write_longlong(value); } public final void write_float(float value) { try { os.writeFloat(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_float"); } } public final void write_double(double value) { try { os.writeDouble(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_double"); } } // String types. public final void write_string(String value) { try { os.writeUTF(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_string"); } } public final void write_wstring(String value) { try { os.writeObject(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_wstring"); } } // Array types. public final void write_boolean_array(boolean[] value, int offset, int length) { for (int i = 0; i < length; i++) { write_boolean(value[offset + i]); } } public final void write_char_array(char[] value, int offset, int length) { for (int i = 0; i < length; i++) { write_char(value[offset + i]); } } public final void write_wchar_array(char[] value, int offset, int length) { write_char_array(value, offset, length); } public final void write_octet_array(byte[] value, int offset, int length) { try { os.write(value, offset, length); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_octet_array"); } } public final void write_short_array(short[] value, int offset, int length) { for (int i = 0; i < length; i++) { write_short(value[offset + i]); } } public final void write_ushort_array(short[] value, int offset, int length){ write_short_array(value, offset, length); } public final void write_long_array(int[] value, int offset, int length) { for (int i = 0; i < length; i++) { write_long(value[offset + i]); } } public final void write_ulong_array(int[] value, int offset, int length) { write_long_array(value, offset, length); } public final void write_longlong_array(long[] value, int offset, int length) { for (int i = 0; i < length; i++) { write_longlong(value[offset + i]); } } public final void write_ulonglong_array(long[] value, int offset,int length) { write_longlong_array(value, offset, length); } public final void write_float_array(float[] value, int offset, int length) { for (int i = 0; i < length; i++) { write_float(value[offset + i]); } } public final void write_double_array(double[] value, int offset, int length) { for (int i = 0; i < length; i++) { write_double(value[offset + i]); } } // Complex types (objects and graphs). public final void write_Object(org.omg.CORBA.Object value) { if (value == null) { IOR nullIOR = IORFactories.makeIOR(orb); nullIOR.write(parent); return; } // IDL to Java formal 01-06-06 1.21.4.2 if (value instanceof org.omg.CORBA.LocalObject) { throw wrapper.writeLocalObject(CompletionStatus.COMPLETED_MAYBE); } IOR ior = ORBUtility.connectAndGetIOR(orb, value); ior.write(parent); return; } public final void write_TypeCode(TypeCode tc) { if (tc == null) { throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE); } TypeCodeImpl tci; if (tc instanceof TypeCodeImpl) { tci = (TypeCodeImpl) tc; } else { tci = new TypeCodeImpl(orb, tc); } tci.write_value((org.omg.CORBA_2_3.portable.OutputStream) parent); } public final void write_any(Any any) { if (any == null) { throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE); } write_TypeCode(any.type()); any.write_value(parent); } public final void write_Principal(Principal p) { // We don't need an implementation for this method, since principal // is absent in GIOP version 1.2 or above. write_long(p.name().length); write_octet_array(p.name(), 0, p.name().length); } public final void write_fixed(java.math.BigDecimal bigDecimal) { // This string might contain sign and/or dot this.write_fixed(bigDecimal.toString(), bigDecimal.signum()); } // The string may contain a sign and dot private void write_fixed(String string, int signum) { int stringLength = string.length(); // Each octet contains (up to) two decimal digits. byte doubleDigit = 0; char ch; byte digit; // First calculate the string length without optional sign and dot. int numDigits = 0; for (int i=0; i<stringLength; i++) { ch = string.charAt(i); if (ch == '-' || ch == '+' || ch == '.') continue; numDigits++; } for (int i=0; i<stringLength; i++) { ch = string.charAt(i); if (ch == '-' || ch == '+' || ch == '.') continue; digit = (byte)Character.digit(ch, 10); if (digit == -1) { throw wrapper.badDigitInFixed( CompletionStatus.COMPLETED_MAYBE); } // If the fixed type has an odd number of decimal digits, then the // representation begins with the first (most significant) digit. // Otherwise, this first half-octet is all zero, and the first // digit is in the second half-octet. if (numDigits % 2 == 0) { doubleDigit |= digit; this.write_octet(doubleDigit); doubleDigit = 0; } else { doubleDigit |= (digit << 4); } numDigits--; } // The sign configuration in the last half-octet of the representation, // is 0xD for negative numbers and 0xC for positive and zero values. if (signum == -1) { doubleDigit |= 0xd; } else { doubleDigit |= 0xc; } this.write_octet(doubleDigit); } public final org.omg.CORBA.ORB orb() { return this.orb; } // org.omg.CORBA_2_3.portable.OutputStream public final void write_value(java.io.Serializable value) { write_value(value, (String) null); } public final void write_value(java.io.Serializable value, java.lang.Class clz) { write_value(value); } public final void write_value(java.io.Serializable value, String repository_id) { try { os.writeObject(value); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_value"); } } public final void write_value(java.io.Serializable value, org.omg.CORBA.portable.BoxedValueHelper factory) { this.write_value(value, (String) null); } public final void write_abstract_interface(java.lang.Object obj) { boolean isCorbaObject = false; // Assume value type. org.omg.CORBA.Object theCorbaObject = null; // Is it a CORBA.Object? if (obj != null && obj instanceof org.omg.CORBA.Object) { theCorbaObject = (org.omg.CORBA.Object)obj; isCorbaObject = true; } // Write the boolean flag. this.write_boolean(isCorbaObject); // Now write out the object. if (isCorbaObject) { write_Object(theCorbaObject); } else { try { write_value((java.io.Serializable)obj); } catch(ClassCastException cce) { if (obj instanceof java.io.Serializable) { throw cce; } else { ORBUtility.throwNotSerializableForCorba( obj.getClass().getName()); } } } } // com.sun.corba.se.os.encoding.MarshalOutputStream public final void start_block() { throw wrapper.giopVersionError(); } public final void end_block() { throw wrapper.giopVersionError(); } public final void putEndian() { throw wrapper.giopVersionError(); } public void writeTo(java.io.OutputStream s) throws IOException { try { os.flush(); bos.writeTo(s); } catch (Exception e) { throw wrapper.javaSerializationException(e, "writeTo"); } } public final byte[] toByteArray() { try { os.flush(); return bos.toByteArray(); // new copy. } catch (Exception e) { throw wrapper.javaSerializationException(e, "toByteArray"); } } // org.omg.CORBA.DataOutputStream public final void write_Abstract (java.lang.Object value) { write_abstract_interface(value); } public final void write_Value(java.io.Serializable value) { write_value(value); } public final void write_any_array(org.omg.CORBA.Any[] value, int offset, int length) { for(int i = 0; i < length; i++) { write_any(value[offset + i]); } } // org.omg.CORBA.portable.ValueBase public final String[] _truncatable_ids() { throw wrapper.giopVersionError(); } // Other. public final int getSize() { try { os.flush(); return bos.size(); } catch (Exception e) { throw wrapper.javaSerializationException(e, "write_boolean"); } } public final int getIndex() { return getSize(); } protected int getRealIndex(int index) { return getSize(); } public final void setIndex(int value) { throw wrapper.giopVersionError(); } public final ByteBuffer getByteBuffer() { throw wrapper.giopVersionError(); } public final void setByteBuffer(ByteBuffer byteBuffer) { throw wrapper.giopVersionError(); } public final boolean isLittleEndian() { // Java serialization uses network byte order, that is, big-endian. return false; } public ByteBufferWithInfo getByteBufferWithInfo() { try { os.flush(); } catch (Exception e) { throw wrapper.javaSerializationException( e, "getByteBufferWithInfo"); } ByteBuffer byteBuffer = ByteBuffer.wrap(bos.getByteArray()); byteBuffer.limit(bos.size()); return new ByteBufferWithInfo(this.orb, byteBuffer, bos.size()); } public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) { throw wrapper.giopVersionError(); } public final BufferManagerWrite getBufferManager() { return bufferManager; } // This will stay a custom add-on until the java-rtf issue is resolved. // Then it should be declared in org.omg.CORBA.portable.OutputStream. // // Pads the string representation of bigDecimal with zeros to fit the given // digits and scale before it gets written to the stream. public final void write_fixed(java.math.BigDecimal bigDecimal, short digits, short scale) { String string = bigDecimal.toString(); String integerPart; String fractionPart; StringBuffer stringBuffer; // Get rid of the sign if (string.charAt(0) == '-' || string.charAt(0) == '+') { string = string.substring(1); } // Determine integer and fraction parts int dotIndex = string.indexOf('.'); if (dotIndex == -1) { integerPart = string; fractionPart = null; } else if (dotIndex == 0 ) { integerPart = null; fractionPart = string; } else { integerPart = string.substring(0, dotIndex); fractionPart = string.substring(dotIndex + 1); } // Pad both parts with zeros as necessary stringBuffer = new StringBuffer(digits); if (fractionPart != null) { stringBuffer.append(fractionPart); } while (stringBuffer.length() < scale) { stringBuffer.append('0'); } if (integerPart != null) { stringBuffer.insert(0, integerPart); } while (stringBuffer.length() < digits) { stringBuffer.insert(0, '0'); } // This string contains no sign or dot this.write_fixed(stringBuffer.toString(), bigDecimal.signum()); } public final void writeOctetSequenceTo( org.omg.CORBA.portable.OutputStream s) { byte[] buf = this.toByteArray(); // new copy. s.write_long(buf.length); s.write_octet_array(buf, 0, buf.length); } public final GIOPVersion getGIOPVersion() { return GIOPVersion.V1_2; } public final void writeIndirection(int tag, int posIndirectedTo) { throw wrapper.giopVersionError(); } void freeInternalCaches() {} void printBuffer() { byte[] buf = this.toByteArray(); System.out.println("+++++++ Output Buffer ++++++++"); System.out.println(); System.out.println("Current position: " + buf.length); //System.out.println("Total length : " + buf.length); System.out.println(); char[] charBuf = new char[16]; try { for (int i = 0; i < buf.length; i += 16) { int j = 0; // For every 16 bytes, there is one line // of output. First, the hex output of // the 16 bytes with each byte separated // by a space. while (j < 16 && j + i < buf.length) { int k = buf[i + j]; if (k < 0) k = 256 + k; String hex = Integer.toHexString(k); if (hex.length() == 1) hex = "0" + hex; System.out.print(hex + " "); j++; } // Add any extra spaces to align the // text column in case we didn't end // at 16 while (j < 16) { System.out.print(" "); j++; } // Now output the ASCII equivalents. Non-ASCII // characters are shown as periods. int x = 0; while (x < 16 && x + i < buf.length) { if (ORBUtility.isPrintable((char)buf[i + x])) { charBuf[x] = (char) buf[i + x]; } else { charBuf[x] = '.'; } x++; } System.out.println(new String(charBuf, 0, x)); } } catch (Throwable t) { t.printStackTrace(); } System.out.println("++++++++++++++++++++++++++++++"); } public void alignOnBoundary(int octetBoundary) { throw wrapper.giopVersionError(); } // Needed by request and reply messages for GIOP versions >= 1.2 only. public void setHeaderPadding(boolean headerPadding) { // no-op. We don't care about body alignment while using // Java serialization. What the GIOP spec states does not apply here. } // ValueOutputStream ----------------------------- public void start_value(String rep_id) { throw wrapper.giopVersionError(); } public void end_value() { throw wrapper.giopVersionError(); } // java.io.OutputStream // Note: These methods are defined in the super class and accessible. //public abstract void write(byte b[]) throws IOException; //public abstract void write(byte b[], int off, int len) // throws IOException; //public abstract void flush() throws IOException; //public abstract void close() throws IOException; }