How To: Use JRuby with JMX for Oracle WebLogic Server 11g

by Pas Apicella    

Published April 2011

The JMX technology, now included in the Java SE platform, provides the tools for building rich, modular, and dynamic solutions for managing and monitoring devices, applications, and service-driven networks.

This article shows how to use the JRuby programming language with JMX to query an Oracle WebLogic Server 11g Release 1 managed server to display runtime information on the instance.

Software Requirements

The following software is presumed to be installed:

The examples should also work with some other versions of this software (but have not been tested on them).

Demo Setup

  1. Verify JDK 1.6 is installed.
      
    $ java -version
    java version "1.6.0_23"
    Java(TM) SE Runtime Environment (build 1.6.0_23-b05)
    Java HotSpot(TM) 64-Bit Server VM (build 19.0-b09, mixed mode)
    
  2. Set JRUBY_HOME to the directory where JRuby is installed and verify JRuby runs.
    
    $ export JRUBY_HOME=$HOME/jruby-1.5.6
    $ export PATH=$PATH:$JRUBY_HOME/bin
    $ jruby -v
    jruby 1.5.6 (ruby 1.8.7 patchlevel 249) (2010-12-03 9cf97c3) 
     (Java HotSpot(TM) Client VM 1.6.0_22) [x86-java]
    
  3. Install the jmx4r GEM for JMX support from JRuby as shown below.
    
    $ 
    jruby -S gem install jmx4r
    JRuby limited openssl loaded. http://jruby.org/openssl
    gem install jruby-openssl for full support.
    Successfully installed jmx4r-0.1.3
    1 gem installed
    Installing ri documentation for jmx4r-0.1.3...
    Installing RDoc documentation for jmx4r-0.1.3...
    
  4. Verify the GEM jmx4r is installed correctly.
    
    $ jruby -S gem list
    *** LOCAL GEMS ***
    
    columnize (0.3.1)
    jmx4r (0.1.3)
    rake (0.8.7)
    rspec (1.3.0)
    ruby-debug (0.10.3)
    ruby-debug-base (0.10.3.2)
    sources (0.0.1)
    
  5. Ensure you have a weblogic domain, which has at least one managed server, to connect to as shown in the image below from the Weblogic Server console application. The manged server we are using in this example is the server named apple running on port 7003 as shown below.
     

wls-jmx-jruby-f1

