1/*
2 * Copyright (c) 2005, 2014, 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
26package com.sun.tools.attach;
27
28import com.sun.tools.attach.spi.AttachProvider;
29import java.util.ArrayList;
30import java.util.List;
31import java.util.Properties;
32import java.io.IOException;
33
34
35/**
36 * A Java virtual machine.
37 *
38 * <p> A {@code VirtualMachine} represents a Java virtual machine to which this
39 * Java virtual machine has attached. The Java virtual machine to which it is
40 * attached is sometimes called the <i>target virtual machine</i>, or <i>target VM</i>.
41 * An application (typically a tool such as a managemet console or profiler) uses a
42 * VirtualMachine to load an agent into the target VM. For example, a profiler tool
43 * written in the Java Language might attach to a running application and load its
44 * profiler agent to profile the running application. </p>
45 *
46 * <p> A VirtualMachine is obtained by invoking the {@link #attach(String) attach} method
47 * with an identifier that identifies the target virtual machine. The identifier is
48 * implementation-dependent but is typically the process identifier (or pid) in
49 * environments where each Java virtual machine runs in its own operating system process.
50 * Alternatively, a {@code VirtualMachine} instance is obtained by invoking the
51 * {@link #attach(VirtualMachineDescriptor) attach} method with a {@link
52 * com.sun.tools.attach.VirtualMachineDescriptor VirtualMachineDescriptor} obtained
53 * from the list of virtual machine descriptors returned by the {@link #list list} method.
54 * Once a reference to a virtual machine is obtained, the {@link #loadAgent loadAgent},
55 * {@link #loadAgentLibrary loadAgentLibrary}, and {@link #loadAgentPath loadAgentPath}
56 * methods are used to load agents into target virtual machine. The {@link
57 * #loadAgent loadAgent} method is used to load agents that are written in the Java
58 * Language and deployed in a {@link java.util.jar.JarFile JAR file}. (See
59 * {@link java.lang.instrument} for a detailed description on how these agents
60 * are loaded and started). The {@link #loadAgentLibrary loadAgentLibrary} and
61 * {@link #loadAgentPath loadAgentPath} methods are used to load agents that
62 * are deployed either in a dynamic library or statically linked into the VM and
63 * make use of the <a href="{@docRoot}/../specs/jvmti.html">JVM Tools Interface</a>.
64 * </p>
65 *
66 * <p> In addition to loading agents a VirtualMachine provides read access to the
67 * {@link java.lang.System#getProperties() system properties} in the target VM.
68 * This can be useful in some environments where properties such as
69 * {@code java.home}, {@code os.name}, or {@code os.arch} are
70 * used to construct the path to agent that will be loaded into the target VM.
71 *
72 * <p> The following example demonstrates how VirtualMachine may be used:</p>
73 *
74 * <pre>
75 *
76 *      // attach to target VM
77 *      VirtualMachine vm = VirtualMachine.attach("2177");
78 *
79 *      // start management agent
80 *      Properties props = new Properties();
81 *      props.put("com.sun.management.jmxremote.port", "5000");
82 *      vm.startManagementAgent(props);
83 *
84 *      // detach
85 *      vm.detach();
86 *
87 * </pre>
88 *
89 * <p> In this example we attach to a Java virtual machine that is identified by
90 * the process identifier {@code 2177}. Then the JMX management agent is
91 * started in the target process using the supplied arguments. Finally, the
92 * client detaches from the target VM. </p>
93 *
94 * <p> A VirtualMachine is safe for use by multiple concurrent threads. </p>
95 *
96 * @since 1.6
97 */
98
99public abstract class VirtualMachine {
100    private AttachProvider provider;
101    private String id;
102    private volatile int hash;        // 0 => not computed
103
104    /**
105     * Initializes a new instance of this class.
106     *
107     * @param   provider
108     *          The attach provider creating this class.
109     * @param   id
110     *          The abstract identifier that identifies the Java virtual machine.
111     *
112     * @throws  NullPointerException
113     *          If {@code provider} or {@code id} is {@code null}.
114     */
115    protected VirtualMachine(AttachProvider provider, String id) {
116        if (provider == null) {
117            throw new NullPointerException("provider cannot be null");
118        }
119        if (id == null) {
120            throw new NullPointerException("id cannot be null");
121        }
122        this.provider = provider;
123        this.id = id;
124    }
125
126    /**
127     * Return a list of Java virtual machines.
128     *
129     * <p> This method returns a list of Java {@link
130     * com.sun.tools.attach.VirtualMachineDescriptor} elements.
131     * The list is an aggregation of the virtual machine
132     * descriptor lists obtained by invoking the {@link
133     * com.sun.tools.attach.spi.AttachProvider#listVirtualMachines
134     * listVirtualMachines} method of all installed
135     * {@link com.sun.tools.attach.spi.AttachProvider attach providers}.
136     * If there are no Java virtual machines known to any provider
137     * then an empty list is returned.
138     *
139     * @return  The list of virtual machine descriptors.
140     */
141    public static List<VirtualMachineDescriptor> list() {
142        ArrayList<VirtualMachineDescriptor> l =
143            new ArrayList<VirtualMachineDescriptor>();
144        List<AttachProvider> providers = AttachProvider.providers();
145        for (AttachProvider provider: providers) {
146            l.addAll(provider.listVirtualMachines());
147        }
148        return l;
149    }
150
151    /**
152     * Attaches to a Java virtual machine.
153     *
154     * <p> This method obtains the list of attach providers by invoking the
155     * {@link com.sun.tools.attach.spi.AttachProvider#providers()
156     * AttachProvider.providers()} method. It then iterates overs the list
157     * and invokes each provider's {@link
158     * com.sun.tools.attach.spi.AttachProvider#attachVirtualMachine(java.lang.String)
159     * attachVirtualMachine} method in turn. If a provider successfully
160     * attaches then the iteration terminates, and the VirtualMachine created
161     * by the provider that successfully attached is returned by this method.
162     * If the {@code attachVirtualMachine} method of all providers throws
163     * {@link com.sun.tools.attach.AttachNotSupportedException AttachNotSupportedException}
164     * then this method also throws {@code AttachNotSupportedException}.
165     * This means that {@code AttachNotSupportedException} is thrown when
166     * the identifier provided to this method is invalid, or the identifier
167     * corresponds to a Java virtual machine that does not exist, or none
168     * of the providers can attach to it. This exception is also thrown if
169     * {@link com.sun.tools.attach.spi.AttachProvider#providers()
170     * AttachProvider.providers()} returns an empty list. </p>
171     *
172     * @param   id
173     *          The abstract identifier that identifies the Java virtual machine.
174     *
175     * @return  A VirtualMachine representing the target VM.
176     *
177     * @throws  SecurityException
178     *          If a security manager has been installed and it denies
179     *          {@link com.sun.tools.attach.AttachPermission AttachPermission}
180     *          {@code ("attachVirtualMachine")}, or another permission
181     *          required by the implementation.
182     *
183     * @throws  AttachNotSupportedException
184     *          If the {@code attachVirtualmachine} method of all installed
185     *          providers throws {@code AttachNotSupportedException}, or
186     *          there aren't any providers installed.
187     *
188     * @throws  IOException
189     *          If an I/O error occurs
190     *
191     * @throws  NullPointerException
192     *          If {@code id} is {@code null}.
193     */
194    public static VirtualMachine attach(String id)
195        throws AttachNotSupportedException, IOException
196    {
197        if (id == null) {
198            throw new NullPointerException("id cannot be null");
199        }
200        List<AttachProvider> providers = AttachProvider.providers();
201        if (providers.size() == 0) {
202            throw new AttachNotSupportedException("no providers installed");
203        }
204        AttachNotSupportedException lastExc = null;
205        for (AttachProvider provider: providers) {
206            try {
207                return provider.attachVirtualMachine(id);
208            } catch (AttachNotSupportedException x) {
209                lastExc = x;
210            }
211        }
212        throw lastExc;
213    }
214
215    /**
216     * Attaches to a Java virtual machine.
217     *
218     * <p> This method first invokes the {@link
219     * com.sun.tools.attach.VirtualMachineDescriptor#provider() provider()} method
220     * of the given virtual machine descriptor to obtain the attach provider. It
221     * then invokes the attach provider's {@link
222     * com.sun.tools.attach.spi.AttachProvider#attachVirtualMachine(VirtualMachineDescriptor)
223     * attachVirtualMachine} to attach to the target VM.
224     *
225     * @param   vmd
226     *          The virtual machine descriptor.
227     *
228     * @return  A VirtualMachine representing the target VM.
229     *
230     * @throws  SecurityException
231     *          If a security manager has been installed and it denies
232     *          {@link com.sun.tools.attach.AttachPermission AttachPermission}
233     *          {@code ("attachVirtualMachine")}, or another permission
234     *          required by the implementation.
235     *
236     * @throws  AttachNotSupportedException
237     *          If the attach provider's {@code attachVirtualmachine}
238     *          throws {@code AttachNotSupportedException}.
239     *
240     * @throws  IOException
241     *          If an I/O error occurs
242     *
243     * @throws  NullPointerException
244     *          If {@code vmd} is {@code null}.
245     */
246    public static VirtualMachine attach(VirtualMachineDescriptor vmd)
247        throws AttachNotSupportedException, IOException
248    {
249        return vmd.provider().attachVirtualMachine(vmd);
250    }
251
252    /**
253     * Detach from the virtual machine.
254     *
255     * <p> After detaching from the virtual machine, any further attempt to invoke
256     * operations on that virtual machine will cause an {@link java.io.IOException
257     * IOException} to be thrown. If an operation (such as {@link #loadAgent
258     * loadAgent} for example) is in progress when this method is invoked then
259     * the behaviour is implementation dependent. In other words, it is
260     * implementation specific if the operation completes or throws
261     * {@code IOException}.
262     *
263     * <p> If already detached from the virtual machine then invoking this
264     * method has no effect. </p>
265     *
266     * @throws  IOException
267     *          If an I/O error occurs
268     */
269    public abstract void detach() throws IOException;
270
271    /**
272     * Returns the provider that created this virtual machine.
273     *
274     * @return  The provider that created this virtual machine.
275     */
276    public final AttachProvider provider() {
277        return provider;
278    }
279
280    /**
281     * Returns the identifier for this Java virtual machine.
282     *
283     * @return  The identifier for this Java virtual machine.
284     */
285    public final String id() {
286        return id;
287    }
288
289    /**
290     * Loads an agent library.
291     *
292     * <p> A <a href="{@docRoot}/../specs/jvmti.html">JVM TI</a>
293     * client is called an <i>agent</i>. It is developed in a native language.
294     * A JVM TI agent is deployed in a platform specific manner but it is typically the
295     * platform equivalent of a dynamic library. Alternatively, it may be statically linked into the VM.
296     * This method causes the given agent library to be loaded into the target
297     * VM (if not already loaded or if not statically linked into the VM).
298     * It then causes the target VM to invoke the {@code Agent_OnAttach} function
299     * or, for a statically linked agent named 'L', the {@code Agent_OnAttach_L} function
300     * as specified in the
301     * <a href="{@docRoot}/../specs/jvmti.html">JVM Tools Interface</a> specification.
302     * Note that the {@code Agent_OnAttach[_L]}
303     * function is invoked even if the agent library was loaded prior to invoking
304     * this method.
305     *
306     * <p> The agent library provided is the name of the agent library. It is interpreted
307     * in the target virtual machine in an implementation-dependent manner. Typically an
308     * implementation will expand the library name into an operating system specific file
309     * name. For example, on UNIX systems, the name {@code L} might be expanded to
310     * {@code libL.so}, and located using the search path specified by the
311     * {@code LD_LIBRARY_PATH} environment variable. If the agent named 'L' is
312     * statically linked into the VM then the VM must export a function named
313     * {@code Agent_OnAttach_L}.</p>
314     *
315     * <p> If the {@code Agent_OnAttach[_L]} function in the agent library returns
316     * an error then an {@link com.sun.tools.attach.AgentInitializationException} is
317     * thrown. The return value from the {@code Agent_OnAttach[_L]} can then be
318     * obtained by invoking the {@link
319     * com.sun.tools.attach.AgentInitializationException#returnValue() returnValue}
320     * method on the exception. </p>
321     *
322     * @param   agentLibrary
323     *          The name of the agent library.
324     *
325     * @param   options
326     *          The options to provide to the {@code Agent_OnAttach[_L]}
327     *          function (can be {@code null}).
328     *
329     * @throws  AgentLoadException
330     *          If the agent library does not exist, the agent library is not
331     *          statically linked with the VM, or the agent library cannot be
332     *          loaded for another reason.
333     *
334     * @throws  AgentInitializationException
335     *          If the {@code Agent_OnAttach[_L]} function returns an error.
336     *
337     * @throws  IOException
338     *          If an I/O error occurs
339     *
340     * @throws  NullPointerException
341     *          If {@code agentLibrary} is {@code null}.
342     *
343     * @see     com.sun.tools.attach.AgentInitializationException#returnValue()
344     */
345    public abstract void loadAgentLibrary(String agentLibrary, String options)
346        throws AgentLoadException, AgentInitializationException, IOException;
347
348    /**
349     * Loads an agent library.
350     *
351     * <p> This convenience method works as if by invoking:
352     *
353     * <blockquote><code>
354     * {@link #loadAgentLibrary(String, String) loadAgentLibrary}(agentLibrary,&nbsp;null);
355     * </code></blockquote>
356     *
357     * @param   agentLibrary
358     *          The name of the agent library.
359     *
360     * @throws  AgentLoadException
361     *          If the agent library does not exist, the agent library is not
362     *          statically linked with the VM, or the agent library cannot be
363     *          loaded for another reason.
364     *
365     * @throws  AgentInitializationException
366     *          If the {@code Agent_OnAttach[_L]} function returns an error.
367     *
368     * @throws  IOException
369     *          If an I/O error occurs
370     *
371     * @throws  NullPointerException
372     *          If {@code agentLibrary} is {@code null}.
373     */
374    public void loadAgentLibrary(String agentLibrary)
375        throws AgentLoadException, AgentInitializationException, IOException
376    {
377        loadAgentLibrary(agentLibrary, null);
378    }
379
380    /**
381     * Load a native agent library by full pathname.
382     *
383     * <p> A <a href="{@docRoot}/../specs/jvmti.html">JVM TI</a>
384     * client is called an <i>agent</i>. It is developed in a native language.
385     * A JVM TI agent is deployed in a platform specific manner but it is typically the
386     * platform equivalent of a dynamic library. Alternatively, the native
387     * library specified by the agentPath parameter may be statically
388     * linked with the VM. The parsing of the agentPath parameter into
389     * a statically linked library name is done in a platform
390     * specific manner in the VM. For example, in UNIX, an agentPath parameter
391     * of {@code /a/b/libL.so} would name a library 'L'.
392     *
393     * See the JVM TI Specification for more details.
394     *
395     * This method causes the given agent library to be loaded into the target
396     * VM (if not already loaded or if not statically linked into the VM).
397     * It then causes the target VM to invoke the {@code Agent_OnAttach}
398     * function or, for a statically linked agent named 'L', the
399     * {@code Agent_OnAttach_L} function as specified in the
400     * <a href="{@docRoot}/../specs/jvmti.html">JVM Tools Interface</a> specification.
401     * Note that the {@code Agent_OnAttach[_L]}
402     * function is invoked even if the agent library was loaded prior to invoking
403     * this method.
404     *
405     * <p> The agent library provided is the absolute path from which to load the
406     * agent library. Unlike {@link #loadAgentLibrary loadAgentLibrary}, the library name
407     * is not expanded in the target virtual machine. </p>
408     *
409     * <p> If the {@code Agent_OnAttach[_L]} function in the agent library returns
410     * an error then an {@link com.sun.tools.attach.AgentInitializationException} is
411     * thrown. The return value from the {@code Agent_OnAttach[_L]} can then be
412     * obtained by invoking the {@link
413     * com.sun.tools.attach.AgentInitializationException#returnValue() returnValue}
414     * method on the exception. </p>
415     *
416     * @param   agentPath
417     *          The full path of the agent library.
418     *
419     * @param   options
420     *          The options to provide to the {@code Agent_OnAttach[_L]}
421     *          function (can be {@code null}).
422     *
423     * @throws  AgentLoadException
424     *          If the agent library does not exist, the agent library is not
425     *          statically linked with the VM, or the agent library cannot be
426     *          loaded for another reason.
427     *
428     * @throws  AgentInitializationException
429     *          If the {@code Agent_OnAttach[_L]} function returns an error.
430     *
431     * @throws  IOException
432     *          If an I/O error occurs
433     *
434     * @throws  NullPointerException
435     *          If {@code agentPath} is {@code null}.
436     *
437     * @see     com.sun.tools.attach.AgentInitializationException#returnValue()
438     */
439    public abstract void loadAgentPath(String agentPath, String options)
440        throws AgentLoadException, AgentInitializationException, IOException;
441
442    /**
443     * Load a native agent library by full pathname.
444     *
445     * <p> This convenience method works as if by invoking:
446     *
447     * <blockquote><code>
448     * {@link #loadAgentPath(String, String) loadAgentPath}(agentLibrary,&nbsp;null);
449     * </code></blockquote>
450     *
451     * @param   agentPath
452     *          The full path to the agent library.
453     *
454     * @throws  AgentLoadException
455     *          If the agent library does not exist, the agent library is not
456     *          statically linked with the VM, or the agent library cannot be
457     *          loaded for another reason.
458     *
459     * @throws  AgentInitializationException
460     *          If the {@code Agent_OnAttach[_L]} function returns an error.
461     *
462     * @throws  IOException
463     *          If an I/O error occurs
464     *
465     * @throws  NullPointerException
466     *          If {@code agentPath} is {@code null}.
467     */
468    public void loadAgentPath(String agentPath)
469       throws AgentLoadException, AgentInitializationException, IOException
470    {
471        loadAgentPath(agentPath, null);
472    }
473
474
475   /**
476     * Loads an agent.
477     *
478     * <p> The agent provided to this method is a path name to a JAR file on the file
479     * system of the target virtual machine. This path is passed to the target virtual
480     * machine where it is interpreted. The target virtual machine attempts to start
481     * the agent as specified by the {@link java.lang.instrument} specification.
482     * That is, the specified JAR file is added to the system class path (of the target
483     * virtual machine), and the {@code agentmain} method of the agent class, specified
484     * by the {@code Agent-Class} attribute in the JAR manifest, is invoked. This
485     * method completes when the {@code agentmain} method completes.
486     *
487     * @param   agent
488     *          Path to the JAR file containing the agent.
489     *
490     * @param   options
491     *          The options to provide to the agent's {@code agentmain}
492     *          method (can be {@code null}).
493     *
494     * @throws  AgentLoadException
495     *          If the agent does not exist, or cannot be started in the manner
496     *          specified in the {@link java.lang.instrument} specification.
497     *
498     * @throws  AgentInitializationException
499     *          If the {@code agentmain} throws an exception
500     *
501     * @throws  IOException
502     *          If an I/O error occurs
503     *
504     * @throws  NullPointerException
505     *          If {@code agent} is {@code null}.
506     */
507    public abstract void loadAgent(String agent, String options)
508        throws AgentLoadException, AgentInitializationException, IOException;
509
510    /**
511     * Loads an agent.
512     *
513     * <p> This convenience method works as if by invoking:
514     *
515     * <blockquote><code>
516     * {@link #loadAgent(String, String) loadAgent}(agent,&nbsp;null);
517     * </code></blockquote>
518     *
519     * @param   agent
520     *          Path to the JAR file containing the agent.
521     *
522     * @throws  AgentLoadException
523     *          If the agent does not exist, or cannot be started in the manner
524     *          specified in the {@link java.lang.instrument} specification.
525     *
526     * @throws  AgentInitializationException
527     *          If the {@code agentmain} throws an exception
528     *
529     * @throws  IOException
530     *          If an I/O error occurs
531     *
532     * @throws  NullPointerException
533     *          If {@code agent} is {@code null}.
534     */
535    public void loadAgent(String agent)
536        throws AgentLoadException, AgentInitializationException, IOException
537    {
538        loadAgent(agent, null);
539    }
540
541    /**
542     * Returns the current system properties in the target virtual machine.
543     *
544     * <p> This method returns the system properties in the target virtual
545     * machine. Properties whose key or value is not a {@code String} are
546     * omitted. The method is approximately equivalent to the invocation of the
547     * method {@link java.lang.System#getProperties System.getProperties}
548     * in the target virtual machine except that properties with a key or
549     * value that is not a {@code String} are not included.
550     *
551     * <p> This method is typically used to decide which agent to load into
552     * the target virtual machine with {@link #loadAgent loadAgent}, or
553     * {@link #loadAgentLibrary loadAgentLibrary}. For example, the
554     * {@code java.home} or {@code user.dir} properties might be
555     * use to create the path to the agent library or JAR file.
556     *
557     * @return  The system properties
558     *
559     * @throws  AttachOperationFailedException
560     *          If the target virtual machine is unable to complete the
561     *          attach operation. A more specific error message will be
562     *          given by {@link AttachOperationFailedException#getMessage()}.
563     *
564     * @throws  IOException
565     *          If an I/O error occurs, a communication error for example,
566     *          that cannot be identified as an error to indicate that the
567     *          operation failed in the target VM.
568     *
569     * @see     java.lang.System#getProperties
570     * @see     #loadAgentLibrary
571     * @see     #loadAgent
572     */
573    public abstract Properties getSystemProperties() throws IOException;
574
575    /**
576     * Returns the current <i>agent properties</i> in the target virtual
577     * machine.
578     *
579     * <p> The target virtual machine can maintain a list of properties on
580     * behalf of agents. The manner in which this is done, the names of the
581     * properties, and the types of values that are allowed, is implementation
582     * specific. Agent properties are typically used to store communication
583     * end-points and other agent configuration details. For example, a debugger
584     * agent might create an agent property for its transport address.
585     *
586     * <p> This method returns the agent properties whose key and value is a
587     * {@code String}. Properties whose key or value is not a {@code String}
588     * are omitted. If there are no agent properties maintained in the target
589     * virtual machine then an empty property list is returned.
590     *
591     * @return       The agent properties
592     *
593     * @throws       AttachOperationFailedException
594     *               If the target virtual machine is unable to complete the
595     *               attach operation. A more specific error message will be
596     *               given by {@link AttachOperationFailedException#getMessage()}.
597     *
598     * @throws       IOException
599     *               If an I/O error occurs, a communication error for example,
600     *               that cannot be identified as an error to indicate that the
601     *               operation failed in the target VM.
602     */
603    public abstract Properties getAgentProperties() throws IOException;
604
605    /**
606     * Starts the JMX management agent in the target virtual machine.
607     *
608     * <p> The configuration properties are the same as those specified on
609     * the command line when starting the JMX management agent. In the same
610     * way as on the command line, you need to specify at least the
611     * {@code com.sun.management.jmxremote.port} property.
612     *
613     * <p> See the online documentation for
614     * {@extLink monitoring_and_management_using_jmx_technology
615     * Monitoring and Management Using JMX Technology} for further details.
616     *
617     * @param   agentProperties
618     *          A Properties object containing the configuration properties
619     *          for the agent.
620     *
621     * @throws  AttachOperationFailedException
622     *          If the target virtual machine is unable to complete the
623     *          attach operation. A more specific error message will be
624     *          given by {@link AttachOperationFailedException#getMessage()}.
625     *
626     * @throws  IOException
627     *          If an I/O error occurs, a communication error for example,
628     *          that cannot be identified as an error to indicate that the
629     *          operation failed in the target VM.
630     *
631     * @throws  IllegalArgumentException
632     *          If keys or values in agentProperties are invalid.
633     *
634     * @throws  NullPointerException
635     *          If agentProperties is null.
636     *
637     * @since   1.8
638     */
639    public abstract void startManagementAgent(Properties agentProperties) throws IOException;
640
641    /**
642     * Starts the local JMX management agent in the target virtual machine.
643     *
644     * <p> See the online documentation for
645     * {@extLink monitoring_and_management_using_jmx_technology
646     * Monitoring and Management Using JMX Technology} for further details.
647     *
648     * @return  The String representation of the local connector's service address.
649     *          The value can be parsed by the
650     *          {@link javax.management.remote.JMXServiceURL#JMXServiceURL(String)}
651     *          constructor.
652     *
653     * @throws  AttachOperationFailedException
654     *          If the target virtual machine is unable to complete the
655     *          attach operation. A more specific error message will be
656     *          given by {@link AttachOperationFailedException#getMessage()}.
657     *
658     * @throws  IOException
659     *          If an I/O error occurs, a communication error for example,
660     *          that cannot be identified as an error to indicate that the
661     *          operation failed in the target VM.
662     *
663     * @since   1.8
664     */
665    public abstract String startLocalManagementAgent() throws IOException;
666
667    /**
668     * Returns a hash-code value for this VirtualMachine. The hash
669     * code is based upon the VirtualMachine's components, and satifies
670     * the general contract of the {@link java.lang.Object#hashCode()
671     * Object.hashCode} method.
672     *
673     * @return  A hash-code value for this virtual machine
674     */
675    public int hashCode() {
676        if (hash != 0) {
677            return hash;
678        }
679        hash = provider.hashCode() * 127 + id.hashCode();
680        return hash;
681    }
682
683    /**
684     * Tests this VirtualMachine for equality with another object.
685     *
686     * <p> If the given object is not a VirtualMachine then this
687     * method returns {@code false}. For two VirtualMachines to
688     * be considered equal requires that they both reference the same
689     * provider, and their {@link VirtualMachineDescriptor#id() identifiers} are equal. </p>
690     *
691     * <p> This method satisfies the general contract of the {@link
692     * java.lang.Object#equals(Object) Object.equals} method. </p>
693     *
694     * @param   ob   The object to which this object is to be compared
695     *
696     * @return  {@code true} if, and only if, the given object is
697     *                a VirtualMachine that is equal to this
698     *                VirtualMachine.
699     */
700    public boolean equals(Object ob) {
701        if (ob == this)
702            return true;
703        if (!(ob instanceof VirtualMachine))
704            return false;
705        VirtualMachine other = (VirtualMachine)ob;
706        if (other.provider() != this.provider()) {
707            return false;
708        }
709        if (!other.id().equals(this.id())) {
710            return false;
711        }
712        return true;
713    }
714
715    /**
716     * Returns the string representation of the {@code VirtualMachine}.
717     */
718    public String toString() {
719        return provider.toString() + ": " + id;
720    }
721}
722