in yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java [1177:1443]
public TypeCode remarshalValue(TypeCode tc, 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 Hashtable<Integer, Integer>(131);
}
final TypeCode origTC = org.apache.yoko.orb.CORBA.TypeCode._OB_getOrigType(tc);
final Header h = new Header();
h.tag = in_.read_long();
if (logger.isLoggable(Level.FINE))
logger.fine(String.format("Read tag value 0x%08x", h.tag));
h.headerPos = buf_.pos_ - 4; // adjust for alignment
h.state.copyFrom(chunkState_);
//
// Remember starting position of this valuetype
//
final int pos = h.headerPos;
//
// Check for special cases (null values and indirections)
//
TypeCode result;
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.
//
@SuppressWarnings("UnnecessaryBoxing")
final Integer newPos = positionTable_.get(oldPos);
if (newPos != null) {
out.write_long(h.tag);
offs = newPos - 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 MARSHAL("Cannot find value for indirection");
}
} else {
if (h.tag < 0x7fffff00) {
throw new MARSHAL("Illegal valuetype tag 0x" + Integer.toHexString(h.tag));
}
if (logger.isLoggable(Level.FINE))
logger.fine(String.format("Remarshalling header with tag value 0x%08x", 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(pos, 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 = VM_NONE.value;
try {
tcId = origTC.id();
if (origTC.kind() == TCKind.tk_value) {
mod = origTC.type_modifier();
}
} catch (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.
//
if (logger.isLoggable(Level.FINE))
logger.fine(String.format("Attempting to resolve typeId \"%s\"", tcId));
//
// See if the TypeCode ID matches any of the valuetype's IDs -
// stop at the first match
//
String id = null;
int idPos;
for (idPos = 0; idPos < h.ids.length; idPos++) {
if (logger.isLoggable(Level.FINER))
logger.finer(String.format(
"Comparing type id \"%s\" against \"%s\"",
tcId, 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
final Class<?> baseType = RepIds.query(tcId).toClass();
if (baseType != null) {
for (idPos = 0; idPos < h.ids.length; idPos++) {
if (logger.isLoggable(Level.FINER))
logger.finer(String.format(
"Considering base types of id \"%s\" against \"%s\"",
tcId, h.ids[idPos]));
final Class idType = RepIds.query(h.ids[idPos]).toClass();
if (idType != null) {
// if these classes are assignment compatible, go with that as the type.
if (logger.isLoggable(Level.FINER))
logger.finer(String.format(
"Comparing type id \"%s\" against \"%s\"",
baseType.getName(), 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;
ValueFactory factory = null;
if (orbInstance_ != null) {
final 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)) {
if (logger.isLoggable(Level.FINE))
logger.fine(String.format("Unable to resolve a factory for type \"%s\"", tcId));
throw new MARSHAL(MinorCodes.describeMarshal(MinorCodes.MinorNoValueFactory) + ": insufficient information to copy valuetype",
MinorCodes.MinorNoValueFactory, CompletionStatus.COMPLETED_NO);
}
//
// If value is custom and there is no factory, then we have
// no way to remarshal the data
//
if ((mod == VM_CUSTOM.value) && (factoryId == null)) {
throw new MARSHAL(MinorCodes.describeMarshal(MinorCodes.MinorNoValueFactory) + ": unable to copy custom valuetype",
MinorCodes.MinorNoValueFactory, 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() == TCKind.tk_value_box)) {
//
// We may need to truncate the state of this value, which
// means we need to revise the list of repository IDs
//
final int numIds = h.ids.length - idPos;
final String[] ids = new String[numIds];
System.arraycopy(h.ids, idPos, ids, idPos - idPos, h.ids.length - idPos);
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);
final 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;
}