Arch2Arch Tab BEA.com
Syndicate this blog (XML)

JRCMD goes remote!

Bookmark Blog Post

del.icio.us del.icio.us
Digg Digg
DZone DZone
Furl Furl
Reddit Reddit

Marcus Hirt's Blog | December 12, 2005  11:49 AM | Comments (1)


JRockit has for quite some time had a very neat way to communicate with the JVM after it has been started, using the ctrl-break/kill -3 signal handler. You simply put a file called ctrlhandler.act in the current working directory, press ctrl-break (Windows) and voila, the file gets parsed and the commands in the file are executed. For more information on this, see my article JRockit 5.0 At Your Fingertips.

We introduced a simpler means of accessing this functionality with the JRCMD command line utility, which can be used to either list all the performance counters or run a ctrl-break handler on JRockit processes on the local machine.

The following example is an extended version of my perfcounter example (shown in an earlier Blog entry of mine) that, just like the JRCMD, allows the performance counters and ctrl-break handlers to be read/executed - but remotely from another machine.


import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.management.Attribute;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

/**
 * Simple code example on how to execute ctrl-break handlers remotely.
 * 
 * Usage: RemoteJRCMD -host <host> -port <host> -user <user>
 * -pass <password> -command <command> [<params>]
 * 
 * All arguments are optional. If no command is specified, all performance
 * counters and their current values are listed.
 * 
 * @author Marcus Hirt
 */
public class RemoteJRCMD
{
   private final static String      KEY_CREDENTIALS                = 
      "jmx.remote.credentials";
   private final static String      JROCKIT_PERFCOUNTER_MBEAN_NAME = 
      "com.jrockit:type=JRockitPerfCounters";
   private final static String      JROCKIT_CONSOLE_MBEAN_NAME     = 
      "com.jrockit:type=JRockitConsole";
   private final static String[]    SIGNATURE                      = 
      new String[] { "java.lang.String" };

   public static void main(String[] args) throws Exception
   {
      HashMap commandMap = new HashMap();
      commandMap.put("-host", "localhost");
      commandMap.put("-port", "7091");
      for (int i = 0; i < args.length; i++)
      {
         if (args[i].startsWith("-"))
         {
            StringBuilder buf = new StringBuilder();
            int j = i + 1;
            while (j < args.length && !args[j].startsWith("-"))
            {
               buf.append(" ");
               buf.append(args[j++]);
            }
            commandMap.put(args[i], buf.toString().trim());
            i = j - 1;
         }
      }
      executeCommand(commandMap.get("-host"), Integer.parseInt(commandMap
            .get("-port")), commandMap.get("-user"), commandMap
            .get("-password"), commandMap.get("-command"));
   }

   public static void executeCommand(String host, int port, String user,
         String password, String command) throws Exception
   {
      MBeanServerConnection server = null;
      JMXConnector jmxc = null;
      Map map = null;
      if (user != null || password != null)
      {
         map = new HashMap();
         final String[] credentials = new String[2];
         credentials[0] = user;
         credentials[1] = password;
         map.put(KEY_CREDENTIALS, credentials);
      }
      // Use same convention as Sun. localhost:0 means "VM, monitor thyself!"
      if (host.equals("localhost") && port == 0)
      {
         server = ManagementFactory.getPlatformMBeanServer();
      }
      else
      {
         jmxc = JMXConnectorFactory.newJMXConnector(createConnectionURL(
               host, port), map);
         jmxc.connect();
         server = jmxc.getMBeanServerConnection();
      }

      System.out.println("Connected to " + host + ":" + port);

      if (command == null)
      {
         ObjectName perfCounterObjectName = new ObjectName(
               JROCKIT_PERFCOUNTER_MBEAN_NAME);
         System.out.println("Listing all counters...");
         MBeanAttributeInfo[] attributes = server.getMBeanInfo(
               perfCounterObjectName).getAttributes();
         System.out.println("Counter\tValue\n=======\t====");

         String[] attributeNames = new String[attributes.length];
         for (int i = 0; i < attributes.length; i++)
         {
            attributeNames[i] = attributes[i].getName();
         }
         Iterator valueIter = server.getAttributes(perfCounterObjectName,
               attributeNames).iterator();
         while (valueIter.hasNext())
         {
            Attribute attr = (Attribute) valueIter.next();
            System.out.println(attr.getName() + "\t=\t" + attr.getValue());
         }
      }
      else
      {
         System.out.println("Invoking the ctrl-break command '" + command
               + "'...");
         ObjectName consoleObjectName = new ObjectName(
               JROCKIT_CONSOLE_MBEAN_NAME);
         Object[] params = new Object[1];
         params[0] = command;
         System.out
               .println("The CtrlBreakCommand returned: \n"
                     + server.invoke(consoleObjectName,
                           "runCtrlBreakHandlerWithResult", params,
                           SIGNATURE));
      }

      if (jmxc != null)
      {
         jmxc.close();
      }
   }

   private static JMXServiceURL createConnectionURL(String host, int port)
         throws MalformedURLException
   {
      return new JMXServiceURL("rmi", "", 0, "/jndi/rmi://" + host + ":"
            + port + "/jmxrmi");
   }
}

The following example would list all the performance counters and their values on localhost on the default port (7091):

java RemoteJRCMD

The following example would start a 60 second JRA recording on a JRockit running at the host bitsy, port 7099, writing the resulting recording to a file called nisse.zip:

java RemoteJRCMD -command jrarecording filename=nisse time=60 -host bitsy -port 7091

And as always, don't forget to enable the JMX management agent of the JRockit you wish to monitor. :)


Comments

Comments are listed in date ascending order (oldest first) | Post Comment

  • Since JRockit R26.2, JRCMD exists for 1.4 too. :)

    Posted by: hirt on August 22, 2006 at 12:52 AM



Only logged in users may post comments. Login Here.

Powered by
Movable Type 3.31