1 /* 2 * Copyright (c) 2005, 2006, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 | MonitorException x) { 139 throw new InternalError(x.getMessage(), x); 140 } 141 for (Object vmid: vms) { 142 if (vmid instanceof Integer) { 143 int pid = ((Integer) vmid).intValue(); 144 String name = vmid.toString(); // default to pid if name not available 145 boolean attachable = false; 146 String address = null; 147 try { 148 MonitoredVm mvm = host.getMonitoredVm(new VmIdentifier(name)); 149 // use the command line as the display name 150 name = MonitoredVmUtil.commandLine(mvm); 151 attachable = MonitoredVmUtil.isAttachable(mvm); 152 address = ConnectorAddressLink.importFrom(pid); 153 mvm.detach(); 154 } catch (Exception x) { 155 // ignore 156 } 157 map.put((Integer) vmid, 158 new LocalVirtualMachine(pid, name, attachable, address)); 159 } 160 } 161 } 162 163 private static final String LOCAL_CONNECTOR_ADDRESS_PROP = 164 "com.sun.management.jmxremote.localConnectorAddress"; 165 166 private static void getAttachableVMs(Map<Integer, LocalVirtualMachine> map) { 167 List<VirtualMachineDescriptor> vms = VirtualMachine.list(); 168 for (VirtualMachineDescriptor vmd : vms) { 169 try { 170 Integer vmid = Integer.valueOf(vmd.id()); 171 if (!map.containsKey(vmid)) { 172 boolean attachable = false; 173 String address = null; 174 try { 175 VirtualMachine vm = VirtualMachine.attach(vmd); 176 attachable = true; 177 Properties agentProps = vm.getAgentProperties(); 178 address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); 179 vm.detach(); 180 } catch (AttachNotSupportedException x) { 181 // not attachable 182 } catch (IOException x) { 183 // ignore 184 } 185 map.put(vmid, new LocalVirtualMachine(vmid.intValue(), 186 vmd.displayName(), 187 attachable, 188 address)); 189 } 190 } catch (NumberFormatException e) { 191 // do not support vmid different than pid 192 } 193 } 194 } 195 196 public static LocalVirtualMachine getLocalVirtualMachine(int vmid) { 197 Map<Integer, LocalVirtualMachine> map = getAllVirtualMachines(); 198 LocalVirtualMachine lvm = map.get(vmid); 199 if (lvm == null) { 200 // Check if the VM is attachable but not included in the list 201 // if it's running with a different security context. 202 // For example, Windows services running 203 // local SYSTEM account are attachable if you have Adminstrator 204 // privileges. 205 boolean attachable = false; 206 String address = null; 207 String name = String.valueOf(vmid); // default display name to pid 208 try { 209 VirtualMachine vm = VirtualMachine.attach(name); 210 attachable = true; 211 Properties agentProps = vm.getAgentProperties(); 212 address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); 213 vm.detach(); 214 lvm = new LocalVirtualMachine(vmid, name, attachable, address); 215 } catch (AttachNotSupportedException x) { 216 // not attachable 217 if (JConsole.isDebug()) { 218 x.printStackTrace(); 219 } 220 } catch (IOException x) { 221 // ignore 222 if (JConsole.isDebug()) { 223 x.printStackTrace(); 224 } 225 } 226 } 227 return lvm; 228 } 229 230 // load the management agent into the target VM 231 private void loadManagementAgent() throws IOException { 232 VirtualMachine vm = null; 233 String name = String.valueOf(vmid); 234 try { 235 vm = VirtualMachine.attach(name); 236 } catch (AttachNotSupportedException x) { 237 IOException ioe = new IOException(x.getMessage()); 238 ioe.initCause(x); 239 throw ioe; 240 } 241 242 String home = vm.getSystemProperties().getProperty("java.home"); 243 244 // Normally in ${java.home}/jre/lib/management-agent.jar but might 245 // be in ${java.home}/lib in build environments. 246 247 String agent = home + File.separator + "jre" + File.separator + 248 "lib" + File.separator + "management-agent.jar"; 249 File f = new File(agent); 250 if (!f.exists()) { 251 agent = home + File.separator + "lib" + File.separator + 252 "management-agent.jar"; 253 f = new File(agent); 254 if (!f.exists()) { 255 throw new IOException("Management agent not found"); 256 } 257 } 258 259 agent = f.getCanonicalPath(); 260 try { 261 vm.loadAgent(agent, "com.sun.management.jmxremote"); 262 } catch (AgentLoadException x) { 263 IOException ioe = new IOException(x.getMessage()); 264 ioe.initCause(x); 265 throw ioe; 266 } catch (AgentInitializationException x) { 267 IOException ioe = new IOException(x.getMessage()); 268 ioe.initCause(x); 269 throw ioe; 270 } 271 272 // get the connector address 273 Properties agentProps = vm.getAgentProperties(); 274 address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); 275 276 vm.detach(); 277 } 278 }