blob: 3e60c4801b0486a8e9d3c6f0eabd5aaadf6b3333 [file] [log] [blame]
/*
* Copyright (c) 1997, 2012, 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.encoding;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.rmi.Remote;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.util.Hashtable;
import java.util.Stack;
import javax.rmi.CORBA.Util;
import javax.rmi.CORBA.ValueHandler;
import javax.rmi.CORBA.ValueHandlerMultiFormat;
import org.omg.CORBA.CustomMarshal;
import org.omg.CORBA.DataOutputStream;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.Object;
import org.omg.CORBA.Principal;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.Any;
import org.omg.CORBA.VM_CUSTOM;
import org.omg.CORBA.VM_TRUNCATABLE;
import org.omg.CORBA.VM_NONE;
import org.omg.CORBA.portable.IDLEntity;
import org.omg.CORBA.portable.CustomValue;
import org.omg.CORBA.portable.StreamableValue;
import org.omg.CORBA.portable.BoxedValueHelper;
import org.omg.CORBA.portable.OutputStream;
import org.omg.CORBA.portable.ValueBase;
import com.sun.org.omg.CORBA.portable.ValueHelper;
import com.sun.corba.se.pept.protocol.MessageMediator;
import com.sun.corba.se.pept.transport.ByteBufferPool;
import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
import com.sun.corba.se.spi.ior.IOR;
import com.sun.corba.se.spi.ior.IORFactories;
import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.orb.ORBVersionFactory;
import com.sun.corba.se.spi.orb.ORBVersion;
import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.impl.encoding.ByteBufferWithInfo;
import com.sun.corba.se.impl.encoding.MarshalOutputStream;
import com.sun.corba.se.impl.encoding.CodeSetConversion;
import com.sun.corba.se.impl.corba.TypeCodeImpl;
import com.sun.corba.se.impl.orbutil.CacheTable;
import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.orbutil.RepositoryIdStrings;
import com.sun.corba.se.impl.orbutil.RepositoryIdUtility;
import com.sun.corba.se.impl.orbutil.RepositoryIdFactory;
import com.sun.corba.se.impl.util.Utility;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;
public class CDROutputStream_1_0 extends CDROutputStreamBase
{
private static final int INDIRECTION_TAG = 0xffffffff;
protected boolean littleEndian;
protected BufferManagerWrite bufferManagerWrite;
ByteBufferWithInfo bbwi;
protected ORB orb;
protected ORBUtilSystemException wrapper ;
protected boolean debug = false;
protected int blockSizeIndex = -1;
protected int blockSizePosition = 0;
protected byte streamFormatVersion;
private static final int DEFAULT_BUFFER_SIZE = 1024;
private static final String kWriteMethod = "write";
// Codebase cache
private CacheTable codebaseCache = null;
// Value cache
private CacheTable valueCache = null;
// Repository ID cache
private CacheTable repositoryIdCache = null;
// Write end flag
private int end_flag = 0;
// Beginning with the resolution to interop issue 3526,
// only enclosing chunked valuetypes are taken into account
// when computing the nesting level. However, we still need
// the old computation around for interoperability with our
// older ORBs.
private int chunkedValueNestingLevel = 0;
private boolean mustChunk = false;
// In block marker
protected boolean inBlock = false;
// Last end tag position
private int end_flag_position = 0;
private int end_flag_index = 0;
// ValueHandler
private ValueHandler valueHandler = null;
// Repository ID handlers
private RepositoryIdUtility repIdUtil;
private RepositoryIdStrings repIdStrs;
// Code set converters (created when first needed)
private CodeSetConversion.CTBConverter charConverter;
private CodeSetConversion.CTBConverter wcharConverter;
// REVISIT - This should be re-factored so that including whether
// to use pool byte buffers or not doesn't need to be known.
public void init(org.omg.CORBA.ORB orb,
boolean littleEndian,
BufferManagerWrite bufferManager,
byte streamFormatVersion,
boolean usePooledByteBuffers)
{
// ORB must not be null. See CDROutputStream constructor.
this.orb = (ORB)orb;
this.wrapper = ORBUtilSystemException.get( this.orb,
CORBALogDomains.RPC_ENCODING ) ;
debug = this.orb.transportDebugFlag;
this.littleEndian = littleEndian;
this.bufferManagerWrite = bufferManager;
this.bbwi = new ByteBufferWithInfo(orb, bufferManager, usePooledByteBuffers);
this.streamFormatVersion = streamFormatVersion;
createRepositoryIdHandlers();
}
public void init(org.omg.CORBA.ORB orb,
boolean littleEndian,
BufferManagerWrite bufferManager,
byte streamFormatVersion)
{
init(orb, littleEndian, bufferManager, streamFormatVersion, true);
}
private final void createRepositoryIdHandlers()
{
repIdUtil = RepositoryIdFactory.getRepIdUtility();
repIdStrs = RepositoryIdFactory.getRepIdStringsFactory();
}
public BufferManagerWrite getBufferManager()
{
return bufferManagerWrite;
}
public byte[] toByteArray() {
byte[] it;
it = new byte[bbwi.position()];
// Micro-benchmarks show ByteBuffer.get(int) out perform the bulk
// ByteBuffer.get(byte[], offset, length).
for (int i = 0; i < bbwi.position(); i++)
it[i] = bbwi.byteBuffer.get(i);
return it;
}
public GIOPVersion getGIOPVersion() {
return GIOPVersion.V1_0;
}
// Called by Request and Reply message. Valid for GIOP versions >= 1.2 only.
// Illegal for GIOP versions < 1.2.
void setHeaderPadding(boolean headerPadding) {
throw wrapper.giopVersionError();
}
protected void handleSpecialChunkBegin(int requiredSize)
{
// No-op for GIOP 1.0
}
protected void handleSpecialChunkEnd()
{
// No-op for GIOP 1.0
}
protected final int computeAlignment(int align) {
if (align > 1) {
int incr = bbwi.position() & (align - 1);
if (incr != 0)
return align - incr;
}
return 0;
}
protected void alignAndReserve(int align, int n) {
bbwi.position(bbwi.position() + computeAlignment(align));
if (bbwi.position() + n > bbwi.buflen)
grow(align, n);
}
//
// Default implementation of grow. Subclassers may override this.
// Always grow the single buffer. This needs to delegate
// fragmentation policy for IIOP 1.1.
//
protected void grow(int align, int n)
{
bbwi.needed = n;
bufferManagerWrite.overflow(bbwi);
}
public final void putEndian() throws SystemException {
write_boolean(littleEndian);
}
public final boolean littleEndian() {
return littleEndian;
}
void freeInternalCaches() {
if (codebaseCache != null)
codebaseCache.done();
if (valueCache != null)
valueCache.done();
if (repositoryIdCache != null)
repositoryIdCache.done();
}
// No such type in java
public final void write_longdouble(double x)
{
throw wrapper.longDoubleNotImplemented(
CompletionStatus.COMPLETED_MAYBE ) ;
}
public void write_octet(byte x)
{
// The 'if' stmt is commented out since we need the alignAndReserve to
// be called, particularly when the first body byte is written,
// to induce header padding to align the body on a 8-octet boundary,
// for GIOP versions 1.2 and above. Refer to internalWriteOctetArray()
// method that also has a similar change.
//if (bbwi.position() + 1 > bbwi.buflen)
alignAndReserve(1, 1);
// REVISIT - Should just use ByteBuffer.put(byte) and let it
// increment the ByteBuffer position. This is true
// for all write operations in this file.
bbwi.byteBuffer.put(bbwi.position(), x);
bbwi.position(bbwi.position() + 1);
}
public final void write_boolean(boolean x)
{
write_octet(x? (byte)1:(byte)0);
}
public void write_char(char x)
{
CodeSetConversion.CTBConverter converter = getCharConverter();
converter.convert(x);
// CORBA formal 99-10-07 15.3.1.6: "In the case of multi-byte encodings
// of characters, a single instance of the char type may only
// hold one octet of any multi-byte character encoding."
if (converter.getNumBytes() > 1)
throw wrapper.invalidSingleCharCtb(CompletionStatus.COMPLETED_MAYBE);
write_octet(converter.getBytes()[0]);
}
// These wchar methods are only used when talking to
// legacy ORBs, now.
private final void writeLittleEndianWchar(char x) {
bbwi.byteBuffer.put(bbwi.position(), (byte)(x & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 8) & 0xFF));
bbwi.position(bbwi.position() + 2);
}
private final void writeBigEndianWchar(char x) {
bbwi.byteBuffer.put(bbwi.position(), (byte)((x >>> 8) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 1, (byte)(x & 0xFF));
bbwi.position(bbwi.position() + 2);
}
private final void writeLittleEndianShort(short x) {
bbwi.byteBuffer.put(bbwi.position(), (byte)(x & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 8) & 0xFF));
bbwi.position(bbwi.position() + 2);
}
private final void writeBigEndianShort(short x) {
bbwi.byteBuffer.put(bbwi.position(), (byte)((x >>> 8) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 1, (byte)(x & 0xFF));
bbwi.position(bbwi.position() + 2);
}
private final void writeLittleEndianLong(int x) {
bbwi.byteBuffer.put(bbwi.position(), (byte)(x & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 8) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 2, (byte)((x >>> 16) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 3, (byte)((x >>> 24) & 0xFF));
bbwi.position(bbwi.position() + 4);
}
private final void writeBigEndianLong(int x) {
bbwi.byteBuffer.put(bbwi.position(), (byte)((x >>> 24) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 16) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 2, (byte)((x >>> 8) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 3, (byte)(x & 0xFF));
bbwi.position(bbwi.position() + 4);
}
private final void writeLittleEndianLongLong(long x) {
bbwi.byteBuffer.put(bbwi.position(), (byte)(x & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 8) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 2, (byte)((x >>> 16) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 3, (byte)((x >>> 24) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 4, (byte)((x >>> 32) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 5, (byte)((x >>> 40) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 6, (byte)((x >>> 48) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 7, (byte)((x >>> 56) & 0xFF));
bbwi.position(bbwi.position() + 8);
}
private final void writeBigEndianLongLong(long x) {
bbwi.byteBuffer.put(bbwi.position(), (byte)((x >>> 56) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 48) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 2, (byte)((x >>> 40) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 3, (byte)((x >>> 32) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 4, (byte)((x >>> 24) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 5, (byte)((x >>> 16) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 6, (byte)((x >>> 8) & 0xFF));
bbwi.byteBuffer.put(bbwi.position() + 7, (byte)(x & 0xFF));
bbwi.position(bbwi.position() + 8);
}
public void write_wchar(char x)
{
// Don't allow transmission of wchar/wstring data with
// foreign ORBs since it's against the spec.
if (ORBUtility.isForeignORB(orb)) {
throw wrapper.wcharDataInGiop10(CompletionStatus.COMPLETED_MAYBE);
}
// If it's one of our legacy ORBs, do what they did:
alignAndReserve(2, 2);
if (littleEndian) {
writeLittleEndianWchar(x);
} else {
writeBigEndianWchar(x);
}
}
public void write_short(short x)
{
alignAndReserve(2, 2);
if (littleEndian) {
writeLittleEndianShort(x);
} else {
writeBigEndianShort(x);
}
}
public final void write_ushort(short x)
{
write_short(x);
}
public void write_long(int x)
{
alignAndReserve(4, 4);
if (littleEndian) {
writeLittleEndianLong(x);
} else {
writeBigEndianLong(x);
}
}
public final void write_ulong(int x)
{
write_long(x);
}
public void write_longlong(long x)
{
alignAndReserve(8, 8);
if (littleEndian) {
writeLittleEndianLongLong(x);
} else {
writeBigEndianLongLong(x);
}
}
public final void write_ulonglong(long x)
{
write_longlong(x);
}
public final void write_float(float x)
{
write_long(Float.floatToIntBits(x));
}
public final void write_double(double x)
{
write_longlong(Double.doubleToLongBits(x));
}
public void write_string(String value)
{
writeString(value);
}
protected int writeString(String value)
{
if (value == null) {
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
}
CodeSetConversion.CTBConverter converter = getCharConverter();
converter.convert(value);
// A string is encoded as an unsigned CORBA long for the
// number of bytes to follow (including a terminating null).
// There is only one octet per character in the string.
int len = converter.getNumBytes() + 1;
handleSpecialChunkBegin(computeAlignment(4) + 4 + len);
write_long(len);
int indirection = get_offset() - 4;
internalWriteOctetArray(converter.getBytes(), 0, converter.getNumBytes());
// Write the null ending
write_octet((byte)0);
handleSpecialChunkEnd();
return indirection;
}
public void write_wstring(String value)
{
if (value == null)
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// Don't allow transmission of wchar/wstring data with
// foreign ORBs since it's against the spec.
if (ORBUtility.isForeignORB(orb)) {
throw wrapper.wcharDataInGiop10(CompletionStatus.COMPLETED_MAYBE);
}
// When talking to our legacy ORBs, do what they did:
int len = value.length() + 1;
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(4 + (len * 2) + computeAlignment(4));
write_long(len);
for (int i = 0; i < len - 1; i++)
write_wchar(value.charAt(i));
// Write the null ending
write_short((short)0);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
// Performs no checks and doesn't tamper with chunking
void internalWriteOctetArray(byte[] value, int offset, int length)
{
int n = offset;
// This flag forces the alignAndReserve method to be called the
// first time an octet is written. This is necessary to ensure
// that the body is aligned on an 8-octet boundary. Note the 'if'
// condition inside the 'while' loop below. Also, refer to the
// write_octet() method that has a similar change.
boolean align = true;
while (n < length+offset) {
int avail;
int bytes;
int wanted;
if ((bbwi.position() + 1 > bbwi.buflen) || align) {
align = false;
alignAndReserve(1, 1);
}
avail = bbwi.buflen - bbwi.position();
wanted = (length + offset) - n;
bytes = (wanted < avail) ? wanted : avail;
for (int i = 0; i < bytes; i++)
bbwi.byteBuffer.put(bbwi.position() + i, value[n+i]);
bbwi.position(bbwi.position() + bytes);
n += bytes;
}
}
public final void write_octet_array(byte b[], int offset, int length)
{
if ( b == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(length);
internalWriteOctetArray(b, offset, length);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
public void write_Principal(Principal p)
{
write_long(p.name().length);
write_octet_array(p.name(), 0, p.name().length);
}
public void write_any(Any any)
{
if ( any == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
write_TypeCode(any.type());
any.write_value(parent);
}
public 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 void write_Object(org.omg.CORBA.Object ref)
{
if (ref == null) {
IOR nullIOR = IORFactories.makeIOR( orb ) ;
nullIOR.write(parent);
return;
}
// IDL to Java formal 01-06-06 1.21.4.2
if (ref instanceof org.omg.CORBA.LocalObject)
throw wrapper.writeLocalObject(CompletionStatus.COMPLETED_MAYBE);
IOR ior = ORBUtility.connectAndGetIOR( orb, ref ) ;
ior.write(parent);
return;
}
// ------------ RMI related methods --------------------------
public void write_abstract_interface(java.lang.Object obj) {
boolean corbaObject = false; // Assume value type.
org.omg.CORBA.Object theObject = null;
// Is it a CORBA.Object?
if (obj != null && obj instanceof org.omg.CORBA.Object) {
// Yes.
theObject = (org.omg.CORBA.Object)obj;
corbaObject = true;
}
// Write our flag...
write_boolean(corbaObject);
// Now write out the object...
if (corbaObject) {
write_Object(theObject);
} 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());
}
}
}
public void write_value(Serializable object, Class clz) {
write_value(object);
}
private void writeWStringValue(String string) {
int indirection = writeValueTag(mustChunk, true, null);
// Write WStringValue's repository ID
write_repositoryId(repIdStrs.getWStringValueRepId());
// Add indirection for object to indirection table
updateIndirectionTable(indirection, string, string);
// Write Value chunk
if (mustChunk) {
start_block();
end_flag--;
chunkedValueNestingLevel--;
} else
end_flag--;
write_wstring(string);
if (mustChunk)
end_block();
// Write end tag
writeEndTag(mustChunk);
}
private void writeArray(Serializable array, Class clazz) {
if (valueHandler == null)
valueHandler = ORBUtility.createValueHandler(); //d11638
// Write value_tag
int indirection = writeValueTag(mustChunk, true,
Util.getCodebase(clazz));
// Write repository ID
write_repositoryId(repIdStrs.createSequenceRepID(clazz));
// Add indirection for object to indirection table
updateIndirectionTable(indirection, array, array);
// Write Value chunk
if (mustChunk) {
start_block();
end_flag--;
chunkedValueNestingLevel--;
} else
end_flag--;
if (valueHandler instanceof ValueHandlerMultiFormat) {
ValueHandlerMultiFormat vh = (ValueHandlerMultiFormat)valueHandler;
vh.writeValue(parent, array, streamFormatVersion);
} else
valueHandler.writeValue(parent, array);
if (mustChunk)
end_block();
// Write end tag
writeEndTag(mustChunk);
}
private void writeValueBase(org.omg.CORBA.portable.ValueBase object,
Class clazz) {
// _REVISIT_ could check to see whether chunking really needed
mustChunk = true;
// Write value_tag
int indirection = writeValueTag(true, true, Util.getCodebase(clazz));
// Get rep id
String repId = ((ValueBase)object)._truncatable_ids()[0];
// Write rep id
write_repositoryId(repId);
// Add indirection for object to indirection table
updateIndirectionTable(indirection, object, object);
// Write Value chunk
start_block();
end_flag--;
chunkedValueNestingLevel--;
writeIDLValue(object, repId);
end_block();
// Write end tag
writeEndTag(true);
}
private void writeRMIIIOPValueType(Serializable object, Class clazz) {
if (valueHandler == null)
valueHandler = ORBUtility.createValueHandler(); //d11638
Serializable key = object;
// Allow the ValueHandler to call writeReplace on
// the Serializable (if the method is present)
object = valueHandler.writeReplace(key);
if (object == null) {
// Write null tag and return
write_long(0);
return;
}
if (object != key) {
if (valueCache != null && valueCache.containsKey(object)) {
writeIndirection(INDIRECTION_TAG, valueCache.getVal(object));
return;
}
clazz = object.getClass();
}
if (mustChunk || valueHandler.isCustomMarshaled(clazz)) {
mustChunk = true;
}
// Write value_tag
int indirection = writeValueTag(mustChunk, true, Util.getCodebase(clazz));
// Write rep. id
write_repositoryId(repIdStrs.createForJavaType(clazz));
// Add indirection for object to indirection table
updateIndirectionTable(indirection, object, key);
if (mustChunk) {
// Write Value chunk
end_flag--;
chunkedValueNestingLevel--;
start_block();
} else
end_flag--;
if (valueHandler instanceof ValueHandlerMultiFormat) {
ValueHandlerMultiFormat vh = (ValueHandlerMultiFormat)valueHandler;
vh.writeValue(parent, object, streamFormatVersion);
} else
valueHandler.writeValue(parent, object);
if (mustChunk)
end_block();
// Write end tag
writeEndTag(mustChunk);
}
public void write_value(Serializable object, String repository_id) {
// Handle null references
if (object == null) {
// Write null tag and return
write_long(0);
return;
}
// Handle shared references
if (valueCache != null && valueCache.containsKey(object)) {
writeIndirection(INDIRECTION_TAG, valueCache.getVal(object));
return;
}
Class clazz = object.getClass();
boolean oldMustChunk = mustChunk;
if (mustChunk)
mustChunk = true;
if (inBlock)
end_block();
if (clazz.isArray()) {
// Handle arrays
writeArray(object, clazz);
} else if (object instanceof org.omg.CORBA.portable.ValueBase) {
// Handle IDL Value types
writeValueBase((org.omg.CORBA.portable.ValueBase)object, clazz);
} else if (shouldWriteAsIDLEntity(object)) {
writeIDLEntity((IDLEntity)object);
} else if (object instanceof java.lang.String) {
writeWStringValue((String)object);
} else if (object instanceof java.lang.Class) {
writeClass(repository_id, (Class)object);
} else {
// RMI-IIOP value type
writeRMIIIOPValueType(object, clazz);
}
mustChunk = oldMustChunk;
// Check to see if we need to start another block for a
// possible outer value
if (mustChunk)
start_block();
}
public void write_value(Serializable object)
{
write_value(object, (String)null);
}
public void write_value(Serializable object, org.omg.CORBA.portable.BoxedValueHelper factory)
{
// Handle null references
if (object == null) {
// Write null tag and return
write_long(0);
return;
}
// Handle shared references
if ((valueCache != null) && valueCache.containsKey(object)) {
writeIndirection(INDIRECTION_TAG, valueCache.getVal(object));
return;
}
boolean oldMustChunk = mustChunk;
boolean isCustom = false;
if (factory instanceof ValueHelper) {
short modifier;
try {
modifier = ((ValueHelper)factory).get_type().type_modifier();
} catch(BadKind ex) { // tk_value_box
modifier = VM_NONE.value;
}
if (object instanceof CustomMarshal &&
modifier == VM_CUSTOM.value) {
isCustom = true;
mustChunk = true;
}
if (modifier == VM_TRUNCATABLE.value)
mustChunk = true;
}
if (mustChunk) {
if (inBlock)
end_block();
// Write value_tag
int indirection = writeValueTag(true,
orb.getORBData().useRepId(),
Util.getCodebase(object.getClass())
);
if (orb.getORBData().useRepId()) {
write_repositoryId(factory.get_id());
}
// Add indirection for object to indirection table
updateIndirectionTable(indirection, object, object);
// Write Value chunk
start_block();
end_flag--;
chunkedValueNestingLevel--;
if (isCustom)
((CustomMarshal)object).marshal(parent);
else
factory.write_value(parent, object);
end_block();
// Write end tag
writeEndTag(true);
}
else {
// Write value_tag
int indirection = writeValueTag(false,
orb.getORBData().useRepId(),
Util.getCodebase(object.getClass())
);
if (orb.getORBData().useRepId()) {
write_repositoryId(factory.get_id());
}
// Add indirection for object to indirection table
updateIndirectionTable(indirection, object, object);
// Write Value chunk
end_flag--;
// no need to test for custom on the non-chunked path
factory.write_value(parent, object);
// Write end tag
writeEndTag(false);
}
mustChunk = oldMustChunk;
// Check to see if we need to start another block for a
// possible outer value
if (mustChunk)
start_block();
}
public int get_offset() {
return bbwi.position();
}
public void start_block() {
if (debug) {
dprint("CDROutputStream_1_0 start_block, position" + bbwi.position());
}
//Move inBlock=true to after write_long since write_long might
//trigger grow which will lead to erroneous behavior with a
//missing blockSizeIndex.
//inBlock = true;
// Save space in the buffer for block size
write_long(0);
//Has to happen after write_long since write_long could
//trigger grow which is overridden by supper classes to
//depend on inBlock.
inBlock = true;
blockSizePosition = get_offset();
// Remember where to put the size of the endblock less 4
blockSizeIndex = bbwi.position();
if (debug) {
dprint("CDROutputStream_1_0 start_block, blockSizeIndex "
+ blockSizeIndex);
}
}
// Utility method which will hopefully decrease chunking complexity
// by allowing us to end_block and update chunk lengths without
// calling alignAndReserve. Otherwise, it's possible to get into
// recursive scenarios which lose the chunking state.
protected void writeLongWithoutAlign(int x) {
if (littleEndian) {
writeLittleEndianLong(x);
} else {
writeBigEndianLong(x);
}
}
public void end_block() {
if (debug) {
dprint("CDROutputStream_1_0.java end_block");
}
if (!inBlock)
return;
if (debug) {
dprint("CDROutputStream_1_0.java end_block, in a block");
}
inBlock = false;
// Test to see if the block was of zero length
// If so, remove the block instead of ending it
// (This can happen if the last field written
// in a value was another value)
if (get_offset() == blockSizePosition) {
// Need to assert that blockSizeIndex == bbwi.position()? REVISIT
bbwi.position(bbwi.position() - 4);
blockSizeIndex = -1;
blockSizePosition = -1;
return;
}
int oldSize = bbwi.position();
bbwi.position(blockSizeIndex - 4);
writeLongWithoutAlign(oldSize - blockSizeIndex);
bbwi.position(oldSize);
blockSizeIndex = -1;
blockSizePosition = -1;
// System.out.println(" post end_block: " + get_offset() + " " + bbwi.position());
}
public org.omg.CORBA.ORB orb()
{
return orb;
}
// ------------ End RMI related methods --------------------------
public final void write_boolean_array(boolean[]value, int offset, int length) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(length);
for (int i = 0; i < length; i++)
write_boolean(value[offset + i]);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
public final void write_char_array(char[]value, int offset, int length) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(length);
for (int i = 0; i < length; i++)
write_char(value[offset + i]);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
public void write_wchar_array(char[]value, int offset, int length) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(computeAlignment(2) + (length * 2));
for (int i = 0; i < length; i++)
write_wchar(value[offset + i]);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
public final void write_short_array(short[]value, int offset, int length) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(computeAlignment(2) + (length * 2));
for (int i = 0; i < length; i++)
write_short(value[offset + i]);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
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) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(computeAlignment(4) + (length * 4));
for (int i = 0; i < length; i++)
write_long(value[offset + i]);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
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) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(computeAlignment(8) + (length * 8));
for (int i = 0; i < length; i++)
write_longlong(value[offset + i]);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
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) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(computeAlignment(4) + (length * 4));
for (int i = 0; i < length; i++)
write_float(value[offset + i]);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
public final void write_double_array(double[]value, int offset, int length) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
// This will only have an effect if we're already chunking
handleSpecialChunkBegin(computeAlignment(8) + (length * 8));
for (int i = 0; i < length; i++)
write_double(value[offset + i]);
// This will only have an effect if we're already chunking
handleSpecialChunkEnd();
}
public void write_string_array(String[] value, int offset, int length) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
for(int i = 0; i < length; i++)
write_string(value[offset + i]);
}
public void write_wstring_array(String[] value, int offset, int length) {
if ( value == null )
throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
for(int i = 0; i < length; i++)
write_wstring(value[offset + i]);
}
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]);
}
//--------------------------------------------------------------------//
// CDROutputStream state management.
//
public void writeTo(java.io.OutputStream s)
throws java.io.IOException
{
byte[] tmpBuf = null;
if (bbwi.byteBuffer.hasArray())
{
tmpBuf = bbwi.byteBuffer.array();
}
else
{
int size = bbwi.position();
tmpBuf = new byte[size];
// Micro-benchmarks are showing a loop of ByteBuffer.get(int) is
// faster than ByteBuffer.get(byte[], offset, length)
for (int i = 0; i < size; i++)
tmpBuf[i] = bbwi.byteBuffer.get(i);
}
s.write(tmpBuf, 0, bbwi.position());
}
public void writeOctetSequenceTo(org.omg.CORBA.portable.OutputStream s) {
byte[] buf = null;
if (bbwi.byteBuffer.hasArray())
{
buf = bbwi.byteBuffer.array();
}
else
{
int size = bbwi.position();
buf = new byte[size];
// Micro-benchmarks are showing a loop of ByteBuffer.get(int) is
// faster than ByteBuffer.get(byte[], offset, length)
for (int i = 0; i < size; i++)
buf[i] = bbwi.byteBuffer.get(i);
}
s.write_long(bbwi.position());
s.write_octet_array(buf, 0, bbwi.position());
}
public final int getSize() {
return bbwi.position();
}
public int getIndex() {
return bbwi.position();
}
public boolean isLittleEndian() {
return littleEndian;
}
public void setIndex(int value) {
bbwi.position(value);
}
public ByteBufferWithInfo getByteBufferWithInfo() {
return bbwi;
}
public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) {
this.bbwi = bbwi;
}
public ByteBuffer getByteBuffer() {
ByteBuffer result = null;;
if (bbwi != null) {
result = bbwi.byteBuffer;
}
return result;
}
public void setByteBuffer(ByteBuffer byteBuffer) {
bbwi.byteBuffer = byteBuffer;
}
private final void updateIndirectionTable(int indirection, java.lang.Object object,
java.lang.Object key) {
// int indirection = get_offset();
if (valueCache == null)
valueCache = new CacheTable(orb,true);
valueCache.put(object, indirection);
if (key != object)
valueCache.put(key, indirection);
}
private final void write_repositoryId(String id) {
// Use an indirection if available
if (repositoryIdCache != null && repositoryIdCache.containsKey(id)) {
writeIndirection(INDIRECTION_TAG, repositoryIdCache.getVal(id));
return;
}
// Write it as a string. Note that we have already done the
// special case conversion of non-Latin-1 characters to escaped
// Latin-1 sequences in RepositoryId.
// It's not a good idea to cache them now that we can have
// multiple code sets.
int indirection = writeString(id);
// Add indirection for id to indirection table
if (repositoryIdCache == null)
repositoryIdCache = new CacheTable(orb,true);
repositoryIdCache.put(id, indirection);
}
private void write_codebase(String str, int pos) {
if (codebaseCache != null && codebaseCache.containsKey(str)) {
writeIndirection(INDIRECTION_TAG, codebaseCache.getVal(str));
}
else {
write_string(str);
if (codebaseCache == null)
codebaseCache = new CacheTable(orb,true);
codebaseCache.put(str, pos);
}
}
private final int writeValueTag(boolean chunkIt, boolean useRepId,
String codebase) {
int indirection = 0;
if (chunkIt && !useRepId){
if (codebase == null) {
write_long(repIdUtil.getStandardRMIChunkedNoRepStrId());
indirection = get_offset() - 4;
} else {
write_long(repIdUtil.getCodeBaseRMIChunkedNoRepStrId());
indirection = get_offset() - 4;
write_codebase(codebase, get_offset());
}
} else if (chunkIt && useRepId){
if (codebase == null) {
write_long(repIdUtil.getStandardRMIChunkedId());
indirection = get_offset() - 4;
} else {
write_long(repIdUtil.getCodeBaseRMIChunkedId());
indirection = get_offset() - 4;
write_codebase(codebase, get_offset());
}
} else if (!chunkIt && !useRepId) {
if (codebase == null) {
write_long(repIdUtil.getStandardRMIUnchunkedNoRepStrId());
indirection = get_offset() - 4;
} else {
write_long(repIdUtil.getCodeBaseRMIUnchunkedNoRepStrId());
indirection = get_offset() - 4;
write_codebase(codebase, get_offset());
}
} else if (!chunkIt && useRepId) {
if (codebase == null) {
write_long(repIdUtil.getStandardRMIUnchunkedId());
indirection = get_offset() - 4;
} else {
write_long(repIdUtil.getCodeBaseRMIUnchunkedId());
indirection = get_offset() - 4;
write_codebase(codebase, get_offset());
}
}
return indirection;
}
private void writeIDLValue(Serializable object, String repID)
{
if (object instanceof StreamableValue) {
((StreamableValue)object)._write(parent);
} else if (object instanceof CustomValue) {
((CustomValue)object).marshal(parent);
} else {
BoxedValueHelper helper = Utility.getHelper(object.getClass(), null, repID);
boolean isCustom = false;
if (helper instanceof ValueHelper && object instanceof CustomMarshal) {
try {
if (((ValueHelper)helper).get_type().type_modifier() == VM_CUSTOM.value)
isCustom = true;
} catch(BadKind ex) {
throw wrapper.badTypecodeForCustomValue( CompletionStatus.COMPLETED_MAYBE,
ex ) ;
}
}
if (isCustom)
((CustomMarshal)object).marshal(parent);
else
helper.write_value(parent, object);
}
}
// Handles end tag compaction...
private void writeEndTag(boolean chunked){
if (chunked) {
if (get_offset() == end_flag_position) {
if (bbwi.position() == end_flag_index) {
// We are exactly at the same position and index as the
// end of the last end tag. Thus, we can back up over it
// and compact the tags.
bbwi.position(bbwi.position() - 4);
} else {
// Special case in which we're at the beginning of a new
// fragment, but the position is the same. We can't back up,
// so we just write the new end tag without compaction. This
// occurs when a value ends and calls start_block to open a
// continuation chunk, but it's called at the very end of
// a fragment.
}
}
writeNestingLevel();
// Remember the last index and position. These are only used when chunking.
end_flag_index = bbwi.position();
end_flag_position = get_offset();
chunkedValueNestingLevel++;
}
// Increment the nesting level
end_flag++;
}
/**
* Handles ORB versioning of the end tag. Should only
* be called if chunking.
*
* If talking to our older ORBs (Standard Extension,
* Kestrel, and Ladybird), write the end flag that takes
* into account all enclosing valuetypes.
*
* If talking a newer or foreign ORB, or if the orb
* instance is null, write the end flag that only takes
* into account the enclosing chunked valuetypes.
*/
private void writeNestingLevel() {
if (orb == null ||
ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
write_long(chunkedValueNestingLevel);
} else {
write_long(end_flag);
}
}
private void writeClass(String repository_id, Class clz) {
if (repository_id == null)
repository_id = repIdStrs.getClassDescValueRepId();
// Write value_tag
int indirection = writeValueTag(mustChunk, true, null);
updateIndirectionTable(indirection, clz, clz);
write_repositoryId(repository_id);
if (mustChunk) {
// Write Value chunk
start_block();
end_flag--;
chunkedValueNestingLevel--;
} else
end_flag--;
writeClassBody(clz);
if (mustChunk)
end_block();
// Write end tag
writeEndTag(mustChunk);
}
// Pre-Merlin/J2EE 1.3 ORBs wrote the repository ID
// and codebase strings in the wrong order. This handles
// backwards compatibility.
private void writeClassBody(Class clz) {
if (orb == null ||
ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
write_value(Util.getCodebase(clz));
write_value(repIdStrs.createForAnyType(clz));
} else {
write_value(repIdStrs.createForAnyType(clz));
write_value(Util.getCodebase(clz));
}
}
// Casts and returns an Object as a Serializable
// This is required for JDK 1.1 only to avoid VerifyErrors when
// passing arrays as Serializable
// private java.io.Serializable make_serializable(java.lang.Object object)
// {
// return (java.io.Serializable)object;
// }
private boolean shouldWriteAsIDLEntity(Serializable object)
{
return ((object instanceof IDLEntity) && (!(object instanceof ValueBase)) &&
(!(object instanceof org.omg.CORBA.Object)));
}
private void writeIDLEntity(IDLEntity object) {
// _REVISIT_ could check to see whether chunking really needed
mustChunk = true;
String repository_id = repIdStrs.createForJavaType(object);
Class clazz = object.getClass();
String codebase = Util.getCodebase(clazz);
// Write value_tag
int indirection = writeValueTag(true, true, codebase);
updateIndirectionTable(indirection, object, object);
// Write rep. id
write_repositoryId(repository_id);
// Write Value chunk
end_flag--;
chunkedValueNestingLevel--;
start_block();
// Write the IDLEntity using reflection
try {
ClassLoader clazzLoader = (clazz == null ? null : clazz.getClassLoader());
final Class helperClass = Utility.loadClassForClass(clazz.getName()+"Helper", codebase,
clazzLoader, clazz, clazzLoader);
final Class argTypes[] = {org.omg.CORBA.portable.OutputStream.class, clazz};
// getDeclaredMethod requires RuntimePermission accessDeclaredMembers
// if a different class loader is used (even though the javadoc says otherwise)
Method writeMethod = null;
try {
writeMethod = (Method)AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public java.lang.Object run() throws NoSuchMethodException {
return helperClass.getDeclaredMethod(kWriteMethod, argTypes);
}
}
);
} catch (PrivilegedActionException pae) {
// this gets caught below
throw (NoSuchMethodException)pae.getException();
}
java.lang.Object args[] = {parent, object};
writeMethod.invoke(null, args);
} catch (ClassNotFoundException cnfe) {
throw wrapper.errorInvokingHelperWrite( CompletionStatus.COMPLETED_MAYBE, cnfe ) ;
} catch(NoSuchMethodException nsme) {
throw wrapper.errorInvokingHelperWrite( CompletionStatus.COMPLETED_MAYBE, nsme ) ;
} catch(IllegalAccessException iae) {
throw wrapper.errorInvokingHelperWrite( CompletionStatus.COMPLETED_MAYBE, iae ) ;
} catch(InvocationTargetException ite) {
throw wrapper.errorInvokingHelperWrite( CompletionStatus.COMPLETED_MAYBE, ite ) ;
}
end_block();
// Write end tag
writeEndTag(true);
}
/* DataOutputStream methods */
public void write_Abstract (java.lang.Object value) {
write_abstract_interface(value);
}
public void write_Value (java.io.Serializable value) {
write_value(value);
}
// 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 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());
}
// This method should be remove by the java-rtf issue.
// Right now the scale and digits information of the type code is lost.
public 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
public 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 length of the string 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);
}
private final static String _id = "IDL:omg.org/CORBA/DataOutputStream:1.0";
private final static String[] _ids = { _id };
public String[] _truncatable_ids() {
if (_ids == null)
return null;
return (String[])_ids.clone();
}
/* for debugging */
public void printBuffer() {
CDROutputStream_1_0.printBuffer(this.bbwi);
}
public static void printBuffer(ByteBufferWithInfo bbwi) {
System.out.println("+++++++ Output Buffer ++++++++");
System.out.println();
System.out.println("Current position: " + bbwi.position());
System.out.println("Total length : " + bbwi.buflen);
System.out.println();
char[] charBuf = new char[16];
try {
for (int i = 0; i < bbwi.position(); 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 < bbwi.position()) {
int k = bbwi.byteBuffer.get(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 < bbwi.position()) {
if (ORBUtility.isPrintable((char)bbwi.byteBuffer.get(i + x)))
charBuf[x] = (char)bbwi.byteBuffer.get(i + x);
else
charBuf[x] = '.';
x++;
}
System.out.println(new String(charBuf, 0, x));
}
} catch (Throwable t) {
t.printStackTrace();
}
System.out.println("++++++++++++++++++++++++++++++");
}
public void writeIndirection(int tag, int posIndirectedTo)
{
// Must ensure that there are no chunks between the tag
// and the actual indirection value. This isn't talked about
// in the spec, but seems to cause headaches in our code.
// At the very least, this method isolates the indirection code
// that was duplicated so often.
handleSpecialChunkBegin(computeAlignment(4) + 8);
// write indirection tag
write_long(tag);
// write indirection
// Use parent.getRealIndex() so that it can be overridden by TypeCodeOutputStreams
/*
System.out.println("CDROutputStream_1_0 writing indirection pos " + posIndirectedTo +
" - real index " + parent.getRealIndex(get_offset()) + " = " +
(posIndirectedTo - parent.getRealIndex(get_offset())));
*/
write_long(posIndirectedTo - parent.getRealIndex(get_offset()));
handleSpecialChunkEnd();
}
protected CodeSetConversion.CTBConverter getCharConverter() {
if (charConverter == null)
charConverter = parent.createCharCTBConverter();
return charConverter;
}
protected CodeSetConversion.CTBConverter getWCharConverter() {
if (wcharConverter == null)
wcharConverter = parent.createWCharCTBConverter();
return wcharConverter;
}
protected void dprint(String msg) {
if (debug)
ORBUtility.dprint(this, msg);
}
void alignOnBoundary(int octetBoundary) {
alignAndReserve(octetBoundary, 0);
}
public void start_value(String rep_id) {
if (debug) {
dprint("start_value w/ rep id "
+ rep_id
+ " called at pos "
+ get_offset()
+ " position "
+ bbwi.position());
}
if (inBlock)
end_block();
// Write value_tag
writeValueTag(true, true, null);
// Write rep. id
write_repositoryId(rep_id);
// Write Value chunk
end_flag--;
chunkedValueNestingLevel--;
// Make sure to chunk the custom data
start_block();
}
public void end_value() {
if (debug) {
dprint("end_value called at pos "
+ get_offset()
+ " position "
+ bbwi.position());
}
end_block();
writeEndTag(true);
// Check to see if we need to start another block for a
// possible outer value. Since we're in the stream
// format 2 custom type contained by another custom
// type, mustChunk should always be true.
//
// Here's why we need to open a continuation chunk:
//
// We need to enclose the default data of the
// next subclass down in chunks. There won't be
// an end tag separating the superclass optional
// data and the subclass's default data.
if (debug) {
dprint("mustChunk is " + mustChunk);
}
if (mustChunk) {
start_block();
}
}
public void close() throws IOException
{
// tell BufferManagerWrite to release any ByteBuffers
getBufferManager().close();
// It's possible bbwi.byteBuffer is shared between
// this OutputStream and an InputStream. Thus, we check
// if the Input/Output streams are using the same ByteBuffer.
// If they sharing the same ByteBuffer we need to ensure only
// one of those ByteBuffers are released to the ByteBufferPool.
if (getByteBufferWithInfo() != null && getByteBuffer() != null)
{
MessageMediator messageMediator = parent.getMessageMediator();
if (messageMediator != null)
{
CDRInputObject inputObj =
(CDRInputObject)messageMediator.getInputObject();
if (inputObj != null)
{
if (inputObj.isSharing(getByteBuffer()))
{
// Set InputStream's ByteBuffer and bbwi to null
// so its ByteBuffer cannot be released to the pool
inputObj.setByteBuffer(null);
inputObj.setByteBufferWithInfo(null);
}
}
}
// release this stream's ByteBuffer to the pool
ByteBufferPool byteBufferPool = orb.getByteBufferPool();
if (debug)
{
// print address of ByteBuffer being released
int bbAddress = System.identityHashCode(bbwi.byteBuffer);
StringBuffer sb = new StringBuffer(80);
sb.append(".close - releasing ByteBuffer id (");
sb.append(bbAddress).append(") to ByteBufferPool.");
String msg = sb.toString();
dprint(msg);
}
byteBufferPool.releaseByteBuffer(getByteBuffer());
bbwi.byteBuffer = null;
bbwi = null;
}
}
}