| /* |
| * 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_); |
| } |
| } |
| } |