1 /*
2  * Copyright (c) 2001, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package nsk.share.jpda;
25 
26 import nsk.share.*;
27 
28 import java.io.*;
29 import java.net.ServerSocket;
30 
31 /**
32  * Parser for JPDA test's launching and connection arguments.
33  * <p>
34  * <Code>DebugeeArgumentHandler</code> handles specific JDI/JDWP/JDB tests
35  * command line arguments related to launching and connection parameters
36  * for debugee VM in addition to general arguments recognized by
37  * <code>ArgumentParser</code>.
38  * <p>
39  * Following is the list of specific options for
40  * <code>DebugeeAgrumentHandler</code>:
41  * <ul>
42  * <li> <code>-test.host=</code>&lt;<i>host</i>&gt; -
43  *   address of a host where test executes
44  * <li> <code>-debugee.host=</code>&lt;<i>host</i>&gt; -
45  *   address of a host where debugee VM executes
46  * <li> <code>-connector=[attaching|listening]</code> -
47  *   connector type to connect to debugee VM
48  * <li> <code>-transport=[socket|shmem]</code> -
49  *   transport type to connect to debugee VM
50  * <li> <code>-transport.port=</code>&lt;<i>port</i>&gt; -
51  *   port number for <code>socket</code> transport
52  * <li> <code>-transport.shname=</code>&lt;<i>name</i>&gt; -
53  *   shared memory name for <code>shmem</code> transport
54  * <li> <code>-transport.address=</code>&lt;<i>dynamic</i>&gt; -
55  *   use dynamically allocated unique transport address for JDWP connection
56  *   ignoring settings for <code>-transport.port</code> and <code>-transport.shname</code>
57  *   (this works only with <code>-connector=listening</code> and <code>-transport=socket</code>)
58  * <li> <code>-debugee.suspend=[yes|no|default]</code> -
59  *   should debugee start in suspend mode or not
60  * <li> <code>-debugee.launch=[local|remote|manual]</code> -
61  *   launch and bind to debugee VM locally, remotely (via BindSever) or manually
62  * <li> <code>-debugee.vmhome=</code>&lt;<i>path</i>&gt; -
63  *   path to JDK used for launching debugee VM
64  * <li> <code>-debugee.vmkind=</code>&lt;<i>name</i>&gt; -
65  *   name of debugee VM launcher executable
66  * <li> <code>-debugee.vmkeys=</code>&lt;<i>string</i>&gt; -
67  *   additional options for launching debugee VM
68  * <li> <code>-jvmdi.strict=[yes|no|default]</code> -
69  *   using JVMDI strict mode
70  * <li> <code>-pipe.port=</code>&lt;<i>port</i>&gt; -
71  *   port number for internal IOPipe connection
72  * <li> <code>-bind.port=</code>&lt;<i>port</i>&gt; -
73  *   port number for BindServer connection
74  * </ul>
75  * <p>
76  * See also list of basic options recognized by
77  * <code>ArgumentParser</code>.
78  * <p>
79  * See also comments to <code>ArgumentParser</code> for list of general
80  * recognized options and how to work with command line arguments and options.
81  *
82  * @see ArgumentParser
83  * @see nsk.share.jdi.ArgumentHandler
84  * @see nsk.share.jdwp.ArgumentHandler
85  */
86 public class DebugeeArgumentHandler extends ArgumentParser {
87 
88     public static final String DEFAULT_PIPE_PORT                                = "7123";
89     public static final String DEFAULT_TRANSPORT_PORT                   = "8123";
90     public static final String DEFAULT_BIND_PORT                                = "9123";
91 
92 
93     /**
94      * Keep a copy of raw command-line arguments and parse them;
95      * but throw an exception on parsing error.
96      *
97      * @param  args  Array of the raw command-line arguments.
98      *
99      * @throws  BadOption  If unknown option or illegal
100      *                     option value found
101      *
102      * @see #setRawArguments(String[])
103      */
DebugeeArgumentHandler(String args[])104     public DebugeeArgumentHandler(String args[]) {
105         super(args);
106     }
107 
108     /**
109      * Return name of the host where test executes, specified by
110      * <code>-test.host</code> command line option or
111      * "<i>localhost</i>" string by default.
112      *
113      * @see #setRawArguments(String[])
114      */
getTestHost()115     public String getTestHost() {
116         return options.getProperty("test.host", "localhost");
117     }
118 
119     /**
120      * Return name of host where the debugee VM is executed, specified by
121      * <code>-debugee.host</code> command line option or value of
122      * getTestHost() by default.
123      *
124      * @see #getTestHost()
125      * @see #setRawArguments(String[])
126      */
getDebugeeHost()127     public String getDebugeeHost() {
128         return options.getProperty("debugee.host", getTestHost());
129     }
130 
131     private boolean transportPortInited = false;
132     /**
133      * Return string representation of port number for socket transport,
134      * specified by <code>-tranport.port</code> command line option or
135      * "<code>DEFAULT_TRANSPORT_PORT</code>" string by default.
136      *
137      * @see #getTransportPortIfNotDynamic()
138      * @see #getTransportPortNumber()
139      * @see #setTransportPortNumber(int)
140      * @see #setRawArguments(String[])
141      */
getTransportPort()142     synchronized public String getTransportPort() {
143         String port = options.getProperty("transport.port");
144         if (port == null) {
145             if (!transportPortInited) {
146                 port = findFreePort();
147                 if (port == null) {
148                     port = DEFAULT_TRANSPORT_PORT;
149                 }
150                 options.setProperty("transport.port", port);
151                 transportPortInited = true;
152             }
153         }
154         return port;
155     }
156 
157     /**
158      * Return string representation of port number for socket transport,
159      * specified by <code>-tranport.port</code> command line option or
160      * "<code>DEFAULT_TRANSPORT_PORT</code>" string by default in case transport address is
161      * not dynamic.
162      * Otherwise null is returned.
163      *
164      * @see #getTransportPort()
165      * @see #getTransportPortNumber()
166      * @see #setTransportPortNumber(int)
167      * @see #setRawArguments(String[])
168      */
getTransportPortIfNotDynamic()169     public String getTransportPortIfNotDynamic() {
170         return ( isTransportAddressDynamic() ?
171                     null : getTransportPort() );
172     }
173 
174     /**
175      * Return string port number for socket transport,
176      * specified by <code>-debugee.port</code> command line option or
177      * <code>DEFAULT_TRANSPORT_PORT</code> port number by default.
178      *
179      * @see #getTransportPort()
180      * @see #getTransportPortIfNotDynamic()
181      * @see #setTransportPortNumber(int)
182      * @see #setRawArguments(String[])
183      */
getTransportPortNumber()184     public int getTransportPortNumber() {
185         String value = getTransportPort();
186         try {
187             return Integer.parseInt(value);
188         } catch (NumberFormatException e) {
189             throw new TestBug("Not integer value of \"-transport.port\" argument: " + value);
190         }
191     }
192 
193     /**
194      * Add or replace value of option <code>-transport.port</code> in options list
195      * with the specified port number.
196      *
197      * @see #getTransportPortNumber()
198      * @see #setRawArguments(String[])
199      */
setTransportPortNumber(int port)200     public void setTransportPortNumber(int port) {
201         String value = Integer.toString(port);
202         setOption("-", "transport.port", value);
203     }
204 
205     /**
206      * Return shared name for shmem transport, specified by
207      * <code>-transport.shname</code> command line option, or
208      * "<i>nskjpdatestchannel</i>" + a process unique string by default.
209      *
210      * @see #setTransportSharedName(String)
211      * @see #setRawArguments(String[])
212      */
213     // Use a unique id for this process by default. This makes sure that
214     // tests running concurrently do not use the same shared name.
215     private static String defaultTransportSharedName
216             = "nskjpdatestchannel" + ProcessHandle.current().pid();
getTransportSharedName()217     public String getTransportSharedName() {
218         return options.getProperty("transport.shname", defaultTransportSharedName);
219     }
220 
221     /**
222      * Add or replace value of option <code>-transport.shname</code> in options list
223      * with the specified name.
224      *
225      * @see #getTransportSharedName()
226      * @see #setRawArguments(String[])
227      */
setTransportSharedName(String name)228     public void setTransportSharedName(String name) {
229         setOption("-", "transport.shname", name);
230     }
231 
232     /**
233      * Return <i>true</i> if <code>-transport.address=dynamic</code> command line option
234      * is specified.
235      *
236      * @see #setRawArguments(String[])
237      */
isTransportAddressDynamic()238     public boolean isTransportAddressDynamic() {
239         String value = options.getProperty("transport.address", null);
240         if (value != null && value.equals("dynamic"))
241             return true;
242         return false;
243     }
244 
245     /**
246      * Return suspend mode for launching debugee VM, specified by
247      * <code>-debugee.suspend</code> command line option, or
248      * "<i>default</i>" string by default.
249      *
250      * @see #isDefaultDebugeeSuspendMode()
251      * @see #willDebugeeSuspended()
252      * @see #setRawArguments(String[])
253      */
getDebugeeSuspendMode()254     public String getDebugeeSuspendMode() {
255         return options.getProperty("debugee.suspend", "default");
256     }
257 
258     /**
259      * Return <i>true</i> if default suspend mode is used
260      * for launching debugee VM.
261      *
262      * @see #getDebugeeSuspendMode()
263      * @see #willDebugeeSuspended()
264      */
isDefaultDebugeeSuspendMode()265     public boolean isDefaultDebugeeSuspendMode() {
266         String mode = getDebugeeSuspendMode();
267         return mode.equals("default");
268     }
269 
270     /**
271      * Return <i>true</i> if debugee VM will be suspended after launching,
272      * either according to specified suspend mode or by default.
273      *
274      * @see #getDebugeeSuspendMode()
275      * @see #isDefaultDebugeeSuspendMode()
276      */
willDebugeeSuspended()277     public boolean willDebugeeSuspended() {
278         if (isLaunchedLocally()) {
279             String mode = getDebugeeSuspendMode();
280             return mode.equals("no");
281         }
282         return true;
283     }
284 
285     private boolean pipePortInited = false;
286     /**
287      * Return string representation of the port number for IOPipe connection,
288      * specified by <code>-pipe.port</code> command line option, or
289      * "<i>DEFAULT_PIPE_PORT</i>" string by default.
290      *
291      * @see #getPipePortNumber()
292      * @see #setPipePortNumber(int)
293      * @see #setRawArguments(String[])
294      */
getPipePort()295     synchronized public String getPipePort() {
296         String port = options.getProperty("pipe.port");
297         if (port == null) {
298             if (!pipePortInited) {
299                 port = findFreePort();
300                 if (port == null) {
301                     port = DEFAULT_PIPE_PORT;
302                 }
303                 pipePortInited = true;
304                 options.setProperty("pipe.port", port);
305             }
306         }
307         return port;
308     }
309 
310     /**
311      * Return port number for IOPipe connection,
312      * specified by <code>-pipe.port</code> command line option, or
313      * <i>DEFAULT_PIPE_PORT</i> port number by default.
314      *
315      * @see #getPipePort()
316      * @see #setPipePortNumber(int)
317      * @see #setRawArguments(String[])
318      */
getPipePortNumber()319     public int getPipePortNumber() {
320         String value = getPipePort();
321         try {
322             return Integer.parseInt(value);
323         } catch (NumberFormatException e) {
324             throw new TestBug("Not integer value of \"-pipe.port\" argument: " + value);
325         }
326     }
327 
328     /**
329      * Add or replace value of option <code>-pipe.port</code> in options list
330      * with the specified port number.
331      *
332      * @see #getPipePortNumber()
333      * @see #setRawArguments(String[])
334      */
setPipePortNumber(int port)335     public void setPipePortNumber(int port) {
336         String value = Integer.toString(port);
337         setOption("-", "pipe.port", value);
338     }
339 
340     /**
341      * Return debugee VM launching mode, specified by
342      * <code>-launch.mode</code> command line option, or
343      * "<i>local</i>" string by default.
344      *
345      * Possible values for this option are:
346      * <ul>
347      * <li> "<code>local</code>"
348      * <li> "<code>remote</code>"
349      * <li> "<code>manual</code>"
350      * </ul>
351      *
352      * @see #isLaunchedLocally()
353      * @see #isLaunchedRemotely()
354      * @see #isLaunchedManually()
355      * @see #setRawArguments(String[])
356      */
getLaunchMode()357     public String getLaunchMode() {
358         return options.getProperty("debugee.launch", "local");
359     }
360 
361     /**
362      * Return <i>true</i> if debugee should be launched locally.
363      *
364      * @see #getLaunchMode()
365      */
isLaunchedLocally()366     public boolean isLaunchedLocally() {
367         return getLaunchMode().equals("local");
368     }
369 
370     /**
371      * Return <i>true</i> if debugee should be launched remotely via
372      * BindServer.
373      *
374      * @see #getLaunchMode()
375      */
isLaunchedRemotely()376     public boolean isLaunchedRemotely() {
377         return getLaunchMode().equals("remote");
378     }
379 
380     /**
381      * Return <i>true</i> if debugee should be launched manually by user.
382      *
383      * @see #getLaunchMode()
384      */
isLaunchedManually()385     public boolean isLaunchedManually() {
386         return getLaunchMode().equals("manual");
387     }
388 
389     /**
390      * Return additional options for launching debugee VM, specified by
391      * <code>-launch.options</code> command line option, or
392      * empty string by default.
393      *
394      * @see #setRawArguments(String[])
395      */
getLaunchOptions()396     public String getLaunchOptions() {
397         String result = options.getProperty("debugee.vmkeys", "").trim();
398         if (result.startsWith("\"") && result.endsWith("\"")) {
399             result = result.substring(1, result.length() - 1);
400         }
401         return result;
402     }
403 
404     /**
405      * Return name of debugee VM launcher executable, specified by
406      * <code>-launch.vmexec</code> command line option, or
407      * "<i>java</i>" string by default.
408      *
409      * @see #setRawArguments(String[])
410      */
getLaunchExecName()411     public String getLaunchExecName() {
412         return options.getProperty("debugee.vmkind", "java");
413     }
414 
415     /**
416      * Return full path to debugee VM launcher executable.
417      *
418      * @see #getLaunchExecName()
419      * @see #getLaunchExecPath(String)
420      * @see #getDebugeeJavaHome()
421      */
getLaunchExecPath()422     public String getLaunchExecPath() {
423         String java_home = getDebugeeJavaHome();
424         return getLaunchExecPath(java_home);
425     }
426 
427     /**
428      * Return full path to VM launcher executable using givet JAVA_HOME path.
429      *
430      * @see #getLaunchExecName()
431      */
getLaunchExecPath(String java_home)432     public String getLaunchExecPath(String java_home) {
433         String filesep = System.getProperty("file.separator");
434         return java_home + filesep + "bin" + filesep + getLaunchExecName();
435     }
436 
437     /**
438      * Return full JAVA_HOME path for debugee VM.
439      *
440      * @see #getLaunchExecName()
441      */
getDebugeeJavaHome()442     public String getDebugeeJavaHome() {
443         String java_home = System.getProperty("java.home");
444         return options.getProperty("debugee.vmhome", java_home);
445     }
446 
447     /**
448      * Return true if default debuggee VM launcher executable is used.
449      *
450      * @see #getLaunchExecName()
451      */
isDefaultLaunchExecName()452     public boolean isDefaultLaunchExecName() {
453         String vmkind = options.getProperty("debugee.vmkind", null);
454         return (vmkind == null);
455     }
456 
457     /**
458      * Return true if default JAVA_HOME path for debuggee VM is used.
459      *
460      * @see #getDebugeeJavaHome()
461      */
isDefaultDebugeeJavaHome()462     public boolean isDefaultDebugeeJavaHome() {
463         String java_home = options.getProperty("debugee.vmhome", null);
464         return (java_home == null);
465     }
466 
467     private boolean bindPortInited = false;
468     /**
469      * Return string representation of the port number for BindServer connection,
470      * specified by <code>-bind.port</code> command line option, or
471      * "<i>DEFAULT_BIND_PORT</i>" string by default.
472      *
473      * @see #getBindPortNumber()
474      * @see #setRawArguments(String[])
475      */
getBindPort()476     public String getBindPort() {
477         String port = options.getProperty("bind.port");
478         if (port == null) {
479             if (!bindPortInited) {
480                 port = findFreePort();
481                 if (port == null) {
482                     port = DEFAULT_BIND_PORT;
483                 }
484                 options.setProperty("bind.port", port);
485                 bindPortInited = true;
486             }
487         }
488         return port;
489     }
490 
491     /**
492      * Return port number for BindServer connection,
493      * specified by <code>-bind.port</code> command line option, or
494      * "<i>DEFAULT_BIND_PORT</i>" port number by default.
495      *
496      * @see #getBindPort()
497      * @see #setRawArguments(String[])
498      */
getBindPortNumber()499     public int getBindPortNumber() {
500         String value = getBindPort();
501         try {
502             return Integer.parseInt(value);
503         } catch (NumberFormatException e) {
504             throw new TestBug("Not integer value of \"bind.port\" argument: " + value);
505         }
506     }
507 
508     /**
509      * Return JVMDI strict mode for launching debugee VM, specified by.
510      * <code>-jvmdi.strict</code> command line option, or
511      * "<i>default</i>" string by default.
512      *
513      * Possible values for this option are:
514      * <ul>
515      * <li> "<code>yes</code>"
516      * <li> "<code>no</code>"
517      * <li> "<code>default</code>"
518      * </ul>
519      *
520      * @see #setRawArguments(String[])
521      */
getJVMDIStrictMode()522     public String getJVMDIStrictMode() {
523         return options.getProperty("jvmdi.strict", "default");
524     }
525 
526     /**
527      * Return <i>true</i> if JVMDI strict mode for launching debugeeVM is used^
528      * either by specifying in command line or by default.
529      *
530      * @see #getJVMDIStrictMode()
531      * @see #isDefaultJVMDIStrictMode()
532      * @see #setRawArguments(String[])
533      */
isJVMDIStrictMode()534     public boolean isJVMDIStrictMode() {
535         String mode = getJVMDIStrictMode();
536         return mode.equals("yes");
537     }
538 
539     /**
540      * Return <i>true</i> if JVMDI default strict mode for launching debugee VM is used.
541      *
542      * @see #getJVMDIStrictMode()
543      * @see #isJVMDIStrictMode()
544      * @see #setRawArguments(String[])
545      */
isDefaultJVMDIStrictMode()546     public boolean isDefaultJVMDIStrictMode() {
547         String mode = getJVMDIStrictMode();
548         return mode.equals("default");
549     }
550 
551     /**
552      * Return type of JDI connector used for connecting to debugee VM, specified by
553      * <code>-connector</code> command line option, or
554      * "<i>listening</i>" string by default.
555      *
556      * Possible values for this option are:
557      * <ul>
558      * <li> "<code>attaching</code>"
559      * <li> "<code>listening</code>"
560      * </ul>
561      *
562      * @see #isAttachingConnector()
563      * @see #isListeningConnector()
564      * @see #setRawArguments(String[])
565      */
getConnectorType()566     public String getConnectorType() {
567         return options.getProperty("connector", "listening");
568     }
569 
570     /**
571      * Return <i>true</i> if type of the used JDI connector is <code>attaching</code>.
572      *
573      * @see #getConnectorType()
574      */
isAttachingConnector()575     public boolean isAttachingConnector() {
576         return getConnectorType().equals("attaching");
577     }
578 
579     /**
580      * Return <i>true</i> if type of the used JDI connector is <code>listening</code>.
581      *
582      * @see #getConnectorType()
583      */
isListeningConnector()584     public boolean isListeningConnector() {
585         return getConnectorType().equals("listening");
586     }
587 
588     /**
589      * Return <i>true</i> if connector type is not actually specified.
590      * In this case getConnectorType() returns some default connector type.
591      *
592      * @see #getConnectorType()
593      */
isDefaultConnector()594     public boolean isDefaultConnector() {
595         return options.getProperty("connector") == null;
596     }
597 
598     /**
599      * Return type of JDWP transport for connecting to debugee VM, specified by
600      * <code>-transport</code> command line option, or
601      * "<i>socket</i>" string by default.
602      *
603      * Possible values for this option are:
604      * <ul>
605      * <li> "<code>socket</code>"
606      * <li> "<code>shmem</code>"
607      * </ul>
608      *
609      * @see #getTransportName()
610      * @see #isSocketTransport()
611      * @see #isShmemTransport()
612      * @see #setRawArguments(String[])
613      */
getTransportType()614     public String getTransportType() {
615         return options.getProperty("transport", "socket");
616     }
617 
618     /**
619      * Return transport name corresponding to the used JDWP transport type.
620      *
621      * @see #getTransportType()
622      */
getTransportName()623     public String getTransportName() {
624         if (isSocketTransport()) {
625             return "dt_socket";
626         } else if (isShmemTransport()) {
627             return "dt_shmem";
628         } else {
629             throw new TestBug("Undefined transport type");
630         }
631     }
632 
633     /**
634      * Return <i>true</i> if the used JDWP transport type is <code>socket</code>,
635      * either by specifying in command line or as a platform default transport.
636      *
637      * @see #getTransportType()
638      */
isSocketTransport()639     public boolean isSocketTransport() {
640         String transport = getTransportType();
641         return transport.equals("socket");
642     }
643 
644     /**
645      * Return <i>true</i> if the used JDWP transport type is <code>shmem</code>,
646      * either by specifying in command line or as a platform default transport.
647      *
648      * @see #getTransportType()
649      */
isShmemTransport()650     public boolean isShmemTransport() {
651         String transport = getTransportType();
652         return transport.equals("shmem");
653     }
654 
655     /**
656      * Return <i>true</i> if transport type is not actually specified.
657      * In this case getTransportType() returns some default transport kind.
658      *
659      * @see #getTransportType()
660      */
isDefaultTransport()661     public boolean isDefaultTransport() {
662         return options.getProperty("transport") == null;
663     }
664 
665     /**
666      * Create <code>Log</code> for debugee application using command line options.
667      */
createDebugeeLog()668     public Log createDebugeeLog() {
669         return new Log(System.err, this);
670     };
671 
672     /**
673      * Create IOPipe for debugee application using command line options.
674      */
createDebugeeIOPipe()675     public IOPipe createDebugeeIOPipe() {
676         return createDebugeeIOPipe(createDebugeeLog());
677     };
678 
679     /**
680      * Create IOPipe for debugee application using connection
681      * parameters from the command line and specify Log.
682      */
createDebugeeIOPipe(Log log)683     public IOPipe createDebugeeIOPipe(Log log) {
684         return new IOPipe(this, log);
685     };
686 
687     /**
688      * Check if an option is aloowed and has proper value.
689      * This method is invoked by <code>parseArgumentss()</code>
690      *
691      * @param option option name
692      * @param value string representation of value
693      *                      (could be an empty string too)
694      *              null if this option has no value
695      * @return <i>true</i> if option is allowed and has proper value
696      *         <i>false</i> if otion is not admissible
697      *
698      * @throws <i>BadOption</i> if option has an illegal value
699      *
700      * @see #parseArguments()
701      */
checkOption(String option, String value)702     protected boolean checkOption(String option, String value) {
703 
704         if(option.equals("traceAll"))
705             return true;
706 
707         // option with any string value
708         if (option.equals("debugee.vmkeys")) {
709             return true;
710         }
711 
712         // option with any nonempty string value
713         if (option.equals("test.host")
714             || option.equals("debugee.host")
715             || option.equals("debugee.vmkind")
716             || option.equals("debugee.vmhome")
717             || option.equals("transport.shname")) {
718             if (value.length() <= 0) {
719                 throw new BadOption(option + ": cannot be an empty string");
720             }
721             return true;
722         }
723 
724         // option with positive integer port value
725         if (option.equals("transport.port")
726             || option.equals("bind.port")
727             || option.equals("pipe.port")) {
728             try {
729                 int number = Integer.parseInt(value);
730                 if (number < 0) {
731                     throw new BadOption(option + ": must be a positive integer");
732                 }
733             } catch (NumberFormatException e) {
734                 throw new BadOption(option + ": must be an integer");
735             }
736             return true;
737         }
738 
739         // options with enumerated values
740 
741         if (option.equals("debugee.suspend")) {
742             if ((!value.equals("yes"))
743                 && (!value.equals("no"))
744                 && (!value.equals("default"))) {
745                 throw new BadOption(option + ": must be one of: "
746                                            + "yes, no, default");
747             }
748             return true;
749         }
750 
751         if (option.equals("debugee.launch")) {
752             if ((!value.equals("local"))
753                 && (!value.equals("remote"))
754                 && (!value.equals("manual"))) {
755                 throw new BadOption(option + ": must be one of: "
756                                            + "local, remote, manual " + value);
757             }
758             return true;
759         }
760 
761         if (option.equals("jvmdi.strict")) {
762             if ((!value.equals("yes"))
763                 && (!value.equals("no"))
764                 && (!value.equals("default"))) {
765                 throw new BadOption(option + ": must be one of: "
766                                            + "yes, no, default");
767             }
768             return true;
769         }
770 
771         if (option.equals("transport")) {
772             if ((!value.equals("socket"))
773                 && (!value.equals("shmem"))) {
774                 throw new BadOption(option + ": must be one of: "
775                                            + "socket, shmem");
776             }
777             return true;
778         }
779 
780         if (option.equals("connector")) {
781             if ((!value.equals("attaching"))
782                 && (!value.equals("listening"))) {
783                 throw new BadOption(option + ": value must be one of: "
784                                            + "attaching, listening");
785             }
786             return true;
787         }
788 
789         if (option.equals("transport.address")) {
790             if (!value.equals("dynamic")) {
791                 throw new BadOption(option + ": must be only: "
792                                            + "dynamic");
793             }
794             return true;
795         }
796 
797         return super.checkOption(option, value);
798     }
799 
800     /**
801      * Check if the values of all options are consistent.
802      * This method is invoked by <code>parseArguments()</code>
803      *
804      * @throws <i>BadOption</i> if options have inconsistent values
805      *
806      * @see #parseArguments()
807      */
checkOptions()808     protected void checkOptions() {
809         super.checkOptions();
810     }
811 
findFreePort()812     private String findFreePort() {
813         ServerSocket ss = null;
814         try {
815             ss = new ServerSocket(0);
816             return String.valueOf(ss.getLocalPort());
817         } catch (IOException e) {
818             return null;
819         } finally {
820             try {
821                 ss.close();
822             } catch (Throwable t) {
823                 // ignore
824             }
825         }
826     }
827 
828 } // DebugeeArgumentHandler
829