Scala で動くRTコンポーネントを作る?

Jython, JRuby ときて、Scala でもRTコンポーネントを作ってみました。
実は Scala を扱うのは初めてで、なかなか勝手がつかめませんでした。

以下のサンプルも動作はするのですが、ひとつだけクリアできなかった問題があります。
RtcDeleteFunc::deleteRtc の引数 rtcBase に null を代入できません。
このままだとMyServiceConsumerImpl インスタンスは解放されないので、今回の Scala RTC サンプルはまあ問題提起みたいなものです。
解決法のわかる方があればアドバイスを。

ExceptionCatcher トレイトは、onInitialize や onExecute で発生したエラーをコンソールに表示するためのものです。
そもそも、RTコンポーネント内のエラーは捕捉しづらい。気がつくとRTシステムエディタ上でRTコンポーネントが真っ赤になって、原因究明にえらい苦労します。
python ではアクション関数ごとにいちいち try 〜 except を書いていたのですが、たった一行の処理に6行も例外処理を書くはめになって非常にしょっぱい。

そこで、トレイトと無名関数の引数渡しを組み合わせて、この部分を簡略化しました。
showIfError {} で処理を囲むことで、{}内で発生した例外をコンソールに表示します。
ただし、MyServiceConsumerImpl のコンストラクタではtry ~ catch が書けなかったり、registerFactory の引数として、RtcXXXFunc を匿名クラスで継承してその場で xxxRtc を実装するあたりではトレイトが使えなかったため、try ~ catch 丸出しになっています。 (ここは普通に継承すべきだったかも……)

/**
 * MyServiceConsumer.scala
 */
import SimpleService.MyService
import jp.go.aist.rtm.RTC.Manager;
import jp.go.aist.rtm.RTC.ModuleInitProc;
import jp.go.aist.rtm.RTC.RTObject_impl;
import jp.go.aist.rtm.RTC.DataFlowComponentBase;
import jp.go.aist.rtm.RTC.RtcDeleteFunc;
import jp.go.aist.rtm.RTC.RtcNewFunc;
import jp.go.aist.rtm.RTC.port.CorbaConsumer;
import jp.go.aist.rtm.RTC.port.CorbaPort;
import jp.go.aist.rtm.RTC.util.Properties;
import RTC.ReturnCode_t;

/*
 * アクションメソッドでのエラーをコンソールに表示する
 */
trait ExceptionCatcher {
  def showIfError[T](f: => T): Unit = {
    try {
      Some(f)
    } catch {
      case e: Exception => e.printStackTrace()
    }
  }
}

/*
 * アクションメソッドの実装
 */
class MyServiceConsumerImpl(manager: Manager) 
	extends DataFlowComponentBase(manager) 
	with ExceptionCatcher
{
  val myServicePort = new CorbaPort("MyService");
  val myservice0Base = new CorbaConsumer(classOf[MyService])

  override def onInitialize: ReturnCode_t = {
    showIfError {
      myServicePort.registerConsumer("myservice0", "MyService", myservice0Base)
      addPort(myServicePort)
    }
    super.onInitialize()
  }

  override def onExecute(ec_id: Int): ReturnCode_t = {
    showIfError {
      println("""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.""")
      val line = readLine("> ")
      if (line == "")
        return super.onExecute(ec_id)
      val argv = line.split(" ")
      val myservice0 = myservice0Base._ptr
      argv(0) match {
        case "echo" if argv.length > 1 => {
          val retmsg = myservice0.echo(argv(1))
          println("echo() return: " + retmsg)
        }
        case "set_value" if argv.length > 1 => {
          myservice0.set_value(argv(1).toFloat)
          printf("Set remote value: %s\n", argv(1))
        }
        case "get_value" => {
          val retval = myservice0.get_value
          printf("Current remote value: %f\n", retval)
        }
        case "get_echo_history" => {
          var i: Int = 0
          val history = myservice0.get_echo_history
          history.foreach { h =>
            i += 1
            printf("%d: %s\n", i, h)
          }
        }
        case "get_value_history" => {
          var i: Int = 0
          val history = myservice0.get_value_history
          history.foreach { h =>
            i += 1
            printf("%d: %s\n", i, h)
          }
        }
        case _ => println("Invalid command or argument(s).")
      }
    }
    super.onExecute(ec_id)
  }
}

object MyServiceConsumer
  extends ModuleInitProc with ExceptionCatcher 
{
  val component_conf = Array(
    "implementation_id", "MyServiceConsumer",
    "type_name", "MyServiceConsumer",
    "description", "MyService Consumer Sample written by Scala",
    "version", "1.0.0",
    "vendor", "thegoodbadandugly",
    "category", "Sample",
    "activity_type", "DataFlowComponent",
    "max_instance", "1",
    "language", "Scala",
    "lang_type", "compile",
    "")

  override def myModuleInit(mgr: Manager) {
    mgr.registerFactory(
      new Properties(component_conf),
      new RtcNewFunc {
        def createRtc(manager: Manager): RTObject_impl = {
          try {
            return new MyServiceConsumerImpl(manager)
          } catch {
          	case e: Exception => e.printStackTrace()
          }
          null
        }
      },
      new RtcDeleteFunc {
        def deleteRtc(rtcBase: RTObject_impl): Unit = {
          try {
            rtcBase// = null
          } catch {
          	case e: Exception => e.printStackTrace()
          }
        }
      }
    )
    mgr.createComponent("MyServiceConsumer")
  }

  def main(args: Array[String]): Unit = {
    val manager = Manager.init(args)
    println("Set module initialization proceduer")
    manager.setModuleInitProc(MyServiceConsumerComp)
    println("Activate manager and register to naming service")
    manager.activateManager
    println("run the manager in blocking mode")
    manager.runManager
  }
}

実行

export RTM_JAVA_ROOT=(OpenRTM-aist-Java をインストールしたディレクトリ)/OpenRTM-aist/1.0
export CLASSPATH=.:$RTM_JAVA_ROOT/jar/OpenRTM-aist-1.0.0.jar:$RTM_JAVA_ROOT/jar/commons-cli-1.1.jar
scalac MyServiceConsumer.scala
scala MyServiceConsumer

MyServiceProvider の方はまた後日。