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.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cyclopsgroup.jmxterm.JavaProcess;
import org.cyclopsgroup.jmxterm.JavaProcessManager;
import org.cyclopsgroup.jmxterm.utils.WeakCastUtils;
/**
* 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 Log LOG = LogFactory.getLog( 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;
/**
* Default constructor
*
* @param classLoader ClassLoader to load JDK internal classes
* @throws Exception
*/
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 );
}
/**
* @inheritDoc
*/
@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 );
}
}
/**
* @inheritDoc
*/
@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;
}
}