blob: e6aa2af62241192b6e8a8229305a65586b23e7d9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.yoko.orb.OB;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.rmi.CORBA.ValueHandler;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.WStringValueHelper;
import org.omg.CORBA.portable.IndirectionException;
import org.omg.CORBA.portable.StreamableValue;
import org.omg.SendingContext.CodeBase;
final public class ValueReader {
static final Logger logger = Logger.getLogger(ValueReader.class.getName());
//
// Chunk data
//
static private class ChunkState {
boolean chunked;
int nestingLevel;
int chunkStart;
int chunkSize;
ChunkState() {
}
ChunkState(ChunkState s) {
copyFrom(s);
}
void copyFrom(ChunkState s) {
chunked = s.chunked;
nestingLevel = s.nestingLevel;
chunkStart = s.chunkStart;
chunkSize = s.chunkSize;
}
}
//
// Valuetype header data
//
static private class Header {
int tag;
int headerPos;
int dataPos;
String[] ids;
final ChunkState state;
Header next; // Java only
String codebase; // Java only
Header() {
ids = new String[0];
state = new ChunkState();
}
boolean isRMIValue () {
return ids != null
&& ids.length > 0
&& ids[0].startsWith ("RMI:");
}
}
private org.apache.yoko.orb.OB.ORBInstance orbInstance_;
private org.apache.yoko.orb.CORBA.InputStream in_;
private org.apache.yoko.orb.OCI.Buffer buf_;
private java.util.Hashtable instanceTable_;
private java.util.Hashtable headerTable_;
private java.util.Hashtable positionTable_ = null;
private ChunkState chunkState_ = new ChunkState();
private Header currentHeader_ = null; // Java only
private ValueHandler valueHandler;
private org.omg.SendingContext.CodeBase remoteCodeBase;
// ------------------------------------------------------------------
// Valuetype creation strategies
// ------------------------------------------------------------------
private static abstract class CreationStrategy {
protected ValueReader reader_;
protected org.apache.yoko.orb.CORBA.InputStream is_;
CreationStrategy(ValueReader reader,
org.apache.yoko.orb.CORBA.InputStream is) {
reader_ = reader;
is_ = is;
}
abstract java.io.Serializable create(Header h);
}
//
// Create a valuebox using a BoxedValueHelper
//
private static class BoxCreationStrategy extends CreationStrategy {
private org.omg.CORBA.portable.BoxedValueHelper helper_;
BoxCreationStrategy(ValueReader reader,
org.apache.yoko.orb.CORBA.InputStream is,
org.omg.CORBA.portable.BoxedValueHelper helper) {
super(reader, is);
helper_ = helper;
}
java.io.Serializable create(Header h) {
Assert._OB_assert(h.tag >= 0x7fffff00 && h.tag != -1);
java.io.Serializable result = helper_.read_value(is_);
if (result != null) {
reader_.addInstance(h.headerPos, result);
return result;
}
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory)
+ ": " + helper_.get_id(), org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
}
//
// Create a value using a class
//
private static class ClassCreationStrategy extends CreationStrategy {
private Class clz_;
ClassCreationStrategy(ValueReader reader,
org.apache.yoko.orb.CORBA.InputStream is, Class clz) {
super(reader, is);
clz_ = clz;
}
java.io.Serializable create(Header h) {
logger.fine("Creating a value object with tag value " + Integer.toHexString(h.tag));
Assert._OB_assert(h.tag >= 0x7fffff00 && h.tag != -1);
if (h.isRMIValue()) {
return reader_.readRMIValue(h, clz_, h.ids[0]);
}
java.io.Serializable result = null;
try {
result = (java.io.Serializable) clz_.newInstance();
reader_.addInstance(h.headerPos, result);
try {
reader_.unmarshalValueState(result);
} catch (org.omg.CORBA.SystemException ex) {
reader_.removeInstance(h.headerPos);
throw ex;
}
return result;
} catch (ClassCastException ex) {
} catch (IllegalAccessException ex) {
} catch (InstantiationException ex) {
}
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory)
+ ": " + clz_.getName(), org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
}
//
// Create a value using a factory
//
private class FactoryCreationStrategy extends CreationStrategy {
private String id_;
private ORBInstance orbInstance_;
FactoryCreationStrategy(ValueReader reader,
org.apache.yoko.orb.CORBA.InputStream is, String id) {
super(reader, is);
id_ = id;
orbInstance_ = is._OB_ORBInstance();
}
private org.omg.CORBA.portable.ValueFactory findFactory(Header h,
org.omg.CORBA.StringHolder id) {
org.omg.CORBA.portable.ValueFactory f = null;
if (orbInstance_ != null) {
ValueFactoryManager manager = orbInstance_.getValueFactoryManager();
if (h.ids.length > 0) {
for (int i = 0; i < h.ids.length; i++) {
f = manager.lookupValueFactoryWithClass(h.ids[i]);
if (f != null) {
id.value = h.ids[i];
break;
}
//
// If we have a formal ID, and we haven't found
// a factory yet, then give up
//
if (id_ != null && h.ids[i].equals(id_))
break;
}
} else if (id_ != null) {
f = manager.lookupValueFactoryWithClass(id_);
id.value = id_;
}
}
return f;
}
private java.io.Serializable createWithFactory(Header h,
org.omg.CORBA.portable.ValueFactory factory) {
//
// The factory's read_value method is expected to create
// an instance of the valuetype and then call the method
// InputStream.read_value(java.io.Serializable) to read
// the valuetype state. We use a stack to remember the
// Header information for use by initializeValue(), which
// is called by read_value().
//
try {
reader_.pushHeader(h);
return factory.read_value(is_);
} finally {
reader_.popHeader();
}
}
private org.omg.CORBA.portable.BoxedValueHelper getBoxedHelper(String id) {
org.omg.CORBA.portable.BoxedValueHelper result = null;
Class helperClass = Util.idToClass(id, "Helper");
if (helperClass != null) {
try {
return (org.omg.CORBA.portable.BoxedValueHelper) helperClass
.newInstance();
} catch (ClassCastException ex) {
} catch (IllegalAccessException ex) {
} catch (InstantiationException ex) {
}
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory)
+ ": invalid BoxedValueHelper for " + id,
org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
return null;
}
java.io.Serializable create(Header h) {
org.omg.CORBA.StringHolder idH = new org.omg.CORBA.StringHolder();
return create(h, idH);
}
java.io.Serializable create(Header h, org.omg.CORBA.StringHolder id) {
Assert._OB_assert(h.tag >= 0x7fffff00 && h.tag != -1);
if (h.isRMIValue ()) {
Serializable result = readRMIValue (h, null, h.ids[0]);
addInstance (h.headerPos, result);
return result;
}
//
// See if a factory exists that can create the value
//
org.omg.CORBA.portable.ValueFactory factory = findFactory(h, id);
if (factory != null) {
java.io.Serializable result = createWithFactory(h, factory);
reader_.addInstance(h.headerPos, result);
return result;
}
//
// Another possibility is that we're unmarshalling a valuebox,
// so we'll try to load the Helper class dynamically
//
org.omg.CORBA.portable.BoxedValueHelper helper = null;
if (h.ids.length > 0) {
//
// If it's a valuebox, at most one id will be marshalled
//
helper = getBoxedHelper(h.ids[0]);
if (helper != null)
id.value = h.ids[0];
}
if (helper == null && id_ != null) {
helper = getBoxedHelper(id_);
if (helper != null)
id.value = id_;
}
if (helper != null) {
java.io.Serializable result = helper.read_value(is_);
reader_.addInstance(h.headerPos, result);
return result;
}
String type = "<unknown>";
if (h.ids.length > 0)
type = h.ids[0];
else if (id_ != null)
type = id_;
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory)
+ ": " + type, org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
}
// ------------------------------------------------------------------
// Private and protected members
// ------------------------------------------------------------------
// Java only
private void addInstance(int pos, java.io.Serializable instance) {
// only add this if we have a real value
if (instance != null) {
instanceTable_.put(new Integer(pos), instance);
}
}
// Java only
private void removeInstance(int pos) {
instanceTable_.remove(new Integer(pos));
}
private void readHeader(Header h) {
logger.fine("Reading header with tag value " + Integer.toHexString(h.tag) + " at pos="
+ in_.buf_.pos_);
//
// Special cases are handled elsewhere
//
Assert._OB_assert(h.tag != 0 && h.tag != -1);
//
// Check if the value is chunked
//
if ((h.tag & 0x00000008) == 8) {
h.state.chunked = true;
} else {
h.state.chunked = false;
}
//
// Check for presence of codebase URL
//
if ((h.tag & 0x00000001) == 1) {
//
// Check for indirection tag
//
int save = buf_.pos_;
int indTag = in_.read_long();
if (indTag == -1) {
int offs = in_.read_long();
if (offs >= -4) {
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection),
org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
int tmp = buf_.pos_;
buf_.pos_ = buf_.pos_ - 4 + offs;
if (buf_.pos_ < 0) {
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection),
org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
h.codebase = in_.read_string();
buf_.pos_ = tmp;
} else {
buf_.pos_ = save;
h.codebase = in_.read_string();
}
logger.finer("Value header codebase value is " + h.codebase);
}
//
// Extract repository ID information
//
if ((h.tag & 0x00000006) == 0) {
logger.finer("No type information was included");
//
// No type information was marshalled
//
} else if ((h.tag & 0x00000006) == 6) {
logger.finer("Multiple types included in header");
//
// Extract a list of repository IDs, representing the
// truncatable types for this value
//
//
// Check for indirection tag (indirected list)
//
int saveList = buf_.pos_;
int indTag = in_.read_long();
boolean indList = (indTag == -1);
if (indList) {
int offs = in_.read_long();
if (offs > -4) {
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection),
org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
saveList = buf_.pos_;
buf_.pos_ = buf_.pos_ - 4 + offs;
if (buf_.pos_ < 0) {
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection),
org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
} else
buf_.pos_ = saveList;
int count = in_.read_long();
h.ids = new String[count];
for (int i = 0; i < count; i++) {
//
// Check for indirection tag (indirected list entry)
//
int saveRep = buf_.pos_;
indTag = in_.read_long();
if (indTag == -1) {
int offs = in_.read_long();
if (offs > -4) {
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection),
org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
saveRep = buf_.pos_;
buf_.pos_ = buf_.pos_ - 4 + offs;
if (buf_.pos_ < 0) {
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection),
org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
h.ids[i] = in_.read_string();
buf_.pos_ = saveRep;
} else {
buf_.pos_ = saveRep;
h.ids[i] = in_.read_string();
}
logger.finer("Value header respoitory id added " + h.ids[i]);
}
//
// Restore buffer position (case of indirected list)
//
if (indList)
buf_.pos_ = saveList;
} else if ((h.tag & 0x00000006) == 2) {
//
// Extract a single repository ID
//
String id;
//
// Check for indirection tag
//
int save = buf_.pos_;
int indTag = in_.read_long();
if (indTag == -1) {
int offs = in_.read_long();
if (offs > -4) {
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection),
org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
save = buf_.pos_;
buf_.pos_ = buf_.pos_ - 4 + offs;
if (buf_.pos_ < 0) {
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection),
org.apache.yoko.orb.OB.MinorCodes.MinorReadInvalidIndirection,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
id = in_.read_string();
buf_.pos_ = save;
} else {
buf_.pos_ = save;
id = in_.read_string();
}
h.ids = new String[1];
h.ids[0] = id;
logger.finer("Single header repository id read " + id);
}
//
// Record beginning of value data
//
h.dataPos = buf_.pos_;
//
// Add entry to header table
//
headerTable_.put(new Integer(h.headerPos), h);
}
private void readChunk(ChunkState state) {
//
// Check for a chunk size
//
int size = in_._OB_readLongUnchecked();
logger.finest("Reading new chunk. Size value is " + Integer.toHexString(size) + " current nest is " + state.nestingLevel + " current position=" + buf_.pos_);
if (size >= 0 && size < 0x7fffff00) // chunk size
{
state.chunkStart = buf_.pos_;
state.chunkSize = size;
} else if (size < 0) // end tag
{
buf_.pos_ -= 4; // rewind
state.chunkStart = buf_.pos_;
state.chunkSize = 0;
} else {
buf_.pos_ -= 4; // rewind
state.chunkStart = 0;
state.chunkSize = 0;
}
logger.finest("Chunk read. start=" + state.chunkStart + ", size=" + state.chunkSize + " buffer position=" + buf_.pos_);
}
private void initHeader(Header h) {
//
// Null values and indirections must be handled by caller
//
Assert._OB_assert(h.tag != 0 && h.tag != -1);
h.headerPos = buf_.pos_ - 4; // adjust for alignment
h.state.copyFrom(chunkState_);
//
// Read value header info
//
readHeader(h);
chunkState_.copyFrom(h.state);
//
// Increment our nesting level if we are chunked
//
if (chunkState_.chunked) {
// logger.finest("Reading chunk for chunked value. Header tag=" + Integer.toHexString(h.tag) + " current position=" + buf_.pos_);
readChunk(chunkState_);
chunkState_.nestingLevel++;
// logger.fine("Chunk nesting level is " + chunkState_.nestingLevel + " current position=" + buf_.pos_ + " chunk size=" + chunkState_.chunkSize);
}
}
private void skipChunk() {
if (chunkState_.chunked) {
logger.fine("Skipping a chunked value. nesting level=" + chunkState_.nestingLevel + " current position is " + buf_.pos_ + " chunk end is " + (chunkState_.chunkStart + chunkState_.chunkSize));
//
// At this point, the unmarshalling code has finished. However,
// we may have a truncated value, or we may have unmarshalled a
// custom value. In either case, we can't be sure that the
// unmarshalling code has positioned the stream at the end of
// this value.
//
// Therefore we will advance, chunk by chunk, until we reach
// the end of the value.
//
//
// Skip to the end of the current chunk (if necessary)
//
if (chunkState_.chunkStart > 0) {
buf_.pos_ = chunkState_.chunkStart;
in_._OB_skip(chunkState_.chunkSize);
logger.finest("Skipping to end of current chunk. New position is " + buf_.pos_);
}
chunkState_.chunkStart = 0;
chunkState_.chunkSize = 0;
//
// Loop until we have reached the end of this value. We may
// have to process nested values, chunks, etc.
//
int level = chunkState_.nestingLevel;
int tag = in_._OB_readLongUnchecked();
logger.finest("Skipping chunk: read tag value =" + tag);
while (tag >= 0 || (tag < 0 && tag < -chunkState_.nestingLevel)) {
if (tag >= 0x7fffff00) {
logger.finest("Skipping chunk: reading a nested chunk value");
//
// This indicates a nested value. We read the header
// information and store it away, in case a subsequent
// indirection refers to this value.
//
level++;
Header nest = new Header();
nest.tag = tag;
nest.headerPos = buf_.pos_ - 4; // adjust for alignment
nest.state.nestingLevel = level;
readHeader(nest);
} else if (tag >= 0) {
logger.finest("Skipping chunk: skipping over a chunk for length " +tag);
//
// Chunk size - advance the stream past the chunk
//
in_._OB_skip(tag);
} else {
logger.finest("Skipping chunk: chunk end tag=" + Integer.toHexString(tag) + " current level=" + level);
//
// tag is less than 0, so this is an end tag for a nested
// value
//
// this can terminate more than a single level.
level = (-tag) - 1;
}
//
// Read the next tag
//
tag = in_._OB_readLongUnchecked();
logger.finest("Skipping chunk: read tag value =" + tag);
}
//
// If the tag is greater than our nesting level, then this
// value coterminates with an outer value. We rewind the
// stream so that the outer value can read this tag.
//
if (tag > -chunkState_.nestingLevel) {
buf_.pos_ -= 4;
}
chunkState_.nestingLevel--;
logger.finest("New chunk nesting level is " + chunkState_.nestingLevel);
if (chunkState_.nestingLevel == 0) {
chunkState_.chunked = false;
}
else {
//
// We're chunked and still processing nested values, so
// another chunk may follow
//
logger.finest("Reading chunk for skipping to end of a chunk");
readChunk(chunkState_);
}
logger.finest("Final chunk state is nesting level=" + chunkState_.nestingLevel + " current position is " + buf_.pos_ + " chunk end is " + (chunkState_.chunkStart + chunkState_.chunkSize));
}
}
//
// Invoke the valuetype to unmarshal its state
//
// Java only
//
private void unmarshalValueState(java.io.Serializable v) {
if (v instanceof org.omg.CORBA.portable.StreamableValue) {
((org.omg.CORBA.portable.StreamableValue) v)._read(in_);
}
else if (v instanceof org.omg.CORBA.CustomMarshal) {
org.omg.CORBA.DataInputStream dis = new org.apache.yoko.orb.CORBA.DataInputStream(
in_);
((org.omg.CORBA.CustomMarshal) v).unmarshal(dis);
} else {
throw new org.omg.CORBA.MARSHAL("Valuetype does not implement "
+ "StreamableValue or " + "CustomMarshal");
}
}
private java.io.Serializable readIndirection(CreationStrategy strategy) {
int offs = in_.read_long();
int pos = buf_.pos_ - 4 + offs;
pos += 3; // adjust for alignment
pos -= (pos & 0x3);
Integer posObj = new Integer(pos);
//
// Check the history for a value that was seen at the specified
// position. Generally, we should expect the value to be present.
// However, in the case of chunking, it's possible for an
// indirection to refer to a nested value in the truncated state
// of an enclosing value, or to a value that we could not
// instantiate.
//
java.io.Serializable v = (java.io.Serializable) instanceTable_
.get(posObj);
if (v != null) {
return v;
} else {
int save = buf_.pos_;
//
// Check for indirection to null value
//
buf_.pos_ = pos; // rewind to offset position
if (in_._OB_readLongUnchecked() == 0) {
buf_.pos_ = save;
// Can't put a null in a Hashtable
// instanceTable_.put(posObj, null);
return null;
}
//
// If it's not null and it's not in our history, then
// there's no hope
//
Header nest = (Header) headerTable_.get(posObj);
if (nest == null)
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory)
+ ": cannot instantiate value for indirection",
org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
/* Maybe we have an indirection to an object
* that is being deserialized. We throw an
* IndirectionException which signals the RMI
* implementation to handle the indirection.
*/
if(nest.isRMIValue()) {
buf_.pos_ = save;
throw new IndirectionException(pos);
}
//
// Create the value
//
buf_.pos_ = nest.dataPos;
ChunkState saveState = new ChunkState(chunkState_);
chunkState_.copyFrom(nest.state);
if (chunkState_.chunked)
// logger.finest("Reading chunk in readIndirection()");
readChunk(chunkState_);
try {
v = strategy.create(nest);
} finally {
//
// Restore state
//
buf_.pos_ = save;
chunkState_.copyFrom(saveState);
}
return v;
}
}
private java.io.Serializable read(CreationStrategy strategy) {
Header h = new Header();
h.tag = in_.read_long();
// logger.fine("Read tag value " + Integer.toHexString(h.tag));
if (h.tag == 0) {
return null;
} else if (h.tag == -1) {
return readIndirection(strategy);
} else if (h.tag < 0x7fffff00) {
throw new org.omg.CORBA.MARSHAL("Illegal valuetype tag 0x"
+ Integer.toHexString(h.tag));
} else {
initHeader(h);
java.io.Serializable vb = strategy.create(h);
skipChunk();
return vb;
}
}
//
// Remarshal each valuetype member
//
private void copyValueState(org.omg.CORBA.TypeCode tc, org.apache.yoko.orb.CORBA.OutputStream out) {
try {
if (tc.kind() == org.omg.CORBA.TCKind.tk_value) {
//
// First copy the state of the concrete base type, if any
//
org.omg.CORBA.TypeCode base = tc.concrete_base_type();
if (base != null) {
copyValueState(base, out);
}
for (int i = 0; i < tc.member_count(); i++) {
// logger.fine("writing member of typecode " + tc.member_type(i).kind().value());
out.write_InputStream(in_, tc.member_type(i));
}
} else if (tc.kind() == org.omg.CORBA.TCKind.tk_value_box) {
out.write_InputStream(in_, tc.content_type());
} else
Assert._OB_assert(false);
} catch (org.omg.CORBA.TypeCodePackage.BadKind ex) {
logger.log(Level.FINER, "Invalid type kind", ex);
Assert._OB_assert(ex);
} catch (org.omg.CORBA.TypeCodePackage.Bounds ex) {
logger.log(Level.FINER, "Invalid type kind", ex);
Assert._OB_assert(ex);
}
}
// Java only
private void pushHeader(Header h) {
h.next = currentHeader_;
currentHeader_ = h;
}
// Java only
private void popHeader() {
Assert._OB_assert(currentHeader_ != null);
currentHeader_ = currentHeader_.next;
}
//
// Search up the valuetype's inheritance hierarchy for a TypeCode
// with the given repository ID
//
private org.omg.CORBA.TypeCode findTypeCode(String id,
org.omg.CORBA.TypeCode tc) {
org.omg.CORBA.TypeCode result = null;
org.omg.CORBA.TypeCode t = tc;
// logger.finer("Locating type code for id " + id);
while (result == null) {
try {
org.omg.CORBA.TypeCode t2 = org.apache.yoko.orb.CORBA.TypeCode
._OB_getOrigType(t);
// logger.finer("Checking typecode " + id + " against " + t2.id());
if (id.equals(t2.id())) {
result = t;
} else if (t2.kind() == org.omg.CORBA.TCKind.tk_value
&& t2.type_modifier() == org.omg.CORBA.VM_TRUNCATABLE.value) {
t = t2.concrete_base_type();
// logger.finer("Iterating with concrete type " + t.id());
} else {
break;
}
} catch (org.omg.CORBA.TypeCodePackage.BadKind ex) {
Assert._OB_assert(ex);
}
}
return result;
}
// ------------------------------------------------------------------
// Public methods
// ------------------------------------------------------------------
public ValueReader(org.apache.yoko.orb.CORBA.InputStream in) {
in_ = in;
buf_ = in._OB_buffer();
orbInstance_ = in._OB_ORBInstance();
instanceTable_ = new java.util.Hashtable(131);
headerTable_ = new java.util.Hashtable(131);
}
java.io.Serializable readRMIValue(Header h, Class clz, String repid)
{
logger.fine("Reading RMI value of type " + repid);
if (valueHandler == null) {
valueHandler = javax.rmi.CORBA.Util.createValueHandler ();
}
if (repid == null) {
repid = h.ids[0];
if (repid == null) {
throw new org.omg.CORBA.MARSHAL("missing repository id");
}
}
String className = Util.idToClassName (repid, "");
String codebase = h.codebase;
Class repoClass = null;
if (codebase == null) {
codebase = in_.__getCodeBase ();
}
repoClass = resolveRepoClass(className, codebase);
// if we have a non-null codebase and can't resolve this, throw an
// exception now. Otherwise, we'll try again after grabbing the remote
// codebase.
if (repoClass == null && codebase != null && codebase.length() > 0) {
throw new org.omg.CORBA.MARSHAL("class "+className
+" not found (cannot load from "+codebase+")");
}
if (remoteCodeBase == null) {
remoteCodeBase = in_.__getSendingContextRuntime ();
}
if (repoClass == null) {
if (codebase == null && remoteCodeBase != null) {
try {
codebase = remoteCodeBase.implementation (repid);
} catch (org.omg.CORBA.SystemException ex) {
// ignore
}
}
if (codebase == null) {
// TODO: add minor code
throw new org.omg.CORBA.MARSHAL
("class "+className+" not found (no codebase provided)");
} else {
repoClass = resolveRepoClass(className, codebase);
if (repoClass == null) {
throw new org.omg.CORBA.MARSHAL("class "+className+" not found (cannot load from " + codebase+ ")");
}
}
}
/* Suns crappy ValueHandler implementation narrows the remote CodeBase
* to a com.sun.org.omg.SendingContext.CodeBase.
* Narrowing CodeBaseProxy is not possible, we
* need a stub.
*/
if (remoteCodeBase instanceof CodeBaseProxy) {
remoteCodeBase = ((CodeBaseProxy) remoteCodeBase).getCodeBase();
}
java.io.Serializable serobj = null;
try {
serobj = valueHandler.readValue(in_, h.headerPos, repoClass, repid, remoteCodeBase);
} catch (RuntimeException ex) {
logger.log(Level.FINE, "RuntimeException happens when reading GIOP stream coming to pos_=" + in_.buf_.pos_);
logger.log(Level.FINE, "Wrong data section: \n" + in_.dumpData());
int currentpos = in_.buf_.pos_;
in_.buf_.pos_ = 0;
logger.log(Level.FINE, "Full GIOP stream dump: \n" + in_.dumpData());
in_.buf_.pos_ = currentpos;
throw ex;
}
return serobj;
}
private Class resolveRepoClass(String name, String codebase)
{
logger.fine("Attempting to resolve class " + name + " from codebase " + codebase);
if (name.startsWith("[")) {
int levels = 0;
for (int i = 0; name.charAt(i) == '['; i++) {
levels++;
}
Class elementClass = null;
// now resolve the element descriptor to a class
switch (name.charAt(levels)) {
case 'Z':
elementClass = Boolean.TYPE;
break;
case 'B':
elementClass = Byte.TYPE;
break;
case 'S':
elementClass = Short.TYPE;
break;
case 'C':
elementClass = Character.TYPE;
break;
case 'I':
elementClass = Integer.TYPE;
break;
case 'J':
elementClass = Long.TYPE;
break;
case 'F':
elementClass = Float.TYPE;
break;
case 'D':
elementClass = Double.TYPE;
break;
case 'L':
// extract the class from the name and resolve that.
elementClass = resolveRepoClass(name.substring(levels + 1, name.indexOf(';')), codebase);
if (elementClass == null) {
return null;
}
break;
}
// ok, we need to recurse and resolve the base array element class
Object arrayInstance = null;
// this is easier with a single level
if (levels == 1) {
arrayInstance = Array.newInstance(elementClass, 0);
}
else {
// all elements will be zero
int[] dimensions = new int[levels];
arrayInstance = Array.newInstance(elementClass, dimensions);
}
// return the class associated with this array
return arrayInstance.getClass();
}
else {
try
{
return javax.rmi.CORBA.Util.loadClass(name, codebase,
Util.getContextClassLoader());
}
catch (ClassNotFoundException ex)
{
// this will be sorted out later
return null;
}
}
}
public java.io.Serializable readValue() {
FactoryCreationStrategy strategy = new FactoryCreationStrategy(this,
in_, null);
return read(strategy);
}
public java.io.Serializable readValue(String id) {
logger.fine("Reading value of type " + id);
FactoryCreationStrategy strategy = new FactoryCreationStrategy(this,
in_, id);
return read(strategy);
}
public java.io.Serializable readValue(Class clz) {
logger.fine("Reading value of type " + clz.getName());
if(clz.equals(String.class)) {
return WStringValueHelper.read(in_);
}
ClassCreationStrategy strategy = new ClassCreationStrategy(this, in_,
clz);
java.io.Serializable result = null;
try {
result = read(strategy);
} catch (org.omg.CORBA.MARSHAL marshalex) {
logger.severe(marshalex.getMessage() + " at pos=" + (in_.buf_.pos_- 4));
if (System.getProperty("org.apache.yoko.ignoreInvalidValueTag").equalsIgnoreCase("true")) {
result = read(strategy);
} else {
throw marshalex;
}
}
return result;
}
public java.io.Serializable readValueBox(
org.omg.CORBA.portable.BoxedValueHelper helper) {
BoxCreationStrategy strategy = new BoxCreationStrategy(this, in_,
helper);
return read(strategy);
}
public void initializeValue(java.io.Serializable value) {
//
// We should have previously pushed a Header on the stack
//
Assert._OB_assert(currentHeader_ != null);
//
// Now that we have an instance, we can put it in our history
//
addInstance(currentHeader_.headerPos, value);
//
// Unmarshal the value's state
//
try {
unmarshalValueState(value);
} catch (org.omg.CORBA.SystemException ex) {
removeInstance(currentHeader_.headerPos);
throw ex;
}
}
public java.lang.Object readAbstractInterface() {
//
// Abstract interfaces are marshalled like a union with a
// boolean discriminator - if true, an objref follows,
// otherwise a valuetype follows
//
if (in_.read_boolean())
return in_.read_Object();
else
return readValue();
}
public java.lang.Object readAbstractInterface(Class clz) {
//
// Abstract interfaces are marshalled like a union with a
// boolean discriminator - if true, an objref follows,
// otherwise a valuetype follows
//
if (in_.read_boolean())
return in_.read_Object(clz);
else
return readValue(clz);
}
//
// Copy a value from out InputStream to the given OutputStream.
// The return value is the most-derived TypeCode of the value
// written to the stream. This may not be the same as the TypeCode
// argument if the value is truncated. Furthermore, the TypeCode
// may not represent the actual most-derived type, since a more-derived
// value may have been read.
//
public org.omg.CORBA.TypeCode remarshalValue(org.omg.CORBA.TypeCode tc,
org.apache.yoko.orb.CORBA.OutputStream out) {
//
// TODO: We've removed the reset of the position table at each top
// level call. We need to perform more testing and analysis to verify
// that this wasn't broken. remarshalDepth was also removed since it
// wasn't being used anywhere except to determine when the table should
// be reset.
//
//
// Create a new Hashtable for each top-level call to remarshalValue
//
if (positionTable_ == null) {
positionTable_ = new java.util.Hashtable(131);
}
org.omg.CORBA.TypeCode origTC = org.apache.yoko.orb.CORBA.TypeCode
._OB_getOrigType(tc);
org.omg.CORBA.TypeCode result = null;
Header h = new Header();
h.tag = in_.read_long();
logger.fine("Read tag value " + Integer.toHexString(h.tag));
h.headerPos = buf_.pos_ - 4; // adjust for alignment
h.state.copyFrom(chunkState_);
//
// Remember starting position of this valuetype
//
int pos = h.headerPos;
//
// Check for special cases (null values and indirections)
//
if (h.tag == 0) {
out.write_long(0);
result = tc;
} else if (h.tag == -1) {
//
// Since offsets can change as we remarshal valuetypes to the
// output stream, we use a table to map old positions to new ones
//
int offs = in_.read_long();
int oldPos = buf_.pos_ - 4 + offs;
oldPos += 3; // adjust alignment to start of value
oldPos -= (oldPos & 0x3);
//
// If we find the position in the table, write the translated
// offset to the output stream. Otherwise, the indirection refers
// to a valuetype that we were unable to create and we therefore
// raise MARSHAL.
//
Integer newPos = (Integer) positionTable_.get(new Integer(oldPos));
if (newPos != null) {
out.write_long(h.tag);
offs = newPos.intValue() - out._OB_pos();
out.write_long(offs);
//
// TODO: The TypeCode may not necessarily reflect the
// TypeCode of the indirected value.
//
result = tc;
} else
throw new org.omg.CORBA.MARSHAL(
"Cannot find value for indirection");
} else {
if (h.tag < 0x7fffff00) {
throw new org.omg.CORBA.MARSHAL("Illegal valuetype tag 0x" + Integer.toHexString(h.tag));
}
logger.fine("Remarshalling header with tag value " + h.tag);
//
// Add valuetype to position map
//
int outPos = out._OB_pos();
outPos += 3; // adjust alignment to start of value
outPos -= (outPos & 0x3);
positionTable_.put(new Integer(pos), new Integer(outPos));
//
// Read value header info
//
readHeader(h);
chunkState_.copyFrom(h.state);
if (chunkState_.chunked) {
logger.finest("Reading chunk in remarshal value()");
readChunk(chunkState_);
chunkState_.nestingLevel++;
}
String tcId = null;
short mod = org.omg.CORBA.VM_NONE.value;
int idPos;
try {
tcId = origTC.id();
if (origTC.kind() == org.omg.CORBA.TCKind.tk_value)
mod = origTC.type_modifier();
} catch (org.omg.CORBA.TypeCodePackage.BadKind ex) {
Assert._OB_assert(ex);
}
//
// We have two methods of extracting the state of a valuetype:
//
// 1) Use the TypeCode
// 2) Use a valuetype factory
//
// Which method we use is determined by the repository IDs
// in the valuetype header.
//
// Our goal is to preserve as much information as possible.
// If the TypeCode describes a more-derived type than any
// available factory, we will use the TypeCode. Otherwise,
// we use a factory to create a temporary instance of the
// valuetype, and subsequently marshal that instance to the
// OutputStream.
//
logger.fine("Attempting to resolve typeId " + tcId);
//
// See if the TypeCode ID matches any of the valuetype's IDs -
// stop at the first match
//
String id = null;
for (idPos = 0; idPos < h.ids.length; idPos++) {
logger.finer("Comparing type id " + tcId + " against " + h.ids[idPos]);
if (tcId.equals(h.ids[idPos])) {
id = h.ids[idPos];
break;
}
}
// if this is null, then try again to see if we can find a class in the ids list
// that is compatible with the base type. This will require resolving the classes.
if (id == null) {
// see if we can resolve the type for the stored type code
Class baseType = Util.idToClass(tcId, "");
if (baseType != null) {
for (idPos = 0; idPos < h.ids.length; idPos++) {
logger.finer("Comparing type id " + tcId + " against " + h.ids[idPos]);
Class idType = Util.idToClass(h.ids[idPos], "");
if (idType != null) {
// if these classes are assignment compatible, go with that as the type.
logger.finer("Comparing type id " + baseType.getName() + " against " + idType.getName());
if (baseType.isAssignableFrom(idType)) {
id = h.ids[idPos];
break;
}
}
}
}
}
//
// See if a factory exists for any of the valuetype's IDs -
// stop at the first match
//
String factoryId = null;
int factoryPos = 0;
org.omg.CORBA.portable.ValueFactory factory = null;
if (orbInstance_ != null) {
ValueFactoryManager manager = orbInstance_
.getValueFactoryManager();
for (factoryPos = 0; factoryPos < h.ids.length; factoryPos++) {
factory = manager
.lookupValueFactoryWithClass(h.ids[factoryPos]);
if (factory != null) {
factoryId = h.ids[factoryPos];
break;
}
}
}
//
// If no ID matched the TypeCode, and no factory was found,
// then we have no way to remarshal the data
//
if (h.ids.length > 0 && id == null && factoryId == null) {
logger.fine("Unable to resolve a factory for type " + tcId);
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory)
+ ": insufficient information to copy valuetype",
org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
//
// If value is custom and there is no factory, then we have
// no way to remarshal the data
//
if (mod == org.omg.CORBA.VM_CUSTOM.value && factoryId == null) {
throw new org.omg.CORBA.MARSHAL(org.apache.yoko.orb.OB.MinorCodes
.describeMarshal(org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory)
+ ": unable to copy custom valuetype",
org.apache.yoko.orb.OB.MinorCodes.MinorNoValueFactory,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
}
//
// If the TypeCode is more descriptive than any available
// factory, or if no identifiers were provided, then use the
// TypeCode, otherwise use the factory
//
// NOTE: (Java only) We also use the TypeCode for boxed values,
// because we don't have the BoxedHelper and may not be
// able to locate one via the class loader.
//
if (idPos < factoryPos || h.ids.length == 0
|| origTC.kind() == org.omg.CORBA.TCKind.tk_value_box) {
int i;
//
// We may need to truncate the state of this value, which
// means we need to revise the list of repository IDs
//
int numIds = h.ids.length - idPos;
String[] ids = new String[numIds];
for (i = idPos; i < h.ids.length; i++)
ids[i - idPos] = h.ids[i];
logger.fine("Copying value state of object using truncated type");
out._OB_beginValue(h.tag, ids, h.state.chunked);
copyValueState(origTC, out);
out._OB_endValue();
result = tc;
} else {
//
// Create a temporary instance to use for marshalling
//
try {
pushHeader(h);
java.io.Serializable vb = factory.read_value(in_);
logger.fine("Creating a temporary copy of the object for marshalling");
try {
out.write_value(vb);
} finally {
removeInstance(h.headerPos);
}
} finally {
popHeader();
}
//
// Determine the TypeCode that is equivalent to the
// factory in use
//
result = findTypeCode(h.ids[factoryPos], tc);
if (result == null)
result = tc;
}
skipChunk();
}
Assert._OB_assert(result != null);
return result;
}
public void readValueAny(org.omg.CORBA.Any any, org.omg.CORBA.TypeCode tc) {
//
// In constrast to other complex types, valuetypes and value boxes
// in Anys cannot simply be "remarshalled". The reason is that
// indirection may occur across multiple Any values in the same
// stream. Therefore, if possible, we should attempt to construct
// the values using a factory so that any shared values will be
// handled correctly.
//
// If a factory cannot be found, we should still remarshal.
// However, if an indirection is encountered which refers to
// a value we were unable to construct, an exception will be
// raised.
//
org.apache.yoko.orb.CORBA.Any obAny = null;
try {
obAny = (org.apache.yoko.orb.CORBA.Any) any;
} catch (ClassCastException ex) {
//
// Any may have been created by a foreign ORB
//
}
org.omg.CORBA.TypeCode origTC = org.apache.yoko.orb.CORBA.TypeCode
._OB_getOrigType(tc);
logger.fine("Reading an Any value of kind=" + origTC.kind().value() + " from position " + buf_.pos_);
//
// Check if the Any contains an abstract interface
//
if (origTC.kind() == org.omg.CORBA.TCKind.tk_abstract_interface) {
boolean b = in_.read_boolean();
if (b) {
logger.fine("Reading an object reference for an abstract interface");
//
// The abstract interface represents an object reference
//
any.insert_Object(in_.read_Object(), tc);
return;
} else {
logger.fine("Reading an object value for an abstract interface");
//
// The abstract interface represents a valuetype. The
// readValue() method will raise an exception if an
// instance of the valuetype could not be created.
// We cannot remarshal in this case because we don't
// have a TypeCode for the valuetype.
//
any.insert_Value(readValue(), tc);
return;
}
}
//
// If the TypeCode's repository ID is that of CORBA::ValueBase,
// then we try to create an instance. The Any could contain a
// valuetype *or* a boxed valuetype.
//
// If creation fails, we cannot remarshal the value, since
// CORBA::ValueBase is not a truncatable base type, and we
// have no other TypeCode information. Truncating to
// CORBA::ValueBase doesn't seem very useful anyway.
//
try {
String id = origTC.id();
logger.fine("Reading an Any value of id=" + id);
if (id.equals("IDL:omg.org/CORBA/ValueBase:1.0")) {
any.insert_Value(readValue(), tc);
return;
}
} catch (org.omg.CORBA.TypeCodePackage.BadKind ex) {
Assert._OB_assert(ex);
}
//
// At this point, the Any contains a valuetype or a boxed valuetype,
// and we have a TypeCode that can be used for remarshalling.
//
//
// Save some state so that we can restore things prior to
// remarshalling
//
int startPos = buf_.pos_;
ChunkState startState = new ChunkState(chunkState_);
//
// No need to worry about truncation for boxed valuetypes
//
if (origTC.kind() == org.omg.CORBA.TCKind.tk_value_box) {
try {
any.insert_Value(readValue(tc.id()), tc);
return;
} catch (org.omg.CORBA.MARSHAL ex) {
//
// Creation failed - restore our state and try remarshalling
//
buf_.pos_ = startPos;
chunkState_.copyFrom(startState);
org.apache.yoko.orb.OCI.Buffer buf = new org.apache.yoko.orb.OCI.Buffer();
org.apache.yoko.orb.CORBA.OutputStream out = new org.apache.yoko.orb.CORBA.OutputStream(
buf);
out._OB_ORBInstance(orbInstance_);
remarshalValue(origTC, out);
org.apache.yoko.orb.CORBA.InputStream in = (org.apache.yoko.orb.CORBA.InputStream) out
.create_input_stream();
Assert._OB_assert(obAny != null);
obAny.replace(tc, in);
return;
} catch (org.omg.CORBA.TypeCodePackage.BadKind ex) {
Assert._OB_assert(ex);
}
} else {
//
// Read valuetype header tag
//
Header h = new Header();
h.tag = in_.read_long();
logger.fine("Read tag value " + Integer.toHexString(h.tag));
//
// Check tag for special cases
//
if (h.tag == 0) {
any.insert_Value(null, tc);
return;
} else if (h.tag != -1 && h.tag < 0x7fffff00) {
throw new org.omg.CORBA.MARSHAL("Illegal valuetype tag 0x"
+ Integer.toHexString(h.tag));
}
//
// Try to create an instance of the valuetype using a factory
//
FactoryCreationStrategy strategy = new FactoryCreationStrategy(
this, in_, null);
try {
if (h.tag == -1) {
//
// TODO: The TypeCode may not necessarily reflect
// the one that was used for the indirected value
// (i.e., the value may have been truncated).
// Fixing this probably requires maintaining a
// map of stream position to TypeCode.
//
logger.fine("Handling a value type indirection value");
any.insert_Value(readIndirection(strategy), tc);
return;
} else {
initHeader(h);
org.omg.CORBA.StringHolder idH = new org.omg.CORBA.StringHolder();
java.io.Serializable vb = strategy.create(h, idH);
logger.fine("Obtained a value of type " + vb.getClass().getName());
skipChunk();
//
// Find the TypeCode for the repository ID that was
// used to instantiate the valuetype. Three things
// can happen:
//
// 1) The TypeCode is equal to tc.
//
// 2) The TypeCode is null. In this case, the instance
// is of a more-derived type than tc, so the best
// we can do is to use tc.
//
// 3) The TypeCode is a base type of tc. In this case,
// the valuetype was truncated.
//
org.omg.CORBA.TypeCode t = null;
if(idH.value != null) {
t = findTypeCode(idH.value, tc);
}
if (t != null) {
any.insert_Value(vb, t);
}
else {
any.insert_Value(vb, tc);
}
return;
}
} catch (org.omg.CORBA.MARSHAL ex) {
logger.log(Level.FINE, "Marshaling exception occurred, attempting to remarshal", ex);
//
// Creation failed - restore our state and try remarshalling
//
buf_.pos_ = startPos;
chunkState_.copyFrom(startState);
org.apache.yoko.orb.OCI.Buffer buf = new org.apache.yoko.orb.OCI.Buffer();
org.apache.yoko.orb.CORBA.OutputStream out = new org.apache.yoko.orb.CORBA.OutputStream(
buf);
out._OB_ORBInstance(orbInstance_);
org.omg.CORBA.TypeCode t = remarshalValue(origTC, out);
org.apache.yoko.orb.CORBA.InputStream in = (org.apache.yoko.orb.CORBA.InputStream) out
.create_input_stream();
Assert._OB_assert(obAny != null);
obAny.replace(t, in);
return;
}
}
Assert._OB_assert(false); // should never reach this point
}
public void beginValue() {
Header h = new Header();
h.tag = in_.read_long();
logger.fine("Read tag value " + Integer.toHexString(h.tag));
Assert._OB_assert(h.tag != 0 && h.tag != -1);
initHeader(h);
}
public void endValue() {
skipChunk();
}
public void checkChunk() {
if (!chunkState_.chunked)
return;
// logger.finest("Checking chunk position. end=" + (chunkState_.chunkStart + chunkState_.chunkSize) + " buffer position=" + buf_.pos_);
//
// If we've reached the end of the current chunk, then check
// for the start of a new chunk
//
if (chunkState_.chunkStart > 0 && chunkState_.chunkStart + chunkState_.chunkSize == buf_.pos_)
{
// logger.finest("Reading chunk from check chunk");
readChunk(chunkState_);
}
}
}