Package my.code.a003.process

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

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.agent.PrintMessage;
import my.code.a003.process.apps.LoiteringApp;
import my.code.a003.process.apps.PrintOnRemoteRequest.MessagePrinterMBean;
import my.code.a003.process.util.ActiveJavaVirtualMachineExplorer;
import my.code.a003.process.util.JarFileProvider;
import my.code.a003.process.util.JarFileProviderMavenStandardsImpl;

import com.sun.tools.attach.VirtualMachine;

/**
* Load extra functionality in form of a Java class, PrintMessage POJO, into target application,
* LoiteringApp, an already running unsuspected simple application, expose as JMXBean as remotely
* callable method, and make it to do naughty things like print "Hello world!" to standard output on
* JMX command, something it was not originally designed to do.
*
* Security, like preventing PrintMessage being called from remote nodes is not covered in this example.
*
* This example is
*
* @see http://www.javaworld.com/community/node/470
* @see http://dhruba.name/2010/02/07/creation-dynamic-loading-and-instrumentation-with-javaagents/
* @see https://blogs.oracle.com/CoreJavaTechTips/entry/the_attach_api
* @see https://blogs.oracle.com/jmxetc/entry/how_to_retrieve_remote_jvm
* @see http://blog.42.nl/articles/connecting-to-a-jvm-programmatically/
*
* @author espinosa
* @since 3.7.2013
*/
public class A07InjectClassToUnsuspectedApplicationAndExposeItAsJmxBean {

  private static final String ADD_MBEAN_AGENT_JAR = "add-mbean-agent.jar";

  public static final Class<?> TESTED_MBEAN_CLASS = PrintMessage.class;

  public static final Class<?> TARGET_APP_MAIN_CLASS = LoiteringApp.class;

  public static final String TESTED_MBEAN_CLASS_NAME = "my.code.a003.process.agent.PrintMessage";

  public static final String TESTED_MBEAN_OBJECT_NAME = "my.code.a003.process.agent:type=PrintMessage";

  private static final JarFileProvider jarFileProvider = new JarFileProviderMavenStandardsImpl();

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

  public void run() throws Exception {
    Process childProcess = null;
    try {

      // start child process
      String classpath = System.getProperty("java.class.path");
      ProcessBuilder childProcessBuilder = new ProcessBuilder(
        "java",
        "-cp", classpath,
        LoiteringApp.class.getName()
        );
      childProcessBuilder.redirectErrorStream(true);
      childProcessBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
      childProcess = childProcessBuilder.start();

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

      // inject PrintMessage to target JVM application, unsuspecting LoiteringApp
      // special Java Agent AddMBeanAgent cause this insertion and expose it as JMXBean on target application
      injectMBeanToTargetProcess(pid, TESTED_MBEAN_CLASS_NAME);

      // connect to child process via MBeans
      JMXServiceURL jmxURL = extractJmxServiceUrl(pid);
      JMXConnector connector = JMXConnectorFactory.connect(jmxURL);
      MBeanServerConnection mbsc = connector.getMBeanServerConnection();
      ObjectName mbeanName = new ObjectName(TESTED_MBEAN_OBJECT_NAME);
      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 void injectMBeanToTargetProcess(int pid, String mbeanClassName) throws Exception {
    com.sun.tools.attach.VirtualMachine vm = VirtualMachine.attach(String.valueOf(pid));
    String agentJar = jarFileProvider.getJarFire(ADD_MBEAN_AGENT_JAR).getAbsolutePath();
    vm.loadAgent(agentJar, mbeanClassName);
    vm.detach();
  }

  private JMXServiceURL extractJmxServiceUrl(int pid) throws Exception {
    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.A07InjectClassToUnsuspectedApplicationAndExposeItAsJmxBean

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.