Takayuki Okazaki's Weblog
ブログ: 岡崎 - Okazaki's blog
20080225 2008年 2月 25日 月曜日
JRubyでJMX
English Translation: (Yahoo!) / (Google)
ずいぶん前の話ですが、IdMセミナーより: Identity ManagerをJMXで監視するというエントリでJMXによるアプリケーションサーバ監視をJRubyからやる。というのをご紹介しました。そのときに、JRuby開発者Thomas Eneboにこんなモジュールを作ってもらいました。ずっと前から紹介しようと思っていたのに、今頃気づきました・・・。すいません・・・。
include Java

import javax.management.DynamicMBean
import javax.management.MBeanInfo
import javax.management.ObjectName
import javax.management.remote.JMXServiceURL
import javax.management.remote.JMXConnectorServerFactory

module JMX
  class MBeanServerConnector
    def initialize(location, server)
      @url = JMXServiceURL.new location
      @server = JMXConnectorServerFactory.newJMXConnectorServer @url, nil, server.server

      if block_given?
    start; yield; stop
      end
    end

    def active?; @server.isActive; end
    def start; @server.start; end
    def stop; @server.stop if active?; end
  end

  # Represents both MBeanServer and MBeanServerConnection
  class MBeanServer
    import javax.management.remote.JMXConnectorFactory
    import javax.management.MBeanServerFactory
    import javax.management.Attribute

    attr_accessor :server
    @@classes = {}

    def initialize(location=nil, username=nil, password=nil)
      if (location)
    url = JMXServiceURL.new location
        if (username)
          credentials = java.lang.String[2].new
          credentials[0], credentials[1] = username, password
          env = {"jmx.remote.credentials" => credentials}
        else
          env = nil
        end
    @server =JMXConnectorFactory.connect(url, env).getMBeanServerConnection
      else
    @server = MBeanServerFactory.createMBeanServer
      end
    end

    def get_mbean(object_name)
      name = ObjectName.new object_name

      raise NoSuchBeanError.new("No name: #{object_name}") unless @server.isRegistered(name)
      @server.getObjectInstance name
      generate_proxy(name)
    end

    def create_mbean(class_name, object_name)
      name = ObjectName.new object_name
      @server.createMBean class_name, name, nil, nil
      generate_proxy(name)
    end

    def default_domain; @server.getDefaultDomain; end
    def domains; @server.domains; end
    def mbean_count; @server.getMBeanCount; end

    def query_names(name=nil, query=nil)
      name = ObjectName.new name
      @server.queryNames(name, query)
    end

    def register_mbean(object, object_name)
      name = ObjectName.new object_name

      @server.registerMBean(object, name)
      generate_proxy(name)
    end

    def generate_proxy(object_name)
      info = @server.getMBeanInfo object_name
      class_name = info.className

      return @@classes[class_name].new if @@classes[class_name]

      # Make local so closure capturage.
      server = @server
      proxy = Class.new
      # Attributes are supported using aref/aset syntax
      proxy.class_eval do
        define_method(:[]) do |name|
          server.getAttribute object_name, name
        end

        define_method(:[]=) do |name, value|
          server.setAttribute object_name, Attribute.new(attr.name, value)
        end
      end

      # Operations get method names (collision potential)
      info.operations.each do |op|     proxy.class_eval do
      define_method(op.name) do |*args|
        args_array = JMX::MBeanServer.args_array(args)
        signature_array = JMX::MBeanServer.signature_array(args_array)
        server.invoke object_name, op.name, args_array, signature_array
      end
    end
      end

      # Add notification listener methods
      proxy.class_eval do
    define_method(:add_notification_listener) do |listener,*rest|
      filter, handback = *rest
      server.addNotificationListener object_name, listener, filter, handback
    end

    define_method(:remove_notification_listener) do |listener|
      server.removeNotificationListener object_name, listener
    end

    define_method(:method_missing) do |method_name, *args|
      args_array = JMX::MBeanServer.args_array(args)
      signature_array = JMX::MBeanServer.signature_array(args_array)
      server.invoke object_name, method_name.to_s, args_array, signature_array
    end
      end

      @@classes[info.className] = proxy

      proxy.new
    end

    class << self
      def args_array(params)
    return nil if params.nil?

    array = java.lang.String[params.length].new
    params.each_with_index { |parm, i| array[i] = parm }

    array
      end

      def signature_array(params)
    return nil if params.nil?

    array = java.lang.String[params.length].new
    params.each_with_index do |parm, i|       array[i] = Java.ruby_to_java(parm).java_class.name
    end
    array
      end
    end
  end

  class NoSuchBeanError < RuntimeError
  end
end

class RubyDynamicMBean   import DynamicMBean

  def initialize(name, description)
    @info = MBeanInfo.new name, description, nil, nil, nil, nil
    @name, @description = name, description
  end

  def getAttribute(attribute); $stderr.puts "getAttribute"; end
  def getAttributes(attributes); $stderr.puts "getAttributes"; end
  def getMBeanInfo; $stderr.puts "getMBeanInfo"; @info; end
  def invoke(actionName, params=nil, signature=nil);     send(actionName, *params)
  end
  def setAttribute(attribute); $stderr.puts "setAttribute"; end
  def setAttributes(attributes); $stderr.puts "setAttributes";  end
  def to_s; "#@name: #@description"; end
  def inspect; "#@name: #@description"; end
  def toString; "#@name: #@description"; end
end
これを使うと、JRubyからJMXを使うときにこんな感じでプログラムを書けます。
require 'jmx'

username = "admin"
password = "adminadmin"
url      = "service:jmx:rmi:///jndi/rmi://localhost:8686/jmxrmi"
server   = JMX::MBeanServer.new url, username, password
listener = server.get_mbean "com.sun.appserv:name=server,type=virtual-server,category=monitor,server=server"

puts "Server started at: #{Time.new(listener["hosts-starttime"])}"
こんな感じで、ほんの数行。JMXの手続きとかは知らなくても大丈夫。


投稿されたコメント:

★ お名前を空欄にするとIPアドレスが、お名前欄に記入されます。
コメント
コメントは無効になっています。
過去の記事
« 11月 2009
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
     
       
今日
Click me to subscribe このブログを購読(RSS)
検索

このブログ著者について
ソフトウエア・インフラストラクチャー・ソリューション本部のソリューション・アーキテクトでした(2008年8月退職)。 本業はSOAソリューションならびにSun Java CAPSによるソリューションのプリセールスをお手伝いするエンジニア、とJavaエバンジェリストグループに参加してセミナーに行ったり、趣味のプログラミング・ネタをこのブログで紹介したりしていました。現在は、ふらふらとwatermint.orgで活動中〜。
リンク
 
SunホットトピックPodcast - SunホットトピックPodcast
 


 

Today's Page Hits: 84