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