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
- 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エントリが異なる理由がわかんないな。