1 /* 2 * Copyright (c) 1998, 2018, 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 com.sun.tools.jdi; 27 28 import java.io.IOException; 29 import java.util.ArrayList; 30 import java.util.Collections; 31 import java.util.Iterator; 32 import java.util.List; 33 import java.util.ResourceBundle; 34 import java.util.ServiceLoader; 35 36 import com.sun.jdi.JDIPermission; 37 import com.sun.jdi.VMDisconnectedException; 38 import com.sun.jdi.VirtualMachine; 39 import com.sun.jdi.VirtualMachineManager; 40 import com.sun.jdi.connect.AttachingConnector; 41 import com.sun.jdi.connect.Connector; 42 import com.sun.jdi.connect.LaunchingConnector; 43 import com.sun.jdi.connect.ListeningConnector; 44 import com.sun.jdi.connect.spi.Connection; 45 import com.sun.jdi.connect.spi.TransportService; 46 47 /* Public for use by com.sun.jdi.Bootstrap */ 48 public class VirtualMachineManagerImpl implements VirtualMachineManagerService { 49 private List<Connector> connectors = new ArrayList<>(); 50 private LaunchingConnector defaultConnector = null; 51 private List<VirtualMachine> targets = new ArrayList<>(); 52 private final ThreadGroup mainGroupForJDI; 53 private ResourceBundle messages = null; 54 private int vmSequenceNumber = 0; 55 private static final int majorVersion = 11; 56 private static final int minorVersion = 0; 57 58 private static final Object lock = new Object(); 59 private static VirtualMachineManagerImpl vmm; 60 61 public static VirtualMachineManager virtualMachineManager() { 62 SecurityManager sm = System.getSecurityManager(); 63 if (sm != null) { 64 JDIPermission vmmPermission = 65 new JDIPermission("virtualMachineManager"); 66 sm.checkPermission(vmmPermission); 67 } 68 synchronized (lock) { 69 if (vmm == null) { 70 vmm = new VirtualMachineManagerImpl(); 71 } 72 } 73 return vmm; 74 } 75 76 protected VirtualMachineManagerImpl() { 77 78 /* 79 * Create a top-level thread group 80 */ 81 ThreadGroup top = Thread.currentThread().getThreadGroup(); 82 ThreadGroup parent = null; 83 while ((parent = top.getParent()) != null) { 84 top = parent; 85 } 86 mainGroupForJDI = new ThreadGroup(top, "JDI main"); 87 88 /* 89 * Load the connectors 90 */ 91 ServiceLoader<Connector> connectorLoader = 92 ServiceLoader.load(Connector.class, Connector.class.getClassLoader()); 93 94 Iterator<Connector> connectors = connectorLoader.iterator(); 95 96 while (connectors.hasNext()) { 97 Connector connector; 98 99 try { 100 connector = connectors.next(); 101 } catch (ThreadDeath x) { 102 throw x; 103 } catch (Exception x) { 104 System.err.println(x); 105 continue; 106 } catch (Error x) { 107 System.err.println(x); 108 continue; 109 } 110 111 addConnector(connector); 112 } 113 114 /* 115 * Load any transport services and encapsulate them with 116 * an attaching and listening connector. 117 */ 118 ServiceLoader<TransportService> transportLoader = 119 ServiceLoader.load(TransportService.class, 120 TransportService.class.getClassLoader()); 121 122 Iterator<TransportService> transportServices = 123 transportLoader.iterator(); 124 125 while (transportServices.hasNext()) { 126 TransportService transportService; 127 128 try { 129 transportService = transportServices.next(); 130 } catch (ThreadDeath x) { 131 throw x; 132 } catch (Exception x) { 133 System.err.println(x); 134 continue; 135 } catch (Error x) { 136 System.err.println(x); 137 continue; 138 } 139 140 addConnector(GenericAttachingConnector.create(transportService)); 141 addConnector(GenericListeningConnector.create(transportService)); 142 } 143 144 // no connectors found 145 if (allConnectors().size() == 0) { 146 throw new Error("no Connectors loaded"); 147 } 148 149 // Set the default launcher. In order to be compatible 150 // 1.2/1.3/1.4 we try to make the default launcher 151 // "com.sun.jdi.CommandLineLaunch". If this connector 152 // isn't found then we arbitarly pick the first connector. 153 // 154 boolean found = false; 155 List<LaunchingConnector> launchers = launchingConnectors(); 156 for (LaunchingConnector lc: launchers) { 157 if (lc.name().equals("com.sun.jdi.CommandLineLaunch")) { 158 setDefaultConnector(lc); 159 found = true; 160 break; 161 } 162 } 163 if (!found && launchers.size() > 0) { 164 setDefaultConnector(launchers.get(0)); 165 } 166 } 167 168 public LaunchingConnector defaultConnector() { 169 if (defaultConnector == null) { 170 throw new Error("no default LaunchingConnector"); 171 } 172 return defaultConnector; 173 } 174 175 public void setDefaultConnector(LaunchingConnector connector) { 176 defaultConnector = connector; 177 } 178 179 public List<LaunchingConnector> launchingConnectors() { 180 List<LaunchingConnector> launchingConnectors = new ArrayList<>(connectors.size()); 181 for (Connector connector: connectors) { 182 if (connector instanceof LaunchingConnector) { 183 launchingConnectors.add((LaunchingConnector)connector); 184 } 185 } 186 return Collections.unmodifiableList(launchingConnectors); 187 } 188 189 public List<AttachingConnector> attachingConnectors() { 190 List<AttachingConnector> attachingConnectors = new ArrayList<>(connectors.size()); 191 for (Connector connector: connectors) { 192 if (connector instanceof AttachingConnector) { 193 attachingConnectors.add((AttachingConnector)connector); 194 } 195 } 196 return Collections.unmodifiableList(attachingConnectors); 197 } 198 199 public List<ListeningConnector> listeningConnectors() { 200 List<ListeningConnector> listeningConnectors = new ArrayList<>(connectors.size()); 201 for (Connector connector: connectors) { 202 if (connector instanceof ListeningConnector) { 203 listeningConnectors.add((ListeningConnector)connector); 204 } 205 } 206 return Collections.unmodifiableList(listeningConnectors); 207 } 208 209 public List<Connector> allConnectors() { 210 return Collections.unmodifiableList(connectors); 211 } 212 213 public List<VirtualMachine> connectedVirtualMachines() { 214 return Collections.unmodifiableList(targets); 215 } 216 217 public void addConnector(Connector connector) { 218 connectors.add(connector); 219 } 220 221 public void removeConnector(Connector connector) { 222 connectors.remove(connector); 223 } 224 225 public synchronized VirtualMachine createVirtualMachine( 226 Connection connection, 227 Process process) throws IOException { 228 229 if (!connection.isOpen()) { 230 throw new IllegalStateException("connection is not open"); 231 } 232 233 VirtualMachine vm; 234 try { 235 vm = new VirtualMachineImpl(this, connection, process, 236 ++vmSequenceNumber); 237 } catch (VMDisconnectedException e) { 238 throw new IOException(e.getMessage()); 239 } 240 targets.add(vm); 241 return vm; 242 } 243 244 public VirtualMachine createVirtualMachine(Connection connection) throws IOException { 245 return createVirtualMachine(connection, null); 246 } 247 248 public void addVirtualMachine(VirtualMachine vm) { 249 targets.add(vm); 250 } 251 252 void disposeVirtualMachine(VirtualMachine vm) { 253 targets.remove(vm); 254 } 255 256 public int majorInterfaceVersion() { 257 return majorVersion; 258 } 259 260 public int minorInterfaceVersion() { 261 return minorVersion; 262 } 263 264 ThreadGroup mainGroupForJDI() { 265 return mainGroupForJDI; 266 } 267 268 String getString(String key) { 269 if (messages == null) { 270 messages = ResourceBundle.getBundle("com.sun.tools.jdi.resources.jdi"); 271 } 272 return messages.getString(key); 273 } 274 }