Package my.code.a003.process

Source Code of my.code.a003.process.A06CallRemoteMethodViaJMX

package my.code.a003.process;

import java.io.File;

import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import my.code.a003.process.apps.PrintOnRemoteRequest;
import my.code.a003.process.apps.PrintOnRemoteRequest.MessagePrinterMBean;
import my.code.a003.process.util.ActiveJavaVirtualMachineExplorer;

/**
* Simple example of (mis)using JMXBeans for remote method invocation. Spawn a child process,
* another JVM, a simple Java application echoing given message on remote call done by MBean
* (JMXBean) interface. Make it print "Hello world!".
* <p>
* Two tricky bits:
* <ol>
* <li>get PID (process ID) of spawned child process (covered in previous examples)
* <li>get MBean connection URL for that PID (main topic for this example)
* </ol>
* <p>
* Note: MBean can be an inner class, see {@link PrintOnRemoteRequest.MessagePrinter} used in this
* example, however I would not recommend it for real world application.
* <p>
* Note: MBean naming is tricky, interface has to have same name as implementation but plus MBean
* suffix, and implementation name is used in {@link ObjectName}
*
* @see http://docs.oracle.com/javase/tutorial/jmx/remote/custom.html
* @see https://blogs.oracle.com/jmxetc/entry/how_to_retrieve_remote_jvm
* @see http://barecode.org/blog.php/establishing-jmx-connections-to-a
* @see http://www.pongasoft.com/blog/yan/entry/connecting_to_a_local_vm/
*
* @author espinosa
* @since 28.6.2013, 2.7.2013
*/
public class A06CallRemoteMethodViaJMX {

  public static void main(String[] args) throws Exception {
    new A06CallRemoteMethodViaJMX().run();
  }

  public void run() throws Exception {
    // start child process
    String classpath = System.getProperty("java.class.path");
    ProcessBuilder childProcessBuilder = new ProcessBuilder(
      "java",
      "-cp", classpath,
      PrintOnRemoteRequest.class.getName()
      );
    childProcessBuilder.redirectErrorStream(true);
    childProcessBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
    Process childProcess = null;
    try {
      childProcess = childProcessBuilder.start();

      // get PID of child application
      Integer pid = ActiveJavaVirtualMachineExplorer.getPid(PrintOnRemoteRequest.class);
      if (pid == null)
        throw new RuntimeException("PID of the child process was not found");

      // connect to child process via MBeans
      JMXServiceURL jmxURL = extractJmxServiceUrl(pid);
      JMXConnector connector = JMXConnectorFactory.connect(jmxURL);
      MBeanServerConnection mbsc = connector.getMBeanServerConnection();
      ObjectName mbeanName = new ObjectName("my.code.a003.process:type=PrintOnRemoteRequest.MessagePrinter");
      MessagePrinterMBean printerProxy = JMX.newMBeanProxy(mbsc, mbeanName,
        MessagePrinterMBean.class, true);

      // call method on child process via MBean
      printerProxy.printMessage("Hello world!");

      // close connection to child application
      connector.close();
    } finally {
      if (childProcess != null) {
        childProcess.destroy();
      }
    }
  }

  private JMXServiceURL extractJmxServiceUrl(int pid) throws Exception {
    // pure madness! just to get local connector address one has to load management-agent.jar to the target application
    // it is the official way! Otherwise localConnectorAddress is always null.
    // See: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6342019 (Bug #6342019 : Provide supported way for JMX clients to obtain local connector address)
    // See: https://blogs.oracle.com/jmxetc/entry/how_to_retrieve_remote_jvm
    // See: http://barecode.org/blog.php/establishing-jmx-connections-to-a
    com.sun.tools.attach.VirtualMachine vm = com.sun.tools.attach.VirtualMachine.attach(String.valueOf(pid));
    String javaHome = vm.getSystemProperties().getProperty("java.home");
    String agentJar = javaHome + File.separator + "lib" + File.separator + "management-agent.jar";
    vm.loadAgent(agentJar, "com.sun.management.jmxremote");
    String localConnectorAddress = vm.getAgentProperties().getProperty(
      "com.sun.management.jmxremote.localConnectorAddress");
    if (localConnectorAddress == null) {
      // Check system properties, some JVM implementations may use system properties instead of agent properties
      localConnectorAddress = vm.getSystemProperties().getProperty(
        "com.sun.management.jmxremote.localConnectorAddress");
    }
    vm.detach();
    System.out.println("Local connector address = " + localConnectorAddress);
    return new JMXServiceURL(localConnectorAddress);
  }
}
TOP

Related Classes of my.code.a003.process.A06CallRemoteMethodViaJMX

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.