1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *
15 *  See the License for the specific language governing permissions and
16 *  limitations under the License.
17 */
18
19/**
20 * @author Vitaly A. Provodin
21 */
22
23/**
24 * Created on 26.01.2005
25 */
26package org.apache.harmony.jpda.tests.framework;
27
28import java.util.HashMap;
29
30/**
31 * This class provides access to options for running JPDA tests.
32 * <p>
33 * The settings are presented as a set of getters and setters for test options,
34 * which can be implemented in different ways. In this implementation test
35 * options are implemented via VM system properties, which can be specified
36 * using option '-D' in VM command line.
37 * <p>
38 * The following options are currently recognized:
39 * <ul>
40 * <li><code>jpda.settings.debuggeeJavaHome</code>
41 *   - path to Java bundle to run debuggee on
42 * <li><code>jpda.settings.debuggeeJavaExec</code>
43 *   - name of Java executable to run debuggee on
44 * <li><code>jpda.settings.debuggeeJavaPath</code>
45 *   - full path to Java executable to run debuggee on
46 * <li><code>jdpa.settings.debuggeeAgentArgument</code>
47 *   - Command-line argument for agent native library. Defaults to "-agentlib:"
48 * <li><code>jpda.settings.debuggeeAgentName</code>
49 *   - name of agent native library
50 * <li><code>jpda.settings.debuggeeAgentExtraOptions</code>
51 *   - extra options for agent
52 * <li><code>jpda.settings.debuggeeClasspath</code>
53 *   - classpath to run debuggee with
54 * <li><code>jpda.settings.debuggeeClassName</code>
55 *   - full name of class to run debuggee with
56 * <li><code>jpda.settings.debuggeeVMExtraOptions</code>
57 *   - extra options to run debuggee with
58 * <li><code>jpda.settings.debuggeeSuspend</code>
59 *   - debuggee suspend mode ("y"|"n")
60 * <li><code>jpda.settings.transportWrapperClass</code>
61 *   - class name of TransportWrapper implementation
62 * <li><code>jpda.settings.transportAddress</code>
63 *   - address for JDWP connection
64 * <li><code>jpda.settings.connectorKind</code>
65 *   - type of JDWP connection (attach or listen)
66 * <li><code>jpda.settings.syncPort</code>
67 *   - port number for sync connection (chosen by the OS if not set or set to 0)
68 * <li><code>jpda.settings.timeout</code>
69 *   - timeout used in JPDA tests
70 * <li><code>jpda.settings.waitingTime</code>
71 *   - timeout for waiting events
72 * </ul>
73 * <li><code>jpda.settings.dumpProcess</code>
74 *   - Command to dump a process' data
75 * </ul>
76 * <li><code>jpda.settings.verbose</code>
77 *   - flag that disables (default) or enables writing messages to the log
78 * </ul>
79 * All options have default values, if they are not specified.
80 *
81 */
82public class TestOptions {
83
84    /** Default timeout value for various operations. */
85    public static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; // 1 minute
86
87    /** Default time interval for waiting for various events. */
88    public static final int DEFAULT_WAITING_TIME = DEFAULT_TIMEOUT;
89
90    /** Default static address for transport connection. */
91    public static final String DEFAULT_ATTACHING_ADDRESS = "127.0.0.1:9898";
92
93    /** Default port number for sync connection. */
94    public static final String DEFAULT_STATIC_SYNC_PORT = "9797";
95
96    /** Default port number for sync connection. */
97    public static final int DEFAULT_SYNC_PORT = 0;
98
99    /** Default class name for transport wrapper. */
100    public static final String DEFAULT_TRANSPORT_WRAPPER
101        = "org.apache.harmony.jpda.tests.framework.jdwp.SocketTransportWrapper";
102
103    /** Default aclass name for debuggee application. */
104    public static final String DEFAULT_DEBUGGEE_CLASS_NAME
105        = "org.apache.harmony.jpda.tests.jdwp.share.debuggee.HelloWorld";
106
107    // current waiting time value (negative means using default value)
108    private long waitingTime = -1;
109
110    // current timeout value (negative means using default value)
111    private long timeout = -1;
112
113    // internally set property values
114    private HashMap<String, String> internalProperties = new HashMap<>();
115
116    /**
117     * Constructs an instance of this class.
118     */
119    public TestOptions() {
120        super();
121    }
122
123    /**
124     * Gets the command line needed to get backtraces/status of a given pid
125     */
126    public String getDumpProcessCommand() {
127      return getProperty("jpda.settings.dumpProcess", "true");
128    }
129
130    /**
131     * Returns path to Java bundle to run debuggee on.
132     *
133     * @return option "jpda.settings.debuggeeJavaHome" or system property
134     *         "java.home" by default.
135     */
136    public String getDebuggeeJavaHome() {
137        return getProperty("jpda.settings.debuggeeJavaHome", getProperty("java.home", null));
138    }
139
140    /**
141     * Returns name of Java executable to run debuggee on.
142     *
143     * @return option "jpda.settings.debuggeeJavaExec" or "java" by default.
144     */
145    public String getDebuggeeJavaExec() {
146        return getProperty("jpda.settings.debuggeeJavaExec", "java");
147    }
148
149    /**
150     * Returns full path to Java executable to run debuggee on.
151     *
152     * @return option "jpda.settings.debuggeeJavaPath" or construct path from
153     *         getDebuggeeJavaHome() and getDebuggeeJavaExec() by default.
154     */
155    public String getDebuggeeJavaPath() {
156        return getProperty("jpda.settings.debuggeeJavaPath",
157                getDebuggeeJavaHome() + "/bin/" + getDebuggeeJavaExec());
158    }
159
160    /**
161     * Returns class name of TransportWrapper implementation.
162     *
163     * @return option "jpda.settings.transportWrapperClass" or
164     *         DEFAULT_TRANSPORT_WRAPPER by default.
165     */
166    public String getTransportWrapperClassName() {
167        return getProperty("jpda.settings.transportWrapperClass",
168                DEFAULT_TRANSPORT_WRAPPER);
169    }
170
171    /**
172     * Returns address for JDWP connection or null for dynamic address.
173     *
174     * @return option "jpda.settings.transportAddress" or null by default.
175     */
176    public String getTransportAddress() {
177        return getProperty("jpda.settings.transportAddress", null);
178    }
179
180    /**
181     * Sets address to attach to debuggee.
182     *
183     * @param address to attach
184     */
185    public void setTransportAddress(String address) {
186        setProperty("jpda.settings.transportAddress", address);
187    }
188
189    /**
190     * Returns command line argument to use with name of JDWP agent library.
191     *
192     * @return option "jpda.settings.debuggeeAgentArgument" or "-agentlib:" by default
193     */
194    public String getDebuggeeAgentArgument() {
195        return getProperty("jpda.settings.debuggeeAgentArgument", "-agentlib:");
196    }
197
198    /**
199     * Returns name of JDWP agent library.
200     *
201     * @return option "jpda.settings.debuggeeAgentName" or "jdwp" by default
202     */
203    public String getDebuggeeAgentName() {
204        return getProperty("jpda.settings.debuggeeAgentName", "jdwp");
205    }
206
207    /**
208     * Returns string with extra options for agent.
209     *
210     * @return option "jpda.settings.debuggeeAgentExtraOptions" or "" by default
211     */
212    public String getDebuggeeAgentExtraOptions() {
213        return getProperty("jpda.settings.debuggeeAgentExtraOptions", "");
214    }
215
216    /**
217     * Returns string with all options for agent including specified connection
218     * address.
219     *
220     * @param address - address to attach
221     * @param isDebuggerListen - true if debugger is listening for connection
222     *
223     * @return string with all agent options
224     */
225    public String getDebuggeeAgentOptions(String address, boolean isDebuggerListen) {
226        String serv;
227        if (isDebuggerListen) {
228            serv = "n";
229        } else {
230            serv = "y";
231        }
232
233        // add ',' to agent extra options if required
234        String agentExtraOptions = getDebuggeeAgentExtraOptions();
235        if (agentExtraOptions.length() > 0 && agentExtraOptions.charAt(0) != ',') {
236            agentExtraOptions = "," + agentExtraOptions;
237        }
238
239        return getProperty("jpda.settings.debuggeeAgentOptions",
240                "transport=dt_socket,address=" + address + ",server=" + serv
241                + ",suspend=" + getDebuggeeSuspend() + agentExtraOptions);
242    }
243
244    /**
245     * Returns VM classpath value to run debuggee with.
246     *
247     * @return option "jpda.settings.debuggeeClasspath" or system property "java.class.path" by
248     * default.
249     */
250    public String getDebuggeeClassPath() {
251        return getProperty("jpda.settings.debuggeeClasspath", getProperty("java.class.path", null));
252    }
253
254    /**
255     * Returns full name of the class to start debuggee with.
256     *
257     * @return option "jpda.settings.debuggeeClassName" or
258     *         "org.apache.harmony.jpda.tests.jdwp.share.debuggee.HelloWorld" by default
259     */
260    public String getDebuggeeClassName() {
261        return getProperty("jpda.settings.debuggeeClassName", DEFAULT_DEBUGGEE_CLASS_NAME);
262    }
263
264    /**
265     * Sets full name of the class to start debuggee with.
266     *
267     * @param className
268     *            full class name
269     */
270    public void setDebuggeeClassName(String className) {
271        setProperty("jpda.settings.debuggeeClassName", className);
272    }
273
274    /**
275     * Returns string with extra options to start debuggee with.
276     *
277     * @return option "jpda.settings.debuggeeVMExtraOptions" or "" by default
278     */
279    public String getDebuggeeVMExtraOptions() {
280        String extOpts = getProperty("jpda.settings.debuggeeVMExtraOptions", "");
281        extOpts = extOpts + " -Djpda.settings.verbose=" + isVerbose();
282        return extOpts;
283    }
284
285    /**
286     * Returns debuggee suspend mode ("y"|"n").
287     *
288     * @return option "jpda.settings.debuggeeSuspend" or "y" by default
289     */
290    public String getDebuggeeSuspend() {
291        return getProperty("jpda.settings.debuggeeSuspend", "y");
292    }
293
294    /**
295     * Returns debuggee suspend mode ("y"|"n").
296     *
297     * @param mode
298     *            suspend mode
299     */
300    public void setDebuggeeSuspend(String mode) {
301        setProperty("jpda.settings.debuggeeSuspend", mode);
302    }
303
304    /**
305     * Checks if debuggee is launched in suspend mode.
306     *
307     * @return true if debuggee is launched in suspend mode
308     */
309    public boolean isDebuggeeSuspend() {
310        return getDebuggeeSuspend().equals("y");
311    }
312
313    /**
314     * Returns string representation of TCP/IP port for synchronization channel.
315     *
316     * @return string with port number or null
317     */
318    public String getSyncPortString() {
319        return getProperty("jpda.settings.syncPort", null);
320    }
321
322    /**
323     * Returns type of connection with debuggee.
324     *
325     * @return system property "jpda.settings.connectorKind" or "listen" by default.
326     */
327    public String getConnectorKind() {
328        return getProperty("jpda.settings.connectorKind", "listen");
329    }
330
331    /**
332     * Checks if attach connection with debuggee.
333     *
334     * @return true, if attach connection, false otherwise.
335     */
336    public boolean isAttachConnectorKind() {
337        return ((getConnectorKind()).equals("attach"));
338
339    }
340
341    /**
342     * Checks if listen connection with debuggee.
343     *
344     * @return true, if listen connection, false otherwise.
345     */
346    public boolean isListenConnectorKind() {
347        return (getConnectorKind().equals("listen"));
348    }
349
350    /**
351     * Sets connectorKind to attach to debuggee.
352     */
353    public void setAttachConnectorKind() {
354        setConnectorKind("attach");
355    }
356
357    /**
358     * Sets connectorKind to listen connection from debuggee.
359     */
360    public void setListenConnectorKind() {
361        setConnectorKind("listen");
362    }
363
364    /**
365     * Sets kind of connector (attach or listen).
366     */
367    public void setConnectorKind(String kind) {
368        setProperty("jpda.settings.connectorKind", kind);
369    }
370
371    /**
372     * Returns kind of launching debuggee VM, which can be "auto" or "manual".
373     *
374     * @return option "jpda.settings.debuggeeLaunchKind" or "auto" by default.
375     */
376    public String getDebuggeeLaunchKind() {
377        return getProperty("jpda.settings.debuggeeLaunchKind", "auto");
378    }
379
380    /**
381     * Returns TCP/IP port for synchronization channel.
382     *
383     * @return port number if it is set, or DEFAULT_SYNC_PORT otherwise.
384     */
385    public int getSyncPortNumber() {
386        String buf = getSyncPortString();
387        if (buf == null) {
388            return DEFAULT_SYNC_PORT;
389        }
390
391        try {
392            return Integer.parseInt(buf);
393        } catch (NumberFormatException e) {
394            throw new TestErrorException(e);
395        }
396    }
397
398    /**
399     * Returns timeout for JPDA tests in milliseconds.
400     *
401     * @return option "jpda.settings.timeout" or DEFAULT_TIMEOUT by default.
402     */
403    public long getTimeout() {
404        if (timeout < 0) {
405            timeout = DEFAULT_TIMEOUT;
406            String buf = getProperty("jpda.settings.timeout", null);
407            if (buf != null) {
408                try {
409                    timeout = Long.parseLong(buf);
410                } catch (NumberFormatException e) {
411                    throw new TestErrorException(e);
412                }
413            }
414        }
415        return timeout;
416    }
417
418    /**
419     * Sets timeout for JPDA tests in milliseconds.
420     *
421     * @param timeout
422     *            timeout to be set
423     */
424    public void setTimeout(long timeout) {
425        if (timeout < 0) {
426            throw new TestErrorException("Cannot set negative timeout value: "
427                    + timeout);
428        }
429        this.timeout = timeout;
430    }
431
432    /**
433     * Returns waiting time for events in milliseconds.
434     *
435     * @return waiting time
436     */
437    public long getWaitingTime() {
438        if (waitingTime < 0) {
439            waitingTime = DEFAULT_WAITING_TIME;
440            String buf = getProperty("jpda.settings.waitingTime", null);
441            if (buf != null) {
442                try {
443                    waitingTime = Long.parseLong(buf);
444                } catch (NumberFormatException e) {
445                    throw new TestErrorException(e);
446                }
447            }
448        }
449        return waitingTime;
450    }
451
452    /**
453     * Sets waiting time for events in milliseconds.
454     *
455     * @param waitingTime
456     *            waiting time to be set
457     */
458    public void setWaitingTime(long waitingTime) {
459        this.waitingTime = waitingTime;
460    }
461
462    /**
463     * Returns whether print to log is enabled.
464     *
465     * @return false (default) if log is disabled or true otherwise.
466     */
467    public boolean isVerbose() {
468        return isTrue(getProperty("jpda.settings.verbose", "true"));
469    }
470
471    /**
472     * Converts text to boolean.
473     *
474     * @param str string representing boolean value
475     * @return boolean
476     */
477    static public boolean isTrue(String str) {
478        return str != null && (
479            str.equalsIgnoreCase("true") ||
480            str.equalsIgnoreCase("yes") ||
481            str.equalsIgnoreCase("on") ||
482            str.equals("1"));
483    }
484
485    /**
486     * Returns value of given property if it was set internally or specified in system properties.
487     *
488     * @param name
489     *           property name
490     * @param defaultValue
491     *           default value for given property
492     * @return string value of given property or default value if no such property found
493     */
494    protected String getProperty(String name, String defaultValue) {
495        String value = internalProperties.get(name);
496        if (value != null) {
497            return value;
498        }
499        return System.getProperty(name, defaultValue);
500    }
501
502    /**
503     * Sets internal value of given property to override corresponding system property.
504     *
505     * @param name
506     *           proparty name
507     * @param value
508     *           value for given property
509     */
510    protected void setProperty(String name, String value) {
511        internalProperties.put(name, value);
512    }
513
514}
515