package org.jacorb.orb.dynany; /* * JacORB - a free Java ORB * * Copyright (C) 1997-2014 Gerald Brose / The JacORB Team. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ import org.jacorb.orb.CDRInputStream; import org.jacorb.orb.CDROutputStream; import org.jacorb.orb.TypeCode; import org.omg.CORBA.TCKind; import org.omg.DynamicAny.DynUnionHelper; import org.omg.DynamicAny.DynAnyFactoryPackage.InconsistentTypeCode; import org.omg.DynamicAny.DynAnyPackage.InvalidValue; import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; import org.slf4j.Logger; /** * CORBA DynUnion * * @author Gerald Brose */ public final class DynUnion extends DynAny implements org.omg.DynamicAny.DynUnion { private org.omg.CORBA.Any discriminator; private org.omg.DynamicAny.DynAny member; private String memberName; private int memberIndex; DynUnion( org.omg.DynamicAny.DynAnyFactory dynFactory, org.omg.CORBA.TypeCode tc, org.jacorb.orb.ORB orb, Logger logger ) throws TypeMismatch { super(dynFactory, orb, logger); org.omg.CORBA.TypeCode _type = TypeCode.originalType( tc ); if( _type.kind() != org.omg.CORBA.TCKind.tk_union ) { throw new TypeMismatch(); } typeCode = _type; pos = 0; limit = 2; try { for( int i = 0; i < typeCode.member_count(); i++ ) { discriminator = typeCode.member_label(i); if( discriminator.type().kind().value() != org.omg.CORBA.TCKind._tk_octet ) { break; } } // rare case when the union only has a default case label if( discriminator.type().kind().value() == org.omg.CORBA.TCKind._tk_octet ) { try { set_to_unlisted_label (); } catch (TypeMismatch e) { throw unexpectedException(e); } } select_member(); } catch( org.omg.CORBA.TypeCodePackage.BadKind e ) { throw unexpectedException(e); } catch( org.omg.CORBA.TypeCodePackage.Bounds e ) { throw unexpectedException(e); } } /** * Overrides from_any() in DynAny */ public void from_any( org.omg.CORBA.Any value ) throws InvalidValue, TypeMismatch { checkDestroyed (); if( ! type().equivalent( value.type() )) { throw new TypeMismatch(); } try { typeCode = TypeCode.originalType( value.type() ); super.from_any( value ); limit = 2; org.omg.CORBA.portable.InputStream is = value.create_input_stream(); discriminator = orb.create_any(); discriminator.type( type().discriminator_type()); discriminator.read_value(is, type().discriminator_type()); org.omg.CORBA.Any member_any = null; for( int i = 0; i < type ().member_count (); i++ ) { if( type().member_label(i).equal( discriminator )) { member_any = orb.create_any(); member_any.read_value( is, type().member_type(i) ); memberName = type().member_name(i); memberIndex = i; break; } } if( member_any == null ) { int def_idx = type().default_index(); if( def_idx != -1 ) { member_any = orb.create_any(); member_any.read_value( is, type().member_type(def_idx) ); memberName = type().member_name(def_idx); memberIndex = def_idx; } } if( member_any != null ) { try { member = dynFactory.create_dyn_any( member_any ); } catch( InconsistentTypeCode e ) { throw unexpectedException(e); } } } catch( org.omg.CORBA.TypeCodePackage.Bounds e ) { throw unexpectedException(e); } catch( org.omg.CORBA.TypeCodePackage.BadKind e ) { throw unexpectedException(e); } } /** * @return an Any that holds a copy of this union */ public org.omg.CORBA.Any to_any() { checkDestroyed (); final CDROutputStream out = new CDROutputStream(orb); try { out.write_value( discriminator.type(), discriminator.create_input_stream() ); if (member != null) { out.write_value( member.type(), member.to_any().create_input_stream()); } org.omg.CORBA.Any out_any = orb.create_any(); out_any.type( type() ); final CDRInputStream in = new CDRInputStream( orb, out.getBufferCopy()); try { out_any.read_value( in, type()); return out_any; } finally { in.close(); } } finally { out.close(); } } /** * Overrides component_count() in DynAny */ public int component_count () { if (has_no_active_member ()) { return 1; } return limit; } /** * Overrides next() in DynAny */ public boolean next() { checkDestroyed (); if( pos < component_count () - 1 ) { pos++; return true; } pos = -1; return false; } /** * Overrides seek() in DynAny */ public boolean seek(int index) { checkDestroyed (); if( index < 0 ) { pos = -1; return false; } if( index < component_count () ) { pos = index; return true; } pos = -1; return false; } /** * Overrides equal() in DynAny */ public boolean equal( org.omg.DynamicAny.DynAny dyn_any ) { checkDestroyed (); if( !type().equal( dyn_any.type()) ) { return false; } org.omg.DynamicAny.DynUnion other = DynUnionHelper.narrow( dyn_any ); if( ! get_discriminator().equal( other.get_discriminator())) { return false; } if( !has_no_active_member() ) { // other must have the same here because we know the // discriminators are equal try { if( ! member.equal( other.member())) { return false; } } catch( Exception e ) { throw unexpectedException(e); } } return true; } /** * @return the current discriminator value */ public org.omg.DynamicAny.DynAny get_discriminator() { checkDestroyed (); try { return dynFactory.create_dyn_any( discriminator ); } catch( InconsistentTypeCode e ) { throw unexpectedException(e); } } /** * sets the discriminator to d * @throws TypeMismatch if the TypeCode of the d parameter * is not equivalent to the TypeCode of the union's discriminator */ public void set_discriminator( org.omg.DynamicAny.DynAny dynAny ) throws TypeMismatch { checkDestroyed (); if( ! dynAny.type().equivalent( discriminator.type() )) { throw new TypeMismatch(); } discriminator = dynAny.to_any(); pos = 1; /* check if the new discriminator is consistent with the currently active member. If not, select a new one */ try { if (memberIndex == typeCode.default_index ()) { // default member, only change the member if a non-default // discriminator value is specified for (int i = 0; i < typeCode.member_count (); i++) { if( type().member_label(i).equal( discriminator )) { select_member(); break; } } } else { // non-default member, check if the member has changed if( ! type().member_label( memberIndex ).equal( discriminator )) { select_member(); } } } catch( org.omg.CORBA.TypeCodePackage.Bounds e ) { throw unexpectedException(e); } catch( org.omg.CORBA.TypeCodePackage.BadKind e ) { throw unexpectedException(e); } // set the current position to zero if there is no active member if (has_no_active_member ()) { pos = 0; } } /** * updates the private instance variables member, member_name and * member_index according to the current discriminator value */ private void select_member() { member = null; try { /* search through all members and compare their label with the discriminator */ for( int i = 0; i < type().member_count(); i++ ) { if( type().member_label(i).equal( discriminator )) { try { member = dynFactory.create_dyn_any_from_type_code( type().member_type(i)); } catch( InconsistentTypeCode e ) { throw unexpectedException(e); } memberName = type().member_name(i); memberIndex = i; break; } } /* none found, use default, if there is one */ if( member == null ) { int def_idx = type().default_index(); if( def_idx != -1 ) { try { member = dynFactory.create_dyn_any_from_type_code(type().member_type(def_idx)); } catch( InconsistentTypeCode e ) { throw unexpectedException(e); } memberName = type().member_name(def_idx); memberIndex = def_idx; } } } catch( org.omg.CORBA.TypeCodePackage.Bounds e ) { throw unexpectedException(e); } catch( org.omg.CORBA.TypeCodePackage.BadKind e ) { throw unexpectedException(e); } } /** * sets the discriminator to a value that is consistent with the * value of the default case of a union; it sets the current * position to zero and causes component_count to return 2. * * @throws TypeMismatch if the union does not have an explicit * default case. */ public void set_to_default_member() throws TypeMismatch { checkDestroyed (); try { int def_idx = type().default_index(); if( def_idx == -1 ) { throw new TypeMismatch(); } pos = 0; // do nothing if the discriminator is already set to a default value if (memberIndex != def_idx) { try { set_to_unlisted_label (); } catch (TypeMismatch e) { throw unexpectedException(e); } select_member(); } } catch( org.omg.CORBA.TypeCodePackage.BadKind e ) { throw unexpectedException(e); } } /** * sets the discriminator to a value that does not correspond to * any of the union's case labels; it sets the current position * to zero and causes component_count to return 1. * * @throws TypeMismatch if the union has an explicit default * case or uses the entire range of discriminator values for * explicit case labels. */ public void set_to_no_active_member() throws TypeMismatch { checkDestroyed (); try { /* if there is a default index, we do have active members */ if( type().default_index() != -1 ) { throw new TypeMismatch(); } pos = 0; // do nothing if discriminator is already set to no active member if (!has_no_active_member ()) { set_to_unlisted_label (); } } catch( org.omg.CORBA.TypeCodePackage.BadKind e ) { throw unexpectedException(e); } } /* find a discriminator value that is not an explicit case label */ private void set_to_unlisted_label () throws TypeMismatch { try { switch( type().discriminator_type().kind().value() ) { case TCKind._tk_boolean: { boolean found; boolean cur_bool; org.omg.CORBA.Any check_val = null; for (int i = 0; i < 2; i++) { if (i == 0) { cur_bool = true; } else { cur_bool = false; } check_val = orb.create_any (); check_val.insert_boolean (cur_bool); found = false; // is the value used as a label? for( int j = 0; j < type().member_count() && !found; j++ ) { if( check_val.equal( type().member_label(j)) ) { found = true; } } if( !found ) { // the value is not found among the union's label discriminator = check_val; return; } } // no unused value found throw new TypeMismatch(); } case TCKind._tk_char: { // assume there is a printable char not used as a label! boolean found; org.omg.CORBA.Any check_val = null; // 33 to 126 defines a reasonable set of printable chars for (int i = 0; i < 127; i++) { check_val = orb.create_any (); check_val.insert_char ((char) i); found = false; // is the value used as a label? for( int j = 0; j < type().member_count() && !found; j++ ) { if( check_val.equal( type().member_label(j)) ) { found = true; } } if( !found ) { // the value is not found among the union's label discriminator = check_val; return; } } // no unused value found, should not happen throw new TypeMismatch(); } case TCKind._tk_short: { // assume there is an unsigned short not used as a label! boolean found; org.omg.CORBA.Any check_val = null; short max_short = 32767; for (short i = 0; i < max_short; i++) { check_val = orb.create_any (); check_val.insert_short (i); found = false; // is the value used as a label? for( int j = 0; j < type().member_count() && !found; j++ ) { if( check_val.equal( type().member_label(j)) ) { found = true; } } if( !found ) { // the value is not found among the union's label discriminator = check_val; return; } } // no unused value found, should not happen throw new TypeMismatch(); } case TCKind._tk_long: { // assume there is an unsigned int not used as a label! boolean found; org.omg.CORBA.Any check_val = null; int max_int = 2147483647; for (int i = 0; i < max_int; i++) { check_val = orb.create_any (); check_val.insert_long (i); found = false; // is the value used as a label? for( int j = 0; j < type().member_count() && !found; j++ ) { if( check_val.equal( type().member_label(j)) ) { found = true; } } if( !found ) { // the value is not found among the union's label discriminator = check_val; return; } } // no unused value found, should not happen throw new TypeMismatch(); } case TCKind._tk_longlong: { // assume there is an unsigned long not used as a label! boolean found; org.omg.CORBA.Any check_val = null; long max_long = 2147483647; // this should be sufficient! for (long i = 0; i < max_long; i++) { check_val = orb.create_any (); check_val.insert_longlong (i); found = false; // is the value used as a label? for( int j = 0; j < type().member_count() && !found; j++ ) { if( check_val.equal( type().member_label(j)) ) { found = true; } } if( !found ) { // the value is not found among the union's label discriminator = check_val; return; } } // no unused value found, should not happen throw new TypeMismatch(); } case TCKind._tk_enum: { org.omg.DynamicAny.DynEnum dynEnum = null; try { dynEnum = (org.omg.DynamicAny.DynEnum) dynFactory.create_dyn_any_from_type_code (discriminator.type()); } catch( InconsistentTypeCode e ) { throw unexpectedException(e); } boolean found; for( int i = 0; i < discriminator.type().member_count(); i++ ) { try { dynEnum.set_as_string( discriminator.type().member_name(i) ); } catch( InvalidValue e ) { throw unexpectedException(e); } found = false; // is the value used as a label? for( int j = 0; j < type().member_count() && !found; j++ ) { if( dynEnum.to_any ().equal( type().member_label(j) ) ) { found = true; } } if( !found ) { // the enum value is not found among the union's label discriminator = dynEnum.to_any(); return; } } // no unused value found throw new TypeMismatch(); } default: throw new TypeMismatch(); } } catch (org.omg.CORBA.TypeCodePackage.BadKind e) { throw unexpectedException(e); } catch (org.omg.CORBA.TypeCodePackage.Bounds e) { throw unexpectedException(e); } } /** * @return true, if the union has no active member (that is, the * union's value consists solely of its discriminator because * the discriminator has a value that is not listed as an explicit * case label). Calling this operation on a union that has a * default case returns false. Calling this operation on a union * that uses the entire range of discriminator values for explicit * case labels returns false. */ public boolean has_no_active_member() { checkDestroyed (); try { if( type().default_index() != -1 ) { return false; } for( int i = 0; i < typeCode.member_count(); i++ ) { if( discriminator.equal( typeCode.member_label(i) )) { return false; } } return true; } catch( org.omg.CORBA.TypeCodePackage.Bounds e ) { throw unexpectedException(e); } catch( org.omg.CORBA.TypeCodePackage.BadKind e ) { throw unexpectedException(e); } } /** * @return the TCKind value of the discriminator's TypeCode. */ public org.omg.CORBA.TCKind discriminator_kind() { checkDestroyed (); return discriminator.type().kind(); } /** * @return the currently active member. * @throws InvalidValue if the union has no active member */ public org.omg.DynamicAny.DynAny member() throws InvalidValue { checkDestroyed (); if( has_no_active_member() ) { throw new InvalidValue(); } return member; } /** * @return the TypeCode kind of the currently active member. * @throws InvalidValue if the union has no active member */ public org.omg.CORBA.TCKind member_kind() throws InvalidValue { checkDestroyed (); if( has_no_active_member() ) { throw new InvalidValue(); } return member.type().kind(); } /** * @return the name of the currently active member. * @throws InvalidValue if the union has no active member */ public String member_name() throws InvalidValue { checkDestroyed (); if( has_no_active_member() ) { throw new InvalidValue(); } return memberName; } public void destroy() { super.destroy(); discriminator = null; member = null; memberName = null; memberIndex = -1; } /* iteration interface */ public org.omg.DynamicAny.DynAny current_component() { checkDestroyed (); if( pos == -1 ) { return null; } if( pos == 0 ) { return get_discriminator(); } try { return member(); } catch (org.omg.DynamicAny.DynAnyPackage.InvalidValue e) { throw unexpectedException(e); } } }