J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun in the LICENSE file that accompanied this code. |
| 10 | * |
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 14 | * version 2 for more details (a copy is included in the LICENSE file that |
| 15 | * accompanied this code). |
| 16 | * |
| 17 | * You should have received a copy of the GNU General Public License version |
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 20 | * |
| 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any questions. |
| 24 | */ |
| 25 | |
| 26 | package sun.tools.jconsole; |
| 27 | |
| 28 | import java.util.*; |
| 29 | import java.io.IOException; |
| 30 | import java.io.File; |
| 31 | |
| 32 | // Sun specific |
| 33 | import com.sun.tools.attach.VirtualMachine; |
| 34 | import com.sun.tools.attach.VirtualMachineDescriptor; |
| 35 | import com.sun.tools.attach.AgentInitializationException; |
| 36 | import com.sun.tools.attach.AgentLoadException; |
| 37 | import com.sun.tools.attach.AttachNotSupportedException; |
| 38 | |
| 39 | // Sun private |
| 40 | import sun.management.ConnectorAddressLink; |
| 41 | import sun.jvmstat.monitor.HostIdentifier; |
| 42 | import sun.jvmstat.monitor.Monitor; |
| 43 | import sun.jvmstat.monitor.MonitoredHost; |
| 44 | import sun.jvmstat.monitor.MonitoredVm; |
| 45 | import sun.jvmstat.monitor.MonitoredVmUtil; |
| 46 | import sun.jvmstat.monitor.MonitorException; |
| 47 | import sun.jvmstat.monitor.VmIdentifier; |
| 48 | |
| 49 | public class LocalVirtualMachine { |
| 50 | private String address; |
| 51 | private String commandLine; |
| 52 | private String displayName; |
| 53 | private int vmid; |
| 54 | private boolean isAttachSupported; |
| 55 | |
| 56 | public LocalVirtualMachine(int vmid, String commandLine, boolean canAttach, String connectorAddress) { |
| 57 | this.vmid = vmid; |
| 58 | this.commandLine = commandLine; |
| 59 | this.address = connectorAddress; |
| 60 | this.isAttachSupported = canAttach; |
| 61 | this.displayName = getDisplayName(commandLine); |
| 62 | } |
| 63 | |
| 64 | private static String getDisplayName(String commandLine) { |
| 65 | // trim the pathname of jar file if it's a jar |
| 66 | String[] res = commandLine.split(" ", 2); |
| 67 | if (res[0].endsWith(".jar")) { |
| 68 | File jarfile = new File(res[0]); |
| 69 | String displayName = jarfile.getName(); |
| 70 | if (res.length == 2) { |
| 71 | displayName += " " + res[1]; |
| 72 | } |
| 73 | return displayName; |
| 74 | } |
| 75 | return commandLine; |
| 76 | } |
| 77 | |
| 78 | public int vmid() { |
| 79 | return vmid; |
| 80 | } |
| 81 | |
| 82 | public boolean isManageable() { |
| 83 | return (address != null); |
| 84 | } |
| 85 | |
| 86 | public boolean isAttachable() { |
| 87 | return isAttachSupported; |
| 88 | } |
| 89 | |
| 90 | public void startManagementAgent() throws IOException { |
| 91 | if (address != null) { |
| 92 | // already started |
| 93 | return; |
| 94 | } |
| 95 | |
| 96 | if (!isAttachable()) { |
| 97 | throw new IOException("This virtual machine \"" + vmid + |
| 98 | "\" does not support dynamic attach."); |
| 99 | } |
| 100 | |
| 101 | loadManagementAgent(); |
| 102 | // fails to load or start the management agent |
| 103 | if (address == null) { |
| 104 | // should never reach here |
| 105 | throw new IOException("Fails to find connector address"); |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | public String connectorAddress() { |
| 110 | // return null if not available or no JMX agent |
| 111 | return address; |
| 112 | } |
| 113 | |
| 114 | public String displayName() { |
| 115 | return displayName; |
| 116 | } |
| 117 | |
| 118 | public String toString() { |
| 119 | return commandLine; |
| 120 | } |
| 121 | |
| 122 | // This method returns the list of all virtual machines currently |
| 123 | // running on the machine |
| 124 | public static Map<Integer, LocalVirtualMachine> getAllVirtualMachines() { |
| 125 | Map<Integer, LocalVirtualMachine> map = |
| 126 | new HashMap<Integer, LocalVirtualMachine>(); |
| 127 | getMonitoredVMs(map); |
| 128 | getAttachableVMs(map); |
| 129 | return map; |
| 130 | } |
| 131 | |
| 132 | private static void getMonitoredVMs(Map<Integer, LocalVirtualMachine> map) { |
| 133 | MonitoredHost host; |
| 134 | Set vms; |
| 135 | try { |
| 136 | host = MonitoredHost.getMonitoredHost(new HostIdentifier((String)null)); |
| 137 | vms = host.activeVms(); |
| 138 | } catch (java.net.URISyntaxException sx) { |
| 139 | throw new InternalError(sx.getMessage()); |
| 140 | } catch (MonitorException mx) { |
| 141 | throw new InternalError(mx.getMessage()); |
| 142 | } |
| 143 | for (Object vmid: vms) { |
| 144 | if (vmid instanceof Integer) { |
| 145 | int pid = ((Integer) vmid).intValue(); |
| 146 | String name = vmid.toString(); // default to pid if name not available |
| 147 | boolean attachable = false; |
| 148 | String address = null; |
| 149 | try { |
| 150 | MonitoredVm mvm = host.getMonitoredVm(new VmIdentifier(name)); |
| 151 | // use the command line as the display name |
| 152 | name = MonitoredVmUtil.commandLine(mvm); |
| 153 | attachable = MonitoredVmUtil.isAttachable(mvm); |
| 154 | address = ConnectorAddressLink.importFrom(pid); |
| 155 | mvm.detach(); |
| 156 | } catch (Exception x) { |
| 157 | // ignore |
| 158 | } |
| 159 | map.put((Integer) vmid, |
| 160 | new LocalVirtualMachine(pid, name, attachable, address)); |
| 161 | } |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | private static final String LOCAL_CONNECTOR_ADDRESS_PROP = |
| 166 | "com.sun.management.jmxremote.localConnectorAddress"; |
| 167 | |
| 168 | private static void getAttachableVMs(Map<Integer, LocalVirtualMachine> map) { |
| 169 | List<VirtualMachineDescriptor> vms = VirtualMachine.list(); |
| 170 | for (VirtualMachineDescriptor vmd : vms) { |
| 171 | try { |
| 172 | Integer vmid = Integer.valueOf(vmd.id()); |
| 173 | if (!map.containsKey(vmid)) { |
| 174 | boolean attachable = false; |
| 175 | String address = null; |
| 176 | try { |
| 177 | VirtualMachine vm = VirtualMachine.attach(vmd); |
| 178 | attachable = true; |
| 179 | Properties agentProps = vm.getAgentProperties(); |
| 180 | address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); |
| 181 | vm.detach(); |
| 182 | } catch (AttachNotSupportedException x) { |
| 183 | // not attachable |
| 184 | } catch (IOException x) { |
| 185 | // ignore |
| 186 | } |
| 187 | map.put(vmid, new LocalVirtualMachine(vmid.intValue(), |
| 188 | vmd.displayName(), |
| 189 | attachable, |
| 190 | address)); |
| 191 | } |
| 192 | } catch (NumberFormatException e) { |
| 193 | // do not support vmid different than pid |
| 194 | } |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | public static LocalVirtualMachine getLocalVirtualMachine(int vmid) { |
| 199 | Map<Integer, LocalVirtualMachine> map = getAllVirtualMachines(); |
| 200 | LocalVirtualMachine lvm = map.get(vmid); |
| 201 | if (lvm == null) { |
| 202 | // Check if the VM is attachable but not included in the list |
| 203 | // if it's running with a different security context. |
| 204 | // For example, Windows services running |
| 205 | // local SYSTEM account are attachable if you have Adminstrator |
| 206 | // privileges. |
| 207 | boolean attachable = false; |
| 208 | String address = null; |
| 209 | String name = String.valueOf(vmid); // default display name to pid |
| 210 | try { |
| 211 | VirtualMachine vm = VirtualMachine.attach(name); |
| 212 | attachable = true; |
| 213 | Properties agentProps = vm.getAgentProperties(); |
| 214 | address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); |
| 215 | vm.detach(); |
| 216 | lvm = new LocalVirtualMachine(vmid, name, attachable, address); |
| 217 | } catch (AttachNotSupportedException x) { |
| 218 | // not attachable |
| 219 | if (JConsole.isDebug()) { |
| 220 | x.printStackTrace(); |
| 221 | } |
| 222 | } catch (IOException x) { |
| 223 | // ignore |
| 224 | if (JConsole.isDebug()) { |
| 225 | x.printStackTrace(); |
| 226 | } |
| 227 | } |
| 228 | } |
| 229 | return lvm; |
| 230 | } |
| 231 | |
| 232 | // load the management agent into the target VM |
| 233 | private void loadManagementAgent() throws IOException { |
| 234 | VirtualMachine vm = null; |
| 235 | String name = String.valueOf(vmid); |
| 236 | try { |
| 237 | vm = VirtualMachine.attach(name); |
| 238 | } catch (AttachNotSupportedException x) { |
| 239 | IOException ioe = new IOException(x.getMessage()); |
| 240 | ioe.initCause(x); |
| 241 | throw ioe; |
| 242 | } |
| 243 | |
| 244 | String home = vm.getSystemProperties().getProperty("java.home"); |
| 245 | |
| 246 | // Normally in ${java.home}/jre/lib/management-agent.jar but might |
| 247 | // be in ${java.home}/lib in build environments. |
| 248 | |
| 249 | String agent = home + File.separator + "jre" + File.separator + |
| 250 | "lib" + File.separator + "management-agent.jar"; |
| 251 | File f = new File(agent); |
| 252 | if (!f.exists()) { |
| 253 | agent = home + File.separator + "lib" + File.separator + |
| 254 | "management-agent.jar"; |
| 255 | f = new File(agent); |
| 256 | if (!f.exists()) { |
| 257 | throw new IOException("Management agent not found"); |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | agent = f.getCanonicalPath(); |
| 262 | try { |
| 263 | vm.loadAgent(agent, "com.sun.management.jmxremote"); |
| 264 | } catch (AgentLoadException x) { |
| 265 | IOException ioe = new IOException(x.getMessage()); |
| 266 | ioe.initCause(x); |
| 267 | throw ioe; |
| 268 | } catch (AgentInitializationException x) { |
| 269 | IOException ioe = new IOException(x.getMessage()); |
| 270 | ioe.initCause(x); |
| 271 | throw ioe; |
| 272 | } |
| 273 | |
| 274 | // get the connector address |
| 275 | Properties agentProps = vm.getAgentProperties(); |
| 276 | address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); |
| 277 | |
| 278 | vm.detach(); |
| 279 | } |
| 280 | } |