/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
/*
 * Licensed Materials - Property of IBM
 * RMI-IIOP v1.0
 * Copyright IBM Corp. 1998 1999  All Rights Reserved
 *
 */

package com.sun.corba.se.impl.corba;

import java.io.Serializable;
import java.math.BigDecimal;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List ;
import java.util.ArrayList ;

import org.omg.CORBA.Principal ;
import org.omg.CORBA.TypeCode ;
import org.omg.CORBA.Any ;
import org.omg.CORBA.CompletionStatus ;
import org.omg.CORBA.TCKind ;

import org.omg.CORBA.portable.Streamable;
import org.omg.CORBA.portable.InputStream;
import org.omg.CORBA.portable.OutputStream;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.TypeCodePackage.Bounds;

import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.orb.ORBVersionFactory;
import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.spi.presentation.rmi.StubAdapter;

import com.sun.corba.se.impl.encoding.CDRInputStream;
import com.sun.corba.se.impl.encoding.EncapsInputStream;
import com.sun.corba.se.impl.encoding.EncapsOutputStream;
import com.sun.corba.se.impl.io.ValueUtility;
import com.sun.corba.se.impl.orbutil.RepositoryIdFactory;
import com.sun.corba.se.impl.orbutil.RepositoryIdStrings;
import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;

// subclasses must provide a matching helper class
public class AnyImpl extends Any
{
    private static final class AnyInputStream extends EncapsInputStream
    {
        public AnyInputStream(EncapsInputStream theStream )
        {
            super( theStream );
        }
    }

    private static final class AnyOutputStream extends EncapsOutputStream
    {
        public AnyOutputStream(ORB orb)
        {
            super((ORB)orb);
        }

        public org.omg.CORBA.portable.InputStream create_input_stream() {
            final org.omg.CORBA.portable.InputStream is = super
                    .create_input_stream();
            AnyInputStream aIS = AccessController
                    .doPrivileged(new PrivilegedAction<AnyInputStream>() {
                        @Override
                        public AnyInputStream run() {
                            return new AnyInputStream(
                                    (com.sun.corba.se.impl.encoding.EncapsInputStream) is);
                        }
                    });
            return aIS;
        }
    }

    //
    // Always valid.
    //
    private TypeCodeImpl typeCode;
    protected ORB orb;
    private ORBUtilSystemException wrapper ;

    //
    // Validity depends upon typecode. The 'value' and 'object' instance
    // members are used to hold immutable types as defined by the
    // isStreamed[] table below. Otherwise, 'stream' is non-null and
    // holds the value in CDR marshaled format. As an optimization, the
    // stream type is an Any extension of CDR stream that is used to
    // detect an optimization in read_value().
    //
    private CDRInputStream stream;
    private long value;
    private java.lang.Object object;

    // Setting the typecode via the type() accessor wipes out the value.
    // An attempt to extract before the value is set will result
    // in a BAD_OPERATION exception being raised.
    private boolean isInitialized = false;

    private static final int DEFAULT_BUFFER_SIZE = 32;

    /*
     * This boolean array tells us if a given typecode must be
     * streamed. Objects that are immutable don't have to be streamed.
     */
    static boolean isStreamed[] = {
        false,  // null
        false,  // void
        false,  // short
        false,  // long
        false,  // ushort
        false,  // ulong
        false,  // float
        false,  // double
        false,  // boolean
        false,  // char
        false,  // octet
        false,  // any
        false,  // TypeCode
        true,   // Principal
        false,  // objref
        true,   // struct
        true,   // union
        false,  // enum
        false,  // string
        true,   // sequence
        true,   // array
        true,   // alias
        true,   // except
        false,  // longlong
        false,  // ulonglong
        false,  // longdouble
        false,  // wchar
        false,  // wstring
        false,  // fixed
        false,  // value
        false,  // value_box (used to be true)
        false,  // native
        false   // abstract interface
    };

