/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2007, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.vm; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import javax.management.MBeanServerConnection; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import org.helios.gmx.util.FreePortFinder; /** * <p>Title: VirtualMachine</p> * <p>Description: Main wrapper class for reflective access to the Java Attach API</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * @version $LastChangedRevision$ * <p><code>org.helios.vm.VirtualMachine</code></p> */ public class VirtualMachine extends BaseWrappedClass { /** A map of virtual machine keyed by their system identity hash codes */ private static final Map<Integer, VirtualMachine> vmInstances = new ConcurrentHashMap<Integer, VirtualMachine>(); /** The JMXServiceURL of this VirtualMachine */ private volatile JMXServiceURL jmxServiceURL = null; /** The agent property representing the JMXServiceURL of the management agent */ public static final String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress"; /** The system property representing the file separator */ public static final String FILE_SEP = "file.separator"; /** The system property representing the JMX Remote Port */ public static final String JMX_PORT = "com.sun.management.jmxremote.port"; /** The JMX management agent jar name */ public static final String JMX_AGENT = "management-agent.jar"; /** The system property representing the java home */ public static final String JAVA_HOME = "java.home"; /** * Retrieves the VirtualMachine wrapper class for the passed VirtualMachine delegate * @param delegate the VirtualMachine delegate * @return the VirtualMachine */ public static VirtualMachine getInstance(Object delegate) { if(delegate==null) throw new IllegalArgumentException("The passed delegate was null", new Throwable()); if(!VirtualMachineBootstrap.getInstance().isInstanceOf(delegate, VirtualMachineBootstrap.VM_CLASS)) { throw new IllegalArgumentException("The passed delegate of type [" + delegate.getClass().getName() + "] is not an instance of [" + VirtualMachineBootstrap.VM_CLASS + "]", new Throwable()); } int key = System.identityHashCode(delegate); VirtualMachine vm = vmInstances.get(key); if(vm==null) { synchronized(vmInstances) { vm = vmInstances.get(key); if(vm==null) { vm = new VirtualMachine(delegate); vmInstances.put(key, vm); } } } return vm; } /** * Creates a new VirtualMachine wrapper instance * @param delegate The delegate */ VirtualMachine(Object delegate) { super(delegate); } /** * Tests this VirtualMachine for equality with another object. * @param obj The object to compare to * @return true if, and only if, the given object is a VirtualMachine that is equal to this VirtualMachine. */ public boolean equals(Object obj){ if(obj==null) return false; return delegate.equals(obj); } /** * Returns the string representation of the VirtualMachine. * @return the string representation of the VirtualMachine. */ public String toString(){ return delegate.toString(); } /** * Returns a hash-code value for this VirtualMachine. The hash code is based upon the VirtualMachine's components, and satifies the general contract of the Object.hashCode method. * @return A hash-code value for this virtual machine */ public int hashCode(){ return delegate.hashCode(); } /** * Returns the provider that created this virtual machine. * @return The provider that created this virtual machine. */ public AttachProvider provider(){ try { pushCl(); return AttachProvider.getInstance( invoke(delegate, null, "provider") ); } finally { popCl(); } } /** * Return a list of Java virtual machines. * @return The list of virtual machine descriptors. */ public static List<VirtualMachineDescriptor> list(){ List<VirtualMachineDescriptor> list = new ArrayList<VirtualMachineDescriptor>(); try { pushCl(); List<?> vmdDelegates = (List<?>)invoke(null, VirtualMachineBootstrap.VM_CLASS, "list"); for(Object del: vmdDelegates) { list.add(VirtualMachineDescriptor.getInstance(del)); } return list; } finally { popCl(); } } /** * Returns the identifier for this Java virtual machine. * @return The identifier for this Java virtual machine. */ public String id() { try { pushCl(); return (String)invoke(delegate, null, "id"); } finally { popCl(); } } /** * Attaches to a Java virtual machine. * @param vmd The virtual machine descriptor. * @return A VirtualMachine representing the target VM. */ public static VirtualMachine attach(VirtualMachineDescriptor vmd) { if(vmd==null) throw new IllegalArgumentException("The passed VirtualMachineDescriptor was null", new Throwable()); try { pushCl(); Object vmDelegate = invoke(null, VirtualMachineBootstrap.VM_CLASS, "attachV", vmd.delegate); return new VirtualMachine(vmDelegate); } catch (Exception e) { throw new RuntimeException("Failed to attach to VirtualMachine [" + vmd.toString() + "]", e); } finally { popCl(); } } /** * Attaches to a Java virtual machine. * @param id The abstract identifier that identifies the Java virtual machine. * @return A VirtualMachine representing the target VM. */ public static VirtualMachine attach(String id) { if(id==null) throw new IllegalArgumentException("The passed VirtualMachine id was null", new Throwable()); try { pushCl(); Object vmDelegate = invoke(null, VirtualMachineBootstrap.VM_CLASS, "attachS", id); return new VirtualMachine(vmDelegate); } catch (Exception e) { throw new RuntimeException("Failed to attach to VirtualMachine [" + id + "]", e); } finally { popCl(); } } /** * Detach from the virtual machine. */ public String detach() { try { pushCl(); return (String)invoke(delegate, null, "detach"); } finally { popCl(); } } /** * Returns the current agent properties in the target virtual machine. * @return The agent properties */ public Properties getAgentProperties() { try { pushCl(); return (Properties)invoke(delegate, null, "getAgentProperties"); } finally { popCl(); } } /** * Returns the current system properties in the target virtual machine. * @return The system properties */ public Properties getSystemProperties() { try { pushCl(); return (Properties)invoke(delegate, null, "getSystemProperties"); } finally { popCl(); } } /** * Loads an agent. * @param agent Path to the JAR file containing the agent. */ public void loadAgent(String agent) { try { pushCl(); invoke(delegate, null, "loadAgentS", agent); } finally { popCl(); } } /** * Loads an agent. * @param agent Path to the JAR file containing the agent. * @param options The options to provide to the agent's agentmain method (can be null). */ public void loadAgent(String agent, String options) { try { pushCl(); invoke(delegate, null, "loadAgentSS", agent, options); } finally { popCl(); } } /** * Loads an agent library. * @param agentLibrary The name of the agent library. */ public void loadAgentLibrary(String agentLibrary) { try { pushCl(); invoke(delegate, null, "loadAgentLibraryS", agentLibrary); } finally { popCl(); } } /** * Loads an agent library. * @param agentLibrary The name of the agent library. * @param options The options to provide to the Agent_OnAttach function (can be null). */ public void loadAgentLibrary(String agentLibrary, String options) { try { pushCl(); invoke(delegate, null, "loadAgentLibrarySS", agentLibrary, options); } finally { popCl(); } } /** * Load a native agent library by full pathname. * @param agentPath The full path to the agent library. */ public void loadAgentPath(String agentPath) { try { pushCl(); invoke(delegate, null, "loadAgentPathS", agentPath); } finally { popCl(); } } /** * Load a native agent library by full pathname. * @param agentPath The full path to the agent library. * @param options The options to provide to the Agent_OnAttach function (can be null). */ public void loadAgentPath(String agentPath, String options) { try { pushCl(); invoke(delegate, null, "loadAgentPathSS", agentPath); } finally { popCl(); } } /** * Returns a {@link MBeanServerConnection} to this VM instance * @return a {@link MBeanServerConnection} to this VM instance */ public MBeanServerConnection getMBeanServerConnection() { try { return getJMXConnector().getMBeanServerConnection(); } catch (Exception e) { throw new RuntimeException("Failed to acquire MBeanServerConnection from VirtualMachine [" + id() + "]", e); } } /** * Returns a {@link JMXConnector} to this VM instance * @return a {@link JMXConnector} to this VM instance */ public JMXConnector getJMXConnector() { try { JMXServiceURL serviceURL = getJMXServiceURL(); return JMXConnectorFactory.connect(serviceURL); } catch (Exception e) { throw new RuntimeException("Failed to acquire JMXConnector from VirtualMachine [" + id() + "]", e); } } /** * Returns a {@link JMXServiceURL} to connect to this VM instance * @return a {@link JMXServiceURL} to connect to this VM instance * TODO: We need to allow this using authentication. */ public JMXServiceURL getJMXServiceURL() { if(jmxServiceURL==null) { synchronized(this) { if(jmxServiceURL==null) { try { String connAddr = getAgentProperties().getProperty(CONNECTOR_ADDRESS); if(connAddr==null) { Properties sysProps = getSystemProperties(); String fileSep = sysProps.getProperty(FILE_SEP, File.separator); String javaHome = sysProps.getProperty(JAVA_HOME); String agentPath = String.format("%s%slib%s%s", javaHome, fileSep, fileSep, JMX_AGENT); loadAgent(agentPath); //, JMX_PORT + "=" + FreePortFinder.getNextFreePort() + ",com.sun.management.jmxremote.authenticate=false"); connAddr = getAgentProperties().getProperty(CONNECTOR_ADDRESS); } if(connAddr==null) throw new RuntimeException("Failed to acquire JMXServiceURL for MBeanServerConnection to VirtualMachine [" + id() + "]", new Throwable()); jmxServiceURL = new JMXServiceURL(connAddr); } catch (Exception e) { throw new RuntimeException("Failed to acquire JMXServiceURL from VirtualMachine [" + id() + "]", e); } } } } return jmxServiceURL; } }