AnyImpl.java revision 672:2bb058ce572e
1/*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25/*
26 * Licensed Materials - Property of IBM
27 * RMI-IIOP v1.0
28 * Copyright IBM Corp. 1998 1999  All Rights Reserved
29 *
30 */
31
32package com.sun.corba.se.impl.corba;
33
34import java.io.Serializable;
35import java.math.BigDecimal;
36import java.security.AccessController;
37import java.security.PrivilegedAction;
38import java.util.List ;
39import java.util.ArrayList ;
40
41import org.omg.CORBA.Principal ;
42import org.omg.CORBA.TypeCode ;
43import org.omg.CORBA.Any ;
44import org.omg.CORBA.CompletionStatus ;
45import org.omg.CORBA.TCKind ;
46
47import org.omg.CORBA.portable.Streamable;
48import org.omg.CORBA.portable.InputStream;
49import org.omg.CORBA.portable.OutputStream;
50import org.omg.CORBA.TypeCodePackage.BadKind;
51import org.omg.CORBA.TypeCodePackage.Bounds;
52
53import com.sun.corba.se.spi.orb.ORB;
54import com.sun.corba.se.spi.orb.ORBVersionFactory;
55import com.sun.corba.se.spi.logging.CORBALogDomains;
56import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
57
58import com.sun.corba.se.impl.encoding.CDRInputStream;
59import com.sun.corba.se.impl.encoding.EncapsInputStream;
60import com.sun.corba.se.impl.encoding.EncapsOutputStream;
61import com.sun.corba.se.impl.io.ValueUtility;
62import com.sun.corba.se.impl.orbutil.RepositoryIdFactory;
63import com.sun.corba.se.impl.orbutil.RepositoryIdStrings;
64import com.sun.corba.se.impl.orbutil.ORBUtility;
65import com.sun.corba.se.impl.logging.ORBUtilSystemException;
66
67// subclasses must provide a matching helper class
68public class AnyImpl extends Any
69{
70    private static final class AnyInputStream extends EncapsInputStream
71    {
72        public AnyInputStream(EncapsInputStream theStream )
73        {
74            super( theStream );
75        }
76    }
77
78    private static final class AnyOutputStream extends EncapsOutputStream
79    {
80        public AnyOutputStream(ORB orb)
81        {
82            super((ORB)orb);
83        }
84
85        public org.omg.CORBA.portable.InputStream create_input_stream() {
86            final org.omg.CORBA.portable.InputStream is = super
87                    .create_input_stream();
88            AnyInputStream aIS = AccessController
89                    .doPrivileged(new PrivilegedAction<AnyInputStream>() {
90                        @Override
91                        public AnyInputStream run() {
92                            return new AnyInputStream(
93                                    (com.sun.corba.se.impl.encoding.EncapsInputStream) is);
94                        }
95                    });
96            return aIS;
97        }
98    }
99
100    //
101    // Always valid.
102    //
103    private TypeCodeImpl typeCode;
104    protected ORB orb;
105    private ORBUtilSystemException wrapper ;
106
107    //
108    // Validity depends upon typecode. The 'value' and 'object' instance
109    // members are used to hold immutable types as defined by the
110    // isStreamed[] table below. Otherwise, 'stream' is non-null and
111    // holds the value in CDR marshaled format. As an optimization, the
112    // stream type is an Any extension of CDR stream that is used to
113    // detect an optimization in read_value().
114    //
115    private CDRInputStream stream;
116    private long value;
117    private java.lang.Object object;
118
119    // Setting the typecode via the type() accessor wipes out the value.
120    // An attempt to extract before the value is set will result
121    // in a BAD_OPERATION exception being raised.
122    private boolean isInitialized = false;
123
124    private static final int DEFAULT_BUFFER_SIZE = 32;
125
126    /*
127     * This boolean array tells us if a given typecode must be
128     * streamed. Objects that are immutable don't have to be streamed.
129     */
130    static boolean isStreamed[] = {
131        false,  // null
132        false,  // void
133        false,  // short
134        false,  // long
135        false,  // ushort
136        false,  // ulong
137        false,  // float
138        false,  // double
139        false,  // boolean
140        false,  // char
141        false,  // octet
142        false,  // any
143        false,  // TypeCode
144        true,   // Principal
145        false,  // objref
146        true,   // struct
147        true,   // union
148        false,  // enum
149        false,  // string
150        true,   // sequence
151        true,   // array
152        true,   // alias
153        true,   // except
154        false,  // longlong
155        false,  // ulonglong
156        false,  // longdouble
157        false,  // wchar
158        false,  // wstring
159        false,  // fixed
160        false,  // value
161        false,  // value_box (used to be true)
162        false,  // native
163        false   // abstract interface
164    };
165
166    static AnyImpl convertToNative(ORB orb, Any any) {
167        if (any instanceof AnyImpl) {
168            return (AnyImpl)any;
169        } else {
170            AnyImpl anyImpl = new AnyImpl(orb, any);
171            anyImpl.typeCode = TypeCodeImpl.convertToNative(orb, anyImpl.typeCode);
172            return anyImpl;
173        }
174    }
175
176    ///////////////////////////////////////////////////////////////////////////
177    // Constructors
178
179    /**
180     * A constructor that sets the Any to contain a null. It also marks
181     * the value as being invalid so that extractions throw an exception
182     * until an insertion has been performed.
183     */
184    public AnyImpl(ORB orb)
185    {
186        this.orb = orb;
187        wrapper = ORBUtilSystemException.get( (com.sun.corba.se.spi.orb.ORB)orb,
188            CORBALogDomains.RPC_PRESENTATION ) ;
189
190        typeCode = orb.get_primitive_tc(TCKind._tk_null);
191        stream = null;
192        object = null;
193        value = 0;
194        // null is a valid value
195        isInitialized = true;
196    }
197
198    //
199    // Create a new AnyImpl which is a copy of obj.
200    //
201    public AnyImpl(ORB orb, Any obj) {
202        this(orb);
203
204        if ((obj instanceof AnyImpl)) {
205            AnyImpl objImpl = (AnyImpl)obj;
206            typeCode = objImpl.typeCode;
207            value = objImpl.value;
208            object = objImpl.object;
209            isInitialized = objImpl.isInitialized;
210
211            if (objImpl.stream != null)
212                stream = objImpl.stream.dup();
213
214        } else {
215            read_value(obj.create_input_stream(), obj.type());
216        }
217    }
218
219    ///////////////////////////////////////////////////////////////////////////
220    // basic accessors
221
222    /**
223     * returns the type of the element contained in the Any.
224     *
225     * @return          the TypeCode for the element in the Any
226     */
227    public TypeCode type() {
228        return typeCode;
229    }
230
231    private TypeCode realType() {
232        return realType(typeCode);
233    }
234
235    private TypeCode realType(TypeCode aType) {
236        TypeCode realType = aType;
237        try {
238            // Note: Indirect types are handled in kind() method
239            while (realType.kind().value() == TCKind._tk_alias) {
240                realType = realType.content_type();
241            }
242        } catch (BadKind bad) { // impossible
243            throw wrapper.badkindCannotOccur( bad ) ;
244        }
245        return realType;
246    }
247
248    /**
249     * sets the type of the element to be contained in the Any.
250     *
251     * @param tc                the TypeCode for the element in the Any
252     */
253    public void type(TypeCode tc)
254    {
255        //debug.log ("type2");
256        // set the typecode
257        typeCode = TypeCodeImpl.convertToNative(orb, tc);
258
259        stream = null;
260        value = 0;
261        object = null;
262        // null is the only legal value this Any can have after resetting the type code
263        isInitialized = (tc.kind().value() == TCKind._tk_null);
264    }
265
266    /**
267     * checks for equality between Anys.
268     *
269     * @param otherAny  the Any to be compared with.
270     * @return          true if the Anys are equal, false otherwise.
271     */
272    public boolean equal(Any otherAny)
273    {
274        //debug.log ("equal");
275
276        if (otherAny == this)
277            return true;
278
279        // first check for typecode equality.
280        // note that this will take aliases into account
281        if (!typeCode.equal(otherAny.type()))
282            return false;
283
284        // Resolve aliases here
285        TypeCode realType = realType();
286
287        // _REVISIT_ Possible optimization for the case where
288        // otherAny is a AnyImpl and the endianesses match.
289        // Need implementation of CDRInputStream.equals()
290        // For now we disable this to encourage testing the generic,
291        // unoptimized code below.
292        // Unfortunately this generic code needs to copy the whole stream
293        // at least once.
294        //    if (AnyImpl.isStreamed[realType.kind().value()]) {
295        //        if (otherAny instanceof AnyImpl) {
296        //            return ((AnyImpl)otherAny).stream.equals(stream);
297        //        }
298        //    }
299        switch (realType.kind().value()) {
300            // handle primitive types
301            case TCKind._tk_null:
302            case TCKind._tk_void:
303                return true;
304            case TCKind._tk_short:
305                return (extract_short() == otherAny.extract_short());
306            case TCKind._tk_long:
307                return (extract_long() == otherAny.extract_long());
308            case TCKind._tk_ushort:
309                return (extract_ushort() == otherAny.extract_ushort());
310            case TCKind._tk_ulong:
311                return (extract_ulong() == otherAny.extract_ulong());
312            case TCKind._tk_float:
313                return (extract_float() == otherAny.extract_float());
314            case TCKind._tk_double:
315                return (extract_double() == otherAny.extract_double());
316            case TCKind._tk_boolean:
317                return (extract_boolean() == otherAny.extract_boolean());
318            case TCKind._tk_char:
319                return (extract_char() == otherAny.extract_char());
320            case TCKind._tk_wchar:
321                return (extract_wchar() == otherAny.extract_wchar());
322            case TCKind._tk_octet:
323                return (extract_octet() == otherAny.extract_octet());
324            case TCKind._tk_any:
325                return extract_any().equal(otherAny.extract_any());
326            case TCKind._tk_TypeCode:
327                return extract_TypeCode().equal(otherAny.extract_TypeCode());
328            case TCKind._tk_string:
329                return extract_string().equals(otherAny.extract_string());
330            case TCKind._tk_wstring:
331                return (extract_wstring().equals(otherAny.extract_wstring()));
332            case TCKind._tk_longlong:
333                return (extract_longlong() == otherAny.extract_longlong());
334            case TCKind._tk_ulonglong:
335                return (extract_ulonglong() == otherAny.extract_ulonglong());
336
337            case TCKind._tk_objref:
338                return (extract_Object().equals(otherAny.extract_Object()));
339            case TCKind._tk_Principal:
340                return (extract_Principal().equals(otherAny.extract_Principal()));
341
342            case TCKind._tk_enum:
343                return (extract_long() == otherAny.extract_long());
344            case TCKind._tk_fixed:
345                return (extract_fixed().compareTo(otherAny.extract_fixed()) == 0);
346            case TCKind._tk_except:
347            case TCKind._tk_struct:
348            case TCKind._tk_union:
349            case TCKind._tk_sequence:
350            case TCKind._tk_array:
351                InputStream copyOfMyStream = this.create_input_stream();
352                InputStream copyOfOtherStream = otherAny.create_input_stream();
353                return equalMember(realType, copyOfMyStream, copyOfOtherStream);
354
355            // Too complicated to handle value types the way we handle
356            // other complex types above. Don't try to decompose it here
357            // for faster comparison, just use Object.equals().
358            case TCKind._tk_value:
359            case TCKind._tk_value_box:
360                return extract_Value().equals(otherAny.extract_Value());
361
362            case TCKind._tk_alias:
363                throw wrapper.errorResolvingAlias() ;
364
365            case TCKind._tk_longdouble:
366                // Unspecified for Java
367                throw wrapper.tkLongDoubleNotSupported() ;
368
369            default:
370                throw wrapper.typecodeNotSupported() ;
371        }
372    }
373
374    // Needed for equal() in order to achieve linear performance for complex types.
375    // Uses up (recursively) copies of the InputStream in both Anys that got created in equal().
376    private boolean equalMember(TypeCode memberType, InputStream myStream, InputStream otherStream) {
377        // Resolve aliases here
378        TypeCode realType = realType(memberType);
379
380        try {
381            switch (realType.kind().value()) {
382                // handle primitive types
383                case TCKind._tk_null:
384                case TCKind._tk_void:
385                    return true;
386                case TCKind._tk_short:
387                    return (myStream.read_short() == otherStream.read_short());
388                case TCKind._tk_long:
389                    return (myStream.read_long() == otherStream.read_long());
390                case TCKind._tk_ushort:
391                    return (myStream.read_ushort() == otherStream.read_ushort());
392                case TCKind._tk_ulong:
393                    return (myStream.read_ulong() == otherStream.read_ulong());
394                case TCKind._tk_float:
395                    return (myStream.read_float() == otherStream.read_float());
396                case TCKind._tk_double:
397                    return (myStream.read_double() == otherStream.read_double());
398                case TCKind._tk_boolean:
399                    return (myStream.read_boolean() == otherStream.read_boolean());
400                case TCKind._tk_char:
401                    return (myStream.read_char() == otherStream.read_char());
402                case TCKind._tk_wchar:
403                    return (myStream.read_wchar() == otherStream.read_wchar());
404                case TCKind._tk_octet:
405                    return (myStream.read_octet() == otherStream.read_octet());
406                case TCKind._tk_any:
407                    return myStream.read_any().equal(otherStream.read_any());
408                case TCKind._tk_TypeCode:
409                    return myStream.read_TypeCode().equal(otherStream.read_TypeCode());
410                case TCKind._tk_string:
411                    return myStream.read_string().equals(otherStream.read_string());
412                case TCKind._tk_wstring:
413                    return (myStream.read_wstring().equals(otherStream.read_wstring()));
414                case TCKind._tk_longlong:
415                    return (myStream.read_longlong() == otherStream.read_longlong());
416                case TCKind._tk_ulonglong:
417                    return (myStream.read_ulonglong() == otherStream.read_ulonglong());
418
419                case TCKind._tk_objref:
420                    return (myStream.read_Object().equals(otherStream.read_Object()));
421                case TCKind._tk_Principal:
422                    return (myStream.read_Principal().equals(otherStream.read_Principal()));
423
424                case TCKind._tk_enum:
425                    return (myStream.read_long() == otherStream.read_long());
426                case TCKind._tk_fixed:
427                    return (myStream.read_fixed().compareTo(otherStream.read_fixed()) == 0);
428                case TCKind._tk_except:
429                case TCKind._tk_struct: {
430                    int length = realType.member_count();
431                    for (int i=0; i<length; i++) {
432                        if ( ! equalMember(realType.member_type(i), myStream, otherStream)) {
433                            return false;
434                        }
435                    }
436                    return true;
437                }
438                case TCKind._tk_union: {
439                    Any myDiscriminator = orb.create_any();
440                    Any otherDiscriminator = orb.create_any();
441                    myDiscriminator.read_value(myStream, realType.discriminator_type());
442                    otherDiscriminator.read_value(otherStream, realType.discriminator_type());
443
444                    if ( ! myDiscriminator.equal(otherDiscriminator)) {
445                        return false;
446                    }
447                    TypeCodeImpl realTypeCodeImpl = TypeCodeImpl.convertToNative(orb, realType);
448                    int memberIndex = realTypeCodeImpl.currentUnionMemberIndex(myDiscriminator);
449                    if (memberIndex == -1)
450                        throw wrapper.unionDiscriminatorError() ;
451
452                    if ( ! equalMember(realType.member_type(memberIndex), myStream, otherStream)) {
453                        return false;
454                    }
455                    return true;
456                }
457                case TCKind._tk_sequence: {
458                    int length = myStream.read_long();
459                    otherStream.read_long(); // just so that the two stream are in sync
460                    for (int i=0; i<length; i++) {
461                        if ( ! equalMember(realType.content_type(), myStream, otherStream)) {
462                            return false;
463                        }
464                    }
465                    return true;
466                }
467                case TCKind._tk_array: {
468                    int length = realType.member_count();
469                    for (int i=0; i<length; i++) {
470                        if ( ! equalMember(realType.content_type(), myStream, otherStream)) {
471                            return false;
472                        }
473                    }
474                    return true;
475                }
476
477                // Too complicated to handle value types the way we handle
478                // other complex types above. Don't try to decompose it here
479                // for faster comparison, just use Object.equals().
480                case TCKind._tk_value:
481                case TCKind._tk_value_box:
482                    org.omg.CORBA_2_3.portable.InputStream mine =
483                        (org.omg.CORBA_2_3.portable.InputStream)myStream;
484                    org.omg.CORBA_2_3.portable.InputStream other =
485                        (org.omg.CORBA_2_3.portable.InputStream)otherStream;
486                    return mine.read_value().equals(other.read_value());
487
488                case TCKind._tk_alias:
489                    // error resolving alias above
490                    throw wrapper.errorResolvingAlias() ;
491
492                case TCKind._tk_longdouble:
493                    throw wrapper.tkLongDoubleNotSupported() ;
494
495                default:
496                    throw wrapper.typecodeNotSupported() ;
497            }
498        } catch (BadKind badKind) { // impossible
499            throw wrapper.badkindCannotOccur() ;
500        } catch (Bounds bounds) { // impossible
501            throw wrapper.boundsCannotOccur() ;
502        }
503    }
504
505    ///////////////////////////////////////////////////////////////////////////
506    // accessors for marshaling/unmarshaling
507
508    /**
509     * returns an output stream that an Any value can be marshaled into.
510     *
511     * @return          the OutputStream to marshal value of Any into
512     */
513    public org.omg.CORBA.portable.OutputStream create_output_stream()
514    {
515        //debug.log ("create_output_stream");
516        final ORB finalorb = this.orb;
517        return AccessController.doPrivileged(new PrivilegedAction<AnyOutputStream>() {
518            @Override
519            public AnyOutputStream run() {
520                return new AnyOutputStream(finalorb);
521            }
522        });
523    }
524
525    /**
526     * returns an input stream that an Any value can be marshaled out of.
527     *
528     * @return          the InputStream to marshal value of Any out of.
529     */
530    public org.omg.CORBA.portable.InputStream create_input_stream()
531    {
532        //
533        // We create a new InputStream so that multiple threads can call here
534        // and read the streams in parallel without thread safety problems.
535        //
536        //debug.log ("create_input_stream");
537        if (AnyImpl.isStreamed[realType().kind().value()]) {
538            return stream.dup();
539        } else {
540            OutputStream os = (OutputStream)orb.create_output_stream();
541            TCUtility.marshalIn(os, realType(), value, object);
542
543            return os.create_input_stream();
544        }
545    }
546
547    ///////////////////////////////////////////////////////////////////////////
548    // marshaling/unmarshaling routines
549
550    //
551    // If the InputStream is a CDRInputStream then we can copy the bytes
552    // since it is in our format and does not have alignment issues.
553    //
554    public void read_value(org.omg.CORBA.portable.InputStream in, TypeCode tc)
555    {
556        //debug.log ("read_value");
557        //
558        // Assume that someone isn't going to think they can keep reading
559        // from this stream after calling us. That would be likely for
560        // an IIOPInputStream but if it is an AnyInputStream then they
561        // presumably obtained it via our create_output_stream() so they could
562        // write the contents of an IDL data type to it and then call
563        // create_input_stream() for us to read it. This is how Helper classes
564        // typically implement the insert() method.
565        // We should probably document this behavior in the 1.1 revision
566        // task force.
567        //
568
569        typeCode = TypeCodeImpl.convertToNative(orb, tc);
570        int kind = realType().kind().value();
571        if (kind >= isStreamed.length) {
572            throw wrapper.invalidIsstreamedTckind( CompletionStatus.COMPLETED_MAYBE,
573                new Integer(kind)) ;
574        }
575
576        if (AnyImpl.isStreamed[kind]) {
577            if ( in instanceof AnyInputStream ) {
578                // could only have been created here
579                stream = (CDRInputStream)in;
580            } else {
581                org.omg.CORBA_2_3.portable.OutputStream out =
582                    (org.omg.CORBA_2_3.portable.OutputStream)orb.create_output_stream();
583                typeCode.copy((org.omg.CORBA_2_3.portable.InputStream)in, out);
584                stream = (CDRInputStream)out.create_input_stream();
585            }
586        } else {
587            java.lang.Object[] objholder = new java.lang.Object[1];
588            objholder[0] = object;
589            long[] longholder = new long[1];
590            TCUtility.unmarshalIn(in, realType(), longholder, objholder);
591            value = longholder[0];
592            object = objholder[0];
593            stream = null;
594        }
595        isInitialized = true;
596    }
597
598
599    //
600    // We could optimize this by noticing whether the target stream
601    // has ever had anything marshaled on it that required an
602    // alignment of greater than 4 (was write_double() ever called on it).
603    // If not, then we can just do a byte array copy without having to
604    // drive the remarshaling through typecode interpretation.
605    //
606    public void write_value(OutputStream out)
607    {
608        //debug.log ("write_value");
609        if (AnyImpl.isStreamed[realType().kind().value()]) {
610            typeCode.copy(stream.dup(), out);
611        } else {
612            // _REVISIT_ check isInitialized whether all we write is TypeCode!
613            TCUtility.marshalIn(out, realType(), value, object);
614        }
615    }
616
617    /**
618     * takes a streamable and inserts its reference into the any
619     *
620     * @param s         the streamable to insert
621     */
622    public void insert_Streamable(Streamable s)
623    {
624        //debug.log ("insert_Streamable");
625        typeCode = TypeCodeImpl.convertToNative(orb, s._type());
626        object = s;
627        isInitialized = true;
628    }
629
630    public Streamable extract_Streamable()
631    {
632        //debug.log( "extract_Streamable" ) ;
633        return (Streamable)object;
634    }
635
636    ///////////////////////////////////////////////////////////////////////////
637    // insertion/extraction/replacement for all basic types
638
639    /**
640     * See the description of the <a href="#anyOps">general Any operations.</a>
641     */
642    public void insert_short(short s)
643    {
644        //debug.log ("insert_short");
645        typeCode = orb.get_primitive_tc(TCKind._tk_short);
646        value = s;
647        isInitialized = true;
648    }
649
650    private String getTCKindName( int tc )
651    {
652        if ((tc >= 0) && (tc < TypeCodeImpl.kindNames.length))
653            return TypeCodeImpl.kindNames[tc] ;
654        else
655            return "UNKNOWN(" + tc + ")" ;
656    }
657
658    private void checkExtractBadOperation( int expected )
659    {
660        if (!isInitialized)
661            throw wrapper.extractNotInitialized() ;
662
663        int tc = realType().kind().value() ;
664        if (tc != expected) {
665            String tcName = getTCKindName( tc ) ;
666            String expectedName = getTCKindName( expected ) ;
667            throw wrapper.extractWrongType( expectedName, tcName ) ;
668        }
669    }
670
671    private void checkExtractBadOperationList( int[] expected )
672    {
673        if (!isInitialized)
674            throw wrapper.extractNotInitialized() ;
675
676        int tc = realType().kind().value() ;
677        for (int ctr=0; ctr<expected.length; ctr++)
678            if (tc == expected[ctr])
679                return ;
680
681        List list = new ArrayList() ;
682        for (int ctr=0; ctr<expected.length; ctr++)
683            list.add( getTCKindName( expected[ctr] ) ) ;
684
685        String tcName = getTCKindName( tc ) ;
686        throw wrapper.extractWrongTypeList( list, tcName ) ;
687    }
688
689    /**
690     * See the description of the <a href="#anyOps">general Any operations.</a>
691     */
692    public short extract_short()
693    {
694        //debug.log ("extract_short");
695        checkExtractBadOperation( TCKind._tk_short ) ;
696        return (short)value;
697    }
698
699    /**
700     * See the description of the <a href="#anyOps">general Any operations.</a>
701     */
702    public void insert_long(int l)
703    {
704        //debug.log ("insert_long");
705        // A long value is applicable to enums as well, so don't erase the enum type code
706        // in case it was initialized that way before.
707        int kind = realType().kind().value();
708        if (kind != TCKind._tk_long && kind != TCKind._tk_enum) {
709            typeCode = orb.get_primitive_tc(TCKind._tk_long);
710        }
711        value = l;
712        isInitialized = true;
713    }
714
715    /**
716     * See the description of the <a href="#anyOps">general Any operations.</a>
717     */
718    public int extract_long()
719    {
720        //debug.log ("extract_long");
721        checkExtractBadOperationList( new int[] { TCKind._tk_long, TCKind._tk_enum } ) ;
722        return (int)value;
723    }
724
725    /**
726     * See the description of the <a href="#anyOps">general Any operations.</a>
727     */
728    public void insert_ushort(short s)
729    {
730        //debug.log ("insert_ushort");
731        typeCode = orb.get_primitive_tc(TCKind._tk_ushort);
732        value = s;
733        isInitialized = true;
734    }
735
736    /**
737     * See the description of the <a href="#anyOps">general Any operations.</a>
738     */
739    public short extract_ushort()
740    {
741        //debug.log ("extract_ushort");
742        checkExtractBadOperation( TCKind._tk_ushort ) ;
743        return (short)value;
744    }
745
746    /**
747     * See the description of the <a href="#anyOps">general Any operations.</a>
748     */
749    public void insert_ulong(int l)
750    {
751        //debug.log ("insert_ulong");
752        typeCode = orb.get_primitive_tc(TCKind._tk_ulong);
753        value = l;
754        isInitialized = true;
755    }
756
757    /**
758     * See the description of the <a href="#anyOps">general Any operations.</a>
759     */
760    public int extract_ulong()
761    {
762        //debug.log ("extract_ulong");
763        checkExtractBadOperation( TCKind._tk_ulong ) ;
764        return (int)value;
765    }
766
767    /**
768     * See the description of the <a href="#anyOps">general Any operations.</a>
769     */
770    public void insert_float(float f)
771    {
772        //debug.log ("insert_float");
773        typeCode = orb.get_primitive_tc(TCKind._tk_float);
774        value = Float.floatToIntBits(f);
775        isInitialized = true;
776    }
777
778    /**
779     * See the description of the <a href="#anyOps">general Any operations.</a>
780     */
781    public float extract_float()
782    {
783        //debug.log ("extract_float");
784        checkExtractBadOperation( TCKind._tk_float ) ;
785        return Float.intBitsToFloat((int)value);
786    }
787
788    /**
789     * See the description of the <a href="#anyOps">general Any operations.</a>
790     */
791    public void insert_double(double d)
792    {
793        //debug.log ("insert_double");
794        typeCode = orb.get_primitive_tc(TCKind._tk_double);
795        value = Double.doubleToLongBits(d);
796        isInitialized = true;
797    }
798
799    /**
800     * See the description of the <a href="#anyOps">general Any operations.</a>
801     */
802    public double extract_double()
803    {
804        //debug.log ("extract_double");
805        checkExtractBadOperation( TCKind._tk_double ) ;
806        return Double.longBitsToDouble(value);
807    }
808
809    /**
810     * See the description of the <a href="#anyOps">general Any operations.</a>
811     */
812    public void insert_longlong(long l)
813    {
814        //debug.log ("insert_longlong");
815        typeCode = orb.get_primitive_tc(TCKind._tk_longlong);
816        value = l;
817        isInitialized = true;
818    }
819
820    /**
821     * See the description of the <a href="#anyOps">general Any operations.</a>
822     */
823    public long extract_longlong()
824    {
825        //debug.log ("extract_longlong");
826        checkExtractBadOperation( TCKind._tk_longlong ) ;
827        return value;
828    }
829
830    /**
831     * See the description of the <a href="#anyOps">general Any operations.</a>
832     */
833    public void insert_ulonglong(long l)
834    {
835        //debug.log ("insert_ulonglong");
836        typeCode = orb.get_primitive_tc(TCKind._tk_ulonglong);
837        value = l;
838        isInitialized = true;
839    }
840
841    /**
842     * See the description of the <a href="#anyOps">general Any operations.</a>
843     */
844    public long extract_ulonglong()
845    {
846        //debug.log ("extract_ulonglong");
847        checkExtractBadOperation( TCKind._tk_ulonglong ) ;
848        return value;
849    }
850
851    /**
852     * See the description of the <a href="#anyOps">general Any operations.</a>
853     */
854    public void insert_boolean(boolean b)
855    {
856        //debug.log ("insert_boolean");
857        typeCode = orb.get_primitive_tc(TCKind._tk_boolean);
858        value = (b)? 1:0;
859        isInitialized = true;
860    }
861
862    /**
863     * See the description of the <a href="#anyOps">general Any operations.</a>
864     */
865    public boolean extract_boolean()
866    {
867        //debug.log ("extract_boolean");
868        checkExtractBadOperation( TCKind._tk_boolean ) ;
869        return (value == 0)? false: true;
870    }
871
872    /**
873     * See the description of the <a href="#anyOps">general Any operations.</a>
874     */
875    public void insert_char(char c)
876    {
877        //debug.log ("insert_char");
878        typeCode = orb.get_primitive_tc(TCKind._tk_char);
879        value = c;
880        isInitialized = true;
881    }
882
883    /**
884     * See the description of the <a href="#anyOps">general Any operations.</a>
885     */
886    public char extract_char()
887    {
888        //debug.log ("extract_char");
889        checkExtractBadOperation( TCKind._tk_char ) ;
890        return (char)value;
891    }
892
893    /**
894     * See the description of the <a href="#anyOps">general Any operations.</a>
895     */
896    public void insert_wchar(char c)
897    {
898        //debug.log ("insert_wchar");
899        typeCode = orb.get_primitive_tc(TCKind._tk_wchar);
900        value = c;
901        isInitialized = true;
902    }
903
904    /**
905     * See the description of the <a href="#anyOps">general Any operations.</a>
906     */
907    public char extract_wchar()
908    {
909        //debug.log ("extract_wchar");
910        checkExtractBadOperation( TCKind._tk_wchar ) ;
911        return (char)value;
912    }
913
914
915    /**
916     * See the description of the <a href="#anyOps">general Any operations.</a>
917     */
918    public void insert_octet(byte b)
919    {
920        //debug.log ("insert_octet");
921        typeCode = orb.get_primitive_tc(TCKind._tk_octet);
922        value = b;
923        isInitialized = true;
924    }
925
926    /**
927     * See the description of the <a href="#anyOps">general Any operations.</a>
928     */
929    public byte extract_octet()
930    {
931        //debug.log ("extract_octet");
932        checkExtractBadOperation( TCKind._tk_octet ) ;
933        return (byte)value;
934    }
935
936    /**
937     * See the description of the <a href="#anyOps">general Any operations.</a>
938     */
939    public void insert_string(String s)
940    {
941        //debug.log ("insert_string");
942        // Make sure type code information for bounded strings is not erased
943        if (typeCode.kind() == TCKind.tk_string) {
944            int length = 0;
945            try {
946                length = typeCode.length();
947            } catch (BadKind bad) {
948                throw wrapper.badkindCannotOccur() ;
949            }
950
951            // Check if bounded strings length is not exceeded
952            if (length != 0 && s != null && s.length() > length) {
953                throw wrapper.badStringBounds( new Integer(s.length()),
954                    new Integer(length) ) ;
955            }
956        } else {
957            typeCode = orb.get_primitive_tc(TCKind._tk_string);
958        }
959        object = s;
960        isInitialized = true;
961    }
962
963    /**
964     * See the description of the <a href="#anyOps">general Any operations.</a>
965     */
966    public String extract_string()
967    {
968        //debug.log ("extract_string");
969        checkExtractBadOperation( TCKind._tk_string ) ;
970        return (String)object;
971    }
972
973    /**
974     * See the description of the <a href="#anyOps">general Any operations.</a>
975     */
976    public void insert_wstring(String s)
977    {
978        //debug.log ("insert_wstring");
979        // Make sure type code information for bounded strings is not erased
980        if (typeCode.kind() == TCKind.tk_wstring) {
981            int length = 0;
982            try {
983                length = typeCode.length();
984            } catch (BadKind bad) {
985                throw wrapper.badkindCannotOccur() ;
986            }
987
988            // Check if bounded strings length is not exceeded
989            if (length != 0 && s != null && s.length() > length) {
990                throw wrapper.badStringBounds( new Integer(s.length()),
991                    new Integer(length) ) ;
992            }
993        } else {
994            typeCode = orb.get_primitive_tc(TCKind._tk_wstring);
995        }
996        object = s;
997        isInitialized = true;
998    }
999
1000    /**
1001     * See the description of the <a href="#anyOps">general Any operations.</a>
1002     */
1003    public String extract_wstring()
1004    {
1005        //debug.log ("extract_wstring");
1006        checkExtractBadOperation( TCKind._tk_wstring ) ;
1007        return (String)object;
1008    }
1009
1010    /**
1011     * See the description of the <a href="#anyOps">general Any operations.</a>
1012     */
1013    public void insert_any(Any a)
1014    {
1015        //debug.log ("insert_any");
1016        typeCode = orb.get_primitive_tc(TCKind._tk_any);
1017        object = a;
1018        stream = null;
1019        isInitialized = true;
1020    }
1021
1022    /**
1023     * See the description of the <a href="#anyOps">general Any operations.</a>
1024     */
1025    public Any extract_any()
1026    {
1027        //debug.log ("extract_any");
1028        checkExtractBadOperation( TCKind._tk_any ) ;
1029        return (Any)object;
1030    }
1031
1032    /**
1033     * See the description of the <a href="#anyOps">general Any operations.</a>
1034     */
1035    public void insert_Object(org.omg.CORBA.Object o)
1036    {
1037        //debug.log ("insert_Object");
1038        if ( o == null ) {
1039            typeCode = orb.get_primitive_tc(TCKind._tk_objref);
1040        } else {
1041            if (StubAdapter.isStub(o)) {
1042                String[] ids = StubAdapter.getTypeIds( o ) ;
1043                typeCode = new TypeCodeImpl(orb, TCKind._tk_objref, ids[0], "");
1044            } else {
1045                throw wrapper.badInsertobjParam(
1046                    CompletionStatus.COMPLETED_MAYBE, o.getClass().getName() ) ;
1047            }
1048        }
1049
1050        object = o;
1051        isInitialized = true;
1052    }
1053
1054    /**
1055     * A variant of the insertion operation that takes a typecode
1056     * argument as well.
1057     */
1058    public void insert_Object(org.omg.CORBA.Object o, TypeCode tc)
1059    {
1060        //debug.log ("insert_Object2");
1061        try {
1062            if ( tc.id().equals("IDL:omg.org/CORBA/Object:1.0") || o._is_a(tc.id()) )
1063                {
1064                    typeCode = TypeCodeImpl.convertToNative(orb, tc);
1065                    object = o;
1066                }
1067            else {
1068                throw wrapper.insertObjectIncompatible() ;
1069            }
1070        } catch ( Exception ex ) {
1071            throw wrapper.insertObjectFailed(ex) ;
1072        }
1073        isInitialized = true;
1074    }
1075
1076    /**
1077     * See the description of the <a href="#anyOps">general Any operations.</a>
1078     */
1079    public org.omg.CORBA.Object extract_Object()
1080    {
1081        //debug.log ("extract_Object");
1082        if (!isInitialized)
1083            throw wrapper.extractNotInitialized() ;
1084
1085        // Check if the object contained here is of the type in typeCode
1086        org.omg.CORBA.Object obj = null;
1087        try {
1088            obj = (org.omg.CORBA.Object) object;
1089            if (typeCode.id().equals("IDL:omg.org/CORBA/Object:1.0") || obj._is_a(typeCode.id())) {
1090                return obj;
1091            } else {
1092                throw wrapper.extractObjectIncompatible() ;
1093            }
1094        } catch ( Exception ex ) {
1095            throw wrapper.extractObjectFailed(ex);
1096        }
1097    }
1098
1099    /**
1100     * See the description of the <a href="#anyOps">general Any operations.</a>
1101     */
1102    public void insert_TypeCode(TypeCode tc)
1103    {
1104        //debug.log ("insert_TypeCode");
1105        typeCode = orb.get_primitive_tc(TCKind._tk_TypeCode);
1106        object = tc;
1107        isInitialized = true;
1108    }
1109
1110    /**
1111     * See the description of the <a href="#anyOps">general Any operations.</a>
1112     */
1113    public TypeCode extract_TypeCode()
1114    {
1115        //debug.log ("extract_TypeCode");
1116        checkExtractBadOperation( TCKind._tk_TypeCode ) ;
1117        return (TypeCode)object;
1118    }
1119
1120    /**
1121     * @deprecated
1122     */
1123    @Deprecated
1124    public void insert_Principal(Principal p)
1125    {
1126        typeCode = orb.get_primitive_tc(TCKind._tk_Principal);
1127        object = p;
1128        isInitialized = true;
1129    }
1130
1131    /**
1132     * @deprecated
1133     */
1134    @Deprecated
1135    public Principal extract_Principal()
1136    {
1137        checkExtractBadOperation( TCKind._tk_Principal ) ;
1138        return (Principal)object;
1139    }
1140
1141    /**
1142     * Note that the Serializable really should be an IDLEntity of
1143     * some kind.  It shouldn't just be an RMI-IIOP type.  Currently,
1144     * we accept and will produce RMI repIds with the latest
1145     * calculations if given a non-IDLEntity Serializable.
1146     */
1147    public Serializable extract_Value()
1148    {
1149        //debug.log ("extract_Value");
1150        checkExtractBadOperationList( new int[] { TCKind._tk_value,
1151            TCKind._tk_value_box, TCKind._tk_abstract_interface } ) ;
1152        return (Serializable)object;
1153    }
1154
1155    public void insert_Value(Serializable v)
1156    {
1157        //debug.log ("insert_Value");
1158        object = v;
1159
1160        TypeCode tc;
1161
1162        if ( v == null ) {
1163            tc = orb.get_primitive_tc (TCKind.tk_value);
1164        } else {
1165            // See note in getPrimitiveTypeCodeForClass.  We
1166            // have to use the latest type code fixes in this
1167            // case since there is no way to know what ORB will
1168            // actually send this Any.  In RMI-IIOP, when using
1169            // Util.writeAny, we can do the versioning correctly,
1170            // and use the insert_Value(Serializable, TypeCode)
1171            // method.
1172            //
1173            // The ORB singleton uses the latest version.
1174            tc = createTypeCodeForClass (v.getClass(), (ORB)ORB.init());
1175        }
1176
1177        typeCode = TypeCodeImpl.convertToNative(orb, tc);
1178        isInitialized = true;
1179    }
1180
1181    public void insert_Value(Serializable v, org.omg.CORBA.TypeCode t)
1182    {
1183        //debug.log ("insert_Value2");
1184        object = v;
1185        typeCode = TypeCodeImpl.convertToNative(orb, t);
1186        isInitialized = true;
1187    }
1188
1189    public void insert_fixed(java.math.BigDecimal value) {
1190        typeCode = TypeCodeImpl.convertToNative(orb,
1191            orb.create_fixed_tc(TypeCodeImpl.digits(value), TypeCodeImpl.scale(value)));
1192        object = value;
1193        isInitialized = true;
1194    }
1195
1196    public void insert_fixed(java.math.BigDecimal value, org.omg.CORBA.TypeCode type)
1197    {
1198        try {
1199            if (TypeCodeImpl.digits(value) > type.fixed_digits() ||
1200                TypeCodeImpl.scale(value) > type.fixed_scale())
1201            {
1202                throw wrapper.fixedNotMatch() ;
1203            }
1204        } catch (org.omg.CORBA.TypeCodePackage.BadKind bk) {
1205            // type isn't even of kind fixed
1206            throw wrapper.fixedBadTypecode( bk ) ;
1207        }
1208        typeCode = TypeCodeImpl.convertToNative(orb, type);
1209        object = value;
1210        isInitialized = true;
1211    }
1212
1213    public java.math.BigDecimal extract_fixed() {
1214        checkExtractBadOperation( TCKind._tk_fixed ) ;
1215        return (BigDecimal)object;
1216    }
1217
1218    /**
1219     * Utility method for insert_Value and Util.writeAny.
1220     *
1221     * The ORB passed in should have the desired ORBVersion.  It
1222     * is used to generate the type codes.
1223     */
1224    public TypeCode createTypeCodeForClass (java.lang.Class c, ORB tcORB)
1225    {
1226        // Look in the cache first
1227        TypeCodeImpl classTC = tcORB.getTypeCodeForClass(c);
1228        if (classTC != null)
1229            return classTC;
1230
1231        // All cases need to be able to create repository IDs.
1232        //
1233        // See bug 4391648 for more info about the tcORB in this
1234        // case.
1235        RepositoryIdStrings repStrs
1236            = RepositoryIdFactory.getRepIdStringsFactory();
1237
1238
1239        // Assertion: c instanceof Serializable?
1240
1241        if ( c.isArray() ) {
1242            // Arrays - may recurse for multi-dimensional arrays
1243            Class componentClass = c.getComponentType();
1244            TypeCode embeddedType;
1245            if ( componentClass.isPrimitive() ) {
1246                embeddedType = getPrimitiveTypeCodeForClass(componentClass,
1247                                                            tcORB);
1248            } else {
1249                embeddedType = createTypeCodeForClass (componentClass,
1250                                                       tcORB);
1251            }
1252            TypeCode t = tcORB.create_sequence_tc (0, embeddedType);
1253
1254            String id = repStrs.createForJavaType(c);
1255
1256            return tcORB.create_value_box_tc (id, "Sequence", t);
1257        } else if ( c == java.lang.String.class ) {
1258            // Strings
1259            TypeCode t = tcORB.create_string_tc (0);
1260
1261            String id = repStrs.createForJavaType(c);
1262
1263            return tcORB.create_value_box_tc (id, "StringValue", t);
1264        }
1265
1266        // Anything else
1267        // We know that this is a TypeCodeImpl since it is our ORB
1268        classTC = (TypeCodeImpl)ValueUtility.createTypeCodeForClass(
1269            tcORB, c, ORBUtility.createValueHandler());
1270        // Intruct classTC to store its buffer
1271        classTC.setCaching(true);
1272        // Update the cache
1273        tcORB.setTypeCodeForClass(c, classTC);
1274        return classTC;
1275    }
1276
1277    /**
1278     * It looks like this was copied from io.ValueUtility at some
1279     * point.
1280     *
1281     * It's used by createTypeCodeForClass.  The tcORB passed in
1282     * should have the desired ORB version, and is used to
1283     * create the type codes.
1284     */
1285    private TypeCode getPrimitiveTypeCodeForClass (Class c, ORB tcORB)
1286    {
1287        //debug.log ("getPrimitiveTypeCodeForClass");
1288
1289        if (c == Integer.TYPE) {
1290            return tcORB.get_primitive_tc (TCKind.tk_long);
1291        } else if (c == Byte.TYPE) {
1292            return tcORB.get_primitive_tc (TCKind.tk_octet);
1293        } else if (c == Long.TYPE) {
1294            return tcORB.get_primitive_tc (TCKind.tk_longlong);
1295        } else if (c == Float.TYPE) {
1296            return tcORB.get_primitive_tc (TCKind.tk_float);
1297        } else if (c == Double.TYPE) {
1298            return tcORB.get_primitive_tc (TCKind.tk_double);
1299        } else if (c == Short.TYPE) {
1300            return tcORB.get_primitive_tc (TCKind.tk_short);
1301        } else if (c == Character.TYPE) {
1302            // For Merlin or later JDKs, or for foreign ORBs,
1303            // we correctly say that a Java char maps to a
1304            // CORBA wchar.  For backwards compatibility
1305            // with our older ORBs, we say it maps to a
1306            // CORBA char.  This is only used in RMI-IIOP
1307            // in our javax.rmi.CORBA.Util delegate's
1308            // writeAny method.  In Java IDL, there's no way
1309            // to know the ORB version that the Any will be
1310            // sent out with -- it could be different than
1311            // the one used to create the Any -- so we use the
1312            // most recent version (see insert_Value).
1313            if (ORBVersionFactory.getFOREIGN().compareTo(tcORB.getORBVersion()) == 0 ||
1314                ORBVersionFactory.getNEWER().compareTo(tcORB.getORBVersion()) <= 0)
1315                return tcORB.get_primitive_tc(TCKind.tk_wchar);
1316            else
1317                return tcORB.get_primitive_tc(TCKind.tk_char);
1318        } else if (c == Boolean.TYPE) {
1319            return tcORB.get_primitive_tc (TCKind.tk_boolean);
1320        } else {
1321            // _REVISIT_ Not sure if this is right.
1322            return tcORB.get_primitive_tc (TCKind.tk_any);
1323        }
1324    }
1325
1326    // Extracts a member value according to the given TypeCode from the given complex Any
1327    // (at the Anys current internal stream position, consuming the anys stream on the way)
1328    // and returns it wrapped into a new Any
1329    public Any extractAny(TypeCode memberType, ORB orb) {
1330        Any returnValue = orb.create_any();
1331        OutputStream out = returnValue.create_output_stream();
1332        TypeCodeImpl.convertToNative(orb, memberType).copy((InputStream)stream, out);
1333        returnValue.read_value(out.create_input_stream(), memberType);
1334        return returnValue;
1335    }
1336
1337    // This method could very well be moved into TypeCodeImpl or a common utility class,
1338    // but is has to be in this package.
1339    static public Any extractAnyFromStream(TypeCode memberType, InputStream input, ORB orb) {
1340        Any returnValue = orb.create_any();
1341        OutputStream out = returnValue.create_output_stream();
1342        TypeCodeImpl.convertToNative(orb, memberType).copy(input, out);
1343        returnValue.read_value(out.create_input_stream(), memberType);
1344        return returnValue;
1345    }
1346
1347    // There is no other way for DynAnys to find out whether the Any is initialized.
1348    public boolean isInitialized() {
1349        return isInitialized;
1350    }
1351}
1352