1 /*
2  * Copyright (c) 2016, 2020, 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 jdk.management.jfr;
27 
28 import java.io.IOException;
29 import java.lang.management.PlatformManagedObject;
30 import java.time.Instant;
31 import java.util.List;
32 import java.util.Map;
33 
34 import jdk.jfr.Configuration;
35 import jdk.jfr.EventType;
36 import jdk.jfr.Recording;
37 
38 /**
39  * Management interface for controlling Flight Recorder.
40  * <p>
41  * The object name for identifying the MXBean in the platform MBean
42  * server is: <blockquote> {@code jdk.management.jfr:type=FlightRecorder} </blockquote>
43  * <p>
44  * Flight Recorder can be configured in the following ways:
45  * <ul>
46  * <li><b>Recording options</b><br>
47  * Specify how long a recording should last, and where and when data
48  * should be dumped.</li>
49  * <li><b>Settings</b><br>
50  * Specify which events should be enabled and what kind information each
51  * event should capture.</li>
52  * <li><b>Configurations</b><br>
53  * Predefined sets of settings, typically derived from a settings file,
54  * that specify the configuration of multiple events simultaneously.</li>
55  * </ul>
56  * <p>
57  * See the package {@code jdk.jfr} documentation for descriptions of the settings
58  * syntax and the {@link ConfigurationInfo} class documentation for configuration information.
59  *
60  * <h2>Recording options</h2>
61  * <p>
62  * The following table shows the options names to use with {@link #setRecordingOptions(long, Map)}
63  * and {@link #getRecordingOptions(long)}.
64  *
65  * <table class="striped">
66  * <caption>Recording options</caption>
67  * <thead>
68  * <tr>
69  * <th scope="col">Name</th>
70  * <th scope="col">Descripion</th>
71  * <th scope="col">Default value</th>
72  * <th scope="col">Format</th>
73  * <th scope="col">Example values</th>
74  * </tr>
75  * </thead>
76  * <tbody>
77  * <tr>
78  * <th scope="row">{@code name}</th>
79  * <td>Sets a human-readable recording name</td>
80  * <td>String representation of the recording id</td>
81  * <td>{@code String}</td>
82  * <td>{@code "My Recording"}, <br>
83  * {@code "profiling"}</td>
84  * </tr>
85  * <tr>
86  * <th scope="row">{@code maxAge}</th>
87  * <td>Specify the length of time that the data is kept in the disk repository until the
88  * oldest data may be deleted. Only works if {@code disk=true}, otherwise
89  * this parameter is ignored.</td>
90  * <td>{@code "0"} (no limit)</td>
91  * <td>{@code "0"} if no limit is imposed, otherwise a string
92  * representation of a positive {@code Long} value followed by an empty space
93  * and one of the following units,<br>
94  * <br>
95  * {@code "ns"} (nanoseconds)<br>
96  * {@code "us"} (microseconds)<br>
97  * {@code "ms"} (milliseconds)<br>
98  * {@code "s"} (seconds)<br>
99  * {@code "m"} (minutes)<br>
100  * {@code "h"} (hours)<br>
101  * {@code "d"} (days)<br>
102  * </td>
103  * <td>{@code "2 h"},<br>
104  * {@code "24 h"},<br>
105  * {@code "2 d"},<br>
106  * {@code "0"}</td>
107  * </tr>
108  * <tr>
109  * <th scope="row">{@code maxSize}</th>
110  * <td>Specifies the size, measured in bytes, at which data is kept in disk
111  * repository. Only works if
112  * {@code disk=true}, otherwise this parameter is ignored.</td>
113  * <td>{@code "0"} (no limit)</td>
114  * <td>String representation of a {@code Long} value, must be positive</td>
115  * <td>{@code "0"}, <br>
116  * {@code "1000000000"}</td>
117  * </tr>
118  * <tr>
119  * <th scope="row">{@code dumpOnExit}</th>
120  * <td>Dumps recording data to disk on Java Virtual Machine (JVM) exit</td>
121  * <td>{@code "false"}</td>
122  * <td>String representation of a {@code Boolean} value, {@code "true"} or
123  * {@code "false"}</td>
124  * <td>{@code "true"},<br>
125  * {@code "false"}</td>
126  * </tr>
127  * <tr>
128  * <th scope="row">{@code destination}</th>
129  * <td>Specifies the path where recording data is written when the recording stops.</td>
130  * <td>{@code "false"}</td>
131  * <td>See {@code Paths#getPath} for format. <br>
132  * If this method is invoked from another process, the data is written on the
133  * machine where the target JVM is running. If destination is a relative path, it
134  * is relative to the working directory where the target JVM was started.}</td>
135  * <td>{@code "c:\recording\recotding.jfr"},<br>
136  * {@code "/recordings/recording.jfr"}, {@code "recording.jfr"}</td>
137  * </tr>
138  * <tr>
139  * <th scope="row">{@code disk}</th>
140  * <td>Stores recorded data as it is recorded</td>
141  * <td><code>"false"</code></td>
142  * <td>String representation of a {@code Boolean} value, {@code "true"} or
143  * {@code "false"}</td>
144  * <td>{@code "true"},<br>
145  * {@code "false"}</td>
146  * <tr>
147  * <th scope="row">{@code duration}</th>
148  * <td>Sets how long the recording should be running</td>
149  * <td>{@code "0"} (no limit, continuous)</td>
150  * <td>{@code "0"} if no limit should be imposed, otherwise a string
151  * representation of a positive {@code Long} followed by an empty space and one
152  * of the following units:<br>
153  * <br>
154  * {@code "ns"} (nanoseconds)<br>
155  * {@code "us"} (microseconds)<br>
156  * {@code "ms"} (milliseconds)<br>
157  * {@code "s"} (seconds)<br>
158  * {@code "m"} (minutes)<br>
159  * {@code "h"} (hours)<br>
160  * {@code "d"} (days)<br>
161  * </td>
162  * <td>{@code "60 s"},<br>
163  * {@code "10 m"},<br>
164  * {@code "4 h"},<br>
165  * {@code "0"}</td>
166  * </tr>
167  * </tbody>
168  * </table>
169  *
170  * @since 9
171  */
172 public interface FlightRecorderMXBean extends PlatformManagedObject {
173     /**
174      * String representation of the {@code ObjectName} for the
175      * {@code FlightRecorderMXBean}.
176      */
177     public static final String MXBEAN_NAME = "jdk.management.jfr:type=FlightRecorder";
178 
179     /**
180      * Creates a recording, but doesn't start it.
181      *
182      * @return a unique ID that can be used to start, stop, close and
183      *         configure the recording
184      *
185      * @throws IllegalStateException if Flight Recorder can't be created (for
186      *         example, if the Java Virtual Machine (JVM) lacks Flight Recorder
187      *         support, or if the file repository can't be created or accessed)
188      *
189      * @throws java.lang.SecurityException if a security manager exists and the
190      *         caller does not have {@code ManagementPermission("control")}
191      *
192      * @see Recording
193      */
newRecording()194     long newRecording() throws IllegalStateException, SecurityException;
195 
196     /**
197      * Creates a snapshot recording of all available recorded data.
198      * <p>
199      * A snapshot is a synthesized recording in a stopped state. If no data is
200      * available, a recording with size {@code 0} is returned.
201      * <p>
202      * A snapshot provides stable access to data for later operations (for example,
203      * operations to change the time interval or to reduce the data size).
204      * <p>
205      * The caller must close the recording when access to the data is no longer
206      * needed.
207      *
208      * @return a unique ID that can be used for reading recording data
209      *
210      * @throws java.lang.SecurityException if a security manager exists and the
211      *         caller does not have {@code ManagementPermission("control")}
212      *
213      * @see Recording
214      */
takeSnapshot()215     public long takeSnapshot();
216 
217     /**
218      * Creates a copy of an existing recording, useful for extracting parts of a
219      * recording.
220      * <p>
221      * The cloned recording contains the same recording data as the
222      * original, but it has a new ID and a name prefixed with
223      * {@code "Clone of recording"}. If the original recording is running, then
224      * the clone is also running.
225      *
226      * @param recordingId the recording ID of the recording to create a clone
227      *        from
228      *
229      * @param stop if the newly created clone is stopped before
230      *        returning.
231      *
232      * @return a unique ID that can be used to start, stop,
233      *         close and configure the recording
234      *
235      * @throws IllegalArgumentException if a recording with the specified ID
236      *         doesn't exist
237      *
238      * @throws java.lang.SecurityException if a security manager exists and the
239      *         caller does not have {@code ManagementPermission("control")}
240      *
241      * @see Recording
242      */
cloneRecording(long recordingId, boolean stop)243     long cloneRecording(long recordingId, boolean stop) throws IllegalArgumentException, SecurityException;
244 
245     /**
246      * Starts the recording with the specified ID.
247      * <p>
248      * A recording that is stopped can't be restarted.
249      *
250      * @param recordingId ID of the recording to start
251      *
252      * @throws IllegalArgumentException if a recording with the specified ID
253      *         doesn't exist
254      *
255      * @throws java.lang.SecurityException if a security manager exists and the
256      *         caller does not have {@code ManagementPermission("control")}
257      *
258      * @see Recording
259      */
startRecording(long recordingId)260     void startRecording(long recordingId) throws IllegalStateException, SecurityException;
261 
262     /**
263      * Stops the running recording with the specified ID.
264      *
265      * @param recordingId the ID of the recording to stop
266      *
267      * @return {@code true} if the recording is stopped, {@code false}
268      *         otherwise
269      *
270      * @throws IllegalArgumentException if a recording with the specified ID
271      *         doesn't exist
272      * @throws IllegalStateException if the recording is not running
273      * @throws java.lang.SecurityException if a security manager exists and the
274      *         caller does not have {@code ManagementPermission("control")}
275      *
276      * @see #newRecording()
277      */
stopRecording(long recordingId)278     boolean stopRecording(long recordingId) throws IllegalArgumentException, IllegalStateException, SecurityException;
279 
280     /**
281      * Closes the recording with the specified ID and releases any system
282      * resources that are associated with the recording.
283      * <p>
284      * If the recording is already closed, invoking this method has no effect.
285      *
286      * @param recordingId the ID of the recording to close
287      *
288      * @throws IllegalArgumentException if a recording with the specified ID
289      *         doesn't exist
290      * @throws IOException if an I/O error occurs
291      * @throws java.lang.SecurityException if a security manager exists and the
292      *         caller does not have {@code ManagementPermission("control")}
293      *
294      * @see #newRecording()
295      */
closeRecording(long recordingId)296     void closeRecording(long recordingId) throws IOException;
297 
298     /**
299      * Opens a data stream for the recording with the specified ID, or {@code 0}
300      * to get data irrespective of recording.
301      * <table class="striped">
302      * <caption>Recording stream options</caption>
303      * <thead>
304      * <tr>
305      * <th scope="col">Name</th>
306      * <th scope="col">Descripion</th>
307      * <th scope="col">Default value</th>
308      * <th scope="col">Format</th>
309      * <th scope="col">Example values</th>
310      * </tr>
311      * </thead>
312      * <tbody>
313      * <tr>
314      * <th scope="row">{@code startTime}</th>
315      * <td>Specifies the point in time to start a recording stream. Due to
316      * how data is stored, some events that start or end prior to the
317      * start time may be included.</td>
318      * <td>{@code Instant.MIN_VALUE.toString()}</td>
319      * <td>ISO-8601. See {@link Instant#toString}<br>
320      * or milliseconds since epoch</td>
321      * <td>{@code "2015-11-03T00:00"},<br>
322      * {@code "1446508800000"}</td>
323      * </tr>
324      * <tr>
325      * <th scope="row">{@code endTime}</th>
326      * <td>Specifies the point in time to end a recording stream. Due to how
327      * data is stored, some events that start or end after the end time may
328      * be included.</td>
329      * <td>{@code Instant.MAX_VALUE.toString()}</td>
330      * <td>ISO-8601. See {@link Instant#toString} <br>
331      * or milliseconds since epoch</td>
332      * <td>{@code "2015-11-03T01:00"}, <br>
333      * {@code "1446512400000"}</td>
334      * </tr>
335      *
336      * <tr>
337      * <th scope="row">{@code blockSize}</th>
338      * <td>Specifies the maximum number of bytes to read with a call to {@code readStream}
339      * </td>
340      * <td>{@code "50000"}</td>
341      * <td>A positive {@code long} value. <br>
342      * <br>
343      * Setting {@code blockSize} to a very high value may result in
344      * {@link OutOfMemoryError} or an {@link IllegalArgumentException}, if the
345      * Java Virtual Machine (JVM) deems the value too large to handle.</td>
346      * <td>{@code "50000"},<br>
347      * {@code "1000000"},<br>
348      * </tr>
349      * <tr>
350      * <th scope="row">{@code streamVersion}</th>
351      * <td>Specifies format to use when reading data from a running recording
352      * </td>
353      * <td>{@code "1.0"}</td>
354      * <td>A version number with a major and minor.<br>
355      * <br>
356      * To be able to read from a running recording the value must be set</td>
357      * <td>{@code "1.0"}
358      * </tr>
359      * </tbody>
360      * </table>
361      * If an option is omitted from the map the default value is used.
362      * <p>
363      * The recording with the specified ID must be stopped before a stream can
364      * be opened, unless the option {@code "streamVersion"} is specified.
365      *
366      * @param recordingId ID of the recording to open the stream for
367      *
368      * @param streamOptions a map that contains the options that controls the amount of data
369      *        and how it is read, or {@code null} to get all data for the
370      *        recording with the default block size
371      *
372      * @return a unique ID for the stream.
373      *
374      * @throws IllegalArgumentException if a recording with the iD doesn't
375      *         exist, or if {@code options} contains invalid values
376      *
377      * @throws IOException if the recording is closed, an I/O error occurs, or
378      *         no data is available for the specified recording or
379      *         interval
380      *
381      * @throws java.lang.SecurityException if a security manager exists and the
382      *         caller does not have {@code ManagementPermission("control")}
383      */
openStream(long recordingId, Map<String, String> streamOptions)384     long openStream(long recordingId, Map<String, String> streamOptions) throws IOException;
385 
386     /**
387      * Closes the recording stream with the specified ID and releases any system
388      * resources that are associated with the stream.
389      * <p>
390      * If the stream is already closed, invoking this method has no effect.
391      *
392      * @param streamId the ID of the stream
393      *
394      * @throws IllegalArgumentException if a stream with the specified ID doesn't
395      *         exist
396      * @throws IOException if an I/O error occurs while trying to close the stream
397      * @throws java.lang.SecurityException if a security manager exists and the
398      *         caller does not have {@code ManagementPermission("control")}
399      *
400      * @see #openStream(long, Map)
401      */
closeStream(long streamId)402     void closeStream(long streamId) throws IOException;
403 
404     /**
405      * Reads a portion of data from the stream with the specified ID, or returns
406      * {@code null} if no more data is available.
407      * <p>
408      * To read all data for a recording, invoke this method repeatedly until
409      * {@code null} is returned.
410      *
411      * @param streamId the ID of the stream
412      *
413      * @return byte array that contains recording data, or {@code null} when no more
414      *         data is available
415      * @throws IOException if the stream is closed, or an I/O error occurred while
416      *         trying to read the stream
417      * @throws IllegalArgumentException if no recording with the stream ID exists
418      * @throws java.lang.SecurityException if a security manager exists and the
419      *         caller does not have {@code ManagementPermission("monitor")}
420      */
readStream(long streamId)421     byte[] readStream(long streamId) throws IOException;
422 
423     /**
424      * Returns a map that contains the options for the recording with the
425      * specified ID (for example, the destination file or time span to keep
426      * recorded data).
427      * <p>
428      * See {@link FlightRecorderMXBean} for available option names.
429      *
430      * @param recordingId the ID of the recording to get options for
431      *
432      * @return a map describing the recording options, not {@code null}
433      *
434      * @throws IllegalArgumentException if no recording with the
435      *         specified ID exists
436      * @throws java.lang.SecurityException if a security manager exists and the
437      *         caller does not have {@code ManagementPermission("monitor")}
438      *
439      */
getRecordingOptions(long recordingId)440     Map<String, String> getRecordingOptions(long recordingId) throws IllegalArgumentException;
441 
442     /**
443      * Returns a {@code Map} that contains the settings for the recording with the specified ID,
444      * (for example, the event thresholds)
445      * <p>
446      * If multiple recordings are running at the same time, more data could be
447      * recorded than what is specified in the {@code Map} object.
448      * <p>
449      * The name in the {@code Map} is the event name and the setting name separated by
450      * {@code "#"} (for example, {@code "jdk.VMInfo#period"}). The value
451      * is a textual representation of the settings value (for example,
452      * {@code "60 s"}).
453      *
454      * @param recordingId the ID of the recordings to get settings for
455      *
456      * @return a map that describes the recording settings, not {@code null}
457      *
458      * @throws IllegalArgumentException if no recording with the specified ID exists
459      * @throws java.lang.SecurityException if a security manager exists and the
460      *         caller does not have {@code ManagementPermission("monitor")}
461      */
getRecordingSettings(long recordingId)462     Map<String, String> getRecordingSettings(long recordingId) throws IllegalArgumentException;
463 
464     /**
465      * Sets a configuration as a string representation for the recording with the
466      * specified ID.
467      *
468      * @param recordingId ID of the recording
469      * @param contents a string representation of the configuration file to use,
470      *        not {@code null}
471      * @throws IllegalArgumentException if no recording with the
472      *         specified ID exists or if the configuration could not be parsed.
473      * @throws java.lang.SecurityException if a security manager exists and the
474      *         caller does not have {@code ManagementPermission("control")}
475      *
476      * @see Configuration#getContents()
477      */
setConfiguration(long recordingId, String contents)478     void setConfiguration(long recordingId, String contents) throws IllegalArgumentException;
479 
480     /**
481      * Sets a predefined configuration for the recording with the specified ID.
482      *
483      * @param recordingId ID of the recording to set the configuration for
484      * @param configurationName the name of the configuration (for example,
485      *        {@code "profile"} or {@code "default"}), not {@code null}
486      * @throws IllegalArgumentException if no recording with the
487      *         specified ID exists
488      * @throws java.lang.SecurityException if a security manager exists and the
489      *         caller does not have {@code ManagementPermission("control")}
490      *
491      * @see #getConfigurations()
492      */
setPredefinedConfiguration(long recordingId, String configurationName)493     void setPredefinedConfiguration(long recordingId, String configurationName) throws IllegalArgumentException;
494 
495     /**
496      * Sets and replaces all previous settings for the specified recording.
497      * <p>
498      * A setting consists of a name/value pair, where <em>name</em> specifies the
499      * event and setting to configure, and the <em>value</em> specifies what to set
500      * it to.
501      * <p>
502      * The name can be formed in the following ways:
503      * <p>
504      * {@code
505      *   <event-name> + "#" + <setting-name>
506      * }
507      * <p>
508      * or
509      * <p>
510      * {@code
511      *   <event-id> + "#" + <setting-name>
512      * }
513      * <p>
514      * For example, to set the sample interval of the CPU Load event to once every
515      * second, use the name {@code "jdk.CPULoad#period"} and the value
516      * {@code "1 s"}. If multiple events use the same name, for example if an event
517      * class is loaded in multiple class loaders, and differentiation is needed
518      * between them, then the name is {@code "56#period"}. The ID for an event is
519      * obtained by invoking {@link jdk.jfr.EventType#getId()} method and is valid
520      * for the Java Virtual Machine (JVM) instance that the event is registered in.
521      * <p>
522      * A list of available event names is retrieved by invoking
523      * {@link jdk.jfr.FlightRecorder#getEventTypes()} and
524      * {@link jdk.jfr.EventType#getName()}. A list of available settings for an
525      * event type is obtained by invoking
526      * {@link jdk.jfr.EventType#getSettingDescriptors()} and
527      * {@link jdk.jfr.ValueDescriptor#getName()}.
528      *
529      * @param recordingId ID of the recording
530      *
531      * @param settings name value map of the settings to set, not {@code null}
532      *
533      * @throws IllegalArgumentException if no recording with the specified ID exists
534      * @throws java.lang.SecurityException if a security manager exists and the
535      *         caller does not have {@code ManagementPermission("control")}
536      *
537      * @see Recording#getId()
538      */
setRecordingSettings(long recordingId, Map<String, String> settings)539     void setRecordingSettings(long recordingId, Map<String, String> settings) throws IllegalArgumentException;
540 
541     /**
542      * Configures the recording options (for example, destination file and time span
543      * to keep data).
544      * <p>
545      * See {@link FlightRecorderMXBean} for a description of the options and values
546      * that can be used. Setting a value to {@code null} restores the value to the
547      * default value.
548      *
549      * @param recordingId the ID of the recording to set options for
550      *
551      * @param options name/value map of the settings to set, not {@code null}
552      *
553      * @throws IllegalArgumentException if no recording with the specified ID exists
554      * @throws java.lang.SecurityException if a security manager exists, and the
555      *         caller does not have {@code ManagementPermission("control")} or an
556      *         option contains a file that the caller does not have permission to
557      *         operate on.
558      * @see Recording#getId()
559      */
setRecordingOptions(long recordingId, Map<String, String> options)560     void setRecordingOptions(long recordingId, Map<String, String> options) throws IllegalArgumentException;
561 
562     /**
563      * Returns the list of the available recordings, not necessarily running.
564      * <p>
565      * <b>MBeanServer access</b>:<br>
566      * The mapped type of {@code RecordingInfo} is {@code CompositeData} with
567      * attributes as specified in the {@link RecordingInfo#from
568      * RecordingInfo.from} method.
569      *
570      * @return list of recordings, not {@code null}
571      *
572      * @throws java.lang.SecurityException if a security manager exists and the
573      *         caller does not have {@code  ManagementPermission("monitor")}
574      *
575      * @see RecordingInfo
576      * @see Recording
577      */
getRecordings()578     List<RecordingInfo> getRecordings();
579 
580     /**
581      * Returns the list of predefined configurations for this Java Virtual Machine (JVM).
582      * <p>
583      * <b>MBeanServer access</b>:<br>
584      * The mapped type of {@code ConfigurationInfo} is {@code CompositeData}
585      * with attributes as specified in the {@link ConfigurationInfo#from
586      * ConfigurationInfo.from} method.
587      *
588      * @return the list of predefined configurations, not {@code null}
589      *
590      * @throws java.lang.SecurityException if a security manager exists and the
591      *         caller does not have {@code ManagementPermission("monitor")}
592      *
593      * @see ConfigurationInfo
594      * @see Configuration
595      */
getConfigurations()596     List<ConfigurationInfo> getConfigurations();
597 
598     /**
599      * Returns the list of currently registered event types.
600      * <p>
601      * <b>MBeanServer access</b>:<br>
602      * The mapped type of {@code EventTypeInfo} is {@code CompositeData} with
603      * attributes as specified in the {@link EventTypeInfo#from
604      * EventTypeInfo.from} method.
605      *
606      * @return the list of registered event types, not {@code null}
607      *
608      * @throws java.lang.SecurityException if a security manager exists and the
609      *         caller does not have {@code ManagementPermission("monitor")}
610      *
611      * @see EventTypeInfo
612      * @see EventType
613      */
getEventTypes()614     List<EventTypeInfo> getEventTypes();
615 
616     /**
617      * Writes recording data to the specified file.
618      * <p>
619      * If this method is invoked remotely from another process, the data is written
620      * to a file named {@code outputFile} on the machine where the target Java
621      * Virtual Machine (JVM) is running. If the file location is a relative path, it
622      * is relative to the working directory where the target JVM was started.
623      *
624      * @param recordingId the ID of the recording to dump data for
625      *
626      * @param outputFile the system-dependent file name where data is written, not
627      *        {@code null}
628      *
629      * @throws IOException if the recording can't be dumped due to an I/O error (for
630      *         example, an invalid path)
631      *
632      * @throws IllegalArgumentException if a recording with the specified ID doesn't
633      *         exist
634      *
635      * @throws IllegalStateException if the recording is not yet started or if it is
636      *         already closed
637      *
638      * @throws SecurityException if a security manager exists and its
639      *         {@code SecurityManager.checkWrite(java.lang.String)} method denies
640      *         write access to the named file or the caller does not have
641      *         {@code ManagmentPermission("control")}
642      *
643      * @see java.nio.file.Path#toString()
644      * @see Recording#dump(java.nio.file.Path)
645      */
copyTo(long recordingId, String outputFile)646     void copyTo(long recordingId, String outputFile) throws IOException, SecurityException;
647 }
648