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