Jdk5JavaProcessManager.java

package org.cyclopsgroup.jmxterm.jdk5;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.Validate;
import org.cyclopsgroup.jmxterm.JavaProcess;
import org.cyclopsgroup.jmxterm.JavaProcessManager;
import org.cyclopsgroup.jmxterm.utils.WeakCastUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * JDK5 specific implementation of {@link JavaProcessManager}
 *
 * @author <a href="mailto:jiaqi.guo@gmail.com">Jiaqi Guo</a>
 */
public class Jdk5JavaProcessManager extends JavaProcessManager {
  private static final String CLASS_HOST_IDENTIFIER = "sun.jvmstat.monitor.HostIdentifier";

  private static final String CLASS_MONITORED_VM = "sun.jvmstat.monitor.MonitoredVm";

  private static final String CLASS_MONITORED_VM_UTIL = "sun.jvmstat.monitor.MonitoredVmUtil";

  private static final String CLASS_VM_IDENTIFIER = "sun.jvmstat.monitor.VmIdentifier";

  private static final Logger LOG = LoggerFactory.getLogger(Jdk5JavaProcessManager.class);

  private final ConnectorAddressLink connectorAddressLink;

  private final Method getMonitoredVm;

  private final MonitoredHost localhost;

  private final Object localhostDelegate;

  private final Class<?> monitoredVmType;

  private final Method toCommandLine;

  private final Constructor<?> vmIdentifierConstructor;

  public Jdk5JavaProcessManager(ClassLoader classLoader) throws Exception {
    Validate.notNull(classLoader, "ClassLoader can't be NULL");
    connectorAddressLink =
        WeakCastUtils.staticCast(
            classLoader.loadClass(ConnectorAddressLink.ORIGINAL_CLASS_NAME),
            ConnectorAddressLink.class);

    Class<?> hic = classLoader.loadClass(CLASS_HOST_IDENTIFIER);
    Object hi = hic.getConstructor(String.class).newInstance((String) null);

    Class<?> mhc = classLoader.loadClass(MonitoredHost.ORIGINAL_CLASS_NAME);
    Method getInstance = mhc.getMethod("getMonitoredHost", hic);
    localhostDelegate = getInstance.invoke(null, hi);
    localhost = WeakCastUtils.cast(localhostDelegate, MonitoredHost.class);
    Class<?> monitoredVmUtilClass = classLoader.loadClass(CLASS_MONITORED_VM_UTIL);
    monitoredVmType = classLoader.loadClass(CLASS_MONITORED_VM);
    toCommandLine = monitoredVmUtilClass.getMethod("commandLine", monitoredVmType);

    Class<?> vmIdentifierType = classLoader.loadClass(CLASS_VM_IDENTIFIER);
    vmIdentifierConstructor = vmIdentifierType.getConstructor(String.class);
    getMonitoredVm = mhc.getMethod("getMonitoredVm", vmIdentifierType);
  }

  @Override
  public JavaProcess get(int pid) {
    Validate.isTrue(pid > 0, "PID " + pid + " isn't valid");
    Object vmid;
    try {
      vmid = vmIdentifierConstructor.newInstance(String.valueOf(pid));
      Object vm = getMonitoredVm.invoke(localhostDelegate, vmid);
      String cmd = (String) toCommandLine.invoke(null, vm);
      return new Jdk5JavaProcess(pid, cmd, connectorAddressLink);
    } catch (InstantiationException e) {
      throw new RuntimeException("Couldn't get infomrmation about PID " + pid, e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException("Couldn't get infomrmation about PID " + pid, e);
    } catch (InvocationTargetException e) {
      throw new RuntimeException("Couldn't get infomrmation about PID " + pid, e);
    }
  }

  @Override
  public List<JavaProcess> list() {
    Set<Integer> pids = localhost.activeVms();
    List<JavaProcess> result = new ArrayList<JavaProcess>(pids.size());
    for (int pid : pids) {
      try {
        result.add(get(pid));
      } catch (RuntimeException e) {
        e.printStackTrace();
        if (LOG.isDebugEnabled()) {
          LOG.debug("Couldn't get PID" + pid, e);
        }
      }
    }
    return result;
  }
}