Running the Demo

  1. The first test involves ensuring we can establish a remote connection to the MBean Server within Weblogic itself. The code file name is test_jmx_weblogic.rb which has content as follows. An MBean server is a repository of MBeans that provides management applications access to MBeans. 
    # verify JMX connection to WebLogic 11g Release 1
    require 'rubygems'
    require 'jmx4r'
    require '/u01/fmw/1034/wlserver_10.3/server/lib/wljmxclient.jar'
    
    java_import java.lang.System
    
    class VerifyWeblogicJMX
    
      def initialize(user, passwd, url)
        @user, @passwd, @url = user, passwd, url
    
        System.setProperty("jmx.remote.protocol.provider.pkgs", "weblogic.management.remote")
    
        @conn = JMX::MBean.establish_connection :url => url, :username => user, :password => passwd
      end
    
      # add getters and setters for all attrributes we wish to expose
      attr_reader :user, :passwd, :url, :conn
    
      def close
        @conn.close unless !@conn
      end
    
      def to_s
        "JMXConnection [user=#{@user}, passwd=#{@passwd}, " +
        "url=#{@url}]"
      end
    
    end
    
    username = "weblogic"
    password = "welcome1"
    url = "service:jmx:iiop://papicell-au.au.oracle.com:7003/jndi/weblogic.management.mbeanservers.runtime"
    
    print "Run at #{Time.now} using JRuby #{RUBY_VERSION}\n\n"
    
    begin
      test = VerifyWeblogicJMX.new(username, password, url)
      puts test
      puts "\nSuccessfully connected to Oracle Weblogic 10.3.x from JRuby using JMX "
    rescue
      puts "\n** Error occured **\n"
      puts "Failed executing Oracle Weblogix JMX demo from JRuby ", $!, "\n"
    ensure
      test.close
    end
    
    print "Ended at #{Time.now}"
    
  2. Edit the lines of code below to connect to your WebLogic server. The format for the URL would be as follows. 


    service:jmx:iiop://{hostname}:{managed-server-port}/jndi/weblogic.management.mbeanservers.runtime

    Edit the line below to ensure you use the Weblogic JMX clientside JAR file. This file exists in the $WLS_HOME/server/lib directory. require '/u01/fmw/1034/wlserver_10.3/server/lib/wljmxclient.jar' Be sure to specify the correct connection credentials for your server.
    
    username = "weblogic"
    password = "welcome1"
    url = "service:jmx:iiop://papicell-au.au.oracle.com:7003/jndi/weblogic.management.mbeanservers.runtime"
    
  3. Run test_jmx_connection.rb using JRuby as shown below.
    
    $ jruby test_jmx_weblogic.rb
    Run at Thu Mar 31 08:09:49 +1100 2011 using JRuby 1.8.7
    
    JMXConnection [user=weblogic, passwd=welcome1,
      url=service:jmx:iiop://papicell-au.au.oracle.com:7003/jndi/weblogic.management.mbeanservers.runtime]
    
    Successfully connected to Oracle Weblogic 10.3.x from JRuby using JMX
    
    Ended at Thu Mar 31 08:09:50 +1100 2011
    
  4. Now we can connect; we will simple query an MBean and get runtime statistics on the running JVM. The program will do the following:
    • Connect using JMX to the Weblogic Managed Server
    • Lookup/Query the MBean with a name as follows - com.bea:ServerRuntime=apple,Name=apple,Type=JVMRuntime
    • Enter a loop and pause for 30 seconds between each request for the MBean data
    The code file name is monitor-mbean.rb, which contains:
    
    require 'rubygems'
    require 'jmx4r'
    require '/u01/fmw/1034/wlserver_10.3/server/lib/wljmxclient.jar'
    
    java_import 'javax.management.ObjectName'
    java_import java.lang.System
    
    def display_array (value)
      data = ""
      value.each do |x|
        data += "\n\t" + x.to_s
      end
      return data
    end
    
    # method used to check if the attribute data contains an array of data and make some sort of effort
    # to display it as text. This is quick and dirty way to do this but generally works for most array 
    # attribute values. If not an array it simply display the attribute value as a string
    
    def display_attribute_data(conn, object_name, attribute)   
      s = conn.get_attribute object_name, attribute
      search_str = s.to_s
     
      if (/^\[Ljava.lang.String/.match(search_str)) or
         (/^\[I/.match(search_str)) or
         (/^\[Ljavax.management.ObjectName/.match(search_str))
        # we have a array with data
        return display_array s
      end
     
      return s;
    end
    
    class JMXConnection
    
      def initialize(user, passwd, url)
        @user, @passwd, @url = user, passwd, url
    
        System.setProperty("jmx.remote.protocol.provider.pkgs", "weblogic.management.remote")
    
        @conn = JMX::MBean.establish_connection :url => url, :username => user, :password => passwd
      end
    
      # add getters and setters for all attrributes we wish to expose
      attr_reader :user, :passwd, :url, :conn
    
      def close
        @conn.close unless !@conn
      end
    
      def to_s
        "JMXConnection [user=#{@user}, passwd=#{@passwd}, " +
        "url=#{@url}]"
      end
    
    end
    
    username = "weblogic"
    password = "welcome1"
    url = "service:jmx:iiop://papicell-au.au.oracle.com:7003/jndi/weblogic.management.mbeanservers.runtime"
    
    print "Run at #{Time.now} using JRuby #{RUBY_VERSION}\n\n"
    
    begin
      jmx_conn = JMXConnection.new(username, password, url)
      puts jmx_conn
      puts "\nSuccessfully connected to Oracle Weblogic 10.3.x from JRuby using JMX "
     
      wls_mbean_name = "com.bea:ServerRuntime=apple,Name=apple,Type=JVMRuntime"
    
      mbean = JMX::MBean.find_by_name wls_mbean_name
      java_object_name = ObjectName.new wls_mbean_name
    
    
      while (true)
        # display attributes key/values
        mbean.attributes.each do |key, value|
          puts "Name: #{value}, Value: #{display_attribute_data jmx_conn.conn, java_object_name, value}\n"
        end
    
        # sleep for 30 seconds
        puts "\nSleeping for 30 seconds....\n"
        sleep 30
      end
    
    
    rescue
      puts "\n** Error occured **\n"
      puts "Failed executing Oracle Weblogix JMX demo from JRuby ", $!, "\n"
    ensure
      jmx_conn.close
    end
    
    print "Ended at #{Time.now}\n"
    
  5. Edit the line below to ensure you use the Weblogic JMX clientside JAR file. This file exists in the $WLS_HOME/server/lib directory.
    
    require '/u01/fmw/1034/wlserver_10.3/server/lib/wljmxclient.jar'
    
    Be sure to specify the correct connection credentials for your server.
    
    username = "weblogic"
    password = "welcome1"
    url = "service:jmx:iiop://papicell-au.au.oracle.com:7003/jndi/weblogic.management.mbeanservers.runtime"
     
  6. Verify output as follows. You will notice that after each iteration attibutes such as "HeapFreePercent" and "HeapFreeCurrent" will change depending on the load on the managed server JVM. (Note: Most of the thread dump attribute data for "ThreadStackDump" has been omitted to make it easier to read.)
    $ jruby monitor-mbean.rb
    
    Run at Mon Apr 04 10:26:46 +1000 2011 using JRuby 1.8.7
    
    JMXConnection [user=weblogic, passwd=welcome1,
       url=service:jmx:iiop://papicell-au.au.oracle.com:7003/jndi/weblogic.management.mbeanservers.runtime]
    Successfully connected to Oracle Weblogic 10.3.x from JRuby using JMX
    Name: Parent, Value: com.bea:Name=apple,Type=ServerRuntime
    Name: Uptime, Value: 2772452
    Name: HeapFreePercent, Value: 90
    Name: JavaVersion, Value: 1.6.0_22
    Name: Type, Value: JVMRuntime
    Name: ThreadStackDump, Value: "[STANDBY] ExecuteThread: '3' for queue: 
      'weblogic.kernel.Default (self-tuning)'" waiting for lock weblogic.work.ExecuteThread@1f2caf4 WAITING
     java.lang.Object.wait(Native Method)
     java.lang.Object.wait(Object.java:485)
     weblogic.work.ExecuteThread.waitForRequest(ExecuteThread.java:160)
     weblogic.work.ExecuteThread.run(ExecuteThread.java:181)
    
    "DynamicListenThread[Default[1]]" RUNNABLE native
     java.net.PlainSocketImpl.socketAccept(Native Method)
     java.net.PlainSocketImpl.accept(PlainSocketImpl.java:390)
     
    .....
    
    Name: OSVersion, Value: 5.10
    Name: JavaVendor, Value: Sun Microsystems Inc.
    Name: HeapFreeCurrent, Value: 210922280
    Name: OSName, Value: SunOS
    Name: Name, Value: apple
    Name: HeapSizeMax, Value: 518979584
    Name: JavaVMVendor, Value: Sun Microsystems Inc.
    Name: HeapSizeCurrent, Value: 259522560
    
    Sleeping for 30 seconds....
    
    Name: Parent, Value: com.bea:Name=apple,Type=ServerRuntime
    Name: Uptime, Value: 2802565
    Name: HeapFreePercent, Value: 90
    Name: JavaVersion, Value: 1.6.0_22
    Name: Type, Value: JVMRuntime
    Name: ThreadStackDump, Value: "[STANDBY] ExecuteThread: '3' for queue: 
      'weblogic.kernel.Default (self-tuning)'" waiting for lock weblogic.work.ExecuteThread@1f2caf4 WAITING
     java.lang.Object.wait(Native Method)
    
    .......
    
    Name: OSVersion, Value: 5.10
    Name: JavaVendor, Value: Sun Microsystems Inc.
    Name: HeapFreeCurrent, Value: 210225232
    Name: OSName, Value: SunOS
    Name: Name, Value: apple
    Name: HeapSizeMax, Value: 518979584
    Name: JavaVMVendor, Value: Sun Microsystems Inc.
    Name: HeapSizeCurrent, Value: 259522560
    
    Sleeping for 30 seconds....
  7. End the program using CTRL-C.

Congratulations, you have just learned how to access a Weblogic Server using JRuby with JMX. You could use such a setup to dynamically check attribute values and alert an administrator should they reach higher or lower then expected values.