    static AnyImpl convertToNative(ORB orb, Any any) {
        if (any instanceof AnyImpl) {
            return (AnyImpl)any;
        } else {
            AnyImpl anyImpl = new AnyImpl(orb, any);
            anyImpl.typeCode = TypeCodeImpl.convertToNative(orb, anyImpl.typeCode);
            return anyImpl;
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // Constructors

    /**
     * A constructor that sets the Any to contain a null. It also marks
     * the value as being invalid so that extractions throw an exception
     * until an insertion has been performed.
     */
    public AnyImpl(ORB orb)
    {
        this.orb = orb;
        wrapper = ORBUtilSystemException.get( (com.sun.corba.se.spi.orb.ORB)orb,
            CORBALogDomains.RPC_PRESENTATION ) ;

        typeCode = orb.get_primitive_tc(TCKind._tk_null);
        stream = null;
        object = null;
        value = 0;
        // null is a valid value
        isInitialized = true;
    }

    //
    // Create a new AnyImpl which is a copy of obj.
    //
    public AnyImpl(ORB orb, Any obj) {
        this(orb);

        if ((obj instanceof AnyImpl)) {
            AnyImpl objImpl = (AnyImpl)obj;
            typeCode = objImpl.typeCode;
            value = objImpl.value;
            object = objImpl.object;
            isInitialized = objImpl.isInitialized;

            if (objImpl.stream != null)
                stream = objImpl.stream.dup();

        } else {
            read_value(obj.create_input_stream(), obj.type());
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // basic accessors

    /**
     * returns the type of the element contained in the Any.
     *
     * @result          the TypeCode for the element in the Any
     */
    public TypeCode type() {
        return typeCode;
    }

    private TypeCode realType() {
        return realType(typeCode);
    }

    private TypeCode realType(TypeCode aType) {
        TypeCode realType = aType;
        try {
            // Note: Indirect types are handled in kind() method
            while (realType.kind().value() == TCKind._tk_alias) {
                realType = realType.content_type();
            }
        } catch (BadKind bad) { // impossible
            throw wrapper.badkindCannotOccur( bad ) ;
        }
        return realType;
    }

    /**
     * sets the type of the element to be contained in the Any.
     *
     * @param tc                the TypeCode for the element in the Any
     */
    public void type(TypeCode tc)
    {
        //debug.log ("type2");
        // set the typecode
        typeCode = TypeCodeImpl.convertToNative(orb, tc);

        stream = null;
        value = 0;
        object = null;
        // null is the only legal value this Any can have after resetting the type code
        isInitialized = (tc.kind().value() == TCKind._tk_null);
    }

    /**
     * checks for equality between Anys.
     *
     * @param otherAny  the Any to be compared with.
     * @result          true if the Anys are equal, false otherwise.
     */
    public boolean equal(Any otherAny)
    {
        //debug.log ("equal");

        if (otherAny == this)
            return true;

        // first check for typecode equality.
        // note that this will take aliases into account
        if (!typeCode.equal(otherAny.type()))
            return false;

        // Resolve aliases here
        TypeCode realType = realType();

        // _REVISIT_ Possible optimization for the case where
        // otherAny is a AnyImpl and the endianesses match.
        // Need implementation of CDRInputStream.equals()
        // For now we disable this to encourage testing the generic,
        // unoptimized code below.
        // Unfortunately this generic code needs to copy the whole stream
        // at least once.
        //    if (AnyImpl.isStreamed[realType.kind().value()]) {
        //        if (otherAny instanceof AnyImpl) {
        //            return ((AnyImpl)otherAny).stream.equals(stream);
        //        }
        //    }
        switch (realType.kind().value()) {
            // handle primitive types
            case TCKind._tk_null:
            case TCKind._tk_void:
                return true;
            case TCKind._tk_short:
                return (extract_short() == otherAny.extract_short());
            case TCKind._tk_long:
                return (extract_long() == otherAny.extract_long());
            case TCKind._tk_ushort:
                return (extract_ushort() == otherAny.extract_ushort());
            case TCKind._tk_ulong:
                return (extract_ulong() == otherAny.extract_ulong());
            case TCKind._tk_float:
                return (extract_float() == otherAny.extract_float());
            case TCKind._tk_double:
                return (extract_double() == otherAny.extract_double());
            case TCKind._tk_boolean:
                return (extract_boolean() == otherAny.extract_boolean());
            case TCKind._tk_char:
                return (extract_char() == otherAny.extract_char());
            case TCKind._tk_wchar:
                return (extract_wchar() == otherAny.extract_wchar());
            case TCKind._tk_octet:
                return (extract_octet() == otherAny.extract_octet());
            case TCKind._tk_any:
                return extract_any().equal(otherAny.extract_any());
            case TCKind._tk_TypeCode:
                return extract_TypeCode().equal(otherAny.extract_TypeCode());
            case TCKind._tk_string:
                return extract_string().equals(otherAny.extract_string());
            case TCKind._tk_wstring:
                return (extract_wstring().equals(otherAny.extract_wstring()));
            case TCKind._tk_longlong:
                return (extract_longlong() == otherAny.extract_longlong());
            case TCKind._tk_ulonglong:
                return (extract_ulonglong() == otherAny.extract_ulonglong());

            case TCKind._tk_objref:
                return (extract_Object().equals(otherAny.extract_Object()));
            case TCKind._tk_Principal:
                return (extract_Principal().equals(otherAny.extract_Principal()));

            case TCKind._tk_enum:
                return (extract_long() == otherAny.extract_long());
            case TCKind._tk_fixed:
                return (extract_fixed().compareTo(otherAny.extract_fixed()) == 0);
            case TCKind._tk_except:
            case TCKind._tk_struct:
            case TCKind._tk_union:
            case TCKind._tk_sequence:
            case TCKind._tk_array:
                InputStream copyOfMyStream = this.create_input_stream();
                InputStream copyOfOtherStream = otherAny.create_input_stream();
                return equalMember(realType, copyOfMyStream, copyOfOtherStream);

            // Too complicated to handle value types the way we handle
            // other complex types above. Don't try to decompose it here
            // for faster comparison, just use Object.equals().
            case TCKind._tk_value:
            case TCKind._tk_value_box:
                return extract_Value().equals(otherAny.extract_Value());

            case TCKind._tk_alias:
                throw wrapper.errorResolvingAlias() ;

            case TCKind._tk_longdouble:
                // Unspecified for Java
                throw wrapper.tkLongDoubleNotSupported() ;

            default:
                throw wrapper.typecodeNotSupported() ;
        }
    }

    // Needed for equal() in order to achieve linear performance for complex types.
    // Uses up (recursively) copies of the InputStream in both Anys that got created in equal().
    private boolean equalMember(TypeCode memberType, InputStream myStream, InputStream otherStream) {
        // Resolve aliases here
        TypeCode realType = realType(memberType);

        try {
            switch (realType.kind().value()) {
                // handle primitive types
                case TCKind._tk_null:
                case TCKind._tk_void:
                    return true;
                case TCKind._tk_short:
                    return (myStream.read_short() == otherStream.read_short());
                case TCKind._tk_long:
                    return (myStream.read_long() == otherStream.read_long());
                case TCKind._tk_ushort:
                    return (myStream.read_ushort() == otherStream.read_ushort());
                case TCKind._tk_ulong:
                    return (myStream.read_ulong() == otherStream.read_ulong());
                case TCKind._tk_float:
                    return (myStream.read_float() == otherStream.read_float());
                case TCKind._tk_double:
                    return (myStream.read_double() == otherStream.read_double());
                case TCKind._tk_boolean:
                    return (myStream.read_boolean() == otherStream.read_boolean());
                case TCKind._tk_char:
                    return (myStream.read_char() == otherStream.read_char());
                case TCKind._tk_wchar:
                    return (myStream.read_wchar() == otherStream.read_wchar());
                case TCKind._tk_octet:
                    return (myStream.read_octet() == otherStream.read_octet());
                case TCKind._tk_any:
                    return myStream.read_any().equal(otherStream.read_any());
                case TCKind._tk_TypeCode:
                    return myStream.read_TypeCode().equal(otherStream.read_TypeCode());
                case TCKind._tk_string:
                    return myStream.read_string().equals(otherStream.read_string());
                case TCKind._tk_wstring:
                    return (myStream.read_wstring().equals(otherStream.read_wstring()));
                case TCKind._tk_longlong:
                    return (myStream.read_longlong() == otherStream.read_longlong());
                case TCKind._tk_ulonglong:
                    return (myStream.read_ulonglong() == otherStream.read_ulonglong());

                case TCKind._tk_objref:
                    return (myStream.read_Object().equals(otherStream.read_Object()));
                case TCKind._tk_Principal:
                    return (myStream.read_Principal().equals(otherStream.read_Principal()));

                case TCKind._tk_enum:
                    return (myStream.read_long() == otherStream.read_long());
                case TCKind._tk_fixed:
                    return (myStream.read_fixed().compareTo(otherStream.read_fixed()) == 0);
                case TCKind._tk_except:
                case TCKind._tk_struct: {
                    int length = realType.member_count();
                    for (int i=0; i<length; i++) {
                        if ( ! equalMember(realType.member_type(i), myStream, otherStream)) {
                            return false;
                        }
                    }
                    return true;
                }
                case TCKind._tk_union: {
                    Any myDiscriminator = orb.create_any();
                    Any otherDiscriminator = orb.create_any();
                    myDiscriminator.read_value(myStream, realType.discriminator_type());
                    otherDiscriminator.read_value(otherStream, realType.discriminator_type());

                    if ( ! myDiscriminator.equal(otherDiscriminator)) {
                        return false;
                    }
                    TypeCodeImpl realTypeCodeImpl = TypeCodeImpl.convertToNative(orb, realType);
                    int memberIndex = realTypeCodeImpl.currentUnionMemberIndex(myDiscriminator);
                    if (memberIndex == -1)
                        throw wrapper.unionDiscriminatorError() ;

                    if ( ! equalMember(realType.member_type(memberIndex), myStream, otherStream)) {
                        return false;
                    }
                    return true;
                }
                case TCKind._tk_sequence: {
                    int length = myStream.read_long();
                    otherStream.read_long(); // just so that the two stream are in sync
                    for (int i=0; i<length; i++) {
                        if ( ! equalMember(realType.content_type(), myStream, otherStream)) {
                            return false;
                        }
                    }
                    return true;
                }
                case TCKind._tk_array: {
                    int length = realType.member_count();
                    for (int i=0; i<length; i++) {
                        if ( ! equalMember(realType.content_type(), myStream, otherStream)) {
                            return false;
                        }
                    }
                    return true;
                }

                // Too complicated to handle value types the way we handle
                // other complex types above. Don't try to decompose it here
                // for faster comparison, just use Object.equals().
                case TCKind._tk_value:
                case TCKind._tk_value_box:
                    org.omg.CORBA_2_3.portable.InputStream mine =
                        (org.omg.CORBA_2_3.portable.InputStream)myStream;
                    org.omg.CORBA_2_3.portable.InputStream other =
                        (org.omg.CORBA_2_3.portable.InputStream)otherStream;
                    return mine.read_value().equals(other.read_value());

                case TCKind._tk_alias:
                    // error resolving alias above
                    throw wrapper.errorResolvingAlias() ;

                case TCKind._tk_longdouble:
                    throw wrapper.tkLongDoubleNotSupported() ;

                default:
                    throw wrapper.typecodeNotSupported() ;
            }
        } catch (BadKind badKind) { // impossible
            throw wrapper.badkindCannotOccur() ;
        } catch (Bounds bounds) { // impossible
            throw wrapper.boundsCannotOccur() ;
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // accessors for marshaling/unmarshaling

    /**
     * returns an output stream that an Any value can be marshaled into.
     *
     * @result          the OutputStream to marshal value of Any into
     */
    public org.omg.CORBA.portable.OutputStream create_output_stream()
    {
        //debug.log ("create_output_stream");
        final ORB finalorb = this.orb;
        return AccessController.doPrivileged(new PrivilegedAction<AnyOutputStream>() {
            @Override
            public AnyOutputStream run() {
                return new AnyOutputStream(finalorb);
            }
        });
    }

    /**
     * returns an input stream that an Any value can be marshaled out of.
     *
     * @result          the InputStream to marshal value of Any out of.
     */
    public org.omg.CORBA.portable.InputStream create_input_stream()
    {
        //
        // We create a new InputStream so that multiple threads can call here
        // and read the streams in parallel without thread safety problems.
        //
        //debug.log ("create_input_stream");
        if (AnyImpl.isStreamed[realType().kind().value()]) {
            return stream.dup();
        } else {
            OutputStream os = (OutputStream)orb.create_output_stream();
            TCUtility.marshalIn(os, realType(), value, object);

            return os.create_input_stream();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // marshaling/unmarshaling routines

    //
    // If the InputStream is a CDRInputStream then we can copy the bytes
    // since it is in our format and does not have alignment issues.
    //
    public void read_value(org.omg.CORBA.portable.InputStream in, TypeCode tc)
    {
        //debug.log ("read_value");
        //
        // Assume that someone isn't going to think they can keep reading
        // from this stream after calling us. That would be likely for
        // an IIOPInputStream but if it is an AnyInputStream then they
        // presumably obtained it via our create_output_stream() so they could
        // write the contents of an IDL data type to it and then call
        // create_input_stream() for us to read it. This is how Helper classes
        // typically implement the insert() method.
        // We should probably document this behavior in the 1.1 revision
        // task force.
        //

        typeCode = TypeCodeImpl.convertToNative(orb, tc);
        int kind = realType().kind().value();
        if (kind >= isStreamed.length) {
            throw wrapper.invalidIsstreamedTckind( CompletionStatus.COMPLETED_MAYBE,
                new Integer(kind)) ;
        }

        if (AnyImpl.isStreamed[kind]) {
            if ( in instanceof AnyInputStream ) {
                // could only have been created here
                stream = (CDRInputStream)in;
            } else {
                org.omg.CORBA_2_3.portable.OutputStream out =
                    (org.omg.CORBA_2_3.portable.OutputStream)orb.create_output_stream();
                typeCode.copy((org.omg.CORBA_2_3.portable.InputStream)in, out);
                stream = (CDRInputStream)out.create_input_stream();
            }
        } else {
            java.lang.Object[] objholder = new java.lang.Object[1];
            objholder[0] = object;
            long[] longholder = new long[1];
            TCUtility.unmarshalIn(in, realType(), longholder, objholder);
            value = longholder[0];
            object = objholder[0];
            stream = null;
        }
        isInitialized = true;
    }


    //
    // We could optimize this by noticing whether the target stream
    // has ever had anything marshaled on it that required an
    // alignment of greater than 4 (was write_double() ever called on it).
    // If not, then we can just do a byte array copy without having to
    // drive the remarshaling through typecode interpretation.
    //
    public void write_value(OutputStream out)
    {
        //debug.log ("write_value");
        if (AnyImpl.isStreamed[realType().kind().value()]) {
            typeCode.copy(stream.dup(), out);
        } else {
            // _REVISIT_ check isInitialized whether all we write is TypeCode!
            TCUtility.marshalIn(out, realType(), value, object);
        }
    }

    /**
     * takes a streamable and inserts its reference into the any
     *
     * @param s         the streamable to insert
     */
    public void insert_Streamable(Streamable s)
    {
        //debug.log ("insert_Streamable");
        typeCode = TypeCodeImpl.convertToNative(orb, s._type());
        object = s;
        isInitialized = true;
    }

    public Streamable extract_Streamable()
    {
        //debug.log( "extract_Streamable" ) ;
        return (Streamable)object;
    }

    ///////////////////////////////////////////////////////////////////////////
    // insertion/extraction/replacement for all basic types

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_short(short s)
    {
        //debug.log ("insert_short");
        typeCode = orb.get_primitive_tc(TCKind._tk_short);
        value = s;
        isInitialized = true;
    }

    private String getTCKindName( int tc )
    {
        if ((tc >= 0) && (tc < TypeCodeImpl.kindNames.length))
            return TypeCodeImpl.kindNames[tc] ;
        else
            return "UNKNOWN(" + tc + ")" ;
    }

    private void checkExtractBadOperation( int expected )
    {
        if (!isInitialized)
            throw wrapper.extractNotInitialized() ;

        int tc = realType().kind().value() ;
        if (tc != expected) {
            String tcName = getTCKindName( tc ) ;
            String expectedName = getTCKindName( expected ) ;
            throw wrapper.extractWrongType( expectedName, tcName ) ;
        }
    }

    private void checkExtractBadOperationList( int[] expected )
    {
        if (!isInitialized)
            throw wrapper.extractNotInitialized() ;

        int tc = realType().kind().value() ;
        for (int ctr=0; ctr<expected.length; ctr++)
            if (tc == expected[ctr])
                return ;

        List list = new ArrayList() ;
        for (int ctr=0; ctr<expected.length; ctr++)
            list.add( getTCKindName( expected[ctr] ) ) ;

        String tcName = getTCKindName( tc ) ;
        throw wrapper.extractWrongTypeList( list, tcName ) ;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public short extract_short()
    {
        //debug.log ("extract_short");
        checkExtractBadOperation( TCKind._tk_short ) ;
        return (short)value;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_long(int l)
    {
        //debug.log ("insert_long");
        // A long value is applicable to enums as well, so don't erase the enum type code
        // in case it was initialized that way before.
        int kind = realType().kind().value();
        if (kind != TCKind._tk_long && kind != TCKind._tk_enum) {
            typeCode = orb.get_primitive_tc(TCKind._tk_long);
        }
        value = l;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public int extract_long()
    {
        //debug.log ("extract_long");
        checkExtractBadOperationList( new int[] { TCKind._tk_long, TCKind._tk_enum } ) ;
        return (int)value;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_ushort(short s)
    {
        //debug.log ("insert_ushort");
        typeCode = orb.get_primitive_tc(TCKind._tk_ushort);
        value = s;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public short extract_ushort()
    {
        //debug.log ("extract_ushort");
        checkExtractBadOperation( TCKind._tk_ushort ) ;
        return (short)value;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_ulong(int l)
    {
        //debug.log ("insert_ulong");
        typeCode = orb.get_primitive_tc(TCKind._tk_ulong);
        value = l;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public int extract_ulong()
    {
        //debug.log ("extract_ulong");
        checkExtractBadOperation( TCKind._tk_ulong ) ;
        return (int)value;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_float(float f)
    {
        //debug.log ("insert_float");
        typeCode = orb.get_primitive_tc(TCKind._tk_float);
        value = Float.floatToIntBits(f);
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public float extract_float()
    {
        //debug.log ("extract_float");
        checkExtractBadOperation( TCKind._tk_float ) ;
        return Float.intBitsToFloat((int)value);
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_double(double d)
    {
        //debug.log ("insert_double");
        typeCode = orb.get_primitive_tc(TCKind._tk_double);
        value = Double.doubleToLongBits(d);
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public double extract_double()
    {
        //debug.log ("extract_double");
        checkExtractBadOperation( TCKind._tk_double ) ;
        return Double.longBitsToDouble(value);
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_longlong(long l)
    {
        //debug.log ("insert_longlong");
        typeCode = orb.get_primitive_tc(TCKind._tk_longlong);
        value = l;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public long extract_longlong()
    {
        //debug.log ("extract_longlong");
        checkExtractBadOperation( TCKind._tk_longlong ) ;
        return value;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_ulonglong(long l)
    {
        //debug.log ("insert_ulonglong");
        typeCode = orb.get_primitive_tc(TCKind._tk_ulonglong);
        value = l;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public long extract_ulonglong()
    {
        //debug.log ("extract_ulonglong");
        checkExtractBadOperation( TCKind._tk_ulonglong ) ;
        return value;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_boolean(boolean b)
    {
        //debug.log ("insert_boolean");
        typeCode = orb.get_primitive_tc(TCKind._tk_boolean);
        value = (b)? 1:0;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public boolean extract_boolean()
    {
        //debug.log ("extract_boolean");
        checkExtractBadOperation( TCKind._tk_boolean ) ;
        return (value == 0)? false: true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_char(char c)
    {
        //debug.log ("insert_char");
        typeCode = orb.get_primitive_tc(TCKind._tk_char);
        value = c;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public char extract_char()
    {
        //debug.log ("extract_char");
        checkExtractBadOperation( TCKind._tk_char ) ;
        return (char)value;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_wchar(char c)
    {
        //debug.log ("insert_wchar");
        typeCode = orb.get_primitive_tc(TCKind._tk_wchar);
        value = c;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public char extract_wchar()
    {
        //debug.log ("extract_wchar");
        checkExtractBadOperation( TCKind._tk_wchar ) ;
        return (char)value;
    }


    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_octet(byte b)
    {
        //debug.log ("insert_octet");
        typeCode = orb.get_primitive_tc(TCKind._tk_octet);
        value = b;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public byte extract_octet()
    {
        //debug.log ("extract_octet");
        checkExtractBadOperation( TCKind._tk_octet ) ;
        return (byte)value;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_string(String s)
    {
        //debug.log ("insert_string");
        // Make sure type code information for bounded strings is not erased
        if (typeCode.kind() == TCKind.tk_string) {
            int length = 0;
            try {
                length = typeCode.length();
            } catch (BadKind bad) {
                throw wrapper.badkindCannotOccur() ;
            }

            // Check if bounded strings length is not exceeded
            if (length != 0 && s != null && s.length() > length) {
                throw wrapper.badStringBounds( new Integer(s.length()),
                    new Integer(length) ) ;
            }
        } else {
            typeCode = orb.get_primitive_tc(TCKind._tk_string);
        }
        object = s;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public String extract_string()
    {
        //debug.log ("extract_string");
        checkExtractBadOperation( TCKind._tk_string ) ;
        return (String)object;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_wstring(String s)
    {
        //debug.log ("insert_wstring");
        // Make sure type code information for bounded strings is not erased
        if (typeCode.kind() == TCKind.tk_wstring) {
            int length = 0;
            try {
                length = typeCode.length();
            } catch (BadKind bad) {
                throw wrapper.badkindCannotOccur() ;
            }

            // Check if bounded strings length is not exceeded
            if (length != 0 && s != null && s.length() > length) {
                throw wrapper.badStringBounds( new Integer(s.length()),
                    new Integer(length) ) ;
            }
        } else {
            typeCode = orb.get_primitive_tc(TCKind._tk_wstring);
        }
        object = s;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public String extract_wstring()
    {
        //debug.log ("extract_wstring");
        checkExtractBadOperation( TCKind._tk_wstring ) ;
        return (String)object;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_any(Any a)
    {
        //debug.log ("insert_any");
        typeCode = orb.get_primitive_tc(TCKind._tk_any);
        object = a;
        stream = null;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public Any extract_any()
    {
        //debug.log ("extract_any");
        checkExtractBadOperation( TCKind._tk_any ) ;
        return (Any)object;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_Object(org.omg.CORBA.Object o)
    {
        //debug.log ("insert_Object");
        if ( o == null ) {
            typeCode = orb.get_primitive_tc(TCKind._tk_objref);
        } else {
            if (StubAdapter.isStub(o)) {
                String[] ids = StubAdapter.getTypeIds( o ) ;
                typeCode = new TypeCodeImpl(orb, TCKind._tk_objref, ids[0], "");
            } else {
                throw wrapper.badInsertobjParam(
                    CompletionStatus.COMPLETED_MAYBE, o.getClass().getName() ) ;
            }
        }

        object = o;
        isInitialized = true;
    }

    /**
     * A variant of the insertion operation that takes a typecode
     * argument as well.
     */
    public void insert_Object(org.omg.CORBA.Object o, TypeCode tc)
    {
        //debug.log ("insert_Object2");
        try {
            if ( tc.id().equals("IDL:omg.org/CORBA/Object:1.0") || o._is_a(tc.id()) )
                {
                    typeCode = TypeCodeImpl.convertToNative(orb, tc);
                    object = o;
                }
            else {
                throw wrapper.insertObjectIncompatible() ;
            }
        } catch ( Exception ex ) {
            throw wrapper.insertObjectFailed(ex) ;
        }
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public org.omg.CORBA.Object extract_Object()
    {
        //debug.log ("extract_Object");
        if (!isInitialized)
            throw wrapper.extractNotInitialized() ;

        // Check if the object contained here is of the type in typeCode
        org.omg.CORBA.Object obj = null;
        try {
            obj = (org.omg.CORBA.Object) object;
            if (typeCode.id().equals("IDL:omg.org/CORBA/Object:1.0") || obj._is_a(typeCode.id())) {
                return obj;
            } else {
                throw wrapper.extractObjectIncompatible() ;
            }
        } catch ( Exception ex ) {
            throw wrapper.extractObjectFailed(ex);
        }
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public void insert_TypeCode(TypeCode tc)
    {
        //debug.log ("insert_TypeCode");
        typeCode = orb.get_primitive_tc(TCKind._tk_TypeCode);
        object = tc;
        isInitialized = true;
    }

    /**
     * See the description of the <a href="#anyOps">general Any operations.</a>
     */
    public TypeCode extract_TypeCode()
    {
        //debug.log ("extract_TypeCode");
        checkExtractBadOperation( TCKind._tk_TypeCode ) ;
        return (TypeCode)object;
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void insert_Principal(Principal p)
    {
        typeCode = orb.get_primitive_tc(TCKind._tk_Principal);
        object = p;
        isInitialized = true;
    }

    /**
     * @deprecated
     */
    @Deprecated
    public Principal extract_Principal()
    {
        checkExtractBadOperation( TCKind._tk_Principal ) ;
        return (Principal)object;
    }

    /**
     * Note that the Serializable really should be an IDLEntity of
     * some kind.  It shouldn't just be an RMI-IIOP type.  Currently,
     * we accept and will produce RMI repIds with the latest
     * calculations if given a non-IDLEntity Serializable.
     */
    public Serializable extract_Value()
    {
        //debug.log ("extract_Value");
        checkExtractBadOperationList( new int[] { TCKind._tk_value,
            TCKind._tk_value_box, TCKind._tk_abstract_interface } ) ;
        return (Serializable)object;
    }

    public void insert_Value(Serializable v)
    {
        //debug.log ("insert_Value");
        object = v;

        TypeCode tc;

        if ( v == null ) {
            tc = orb.get_primitive_tc (TCKind.tk_value);
        } else {
            // See note in getPrimitiveTypeCodeForClass.  We
            // have to use the latest type code fixes in this
            // case since there is no way to know what ORB will
            // actually send this Any.  In RMI-IIOP, when using
            // Util.writeAny, we can do the versioning correctly,
            // and use the insert_Value(Serializable, TypeCode)
            // method.
            //
            // The ORB singleton uses the latest version.
            tc = createTypeCodeForClass (v.getClass(), (ORB)ORB.init());
        }

        typeCode = TypeCodeImpl.convertToNative(orb, tc);
        isInitialized = true;
    }

    public void insert_Value(Serializable v, org.omg.CORBA.TypeCode t)
    {
        //debug.log ("insert_Value2");
        object = v;
        typeCode = TypeCodeImpl.convertToNative(orb, t);
        isInitialized = true;
    }

    public void insert_fixed(java.math.BigDecimal value) {
        typeCode = TypeCodeImpl.convertToNative(orb,
            orb.create_fixed_tc(TypeCodeImpl.digits(value), TypeCodeImpl.scale(value)));
        object = value;
        isInitialized = true;
    }

    public void insert_fixed(java.math.BigDecimal value, org.omg.CORBA.TypeCode type)
    {
        try {
            if (TypeCodeImpl.digits(value) > type.fixed_digits() ||
                TypeCodeImpl.scale(value) > type.fixed_scale())
            {
                throw wrapper.fixedNotMatch() ;
            }
        } catch (org.omg.CORBA.TypeCodePackage.BadKind bk) {
            // type isn't even of kind fixed
            throw wrapper.fixedBadTypecode( bk ) ;
        }
        typeCode = TypeCodeImpl.convertToNative(orb, type);
        object = value;
        isInitialized = true;
    }

    public java.math.BigDecimal extract_fixed() {
        checkExtractBadOperation( TCKind._tk_fixed ) ;
        return (BigDecimal)object;
    }

    /**
     * Utility method for insert_Value and Util.writeAny.
     *
     * The ORB passed in should have the desired ORBVersion.  It
     * is used to generate the type codes.
     */
    public TypeCode createTypeCodeForClass (java.lang.Class c, ORB tcORB)
    {
        // Look in the cache first
        TypeCodeImpl classTC = tcORB.getTypeCodeForClass(c);
        if (classTC != null)
            return classTC;

        // All cases need to be able to create repository IDs.
        //
        // See bug 4391648 for more info about the tcORB in this
        // case.
        RepositoryIdStrings repStrs
            = RepositoryIdFactory.getRepIdStringsFactory();


        // Assertion: c instanceof Serializable?

        if ( c.isArray() ) {
            // Arrays - may recurse for multi-dimensional arrays
            Class componentClass = c.getComponentType();
            TypeCode embeddedType;
            if ( componentClass.isPrimitive() ) {
                embeddedType = getPrimitiveTypeCodeForClass(componentClass,
                                                            tcORB);
            } else {
                embeddedType = createTypeCodeForClass (componentClass,
                                                       tcORB);
            }
            TypeCode t = tcORB.create_sequence_tc (0, embeddedType);

            String id = repStrs.createForJavaType(c);

            return tcORB.create_value_box_tc (id, "Sequence", t);
        } else if ( c == java.lang.String.class ) {
            // Strings
            TypeCode t = tcORB.create_string_tc (0);

            String id = repStrs.createForJavaType(c);

            return tcORB.create_value_box_tc (id, "StringValue", t);
        }

        // Anything else
        // We know that this is a TypeCodeImpl since it is our ORB
        classTC = (TypeCodeImpl)ValueUtility.createTypeCodeForClass(
            tcORB, c, ORBUtility.createValueHandler());
        // Intruct classTC to store its buffer
        classTC.setCaching(true);
        // Update the cache
        tcORB.setTypeCodeForClass(c, classTC);
        return classTC;
    }

    /**
     * It looks like this was copied from io.ValueUtility at some
     * point.
     *
     * It's used by createTypeCodeForClass.  The tcORB passed in
     * should have the desired ORB version, and is used to
     * create the type codes.
     */
    private TypeCode getPrimitiveTypeCodeForClass (Class c, ORB tcORB)
    {
        //debug.log ("getPrimitiveTypeCodeForClass");

        if (c == Integer.TYPE) {
            return tcORB.get_primitive_tc (TCKind.tk_long);
        } else if (c == Byte.TYPE) {
            return tcORB.get_primitive_tc (TCKind.tk_octet);
        } else if (c == Long.TYPE) {
            return tcORB.get_primitive_tc (TCKind.tk_longlong);
        } else if (c == Float.TYPE) {
            return tcORB.get_primitive_tc (TCKind.tk_float);
        } else if (c == Double.TYPE) {
            return tcORB.get_primitive_tc (TCKind.tk_double);
        } else if (c == Short.TYPE) {
            return tcORB.get_primitive_tc (TCKind.tk_short);
        } else if (c == Character.TYPE) {
            // For Merlin or later JDKs, or for foreign ORBs,
            // we correctly say that a Java char maps to a
            // CORBA wchar.  For backwards compatibility
            // with our older ORBs, we say it maps to a
            // CORBA char.  This is only used in RMI-IIOP
            // in our javax.rmi.CORBA.Util delegate's
            // writeAny method.  In Java IDL, there's no way
            // to know the ORB version that the Any will be
            // sent out with -- it could be different than
            // the one used to create the Any -- so we use the
            // most recent version (see insert_Value).
            if (ORBVersionFactory.getFOREIGN().compareTo(tcORB.getORBVersion()) == 0 ||
                ORBVersionFactory.getNEWER().compareTo(tcORB.getORBVersion()) <= 0)
                return tcORB.get_primitive_tc(TCKind.tk_wchar);
            else
                return tcORB.get_primitive_tc(TCKind.tk_char);
        } else if (c == Boolean.TYPE) {
            return tcORB.get_primitive_tc (TCKind.tk_boolean);
        } else {
            // _REVISIT_ Not sure if this is right.
            return tcORB.get_primitive_tc (TCKind.tk_any);
        }
    }

    // Extracts a member value according to the given TypeCode from the given complex Any
    // (at the Anys current internal stream position, consuming the anys stream on the way)
    // and returns it wrapped into a new Any
    public Any extractAny(TypeCode memberType, ORB orb) {
        Any returnValue = orb.create_any();
        OutputStream out = returnValue.create_output_stream();
        TypeCodeImpl.convertToNative(orb, memberType).copy((InputStream)stream, out);
        returnValue.read_value(out.create_input_stream(), memberType);
        return returnValue;
    }

    // This method could very well be moved into TypeCodeImpl or a common utility class,
    // but is has to be in this package.
    static public Any extractAnyFromStream(TypeCode memberType, InputStream input, ORB orb) {
        Any returnValue = orb.create_any();
        OutputStream out = returnValue.create_output_stream();
        TypeCodeImpl.convertToNative(orb, memberType).copy(input, out);
        returnValue.read_value(out.create_input_stream(), memberType);
        return returnValue;
    }

    // There is no other way for DynAnys to find out whether the Any is initialized.
    public boolean isInitialized() {
        return isInitialized;
    }
}
