/**
*
* Copyright 2004-2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geronimo.interop.rmi.iiop;
import org.omg.CORBA.TCKind;
import org.apache.geronimo.interop.util.IntegerCache;
import org.apache.geronimo.interop.util.ArrayUtil;
import org.apache.geronimo.interop.SystemException;
import java.io.IOException;
import java.io.NotActiveException;
import java.io.ObjectStreamClass;
import java.util.HashMap;
import java.util.ArrayList;
import java.lang.reflect.Array;
/**
** TODO: package-private methods???
**/
public class ObjectInputStream extends java.io.ObjectInputStream
{
public static ObjectInputStream getInstance()
{
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream();
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
ois = null;
}
return ois;
}
public static ObjectInputStream getInstance(org.apache.geronimo.interop.rmi.iiop.CdrInputStream cdrInput)
{
ObjectInputStream input = getInstance();
input.init(cdrInput);
return input;
}
public static ObjectInputStream getPooledInstance()
{
ObjectInputStream input = null;
if (input == null)
{
input = getInstance();
}
return input;
}
// -----------------------------------------------------------------------
// inner classes
// -----------------------------------------------------------------------
protected static class StreamState
{
ValueType type;
Object value;
int offset;
StreamState(ValueType type, Object value, int offset)
{
this.type = type;
this.value = value;
this.offset = offset;
}
}
// -----------------------------------------------------------------------
// public data
// -----------------------------------------------------------------------
public static final int MAXIMUM_BLOCK_LENGTH = 0x7fffff00;
public CdrInputStream _cdrInput;
public Object[] thisAsObjectArray;
// -----------------------------------------------------------------------
// private data
// -----------------------------------------------------------------------
private int _blockLength = MAXIMUM_BLOCK_LENGTH;
private int _endLevel = 0;
private HashMap _indirection;
private boolean _isChunked = false;
private ArrayList _stack;
// -----------------------------------------------------------------------
// public methods
// -----------------------------------------------------------------------
public ObjectInputStream() throws IOException
{
}
public void $reset()
{
_cdrInput.reset();
if (_indirection != null)
{
_indirection.clear();
}
if (_stack != null)
{
_stack.clear();
}
_blockLength = MAXIMUM_BLOCK_LENGTH;
_endLevel = 0;
_isChunked = false;
}
public void recycle()
{
$reset();
}
// public methods from java.io.ObjectInputStream
public boolean readBoolean()
{
return _cdrInput.read_boolean();
}
public char readChar()
{
return _cdrInput.read_wchar();
}
public byte readByte()
{
return _cdrInput.read_octet();
}
public short readShort()
{
return _cdrInput.read_short();
}
public int readInt()
{
return _cdrInput.read_long();
}
public long readLong()
{
return _cdrInput.read_longlong();
}
public float readFloat()
{
return _cdrInput.read_float();
}
public double readDouble()
{
return _cdrInput.read_double();
}
public Object readObjectOverride()
{
return readObject(ValueType.OBJECT_VALUE_TYPE, true);
}
public void defaultReadObject() throws IOException, ClassNotFoundException, NotActiveException
{
StreamState state = top();
readDeclaredFields(state.type, state.value);
}
public java.io.ObjectInputStream.GetField readFields()
throws IOException, ClassNotFoundException
{
StreamState state = top();
Class currentClass = state.type.getTheClass();
if(currentClass == null)
{
throw new IOException("readFields: class from ValueType is null");
}
java.io.ObjectStreamClass osc = ObjectStreamClass.lookup(currentClass);
if(osc == null)
{
throw new IOException("readFields: ObjectSteamClass is null");
}
org.apache.geronimo.interop.rmi.iiop.GetField gf = new org.apache.geronimo.interop.rmi.iiop.GetField(osc);
gf.readFields(this);
return gf;
}
// -----------------------------------------------------------------------
// public methods used by generated and package-internal code
// -----------------------------------------------------------------------
public Exception readException(ValueType type)
{
return (Exception)readObject(type, false);
}
public Object readObject(ValueType type)
{
return readObject(type, false);
}
// -----------------------------------------------------------------------
// protected methods
// -----------------------------------------------------------------------
protected void init(org.apache.geronimo.interop.rmi.iiop.CdrInputStream cdrInput)
{
_cdrInput = cdrInput;
thisAsObjectArray = new Object[] { this };
}
protected void putIndirection(Integer key, Object value)
{
if (_indirection == null)
{
_indirection = new HashMap();
}
_indirection.put(key, value);
}
protected Object readObject(ValueType declaredType, boolean calledByCustomSerialization)
{
org.omg.CORBA.TypeCode tc = null;
if (calledByCustomSerialization)
{
boolean isObjectRef = _cdrInput.read_boolean();
if (isObjectRef)
{
org.omg.CORBA.Object ref = _cdrInput.read_Object();
endBlock();
if (_blockLength == MAXIMUM_BLOCK_LENGTH)
{
startBlock();
}
return ref;
}
}
int tag = _cdrInput.read_ulong();
int saveOffset = _cdrInput._offset - 4;
Object value;
if (tag == ValueType.INDIRECTION_TAG)
{
// Indirection to value already read (or cyclic value being read).
saveOffset = _cdrInput._offset;
int offset = _cdrInput.read_long();
Integer key = IntegerCache.get(saveOffset + offset);
if (_indirection != null)
{
value = _indirection.get(key);
if (value != null)
{
return value;
}
}
throw new org.omg.CORBA.MARSHAL("invalid indirection offset = " + offset);
}
else
{
_cdrInput._offset = saveOffset;
}
if(calledByCustomSerialization)
{
}
else if (declaredType.isAnyOrObjectRefOrAbstractInterface)
{
boolean isObjectRef = false;
if (declaredType.isObjectRef)
{
return _cdrInput.read_Object();
}
else if (declaredType.isAny)
{
tc = _cdrInput.read_TypeCode();
int kind = tc.kind().value();
if(kind == TCKind._tk_null)
{
return null;
}
if(kind == TCKind._tk_objref)
{
isObjectRef = true;
}
else if(kind == TCKind._tk_abstract_interface)
{
isObjectRef = _cdrInput.read_boolean();
}
if(isObjectRef)
{
saveOffset = _cdrInput._offset;
int checkValue = _cdrInput.read_ulong();
if(checkValue == 0)
{
return null;
}
_cdrInput._offset = saveOffset;
return _cdrInput.read_Object();
}
}
else if (declaredType.isAbstractInterface)
{
isObjectRef = _cdrInput.read_boolean();
if (isObjectRef)
{
return _cdrInput.read_Object();
}
}
else
{
throw new IllegalStateException(declaredType.toString());
}
}
tag = _cdrInput.read_long();
saveOffset = _cdrInput._offset - 4;
if (tag == ValueType.NULL_VALUE_TAG)
{
return null;
}
if( ((tag & 0x7F000000) == 0) && tag != ValueType.INDIRECTION_TAG ) //chunk size
{
tag = _cdrInput.read_long();
saveOffset = _cdrInput._offset - 4;
}
if (tag == ValueType.INDIRECTION_TAG)
{
// Indirection to value already read (or cyclic value being read).
saveOffset = _cdrInput._offset;
int offset = _cdrInput.read_long();
Integer key = IntegerCache.get(saveOffset + offset);
if (_indirection != null)
{
value = _indirection.get(key);
if (value != null)
{
return value;
}
}
throw new org.omg.CORBA.MARSHAL("invalid indirection offset = " + offset);
}
ValueType actualType;
boolean saveIsChunked = _isChunked;
_isChunked = (tag & 0x00000008) != 0;
String codebaseURL = null;
if ((tag & 0x00000001) == 1)
{
codebaseURL = readMetaString();
}
switch (tag & 0x00000006)
{
case 0: // NO_TYPE_VALUE_TAG
{
actualType = declaredType;
if (tc != null)
{
try
{
String id = tc.id();
if (id != null)
{
int kind = tc.kind().value();
if (kind == TCKind._tk_value_box)
{
kind = tc.content_type().kind().value();
if (kind == TCKind._tk_wstring)
{
actualType = ValueType.STRING_VALUE_TYPE;
}
}
}
}
catch (Exception ex)
{
throw new SystemException(ex);
}
}
}
break;
case 2: // SINGLE_TYPE_VALUE_TAG
{
String repositoryID = readMetaString();
// TODO requiresCustomSerialization = (Boolean)_specialCaseReposIds.get(repositoryID);
actualType = ValueType.getInstanceByID(repositoryID);
}
break;
case 6: // TYPE_LIST_VALUE_TAG
{
int n = _cdrInput.read_ulong();
if (n < 1)
{
throw new org.omg.CORBA.MARSHAL("invalid type list length = " + n);
}
String repositoryID = readMetaString();
// TODO requiresCustomSerialization = (Boolean)_specialCaseReposIds.get(repositoryID);
actualType = ValueType.getInstanceByID(repositoryID);
for (int i = 1; i < n; i++)
{
String ignore = readMetaString();
}
}
break;
default:
throw new org.omg.CORBA.MARSHAL("invalid value tag = " + tag);
}
if (actualType.isObjectRef)
{
value = actualType.helper.read(this);
return value;
}
startBlock();
if (_isChunked)
{
_endLevel--;
}
Integer key = new Integer(saveOffset);
switch (actualType.readWriteCase)
{
case ValueType.CASE_ARRAY:
value = readArray(actualType, key);
break;
case ValueType.CASE_CLASS:
value = readClassDesc();
putIndirection(key, value);
break;
case ValueType.CASE_IDL_ENTITY:
value = actualType.helper.read(this);
putIndirection(key, value);
break;
// case ValueType.CASE_IDL_OBJECT: // already handled above
case ValueType.CASE_STRING:
value = _cdrInput.read_wstring();
putIndirection(key, value);
break;
default:
value = actualType.newInstance();
putIndirection(key, value);
Object newValue = readObjectState(actualType, value, false); // requiresCustomSerialization);
if (newValue != value)
{
value = newValue;
putIndirection(key, value);
}
}
endBlock();
readEndTag();
_isChunked = saveIsChunked;
startBlock();
return value;
}
protected String readMetaString()
{
String id;
int saveOffset = _cdrInput._offset;
int tag = _cdrInput.read_long();
if (tag == ValueType.INDIRECTION_TAG)
{
saveOffset = _cdrInput._offset;
int offset = _cdrInput.read_long();
Integer key = IntegerCache.get(saveOffset + offset);
id = _indirection == null ? null : (String)_indirection.get(key);
if (id == null)
{
throw new org.omg.CORBA.MARSHAL("invalid indirection offset = " + offset);
}
}
else
{
_cdrInput._offset = saveOffset;
id = _cdrInput.read_string();
putIndirection(IntegerCache.get(saveOffset), id);
}
return id;
}
protected Object readObjectState(ValueType valueType, Object value, boolean requiresCustomSerialization)
{
if (valueType.isExternalizable)
{
byte format = _cdrInput.read_octet();
valueType.readExternal(value, this);
return value;
}
if (valueType.hasParentState)
{
value = readObjectState(valueType.parent, value, false);
}
if (valueType.hasWriteObject || requiresCustomSerialization)
{
byte format = _cdrInput.read_octet();
boolean defaultWriteObjectCalled = _cdrInput.read_boolean();
}
if (valueType.hasReadObject)
{
push(new StreamState(valueType, value, _cdrInput._offset));
/* TODO
if (repositoryID.equals(_SUN_JDK_BIG_DECIMAL_REPOSID))
{
// Sun's first field is an int
int scale = readInt();
// Sun's second field is a java.math.BigInteger
java.math.BigInteger intVal = (java.math.BigInteger)readObject(java.math.BigInteger.class);
// Create BigDecimal using scale and intVal
value = new java.math.BigDecimal(intVal, scale);
}
else if (repositoryID.equals(_IBM_JDK_BIG_DECIMAL_REPOSID))
{
byte format = _cdrInput.read_octet();
boolean defaultWriteObjectCalled = _cdrInput.read_boolean();
// IBM's first field is a long
long intLong = readLong();
// IBM's second field is a int
int scale = readInt();
// IBM's third field is a java.math.BigInteger
java.math.BigInteger intVal = (java.math.BigInteger)readObject(java.math.BigInteger.class);
// We can ignore the long, since IBM doesn't use it
// in the writeObject, to ensure backward's compatibility
// with their previous versions which don't have the long.
value = new java.math.BigDecimal(intVal, scale);
}
else
*/
{
valueType.readObject(value, this);
}
pop();
}
else
{
readDeclaredFields(valueType, value);
}
while (value != null && valueType.hasReadResolve)
{
value = valueType.readResolve(value);
if(value != null)
{
Class vc = value.getClass();
valueType = ValueType.getInstance(vc);
}
}
return value;
}
protected void readDeclaredFields(ValueType valueType, Object value)
{
int n = valueType.fields.length;
for (int f = 0; f < n; f++)
{
ValueTypeField field = valueType.fields[f];
int primitive = field.primitive;
if (primitive != 0)
{
readPrimitive(primitive, field, value);
}
else
{
field.set(value, readObject(field.type, false));
}
}
}
protected Object readClassDesc()
{
String codebase = (String)readObject(ValueType.STRING_VALUE_TYPE);
String id = (String)readObject(ValueType.STRING_VALUE_TYPE);
return ValueType.getInstanceByID(id)._class;
}
protected Object readArray(ValueType arrayType, Integer key)
{
Object value = null;
int primitive = arrayType.primitiveArray;
if (primitive != 0)
{
value = arrayType.helper.read(this);
putIndirection(key, value);
}
else
{
int n = _cdrInput.read_ulong();
Object[] array;
try
{
array = n == 0 ? ArrayUtil.EMPTY_OBJECT_ARRAY : (Object[])Array.newInstance(arrayType.element._class, n);
}
catch (Exception ex)
{
throw new SystemException(ex);
}
putIndirection(key, array);
for (int i = 0; i < n; i++)
{
array[i] = readObject(arrayType.element, false);
}
value = array;
}
return value;
}
private void readPrimitive(int primitive, ValueTypeField field, Object value)
{
switch (primitive)
{
case PrimitiveType.BOOLEAN:
field.setBoolean(value, _cdrInput.read_boolean());
break;
case PrimitiveType.BYTE:
field.setByte(value, _cdrInput.read_octet());
break;
case PrimitiveType.CHAR:
field.setChar(value, _cdrInput.read_wchar());
break;
case PrimitiveType.DOUBLE:
field.setDouble(value, _cdrInput.read_double());
break;
case PrimitiveType.FLOAT:
field.setFloat(value, _cdrInput.read_float());
break;
case PrimitiveType.INT:
field.setInt(value, _cdrInput.read_long());
break;
case PrimitiveType.LONG:
field.setLong(value, _cdrInput.read_longlong());
break;
case PrimitiveType.SHORT:
field.setShort(value, _cdrInput.read_short());
break;
default:
throw new IllegalStateException();
}
}
/**
** This method handle end tag compaction. Note that it is lazy in the
** sense that it always assumes a tag has been compacted if the end tag
** is not what it expected.
**/
protected void readEndTag()
{
if (_isChunked)
{
int anEndTag = _cdrInput.read_long();
if (anEndTag != _endLevel)
{
_cdrInput._offset -= 4;
}
_endLevel++;
}
}
protected void startBlock()
{
if (! _isChunked)
{
return;
}
_blockLength = _cdrInput.read_long();
if (_blockLength >= 0
&& _blockLength < MAXIMUM_BLOCK_LENGTH)
{
_blockLength += _cdrInput._offset;
}
else
{
// Not a chunk length field.
_blockLength = MAXIMUM_BLOCK_LENGTH;
_cdrInput._offset -= 4;
}
}
protected void endBlock()
{
// If in a chunk, check for underflow or overflow.
if (_blockLength != MAXIMUM_BLOCK_LENGTH)
{
if (_blockLength == _cdrInput._offset)
{
// Chunk ended correctly.
_blockLength = MAXIMUM_BLOCK_LENGTH;
}
}
}
protected void push(StreamState state)
{
if (_stack == null)
{
_stack = new ArrayList();
}
_stack.add(state);
}
protected void pop()
{
int n = _stack.size();
if (n == 0)
{
throw new SystemException("pop: state stack empty");
}
_stack.remove(n - 1);
}
protected StreamState top()
{
int n = _stack.size();
if (n == 0)
{
throw new SystemException("top: state stack empty");
}
return (StreamState)_stack.get(n - 1);
}
}