Welcome to the "trac"-ing site of soap4r!
[soap4r] [httpclient] [openpgp4u] [pkcs1] [logger] [csv] [vtr]

Changeset 166

Show
Ignore:
Timestamp:
07/04/01 12:46:59 (8 years ago)
Author:
nakahiro
Message:

Completely re-written.
Added mappingRegistry interface.
Changed soap2obj and obj2soap's interface.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/lib/soap/rpcUtils.rb

    r154 r166  
    8484 
    8585  ApacheSOAPTypeNamespace = 'http://xml.apache.org/xml-soap' 
     86 
     87 
     88  ### 
     89  ## Ruby's obj <-> SOAP/OM mapping registry. 
     90  # 
     91  class Factory 
     92    class FactoryError < Error; end 
     93 
     94    def obj2soap( soapKlass, obj, info, map ) 
     95      raise NotImplementError.new 
     96    end 
     97 
     98    def soap2obj( objKlass, node, info, map ) 
     99      raise NotImplementError.new 
     100    end 
     101 
     102  protected 
     103 
     104    def getTypeName( obj ) 
     105      ret = nil 
     106      begin 
     107        ret = obj.instance_eval( "@typeName" ) || obj.instance_eval( "@@typeName" ) 
     108      rescue NameError 
     109      end 
     110      ret 
     111    end 
     112 
     113    def getNamespace( obj ) 
     114      ret = nil 
     115      begin 
     116        ret = obj.instance_eval( "@typeNamespace" ) || obj.instance_eval( "@@typeNamespace" ) 
     117      rescue NameError 
     118      end 
     119      ret 
     120    end 
     121 
     122    def createEmptyObject( klass ) 
     123      klass.module_eval <<-EOS 
     124        begin 
     125          alias __initialize initialize 
     126        rescue NameError 
     127        end 
     128        def initialize; end 
     129      EOS 
     130 
     131      obj = klass.new 
     132 
     133      klass.module_eval <<-EOS 
     134        undef initialize 
     135        begin 
     136          alias initialize __initialize 
     137        rescue NameError 
     138        end 
     139      EOS 
     140 
     141      obj 
     142    end 
     143 
     144    def addWriter( klass, values ) 
     145      values.each do |name, value| 
     146        klass.module_eval <<-EOS 
     147          begin 
     148            alias __#{ name }= #{ name }= 
     149          rescue NameError 
     150          end 
     151          def #{ name }=( var ) 
     152            @#{ name } = var 
     153          end 
     154        EOS 
     155      end 
     156    end 
     157 
     158    def restoreWriter( klass, values ) 
     159      values.each do |name, value| 
     160        klass.module_eval <<-EOS 
     161          undef #{ name }= 
     162          begin 
     163            alias #{ name }= __#{ name }= 
     164          rescue NameError 
     165          end 
     166        EOS 
     167      end 
     168    end 
     169 
     170    def setInstanceVar( obj, var ) 
     171      obj.instance_eval( "alias __initialize initialize; def initialize; end" ) 
     172      obj.instance_eval( "undef initialize; alias initialize __initialize" ) 
     173      obj 
     174    end 
     175 
     176    def toType( name ) 
     177      capitalize( name ) 
     178    end 
     179 
     180    # Create NCName 
     181    def toTypeName( name ) 
     182      name.gsub( ':', '_' ) 
     183    end 
     184 
     185    def capitalize( target ) 
     186      target.gsub('^([a-z])') { $1.tr!('[a-z]', '[A-Z]') } 
     187    end 
     188  end 
     189 
     190  class BasetypeFactory_ < Factory 
     191    def obj2soap( soapKlass, obj, info, map ) 
     192      soapKlass.new( obj ) 
     193    end 
     194 
     195    def soap2obj( objKlass, node, info, map ) 
     196      node.data 
     197    end 
     198  end 
     199 
     200  class Base64Factory_ < Factory 
     201    def obj2soap( soapKlass, obj, info, map ) 
     202      raise FactoryError.new 
     203    end 
     204 
     205    def soap2obj( objKlass, node, info, map ) 
     206      node.toString 
     207    end 
     208  end 
     209 
     210  class CompoundtypeFactory_ < Factory 
     211    def obj2soap( soapKlass, obj, info, map ) 
     212      if soapKlass == SOAP::SOAPArray 
     213        # [ [1], [2] ] is converted to Array of Array, not 2-D Array. 
     214        # To create M-D Array, you must call RPCUtils.ary2md. 
     215        typeName = getTypeName( obj.type ) 
     216        typeNamespace = getNamespace( obj.type ) || RubyTypeNamespace 
     217        unless typeName 
     218          typeName = XSD::AnyTypeLiteral 
     219          typeNamespace = XSD::Namespace 
     220        end 
     221        param = SOAPArray.new( typeName ) 
     222        param.typeNamespace = typeNamespace 
     223        obj.each do | var | 
     224          param.add( RPCUtils.obj2soap( var, map )) 
     225        end 
     226        param 
     227      elsif soapKlass == SOAP::SOAPStruct 
     228        param = SOAPStruct.new( toTypeName( obj.type.to_s )) 
     229        param.typeNamespace = getNamespace( obj.type ) || RubyTypeNamespace 
     230        obj.members.each do |member| 
     231          param.add( member, RPCUtils.obj2soap( obj[ member ], map )) 
     232        end 
     233        param 
     234      else 
     235        nil 
     236      end 
     237    end 
     238 
     239    def soap2obj( objKlass, node, info, map ) 
     240      if node.is_a?( SOAPArray ) 
     241        obj = node.soap2array { | elem | 
     242          RPCUtils.soap2obj( elem, map ) 
     243        } 
     244        obj.instance_eval( "@typeName = '#{ node.typeName }'; @typeNamespace = '#{ node.typeNamespace }'" ) 
     245        obj 
     246      elsif node.is_a?( SOAPStruct ) 
     247        if node.typeEqual( XSD::Namespace, XSD::AnyTypeLiteral ) 
     248          unknownObj( node, map ) 
     249        else 
     250          struct2obj( node, map ) 
     251        end 
     252      else 
     253        raise FactoryError.new( "Unknown compound type: #{ node }" ) 
     254      end 
     255    end 
     256 
     257  private 
     258 
     259    def unknownObj( node, map ) 
     260      klass = Object    # SOAP::RPCUtils::Object 
     261      Thread.critical = true 
     262      addWriter( klass, node ) 
     263      obj = klass.new 
     264      node.each do |name, value| 
     265        obj.send( name + "=", RPCUtils.soap2obj( value, map )) 
     266      end 
     267      restoreWriter( klass, node ) 
     268      Thread.critical = false 
     269      obj.typeNamespace = node.typeNamespace 
     270      obj.typeName = node.typeName 
     271      obj 
     272    end 
     273 
     274    def struct2obj( node, map ) 
     275      obj = nil 
     276      typeName = node.typeName || node.instance_eval( "@name" ) 
     277      begin 
     278        klass = self.instance_eval( toType( typeName )) 
     279        if getNamespace( klass ) != node.typeNamespace 
     280          raise NameError.new() 
     281        elsif getTypeName( klass ) and ( getTypeName( klass ) != typeName ) 
     282          raise NameError.new() 
     283        end 
     284 
     285        Thread.critical = true 
     286        addWriter( klass, node ) 
     287        obj = createEmptyObject( klass ) 
     288        node.each do |name, value| 
     289          obj.send( name + "=", RPCUtils.soap2obj( value, map )) 
     290        end 
     291        restoreWriter( klass, node ) 
     292        Thread.critical = false 
     293 
     294      rescue NameError 
     295        klass = nil 
     296        structName = toType( typeName ) 
     297        if ( Struct.constants - Struct.superclass.constants ).member?( structName ) 
     298          klass = Struct.const_get( structName ) 
     299          if klass.members.length != node.members.length 
     300            klass = Struct.new( structName, *node.members ) 
     301          end 
     302        else 
     303          klass = Struct.new( structName, *node.members ) 
     304        end 
     305        obj = klass.new 
     306        node.each do | name, value | 
     307          obj.send( name + "=", RPCUtils.soap2obj( value, map )) 
     308        end 
     309      end 
     310 
     311      obj 
     312    end 
     313  end 
     314 
     315  class HashFactory_ < Factory 
     316    def obj2soap( soapKlass, obj, info, map ) 
     317      if obj.is_a?( Hash ) 
     318        param = SOAPStruct.new( "Map" ) 
     319        param.typeNamespace = ApacheSOAPTypeNamespace 
     320        i = 1 
     321        obj.each do | key, value | 
     322          elem = SOAPStruct.new( "mapItem" ) 
     323          elem.add( "key", RPCUtils.obj2soap( key, map )) 
     324          elem.add( "value", RPCUtils.obj2soap( value, map )) 
     325          param.add( "item#{ i }", elem ) 
     326          i += 1 
     327        end 
     328        param 
     329      else 
     330        nil 
     331      end 
     332    end 
     333 
     334    def soap2obj( objKlass, node, info, map ) 
     335      if node.typeEqual( RubyTypeNamespace, 'Hash' ) 
     336        obj = Hash.new 
     337        keyArray = RPCUtils.soap2obj( node.key, map ) 
     338        valueArray = RPCUtils.soap2obj( node.value, map ) 
     339        while !keyArray.empty? 
     340          obj[ keyArray.shift ] = valueArray.shift 
     341        end 
     342        obj 
     343      elsif node.typeEqual( ApacheSOAPTypeNamespace, 'Map' ) 
     344        obj = Hash.new 
     345        node.each do | key, value | 
     346          obj[ RPCUtils.soap2obj( value.key, map ) ] = 
     347            RPCUtils.soap2obj( value.value, map ) 
     348        end 
     349        obj 
     350      else 
     351        raise FactoryError.new( "#{ node } is not a Hash." ) 
     352      end 
     353    end 
     354  end 
     355 
     356  class UnknownKlassFactory_ < Factory 
     357    def obj2soap( soapKlass, obj, info, map ) 
     358      typeName = getTypeName( obj.type ) || obj.type.to_s 
     359      param = SOAPStruct.new( typeName  ) 
     360      param.typeNamespace = getNamespace( obj.type ) || RubyCustomTypeNamespace 
     361      if obj.type.ancestors.member?( Marshallable ) 
     362        obj.instance_variables do |var, data| 
     363          name = var.dup.sub!( /^@/, '' ) 
     364          param.add( name, RPCUtils.obj2soap( data, map )) 
     365        end 
     366      else 
     367        obj.instance_variables.each do |var| 
     368          name = var.dup.sub!( /^@/, '' ) 
     369          param.add( name, RPCUtils.obj2soap( obj.instance_eval( var ), map )) 
     370        end 
     371      end 
     372      param 
     373    end 
     374 
     375    def soap2obj( objKlass, node, info, map ) 
     376      node 
     377    end 
     378  end 
     379 
     380=begin 
     381    when SOAP::RPCUtils::Object 
     382      typeName = obj.typeName 
     383      param = SOAPStruct.new( typeName  ) 
     384      param.typeNamespace = obj.typeNamespace 
     385      obj.instance_variables do |var, data| 
     386        name = var.dup.sub!( /^@/, '' ) 
     387        param.add( name, RPCUtils.obj2soap( data )) 
     388      end 
     389      param 
     390=end 
     391 
     392  class TypedStructFactory_ < Factory 
     393    def obj2soap( soapKlass, obj, info, map ) 
     394      typeName = info[1] 
     395      param = SOAPStruct.new( typeName  ) 
     396      param.typeNamespace = info[0] 
     397      if obj.type.ancestors.member?( Marshallable ) 
     398        obj.instance_variables do |var, data| 
     399          name = var.dup.sub!( /^@/, '' ) 
     400          param.add( name, RPCUtils.obj2soap( data, map )) 
     401        end 
     402      else 
     403        obj.instance_variables.each do |var| 
     404          name = var.dup.sub!( /^@/, '' ) 
     405          param.add( name, RPCUtils.obj2soap( obj.instance_eval( var ), map )) 
     406        end 
     407      end 
     408      param 
     409    end 
     410 
     411    def soap2obj( objKlass, node, info, map ) 
     412      if ( node.typeNamespace != info[0] ) || ( node.typeName != info[1] ) 
     413        raise FactoryError.new( "Type mismatch" ) 
     414      end 
     415 
     416      typeName = info[1] 
     417      Thread.critical = true 
     418      addWriter( objKlass, node ) 
     419      obj = createEmptyObject( objKlass ) 
     420      node.each do |name, value| 
     421        obj.send( name + "=", RPCUtils.soap2obj( value, map )) 
     422      end 
     423      restoreWriter( objKlass, node ) 
     424      Thread.critical = false 
     425 
     426      obj 
     427    end 
     428  end 
     429 
     430  class MappingRegistry 
     431    class MappingError < Error; end 
     432 
     433    class Mapping 
     434      def initialize( mappingRegistry ) 
     435        @map = [] 
     436        @registry = mappingRegistry 
     437      end 
     438 
     439      def obj2soap( klass, obj ) 
     440        @map.each do | objKlass, soapKlass, factory, info | 
     441          if klass.ancestors.include?( objKlass ) 
     442            ret = factory.obj2soap( soapKlass, obj, info, @registry ) 
     443            return ret if ret 
     444          end 
     445        end 
     446        nil 
     447      end 
     448 
     449      def soap2obj( klass, node ) 
     450        @map.each do | objKlass, soapKlass, factory, info | 
     451          if klass == soapKlass 
     452            begin 
     453              return factory.soap2obj( objKlass, node, info, @registry ) 
     454            rescue Factory::FactoryError 
     455            end 
     456          end 
     457        end 
     458        raise MappingError.new( "Unknown klass: #{ klass }" ) 
     459      end 
     460 
     461      def init( initMapping = [] ) 
     462        clear 
     463        initMapping.each do | objKlass, soapKlass, factory, info | 
     464          set( objKlass, soapKlass, factory, info ) 
     465        end 
     466      end 
     467 
     468      def set( objKlass, soapKlass, factory, info ) 
     469        @map << [ objKlass, soapKlass, factory, info ] 
     470      end 
     471 
     472      def clear 
     473        @map.clear 
     474      end 
     475    end 
     476 
     477    BasetypeFactory = BasetypeFactory_.new 
     478    CompoundtypeFactory = CompoundtypeFactory_.new 
     479    Base64Factory = Base64Factory_.new 
     480    HashFactory = HashFactory_.new 
     481    UnknownKlassFactory = UnknownKlassFactory_.new 
     482    TypedStructFactory = TypedStructFactory_.new 
     483 
     484    SOAPBaseMapping = [ 
     485      [ ::NilClass,     ::SOAP::SOAPNil,        BasetypeFactory ], 
     486      [ ::TrueClass,    ::SOAP::SOAPBoolean,    BasetypeFactory ], 
     487      [ ::FalseClass,   ::SOAP::SOAPBoolean,    BasetypeFactory ], 
     488      [ ::String,       ::SOAP::SOAPString,     BasetypeFactory ], 
     489      [ ::Time,         ::SOAP::SOAPDateTime,   BasetypeFactory ], 
     490      [ ::Date,         ::SOAP::SOAPDateTime,   BasetypeFactory ], 
     491      [ ::Float,        ::SOAP::SOAPFloat,      BasetypeFactory ], 
     492      [ ::Float,        ::SOAP::SOAPDouble,     BasetypeFactory ], 
     493      [ ::Integer,      ::SOAP::SOAPInt,        BasetypeFactory ], 
     494      [ ::Integer,      ::SOAP::SOAPInteger,    BasetypeFactory ], 
     495      [ ::String,       ::SOAP::SOAPBase64,     Base64Factory ], 
     496      [ ::Array,        ::SOAP::SOAPArray,      CompoundtypeFactory ], 
     497      [ ::Struct,       ::SOAP::SOAPStruct,     CompoundtypeFactory ], 
     498    ] 
     499 
     500    UserMapping = [ 
     501      [ ::Hash,         ::SOAP::SOAPStruct,     HashFactory ], 
     502    ] 
     503 
     504    def initialize() 
     505      @userMap = Mapping.new( self ) 
     506      @baseMap = Mapping.new( self ) 
     507      @baseMap.init( SOAPBaseMapping ) 
     508      @defaultFactory = UnknownKlassFactory 
     509    end 
     510 
     511    def set( objKlass, soapKlass, factory, info ) 
     512      @userMap.set( objKlass, soapKlass, factory, info ) 
     513    end 
     514 
     515    def obj2soap( klass, obj ) 
     516      @userMap.obj2soap( klass, obj ) || 
     517        @baseMap.obj2soap( klass, obj ) || 
     518        @defaultFactory.obj2soap( klass, obj, nil, self ) 
     519    end 
     520 
     521    def soap2obj( klass, node ) 
     522      begin 
     523        return @userMap.soap2obj( klass, node ) 
     524      rescue MappingError 
     525        begin 
     526          return @baseMap.soap2obj( klass, node ) 
     527        rescue MappingError 
     528        end 
     529      end 
     530 
     531      @defaultFactory.soap2obj( klass, node, nil, self ) 
     532    end 
     533 
     534    def defaultFactory=( newFactory ) 
     535      @defaultFactory = newFactory 
     536    end 
     537  end 
    86538 
    87539 
     
    227679 
    228680 
    229   def obj2soap( obj ) 
    230     case obj 
    231     when SOAPBasetype, SOAPCompoundtype 
    232       obj 
    233     when NilClass 
    234       SOAPNil.new 
    235     when TrueClass, FalseClass 
    236       SOAPBoolean.new( obj ) 
    237     when String 
    238       SOAPString.new( obj ) 
    239     when Time, Date 
    240       SOAPDateTime.new( obj ) 
    241     when Float 
    242       SOAPFloat.new( obj ) 
    243     when Integer 
    244       if (( -2147483648 <= obj ) && ( obj <= +2147483647 ))  
    245         SOAPInt.new( obj ) 
    246       else 
    247         SOAPInteger.new( obj ) 
    248       end 
    249     when Array 
    250       # [ [1], [2] ] is converted to Array of Array, not 2-D Array. 
    251       # To create M-D Array, you must create SOAPArray manually now. 
    252       typeName = getTypeName( obj ) 
    253       typeNamespace = getNamespace( obj ) || RubyTypeNamespace 
    254       unless typeName 
    255         typeName = XSD::AnyTypeLiteral 
    256         typeNamespace = XSD::Namespace 
    257       end 
    258       param = SOAPArray.new( typeName ) 
    259       param.typeNamespace = typeNamespace 
    260       obj.each do | var | 
    261         param.add( obj2soap( var )) 
    262       end 
    263       param 
    264     when Hash 
    265       param = SOAPStruct.new( "Map" ) 
    266       param.typeNamespace = ApacheSOAPTypeNamespace 
    267       i = 1 
    268       obj.each do | key, value | 
    269         elem = SOAPStruct.new( "mapItem" ) 
    270         elem.add( "key", obj2soap( key )) 
    271         elem.add( "value", obj2soap( value )) 
    272         param.add( "item#{ i }", elem ) 
    273         i += 1 
    274       end 
    275       param 
    276     when Struct 
    277       param = SOAPStruct.new( toTypeName( obj.type.to_s )) 
    278       param.typeNamespace = getNamespace( obj ) || RubyTypeNamespace 
    279       obj.members.each do |member| 
    280         param.add( member, obj2soap( obj[ member ] )) 
    281       end 
    282       param 
    283     when SOAP::RPCUtils::Object 
    284       typeName = obj.typeName 
    285       param = SOAPStruct.new( typeName  ) 
    286       param.typeNamespace = obj.typeNamespace 
    287       obj.instance_variables do |var, data| 
    288         name = var.dup.sub!( /^@/, '' ) 
    289         param.add( name, obj2soap( data )) 
    290       end 
    291       param 
    292     else 
    293       typeName = getTypeName( obj ) || obj.type.to_s 
    294       param = SOAPStruct.new( typeName  ) 
    295       param.typeNamespace = getNamespace( obj ) || RubyCustomTypeNamespace 
    296       if obj.type.ancestors.member?( Marshallable ) 
    297         obj.instance_variables do |var, data| 
    298           name = var.dup.sub!( /^@/, '' ) 
    299           param.add( name, obj2soap( data )) 
    300         end 
    301       else 
    302         obj.instance_variables.each do |var| 
    303           name = var.dup.sub!( /^@/, '' ) 
    304           param.add( name, obj2soap( obj.instance_eval( var ))) 
    305         end 
    306       end 
    307       param 
    308     end 
    309   end 
    310  
    311  
    312   def soap2obj( node ) 
    313     case node 
    314     when SOAPReference 
     681  def RPCUtils.obj2soap( obj, mappingRegistry = MappingRegistry.new ) 
     682    mappingRegistry ||= MappingRegistry.new 
     683    if obj.is_a?( SOAPBasetype ) || obj.is_a?( SOAPCompoundtype ) 
     684      return obj 
     685    end 
     686    return mappingRegistry.obj2soap( obj.type, obj ) 
     687  end 
     688 
     689 
     690  def RPCUtils.soap2obj( node, mappingRegistry = MappingRegistry.new ) 
     691    mappingRegistry ||= MappingRegistry.new 
     692    if node.is_a?( SOAPReference ) 
    315693      # ToDo: multi-reference decoding... 
    316       soap2obj( node.__getobj__ ) 
    317     when SOAPNil 
    318       nil 
    319     when SOAPBase64 
    320       # Stringify 
    321       node.toString 
    322     when SOAPArray 
    323       obj = node.soap2array { | elem | 
    324         soap2obj( elem ) 
    325       } 
    326       obj.instance_eval( "@typeName = '#{ node.typeName }'; @typeNamespace = '#{ node.typeNamespace }'" ) 
    327       obj 
    328     when SOAPStruct 
    329       if node.typeEqual( RubyTypeNamespace, 'Hash' ) 
    330         obj = Hash.new 
    331         keyArray = soap2obj( node.key ) 
    332         valueArray = soap2obj( node.value ) 
    333         while !keyArray.empty? 
    334           obj[ keyArray.shift ] = valueArray.shift 
    335         end 
    336         obj 
    337       elsif node.typeEqual( ApacheSOAPTypeNamespace, 'Map' ) 
    338         obj = Hash.new 
    339         node.each do | key, value | 
    340           obj[ soap2obj( value.key ) ] = soap2obj( value.value ) 
    341         end 
    342         obj 
    343       elsif node.typeEqual( XSD::Namespace, XSD::AnyTypeLiteral ) 
    344         unknownObj( node ) 
    345       else 
    346         struct2obj( node ) 
    347       end 
    348     when XSDBase 
    349       node.data 
    350     else 
    351       node 
    352     end 
    353   end 
    354  
    355  
    356   def ary2md( ary, rank ) 
     694      return RPCUtils.soap2obj( node.__getobj__, mappingRegistry ) 
     695    end 
     696    return mappingRegistry.soap2obj( node.type, node ) 
     697  end 
     698 
     699 
     700  def RPCUtils.ary2md( ary, rank ) 
    357701    mdAry = SOAPArray.new( XSD::AnyTypeLiteral, rank ) 
    358702    mdAry.typeNamespace = XSD::Namespace 
     
    363707  end 
    364708 
    365  
    366 private 
    367  
    368   def addMDAry( mdAry, ary, indices ) 
    369     0.upto( ary.size - 1 ) do | idx | 
    370       if ary[ idx ].is_a?( Array ) 
    371         addMDAry( mdAry, ary[ idx ], indices + [ idx ] ) 
    372       else 
    373         mdAry[ *( indices + [ idx ] ) ] = obj2soap( ary[ idx ] ) 
    374       end 
    375     end 
    376   end 
    377  
    378   def getTypeName( obj ) 
    379     ret = nil 
    380     begin 
    381       ret = obj.instance_eval( "@typeName" ) || obj.instance_eval( "@@typeName" ) 
    382     rescue NameError 
    383     end 
    384     ret 
    385   end 
    386  
    387   def getNamespace( obj ) 
    388     ret = nil 
    389     begin 
    390       ret = obj.instance_eval( "@typeNamespace" ) || obj.instance_eval( "@@typeNamespace" ) 
    391     rescue NameError 
    392     end 
    393     ret 
    394   end 
    395  
    396   def unknownObj( node ) 
    397     klass = Object      # SOAP::RPCUtils::Object 
    398     Thread.critical = true 
    399     addWriter( klass, node ) 
    400     obj = klass.new 
    401     node.each do |name, value| 
    402       obj.send( name + "=", soap2obj( value )) 
    403     end 
    404     restoreWriter( klass, node ) 
    405     Thread.critical = false 
    406     obj.typeNamespace = node.typeNamespace 
    407     obj.typeName = node.typeName 
    408     obj 
    409   end 
    410  
    411   def struct2obj( node ) 
    412     obj = nil 
    413     typeName = node.typeName || node.instance_eval( "@name" ) 
    414     begin 
    415       klass = Object.const_get( toType( typeName )) 
    416       if getNamespace( klass ) != node.typeNamespace 
    417         raise NameError.new() 
    418       elsif getTypeName( klass ) and ( getTypeName( klass ) != typeName ) 
    419         raise NameError.new() 
    420       end 
    421  
    422       Thread.critical = true 
    423       addWriter( klass, node ) 
    424       obj = createEmptyObject( klass ) 
    425       node.each do |name, value| 
    426         obj.send( name + "=", soap2obj( value )) 
    427       end 
    428       restoreWriter( klass, node ) 
    429       Thread.critical = false 
    430  
    431     rescue NameError 
    432       klass = nil 
    433       structName = toType( typeName ) 
    434       if ( Struct.constants - Struct.superclass.constants ).member?( structName ) 
    435         klass = Struct.const_get( structName ) 
    436         if klass.members.length != node.members.length 
    437           klass = Struct.new( structName, *node.members ) 
    438         end 
    439       else 
    440         klass = Struct.new( structName, *node.members ) 
    441       end 
    442       obj = klass.new 
    443       node.each do | name, value | 
    444         obj.send( name + "=", soap2obj( value )) 
    445       end 
    446     end 
    447  
    448     obj 
    449   end 
    450  
    451   def createEmptyObject( klass ) 
    452     klass.module_eval <<EOS 
    453       begin 
    454         alias __initialize initialize 
    455       rescue NameError 
    456       end 
    457       def initialize; end 
    458 EOS 
    459  
    460     obj = klass.new 
    461  
    462     klass.module_eval <<EOS 
    463       undef initialize 
    464       begin 
    465         alias initialize __initialize 
    466       rescue NameError 
    467       end 
    468 EOS 
    469     obj 
    470   end 
    471  
    472   def addWriter( klass, values ) 
    473     values.each do |name, value| 
    474       klass.module_eval <<EOS 
    475         begin 
    476           alias __#{ name }= #{ name }= 
    477         rescue NameError 
    478         end 
    479         def #{ name }=( var ) 
    480           @#{ name } = var 
    481         end 
    482 EOS 
    483     end 
    484   end 
    485  
    486   def restoreWriter( klass, values ) 
    487     values.each do |name, value| 
    488       klass.module_eval <<EOS 
    489         undef #{ name }= 
    490         begin 
    491           alias #{ name }= __#{ name }= 
    492         rescue NameError 
    493         end 
    494 EOS 
    495     end 
    496   end 
    497  
    498   def setInstanceVar( obj, var ) 
    499     obj.instance_eval( "alias __initialize initialize; def initialize; end" ) 
    500     obj.instance_eval( "undef initialize; alias initialize __initialize" ) 
    501     obj 
    502   end 
    503  
    504   def toType( name ) 
    505     capitalize( name ) 
    506   end 
    507  
    508   # Create NCName 
    509   def toTypeName( name ) 
    510     name.gsub( ':', '_' ) 
    511   end 
    512  
    513   def capitalize( target ) 
    514     target.gsub('^([a-z])') { $1.tr!('[a-z]', '[A-Z]') } 
     709  class << RPCUtils 
     710  private 
     711    def addMDAry( mdAry, ary, indices ) 
     712      0.upto( ary.size - 1 ) do | idx | 
     713        if ary[ idx ].is_a?( Array ) 
     714          addMDAry( mdAry, ary[ idx ], indices + [ idx ] ) 
     715        else 
     716          mdAry[ *( indices + [ idx ] ) ] = RPCUtils.obj2soap( ary[ idx ] ) 
     717        end 
     718      end 
     719    end 
    515720  end 
    516721end