How to set JMX remote port system environment parameters through java code for remote monitoring?

Devesh picture Devesh · Sep 1, 2011 · Viewed 25.3k times · Source

I have a program which requires dynamically (i.e. at run time) opening an available socket and start a JMX agent on it. This JMX parameters are being set inside the Java code and not through command line. This works fine. Thereafter it is needed to monitor( i.e issue JMX commands etc) through Java Visual VM remotely

The RMI server agent in the program is on the lines of out of box management described at: http://download.oracle.com/javase/6/docs/technotes/guides/management/agent.html

The question I have can be summarized as: How can such command line properties be set to the system level through the Java code, so that remote profiling can be used??

-Dcom.sun.management.jmxremote.port=1234

If the "jmxremote.port" and other parameters are set through command line, remote monitoring works fine. I am trying to find a way to do this through Java and not through the command line.

The program can not specify the port through the command line as the new available port has to be figured out at run time.

The process needs remote monitoring and it works fine locally. If the following parameters are not specified at command line, Java Visual VM does not connect to the process.

-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=10.0.0.128

I have tried.

System.setProperty("com.sun.management.jmxremote.port",Integer.toString(port));

This is one of the first things done in the program before starting the JMXConnectorServer. Unfortunately it is not recognized. Only the run time properties (i.e. specified through command line are recognized for JMX connection by Java Visual VM).

Also came across the way properties can be extracted from java collection classes but could not reach how to trace the property "com.sun.management.jmxremote.port="

public static void setEnv(Map<String, String> newenv) throws Exception {
  Class[] classes = Collections.class.getDeclaredClasses();
  Map<String, String> env = System.getenv();

  for(Class cl : classes) {

    if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {

      Field field = cl.getDeclaredField("m");
      field.setAccessible(true);

      Object obj = field.get(env);
      Map<String, String> map = (Map<String, String>) obj;

      //map.clear();
      map.putAll(newenv);
    }
  }
}

Any help would be appreciated!

Answer

Mark Butler picture Mark Butler · Jul 23, 2013

kbec's answer showed the way but did not work for me - however by looking at this post I was able to modify it and get a working solution.

public static String loadJMXAgent(int port) throws IOException,
        AttachNotSupportedException, AgentLoadException,
        AgentInitializationException {
    String name = ManagementFactory.getRuntimeMXBean().getName();
    VirtualMachine vm = VirtualMachine.attach(name.substring(0,
            name.indexOf('@')));

    String lca = vm.getAgentProperties().getProperty(
            "com.sun.management.jmxremote.localConnectorAddress");
    if (lca == null) {
        Path p = Paths.get(System.getProperty("java.home")).normalize();
        if (!"jre".equals(p.getName(p.getNameCount() - 1).toString()
                .toLowerCase())) {
            p = p.resolve("jre");
        }
        File f = p.resolve("lib").resolve("management-agent.jar").toFile();
        if (!f.exists()) {
            throw new IOException("Management agent not found");
        }
        String options = String.format("com.sun.management.jmxremote.port=%d, " +
                "com.sun.management.jmxremote.authenticate=false, " +
                "com.sun.management.jmxremote.ssl=false", port);
        vm.loadAgent(f.getCanonicalPath(), options);
        lca = vm.getAgentProperties().getProperty(
                "com.sun.management.jmxremote.localConnectorAddress");
    }
    vm.detach();
    return lca;
}

This works in Eclipse however getting it to work at the command line is a different matter - there is some discussion about this here Why does using the Java Attach API fail on linux? (even though maven build completes) but I found adding $JAVA_HOME/lib/tools.jar to my classpath solved the problem.