今回で、JMX関連は1度終わりにしようかなぁと思います。最後は、MXBeanです。
お題はやはり、以下のサイトのサンプルをScalaで書き直し。
http://www.javainthebox.net/laboratory/JavaSE6/userdefinedmxbeans/mxbean.html
まあ、MXBeanのAttributeとかOperationはこちらで元々使っていたサンプルがベースになっていますけどね。
では、まずは普通のMXBean。
MyMXBean.scala
import scala.reflect.BeanProperty trait MyMXBean { @BeanProperty var count: Int def execute(): Unit } class MyMXBeanImpl(val name: String) extends MyMXBean { @BeanProperty var count: Int = _ def execute(): Unit = { count += 1 printf("Execute[%s], count[%d]\n", name, count) } }
パッと見、名前が「MXBean」で終わっていることを覗いてほぼStandardMBeanと同じです。まあ、クラス名に対する縛りはStandardMBeanよりも緩そうな感じですが。
続いて、CompositeDataを利用するMXBean。最初は、MXBeanの定義です。
MyCompositeMXBean.scala
import scala.reflect.BeanProperty trait MyCompositeMXBean { @BeanProperty var count: Int @BeanProperty val myName: MyName def execute(): Unit } class MyCompositeMXBeanImpl(val first: String, val last: String) extends MyCompositeMXBean { @BeanProperty var count: Int = _ @BeanProperty val myName: MyName = new MyName(first, last) def execute(): Unit = { count += 1 printf("Execute[%s:%s], count[%d]\n", first, last, count) } }
MXBeanが使用するCompositeDataの定義。
MyCompositeData.scala
import scala.reflect.BeanProperty import javax.management.openmbean.{CompositeData, CompositeDataSupport, CompositeType} import sun.management.{LazyCompositeData, MappedMXBeanType} object MyName { def apply(cd: CompositeData): MyName = { MyNameCompositeData.validateCompositeData(cd) new MyName(MyNameCompositeData.first(cd), MyNameCompositeData.last(cd)) } def from(cd: CompositeData): MyName = cd match { case null => null case name: MyNameCompositeData => name.myName case _ => apply(cd) } } class MyName(@BeanProperty val first: String, @BeanProperty val last: String) object MyNameCompositeData { private val NAME_FIRST: String = "first" private val NAME_LAST: String = "last" val MY_NAME_COMPOSITE_TYPE: CompositeType = MappedMXBeanType.toOpenType(classOf[MyName]).asInstanceOf[CompositeType] val MY_NAME_ITEM_NAMES: Array[String] = Array(NAME_FIRST, NAME_LAST) def toCompositeData(myName: MyName): CompositeData = new MyNameCompositeData(myName).getCompositeData def first(cd: CompositeData): String = cd.get(NAME_FIRST).asInstanceOf[String] def last(cd: CompositeData): String = cd.get(NAME_LAST).asInstanceOf[String] def validateCompositeData(cd: CompositeData): Unit = { require(cd != null) //require(!LazyCompositeData.isTypeMatched(MY_NAME_COMPOSITE_TYPE, cd.getCompositeType)) } } class MyNameCompositeData(@BeanProperty val myName: MyName) extends LazyCompositeData { import MyNameCompositeData._ protected def getCompositeData: CompositeData = new CompositeDataSupport(MY_NAME_COMPOSITE_TYPE, MY_NAME_ITEM_NAMES, Array(myName.first,myName.last)) }
なんかMyとか付いてますが、基本的にはサイトのサンプルと同じです。ただ、LazyCompositeData#isTypeMatchedはprotected staticなメソッドのため、Scalaからは呼び出すことができないので断念しました。
最後、@MXBeanアノテーションを使用したMXBeanの作成。MXBeanの定義。
MyEasyMXBean.scala
import scala.reflect.BeanProperty import javax.management.MXBean @MXBean trait MyEasyMXBean { @BeanProperty var count: Int @BeanProperty val easyName: EasyName def execute(): Unit } class MyEasyMXBeanImpl(val name: String) extends MyEasyMXBean { @BeanProperty var count: Int = _ @BeanProperty val easyName: EasyName = new EasyName(name) def execute(): Unit = { count += 1 printf("Execute[%s], count[%d]\n", name, count) } }
続いて、複合型の定義です。
EasyName.scala
import scala.reflect.BeanProperty import java.beans.ConstructorProperties class EasyName @ConstructorProperties(Array("name"))(@BeanProperty val name: String)
Scalaでコンストラクタにアノテーションを付ける??と一瞬戸惑いましたが、アクセス修飾子とかの指定方法から冷静に考えると、上記の位置でよさそうですよね。
いずれも、MBeanServerに普通に登録すればJConsoleなどで確認することができます。
登録したMXBeanをJConsoleで見たところ。Scalaのフィールドに対応するメソッドが見えてしまっているのはご愛嬌。