1 /*
   2  * Copyright (c) 2000, 2003, 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 package com.sun.corba.se.impl.dynamicany;
  27 
  28 import org.omg.CORBA.TypeCode;
  29 import org.omg.CORBA.TCKind;
  30 import org.omg.CORBA.Any;
  31 import org.omg.CORBA.TypeCodePackage.BadKind;
  32 import org.omg.CORBA.TypeCodePackage.Bounds;
  33 import org.omg.CORBA.portable.InputStream;
  34 import org.omg.DynamicAny.*;
  35 import org.omg.DynamicAny.DynAnyPackage.TypeMismatch;
  36 import org.omg.DynamicAny.DynAnyPackage.InvalidValue;
  37 import org.omg.DynamicAny.DynAnyFactoryPackage.InconsistentTypeCode;
  38 
  39 import com.sun.corba.se.spi.orb.ORB ;
  40 import com.sun.corba.se.spi.logging.CORBALogDomains ;
  41 import com.sun.corba.se.impl.logging.ORBUtilSystemException ;
  42 
  43 public class DynUnionImpl extends DynAnyConstructedImpl implements DynUnion
  44 {
  45     //
  46     // Instance variables
  47     //
  48 
  49     DynAny discriminator = null;
  50     // index either points to the discriminator or the named member is it exists.
  51     // The currently active member, which is of the same type as the discriminator.
  52     DynAny currentMember = null;
  53     int currentMemberIndex = NO_INDEX;
  54 
  55     //
  56     // Constructors
  57     //
  58 
  59     private DynUnionImpl() {
  60         this(null, (Any)null, false);
  61     }
  62 
  63     protected DynUnionImpl(ORB orb, Any any, boolean copyValue) {
  64         // We can be sure that typeCode is of kind tk_union
  65         super(orb, any, copyValue);
  66     }
  67 
  68     protected DynUnionImpl(ORB orb, TypeCode typeCode) {
  69         // We can be sure that typeCode is of kind tk_union
  70         super(orb, typeCode);
  71     }
  72 
  73     protected boolean initializeComponentsFromAny() {
  74         try {
  75             InputStream input = any.create_input_stream();
  76             Any discriminatorAny = DynAnyUtil.extractAnyFromStream(discriminatorType(), input, orb);
  77             discriminator = DynAnyUtil.createMostDerivedDynAny(discriminatorAny, orb, false);
  78             currentMemberIndex = currentUnionMemberIndex(discriminatorAny);
  79             Any memberAny = DynAnyUtil.extractAnyFromStream(memberType(currentMemberIndex), input, orb);
  80             currentMember = DynAnyUtil.createMostDerivedDynAny(memberAny, orb, false);
  81             components = new DynAny[] {discriminator, currentMember};
  82         } catch (InconsistentTypeCode ictc) { // impossible
  83         }
  84         return true;
  85     }
  86 
  87     // Sets the current position to zero.
  88     // The discriminator value is set to a value consistent with the first named member
  89     // of the union. That member is activated and (recursively) initialized to its default value.
  90     protected boolean initializeComponentsFromTypeCode() {
  91         //System.out.println(this + " initializeComponentsFromTypeCode");
  92         try {
  93             // We can be sure that memberCount() > 0 according to the IDL language spec
  94             discriminator = DynAnyUtil.createMostDerivedDynAny(memberLabel(0), orb, false);
  95             index = 0;
  96             currentMemberIndex = 0;
  97             currentMember = DynAnyUtil.createMostDerivedDynAny(memberType(0), orb);
  98             components = new DynAny[] {discriminator, currentMember};
  99         } catch (InconsistentTypeCode ictc) { // impossible
 100         }
 101         return true;
 102     }
 103 
 104     //
 105     // Convenience methods
 106     //
 107 
 108     private TypeCode discriminatorType() {
 109         TypeCode discriminatorType = null;
 110         try {
 111             discriminatorType = any.type().discriminator_type();
 112         } catch (BadKind bad) {
 113         }
 114         return discriminatorType;
 115     }
 116 
 117     private int memberCount() {
 118         int memberCount = 0;
 119         try {
 120             memberCount = any.type().member_count();
 121         } catch (BadKind bad) {
 122         }
 123         return memberCount;
 124     }
 125 
 126     private Any memberLabel(int i) {
 127         Any memberLabel = null;
 128         try {
 129             memberLabel = any.type().member_label(i);
 130         } catch (BadKind bad) {
 131         } catch (Bounds bounds) {
 132         }
 133         return memberLabel;
 134     }
 135 
 136     private TypeCode memberType(int i) {
 137         TypeCode memberType = null;
 138         try {
 139             memberType = any.type().member_type(i);
 140         } catch (BadKind bad) {
 141         } catch (Bounds bounds) {
 142         }
 143         return memberType;
 144     }
 145 
 146     private String memberName(int i) {
 147         String memberName = null;
 148         try {
 149             memberName = any.type().member_name(i);
 150         } catch (BadKind bad) {
 151         } catch (Bounds bounds) {
 152         }
 153         return memberName;
 154     }
 155 
 156     private int defaultIndex() {
 157         int defaultIndex = -1;
 158         try {
 159             defaultIndex = any.type().default_index();
 160         } catch (BadKind bad) {
 161         }
 162         return defaultIndex;
 163     }
 164 
 165     private int currentUnionMemberIndex(Any discriminatorValue) {
 166         int memberCount = memberCount();
 167         Any memberLabel;
 168         for (int i=0; i<memberCount; i++) {
 169             memberLabel = memberLabel(i);
 170             if (memberLabel.equal(discriminatorValue)) {
 171                 return i;
 172             }
 173         }
 174         if (defaultIndex() != -1) {
 175             return defaultIndex();
 176         }
 177         return NO_INDEX;
 178     }
 179 
 180     protected void clearData() {
 181         super.clearData();
 182         discriminator = null;
 183         // Necessary to guarantee OBJECT_NOT_EXIST in member()
 184         currentMember.destroy();
 185         currentMember = null;
 186         currentMemberIndex = NO_INDEX;
 187     }
 188 
 189     //
 190     // DynAny interface methods
 191     //
 192 
 193     // _REVISIT_ More efficient copy operation
 194 
 195     //
 196     // DynUnion interface methods
 197     //
 198 
 199     /**
 200     * Returns the current discriminator value.
 201     */
 202     public org.omg.DynamicAny.DynAny get_discriminator () {
 203         if (status == STATUS_DESTROYED) {
 204             throw wrapper.dynAnyDestroyed() ;
 205         }
 206         return (checkInitComponents() ? discriminator : null);
 207     }
 208 
 209     // Sets the discriminator of the DynUnion to the specified value.
 210     // If the TypeCode of the parameter is not equivalent
 211     // to the TypeCode of the unions discriminator, the operation raises TypeMismatch.
 212     //
 213     // Setting the discriminator to a value that is consistent with the currently
 214     // active union member does not affect the currently active member.
 215     // Setting the discriminator to a value that is inconsistent with the currently
 216     // active member deactivates the member and activates the member that is consistent
 217     // with the new discriminator value (if there is a member for that value)
 218     // by initializing the member to its default value.
 219     //
 220     // If the discriminator value indicates a non-existent union member
 221     // this operation sets the current position to 0
 222     // (has_no_active_member returns true in this case).
 223     // Otherwise the current position is set to 1 (has_no_active_member returns false and
 224     // component_count returns 2 in this case).
 225     public void set_discriminator (org.omg.DynamicAny.DynAny newDiscriminator)
 226         throws org.omg.DynamicAny.DynAnyPackage.TypeMismatch
 227     {
 228         if (status == STATUS_DESTROYED) {
 229             throw wrapper.dynAnyDestroyed() ;
 230         }
 231         if ( ! newDiscriminator.type().equal(discriminatorType())) {
 232             throw new TypeMismatch();
 233         }
 234         newDiscriminator = DynAnyUtil.convertToNative(newDiscriminator, orb);
 235         Any newDiscriminatorAny = getAny(newDiscriminator);
 236         int newCurrentMemberIndex = currentUnionMemberIndex(newDiscriminatorAny);
 237         if (newCurrentMemberIndex == NO_INDEX) {
 238             clearData();
 239             index = 0;
 240         } else {
 241             // _REVISIT_ Could possibly optimize here if we don't need to initialize components
 242             checkInitComponents();
 243             if (currentMemberIndex == NO_INDEX || newCurrentMemberIndex != currentMemberIndex) {
 244                 clearData();
 245                 index = 1;
 246                 currentMemberIndex = newCurrentMemberIndex;
 247                 try {
 248                 currentMember = DynAnyUtil.createMostDerivedDynAny(memberType(currentMemberIndex), orb);
 249                 } catch (InconsistentTypeCode ictc) {}
 250                 discriminator = newDiscriminator;
 251                 components = new DynAny[] { discriminator, currentMember };
 252                 representations = REPRESENTATION_COMPONENTS;
 253             }
 254         }
 255     }
 256 
 257     // Sets the discriminator to a value that is consistent with the value
 258     // of the default case of a union; it sets the current position to
 259     // zero and causes component_count to return 2.
 260     // Calling set_to_default_member on a union that does not have an explicit
 261     // default case raises TypeMismatch.
 262     public void set_to_default_member ()
 263         throws org.omg.DynamicAny.DynAnyPackage.TypeMismatch
 264     {
 265         if (status == STATUS_DESTROYED) {
 266             throw wrapper.dynAnyDestroyed() ;
 267         }
 268         int defaultIndex = defaultIndex();
 269         if (defaultIndex == -1) {
 270             throw new TypeMismatch();
 271         }
 272         try {
 273             clearData();
 274             index = 1;
 275             currentMemberIndex = defaultIndex;
 276             currentMember = DynAnyUtil.createMostDerivedDynAny(memberType(defaultIndex), orb);
 277             components = new DynAny[] {discriminator, currentMember};
 278             Any discriminatorAny = orb.create_any();
 279             discriminatorAny.insert_octet((byte)0);
 280             discriminator = DynAnyUtil.createMostDerivedDynAny(discriminatorAny, orb, false);
 281             representations = REPRESENTATION_COMPONENTS;
 282         } catch (InconsistentTypeCode ictc) {}
 283     }
 284 
 285     // Sets the discriminator to a value that does not correspond
 286     // to any of the unions case labels.
 287     // It sets the current position to zero and causes component_count to return 1.
 288     // Calling set_to_no_active_member on a union that has an explicit default case
 289     // or on a union that uses the entire range of discriminator values
 290     // for explicit case labels raises TypeMismatch.
 291     public void set_to_no_active_member ()
 292         throws org.omg.DynamicAny.DynAnyPackage.TypeMismatch
 293     {
 294         if (status == STATUS_DESTROYED) {
 295             throw wrapper.dynAnyDestroyed() ;
 296         }
 297         // _REVISIT_ How does one check for "entire range of discriminator values"?
 298         if (defaultIndex() != -1) {
 299             throw new TypeMismatch();
 300         }
 301         checkInitComponents();
 302         Any discriminatorAny = getAny(discriminator);
 303         // erase the discriminators value so that it does not correspond
 304         // to any of the unions case labels
 305         discriminatorAny.type(discriminatorAny.type());
 306         index = 0;
 307         currentMemberIndex = NO_INDEX;
 308         // Necessary to guarantee OBJECT_NOT_EXIST in member()
 309         currentMember.destroy();
 310         currentMember = null;
 311         components[0] = discriminator;
 312         representations = REPRESENTATION_COMPONENTS;
 313     }
 314 
 315     // Returns true if the union has no active member
 316     // (that is, the unions value consists solely of its discriminator because the
 317     // discriminator has a value that is not listed as an explicit case label).
 318     // Calling this operation on a union that has a default case returns false.
 319     // Calling this operation on a union that uses the entire range of discriminator
 320     // values for explicit case labels returns false.
 321     public boolean has_no_active_member () {
 322         if (status == STATUS_DESTROYED) {
 323             throw wrapper.dynAnyDestroyed() ;
 324         }
 325         // _REVISIT_ How does one check for "entire range of discriminator values"?
 326         if (defaultIndex() != -1) {
 327             return false;
 328         }
 329         checkInitComponents();
 330         return (checkInitComponents() ? (currentMemberIndex == NO_INDEX) : false);
 331     }
 332 
 333     public org.omg.CORBA.TCKind discriminator_kind () {
 334         if (status == STATUS_DESTROYED) {
 335             throw wrapper.dynAnyDestroyed() ;
 336         }
 337         return discriminatorType().kind();
 338     }
 339 
 340     // Returns the currently active member.
 341     // If the union has no active member, the operation raises InvalidValue.
 342     // Note that the returned reference remains valid only for as long
 343     // as the currently active member does not change.
 344     // Using the returned reference beyond the life time
 345     // of the currently active member raises OBJECT_NOT_EXIST.
 346     public org.omg.DynamicAny.DynAny member ()
 347         throws org.omg.DynamicAny.DynAnyPackage.InvalidValue
 348     {
 349         if (status == STATUS_DESTROYED) {
 350             throw wrapper.dynAnyDestroyed() ;
 351         }
 352         if ( ! checkInitComponents() || currentMemberIndex == NO_INDEX)
 353             throw new InvalidValue();
 354         return currentMember;
 355     }
 356 
 357     // Returns the name of the currently active member.
 358     // If the unions TypeCode does not contain a member name for the currently active member,
 359     // the operation returns an empty string.
 360     // Calling member_name on a union without an active member raises InvalidValue.
 361     public String member_name ()
 362         throws org.omg.DynamicAny.DynAnyPackage.InvalidValue
 363     {
 364         if (status == STATUS_DESTROYED) {
 365             throw wrapper.dynAnyDestroyed() ;
 366         }
 367         if ( ! checkInitComponents() || currentMemberIndex == NO_INDEX)
 368             throw new InvalidValue();
 369         String memberName = memberName(currentMemberIndex);
 370         return (memberName == null ? "" : memberName);
 371     }
 372 
 373     // Returns the TCKind value of the TypeCode of the currently active member.
 374     // If the union has no active member, the operation raises InvalidValue.
 375     public org.omg.CORBA.TCKind member_kind ()
 376         throws org.omg.DynamicAny.DynAnyPackage.InvalidValue
 377     {
 378         if (status == STATUS_DESTROYED) {
 379             throw wrapper.dynAnyDestroyed() ;
 380         }
 381         if ( ! checkInitComponents() || currentMemberIndex == NO_INDEX)
 382             throw new InvalidValue();
 383         return memberType(currentMemberIndex).kind();
 384     }
 385 }