JRuby で動くRTコンポーネントを作り直す
thegoodbadugly:1335170735:title は、Jython 版のRTCのソースをとにかく JRuby で動くようにしたものなので、Ruby らしいコードは書いていません。
Scala 版がいい感じに書けてちょっとくやしいので、書き直してみました。
MyServiceConsumer.rb
#!/usr/bin/env jruby require 'readline' require 'java' begin java_import 'jp.go.aist.rtm.RTC.DataFlowComponentBase' java_import 'jp.go.aist.rtm.RTC.port.CorbaPort' rescue NameError # _SDOPackage が NameError になるが、実行には問題ないので無視する retry if $!.name == "_SDOPackage" raise end java_import 'jp.go.aist.rtm.RTC.port.CorbaConsumer' java_import 'jp.go.aist.rtm.RTC.util.Properties' java_import 'jp.go.aist.rtm.RTC.RtcNewFunc' java_import 'jp.go.aist.rtm.RTC.RtcDeleteFunc' java_import 'jp.go.aist.rtm.RTC.Manager' java_import 'jp.go.aist.rtm.RTC.ModuleInitProc' java_import 'SimpleService.MyService' # アクションメソッドなどのコールバック関数の中で起きたエラーをコンソールに表示する。 # 各コールバック関数内で、処理を show_if_error do ... end の中に書くだけで済む。 def show_if_error begin yield rescue puts $! puts $@ raise end end # アクションの内容を実装 class MyServiceConsumerImpl < DataFlowComponentBase def initialize(manager) show_if_error do super(manager) @myServicePort = CorbaPort.new("MyService") # initialization of Consumer @myservice0 = CorbaConsumer.new(MyService.java_class) end end def onInitialize show_if_error do # Set service consumers to Ports @myServicePort.registerConsumer("myservice0", "MyService", @myservice0) # Set CORBA Service Ports addPort(@myServicePort) super end end def onExecute(ec_id) show_if_error do puts <<EOS Command list: echo [msg] : echo message. set_value [value]: set value. get_value : get current value. get_echo_history : get input messsage history. get_value_history: get input value history. EOS line = Readline.readline("> ", true) return super if line.empty? cmd, *args = line.split args = args*" " myservice = @myservice0._ptr case cmd when "echo" if args.empty? puts "Invalid argument(s).\n\n" else msg = myservice.echo(args) puts "echo() return: #{msg}\n\n" end when "set_value" if args.empty? puts "Invalid argument(s).\n\n" else value = args.to_f myservice.set_value(value) puts "Set remote value: #{value}\n\n" end when "get_value" puts "Current remote value: #{myservice.get_value}\n\n" when "get_echo_history" myservice.get_echo_history.each_with_index { |h, i| puts "#{i}: #{h}"} puts when "get_value_history" myservice.get_value_history.each_with_index { |h, i| puts "#{i}: #{h}"} puts else puts "Invalid command or argument(s).\n\n" end super end end end $component_conf = ["implementation_id", "MyServiceConsumer", "type_name", "MyServiceConsumer", "description", "MyService Consumer Sample written by JRuby", "version", "1.1.0", "vendor", "thegoodbadugly", "category", "Sample", "activity_type", "DataFlowComponent", "max_instance", "1", "language", "JRuby", "lang_type", "SCRIPT", ""] init_proc = ModuleInitProc.new # 特異メソッドで実装 def init_proc.myModuleInit(manager) prop = Properties.new($component_conf.to_java(:String)) newfunc = RtcNewFunc.new def newfunc.createRtc(manager) show_if_error do MyServiceConsumerImpl.new(manager) end end deletefunc = RtcDeleteFunc.new def deleteRtc(rtcBase) show_if_error do rtcBase = nil end end manager.registerFactory(prop, newfunc, deletefunc) # Create a component manager.createComponent("MyServiceConsumer") end mgr = Manager.init(ARGV) puts "Set module initialization proceduer" mgr.setModuleInitProc(init_proc) puts "Activate manager and register to naming service" mgr.activateManager puts "run the manager in blocking mode" mgr.runManager
show_if_error がグローバルに使えるのがRubyの強みでしょうか。
case ~ when は Scala の match ほどきれいには行かなかった。
init_proc のくだりは JRuby ならではでしょうか。Java のインターフェースをいきなり new して特異メソッドを定義。決まった!って感じ。