1 /*
2  * Copyright (c) 2005, 2013, 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.attach.spi;
27 
28 import java.io.IOException;
29 import java.util.Collections;
30 import java.util.Iterator;
31 import java.util.ArrayList;
32 import java.util.List;
33 import com.sun.tools.attach.VirtualMachine;
34 import com.sun.tools.attach.VirtualMachineDescriptor;
35 import com.sun.tools.attach.AttachPermission;
36 import com.sun.tools.attach.AttachNotSupportedException;
37 import java.util.ServiceLoader;
38 
39 /**
40  * Attach provider class for attaching to a Java virtual machine.
41  *
42  * <p> An attach provider is a concrete subclass of this class that has a
43  * zero-argument constructor and implements the abstract methods specified
44  * below. </p>
45  *
46  * <p> An attach provider implementation is typically tied to a Java virtual
47  * machine implementation, version, or even mode of operation. That is, a specific
48  * provider implementation will typically only be capable of attaching to
49  * a specific Java virtual machine implementation or version. For example, Sun's
50  * JDK implementation ships with provider implementations that can only attach to
51  * Sun's <i>HotSpot</i> virtual machine. In general, if an environment
52  * consists of Java virtual machines of different versions and from different
53  * vendors then there will be an attach provider implementation for each
54  * <i>family</i> of implementations or versions. </p>
55  *
56  * <p> An attach provider is identified by its {@link #name <i>name</i>} and
57  * {@link #type <i>type</i>}. The <i>name</i> is typically, but not required to
58  * be, a name that corresponds to the VM vendor. The Sun JDK implementation,
59  * for example, ships with attach providers that use the name <i>"sun"</i>. The
60  * <i>type</i> typically corresponds to the attach mechanism. For example, an
61  * implementation that uses the Doors inter-process communication mechanism
62  * might use the type <i>"doors"</i>. The purpose of the name and type is to
63  * identify providers in environments where there are multiple providers
64  * installed. </p>
65  *
66  * <p> AttachProvider implementations are loaded and instantiated at the first
67  * invocation of the {@link #providers() providers} method. This method
68  * attempts to load all provider implementations that are installed on the
69  * platform. </p>
70  *
71  * <p> All of the methods in this class are safe for use by multiple
72  * concurrent threads. </p>
73  *
74  * @since 1.6
75  */
76 
77 @jdk.Exported
78 public abstract class AttachProvider {
79 
80     private static final Object lock = new Object();
81     private static List<AttachProvider> providers = null;
82 
83     /**
84      * Initializes a new instance of this class.  </p>
85      *
86      * @throws  SecurityException
87      *          If a security manager has been installed and it denies
88      *          {@link com.sun.tools.attach.AttachPermission AttachPermission}
89      *          <tt>("createAttachProvider")</tt>
90      */
AttachProvider()91     protected AttachProvider() {
92         SecurityManager sm = System.getSecurityManager();
93         if (sm != null)
94             sm.checkPermission(new AttachPermission("createAttachProvider"));
95     }
96 
97     /**
98      * Return this provider's name. </p>
99      *
100      * @return  The name of this provider
101      */
name()102     public abstract String name();
103 
104     /**
105      * Return this provider's type. </p>
106      *
107      * @return  The type of this provider
108      */
type()109     public abstract String type();
110 
111     /**
112      * Attaches to a Java virtual machine.
113      *
114      * <p> A Java virtual machine is identified by an abstract identifier. The
115      * nature of this identifier is platform dependent but in many cases it will be the
116      * string representation of the process identifier (or pid). </p>
117      *
118      * <p> This method parses the identifier and maps the identifier to a Java
119      * virtual machine (in an implementation dependent manner). If the identifier
120      * cannot be parsed by the provider then an {@link
121      * com.sun.tools.attach.AttachNotSupportedException AttachNotSupportedException}
122      * is thrown. Once parsed this method attempts to attach to the Java virtual machine.
123      * If the provider detects that the identifier corresponds to a Java virtual machine
124      * that does not exist, or it corresponds to a Java virtual machine that does not support
125      * the attach mechanism implemented by this provider, or it detects that the
126      * Java virtual machine is a version to which this provider cannot attach, then
127      * an <code>AttachNotSupportedException</code> is thrown. </p>
128      *
129      * @param  id
130      *         The abstract identifier that identifies the Java virtual machine.
131      *
132      * @return  VirtualMachine representing the target virtual machine.
133      *
134      * @throws  SecurityException
135      *          If a security manager has been installed and it denies
136      *          {@link com.sun.tools.attach.AttachPermission AttachPermission}
137      *          <tt>("attachVirtualMachine")</tt>, or other permission
138      *          required by the implementation.
139      *
140      * @throws  AttachNotSupportedException
141      *          If the identifier cannot be parsed, or it corresponds to
142      *          to a Java virtual machine that does not exist, or it
143      *          corresponds to a Java virtual machine which this
144      *          provider cannot attach.
145      *
146      * @throws  IOException
147      *          If some other I/O error occurs
148      *
149      * @throws  NullPointerException
150      *          If <code>id</code> is <code>null</code>
151      */
attachVirtualMachine(String id)152     public abstract VirtualMachine attachVirtualMachine(String id)
153         throws AttachNotSupportedException, IOException;
154 
155     /**
156      * Attaches to a Java virtual machine.
157      *
158      * <p> A Java virtual machine can be described using a {@link
159      * com.sun.tools.attach.VirtualMachineDescriptor VirtualMachineDescriptor}.
160      * This method invokes the descriptor's {@link
161      * com.sun.tools.attach.VirtualMachineDescriptor#provider() provider()} method
162      * to check that it is equal to this provider. It then attempts to attach to the
163      * Java virtual machine.
164      *
165      * @param  vmd
166      *         The virtual machine descriptor
167      *
168      * @return  VirtualMachine representing the target virtual machine.
169      *
170      * @throws  SecurityException
171      *          If a security manager has been installed and it denies
172      *          {@link com.sun.tools.attach.AttachPermission AttachPermission}
173      *          <tt>("attachVirtualMachine")</tt>, or other permission
174      *          required by the implementation.
175      *
176      * @throws  AttachNotSupportedException
177      *          If the descriptor's {@link
178      *          com.sun.tools.attach.VirtualMachineDescriptor#provider() provider()} method
179      *          returns a provider that is not this provider, or it does not correspond
180      *          to a Java virtual machine to which this provider can attach.
181      *
182      * @throws  IOException
183      *          If some other I/O error occurs
184      *
185      * @throws  NullPointerException
186      *          If <code>vmd</code> is <code>null</code>
187      */
attachVirtualMachine(VirtualMachineDescriptor vmd)188     public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
189         throws AttachNotSupportedException, IOException
190     {
191         if (vmd.provider() != this) {
192             throw new AttachNotSupportedException("provider mismatch");
193         }
194         return attachVirtualMachine(vmd.id());
195     }
196 
197     /**
198      * Lists the Java virtual machines known to this provider.
199      *
200      * <p> This method returns a list of {@link
201      * com.sun.tools.attach.VirtualMachineDescriptor} elements. Each
202      * <code>VirtualMachineDescriptor</code> describes a Java virtual machine
203      * to which this provider can <i>potentially</i> attach.  There isn't any
204      * guarantee that invoking {@link #attachVirtualMachine(VirtualMachineDescriptor)
205      * attachVirtualMachine} on each descriptor in the list will succeed.
206      *
207      * @return  The list of virtual machine descriptors which describe the
208      *          Java virtual machines known to this provider (may be empty).
209      */
listVirtualMachines()210     public abstract List<VirtualMachineDescriptor> listVirtualMachines();
211 
212 
213     /**
214      * Returns a list of the installed attach providers.
215      *
216      * <p> An AttachProvider is installed on the platform if:
217      *
218      * <ul>
219      *   <li><p>It is installed in a JAR file that is visible to the defining
220      *   class loader of the AttachProvider type (usually, but not required
221      *   to be, the {@link java.lang.ClassLoader#getSystemClassLoader system
222      *   class loader}).</p></li>
223      *
224      *   <li><p>The JAR file contains a provider configuration named
225      *   <tt>com.sun.tools.attach.spi.AttachProvider</tt> in the resource directory
226      *   <tt>META-INF/services</tt>. </p></li>
227      *
228      *   <li><p>The provider configuration file lists the full-qualified class
229      *   name of the AttachProvider implementation. </p></li>
230      * </ul>
231      *
232      * <p> The format of the provider configuration file is one fully-qualified
233      * class name per line. Space and tab characters surrounding each class name,
234      * as well as blank lines are ignored. The comment character is
235      *  <tt>'#'</tt> (<tt>0x23</tt>), and on each line all characters following
236      * the first comment character are ignored. The file must be encoded in
237      * UTF-8. </p>
238      *
239      * <p> AttachProvider implementations are loaded and instantiated
240      * (using the zero-arg constructor) at the first invocation of this method.
241      * The list returned by the first invocation of this method is the list
242      * of providers. Subsequent invocations of this method return a list of the same
243      * providers. The list is unmodifable.</p>
244      *
245      * @return  A list of the installed attach providers.
246      */
providers()247     public static List<AttachProvider> providers() {
248         synchronized (lock) {
249             if (providers == null) {
250                 providers = new ArrayList<AttachProvider>();
251 
252                 ServiceLoader<AttachProvider> providerLoader =
253                     ServiceLoader.load(AttachProvider.class,
254                                        AttachProvider.class.getClassLoader());
255 
256                 Iterator<AttachProvider> i = providerLoader.iterator();
257 
258                 while (i.hasNext()) {
259                     try {
260                         providers.add(i.next());
261                     } catch (Throwable t) {
262                         if (t instanceof ThreadDeath) {
263                             ThreadDeath td = (ThreadDeath)t;
264                             throw td;
265                         }
266                         // Ignore errors and exceptions
267                         System.err.println(t);
268                     }
269                 }
270             }
271             return Collections.unmodifiableList(providers);
272         }
273     }
274 }
275