Monday, May 28, 2007

Ruby-esque JMX -- Part 2

Below is the code from the JMX tinkering. I snake-ized the keys to be more Ruby-esque, per Ed's suggestion.

require 'java'
include Java

# Obviously stolen from Rails ActiveSupport for underscoring strings
class String
def underscore
self.to_s.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end

module JMX
class MBean
include_class 'javax.management.ObjectName'
include_package "java.lang.management"
include_package "javax.management"
include_package "javax.management.remote"
include_class "java.util.HashMap"
attr_accessor :name
def initialize(object_name)
@object_name = object_name
@name = @object_name.to_s
end

def attributes
attrs = MBean.connection.getMBeanInfo(@object_name).attributes rescue []
attrs.inject({}) do |list, a|
list[a.name.underscore] = MBean.connection.getAttribute(@object_name, "#{a.name}") rescue "Unknown"
list
end
end

def self.find_all_by_name(name)
object_name = ObjectName.new(name)
beans = MBean.connection.queryMBeans(object_name,nil )
beans.collect {|bean| MBean.new(bean.get_object_name)}
end

def self.find_by_name(name)
#obviously inefficient
find_all_by_name(name).first
end

def self.connection
@@mbsc ||= begin
#load from some config file later maybe
url = "service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"
connector = JMXConnectorFactory::connect(JMXServiceURL.new(url), HashMap.new)
connector.getMBeanServerConnection
end
end
protected

def method_missing(method, *args, &block)
attributes.keys.include?(method.to_s) ? attributes[method.to_s] : super
end
end
end

#Find all the MBeans matching some object name
mbeans = JMX::MBean.find_all_by_name("java.lang:*")
puts "Found #{mbeans.size} beans"

#Find a bean, and get its attribute
bean = JMX::MBean.find_by_name("java.lang:type=ClassLoading")
puts "There are #{bean.loaded_class_count} classes loaded in that VM"

3 comments:

jeff said...

Cool script. The Rails idioms make the code more readable (and more Ruby-esque than my version)

Do you plan to extend it to support writing attributes and invoking operations?

jeff
http://jmesnil.net/weblog/

Aaron Batalion said...

Jeff,
I primarily needed to retrieve read only attributes, but adding method invocation shouldnt be too hard. As long as you can inspect the beans to determine method signatures. Feel free to grab the code and play around with the idea. The method missing approach will have to be slightly modified, but not significantly.

jeff said...

Aaron, fyi I added some of you code to my protoypes and released a very simple library: jmx4r[1].

I also took the opportunity to add suport for writable attributes & operations invocations[2].

--jeff
http://jmesnil.net/weblog/

[1] http://code.google.com/p/jmx4r/
[2] http://jmesnil.net/weblog/2007/06/11/jmx4r-a-jmx-libary-for-jruby/