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 して特異メソッドを定義。決まった!って感じ。