public TypeCode remarshalValue()

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;
    }