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

SOAP4Rで遊ぼう_3

このまま調子に乗ってtutorialなんて書いちゃうかも!なんて思ったNaHiが甘かった。

wiki:SOAP4Rで遊ぼう_2 では、RAA.rbをrequireしただけで、 SOAP::RPCUtils::Objectの特異オブジェクトだったものが、Ownerクラスのインスタンスになりました。 RAAのSOAPインタフェイスの他のメソッドを叩くと、同様に、 戻り値に応じて適宜InfoインスタンスやProductインスタンスが生成されます。

何故でしょう。RAA.rbを見る限り、単にいろんなクラスを定義してあるだけです。 どうやって戻り値とクラスを対応付けるんでしょうか。実はsoap4rは、 相手側から(JavaやPerlかも)ある名前の型の構造体が渡ってくると、 同じ名前のクラスを探してインスタンス化します。 例えば「"Owner"という型の構造体がやってきた→Ownerという名前のクラスを探す」わけです ((-そのため、以下の例のうち、RAA::Ownerクラスに戻すためには、 適当な位置でinclude RAAしとくだけでうまく対応付けられることもあります-))。

これでは困ることもあるでしょう。 Ownerじゃなくて、MyOwner?やOwner2、あるいはRAA::Ownerクラスのインスタンスを 生成したくなったらどうすればいいんでしょう。

そのためには、MappingRegistry?というクラスを使います。その使い方は!

続きは次回(←。。。

では続きです。

MappingRegistry?クラスのインスタンスは、 「Rubyオブジェクト←→SOAPオブジェクト(文字列、数値などの基本型、配列、構造体)」 の対応付け(マッピング)情報を保持します。 事前にこのマッピング情報を登録しておき、SOAPによるメソッド呼び出しなどのときに 渡して使います

では、これまでのサンプルを元に試してみましょう。 wiki:SOAP4Rで遊ぼう_2 では、WSDLから定義したRAA.rbを使うことで、 RAAの作者情報(SOAP上では"http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.1" という名前空間の"Owner"という型)を、Ownerクラスインスタンスにマップさせました。 ここではRAA.rbは使わず、自分で定義した、MyModule::MyOwner?にマップさせます。

  $ cat foo.rb
  require 'soap/wsdlDriver'
  
  wsdl = 'http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.1/'
  raa = SOAP::WSDLDriverFactory.new(wsdl).createDriver
  raa.generate_explicit_type = true
  
  # ここまで同じ。以下が追加分
  module MyModule
    class MyOwner
      attr_reader :id
      attr_reader :name
      attr_reader :email
  
      def inspect
        <<__EOS__
  #{self.class}
    id: #{id}
    name: #{name}
    email: #{email}
  __EOS__
      end
    end
  end
  
  # マッピング情報を登録するインスタンスの生成。
  map = ::SOAP::Mapping::Registry.new
  # ::MyModule::MyOwner <-> {http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.1}Owner
  map.set(
    ::MyModule::MyOwner,
    ::SOAP::SOAPStruct,
    ::SOAP::Mapping::Registry::TypedStructFactory,
    { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.1", "Owner") }
  )
  
  # ドライバにマッピング情報を指定。
  raa.mapping_registry = map
  
  # 後は同じ。指定したマッピング情報を使うので、MyModule::MyOwnerにマップされるはず
  firstProjectOf153, = raa.getInfoFromOwnerId(153)
  firstProjectOf587, = raa.getInfoFromOwnerId(587)
  p firstProjectOf153.owner
  p firstProjectOf587.owner

MappingRegistry#map?には、

  • Ruby側クラス
  • SOAP側内部クラス
  • 変換用ファクトリクラス
  • 更に追加情報として、SOAP上構造体の名前(名前空間と名称)

を指定します。 Ownerは構造体であるため、内部クラスとしてSOAPStructを、変換用ファクトリクラスとしては、 構造体用ファクトリクラスを指定します。 (ファクトリの種類についてはsoap/mappingRegistry.rbを参照してください)

では起動してみましょう。

  $ ruby foo.rb
  MyModule::MyOwner
    id: 153
    name: Paul Duncan (pabs)
    email: mailto:pabs@pablotron.org

  MyModule::MyOwner
    id: 587
    name: Paul Duncan (pabs)
    email: mailto:pabs@pablotron.org

サーバ側から返ってきている情報は同じなんですが、Ruby上ではMyModule::MyOwner?に マップされています。

しまった。inspectを書き換えたはいいけど、これじゃ↑の2エントリが異なる理由がわかんないな。