1/*
2 * Copyright (c) 2005, 2015, 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
24import java.util.Map;
25import java.util.HashMap;
26import java.util.Properties;
27import java.lang.reflect.Method;
28import javax.management.remote.JMXConnectorServerMBean;
29
30// utility class for MXBean* tests coming from JMX Tonga test suite
31class Utils {
32
33    // DEBUG is printed depending on the DEBUG and DEBUG_LEVEL JAVA property
34    private static final String DEBUG_HEADER = "[debug] ";
35
36    // DEBUG levels
37    private static int selectedDebugLevel = 0;
38    static final int DEBUG_STANDARD = 1;
39    static final int DEBUG_VERBOSE = 2;  // Mainly used for stress tests
40    static final int DEBUG_ALL = DEBUG_STANDARD | DEBUG_VERBOSE;
41
42    static void parseDebugProperties() {
43        int level = 0;
44        Properties p = System.getProperties();
45
46        // get selected levels
47        if (p.getProperty("DEBUG_STANDARD") != null) {
48            level |= DEBUG_STANDARD;
49        }
50
51        if (p.getProperty("DEBUG_VERBOSE") != null) {
52            level |= DEBUG_VERBOSE;
53        }
54
55        if (p.getProperty("DEBUG_ALL") != null) {
56            level |= DEBUG_ALL;
57        }
58
59        selectedDebugLevel = level;
60    }
61
62    /**
63     * Reproduces the original parsing and collection of test parameters
64     * from the DTonga JMX test suite.
65     *
66     * Collects passed args and returns them in a map(argname, value) structure,
67     * which will be then propagated as necessary to various called methods.
68     */
69    static Map<String, Object> parseParameters(String args[])
70    throws Exception {
71        Utils.debug(DEBUG_STANDARD, "TestRoot::parseParameters: Start");
72        HashMap<String, Object> map = new HashMap<>();
73
74        for ( int i = 0; i < args.length; i++ ) {
75            if ( args[i].trim().startsWith("-") ) {
76                if ((i+1) < args.length && !args[i+1].startsWith("-") ) {
77                    Utils.debug(DEBUG_STANDARD,
78                        "TestRoot::parseParameters: added in map = " +
79                        args[i] +
80                        " with value " +
81                        args[i+1]) ;
82                    map.put(args[i].trim(), args[i+1].trim()) ;
83                } else if ((i+1) < args.length && args[i+1].startsWith("-") ||
84                           (i+1) == args.length ) {
85                    Utils.debug(DEBUG_STANDARD,
86                            "TestRoot::parseParameters: added in map = " +
87                            args[i] +
88                            " with null value") ;
89                    map.put(args[i].trim(), null) ;
90                } else {
91                    System.out.println(
92                        "TestRoot::parseParameters: (WARNING) not added in map = " +
93                        args[i]) ;
94                }
95            }
96        }
97
98        Utils.debug(DEBUG_STANDARD, "TestRoot::parseParameters: Done") ;
99        return map ;
100    }
101
102    /**
103     * This method is to be used in all tests to print anything
104     * that is temporary.
105     * Printing is done only when debug is activated by the property DEBUG.
106     * Printing depends also on the DEBUG_LEVEL property.
107     * Here it encapsulates a System.out.println.
108     */
109    public static void debug(int level, String line) {
110        if ((selectedDebugLevel & level) != 0) {
111            System.out.println(DEBUG_HEADER + line);
112        }
113    }
114
115    /**
116     * Do print stack trace when withStack is true.
117     * Does try to call getTargetException() and getTargetError() then
118     * print embedded stacks in the case of an Exception wrapping
119     * another Exception or an Error. Recurse until no more wrapping
120     * is found.
121     */
122    public static void printThrowable(Throwable theThro, boolean withStack) {
123        try {
124            if (withStack) {
125                theThro.printStackTrace(System.out);
126            }
127            if (theThro instanceof Exception) {
128                Exception t = (Exception) theThro;
129                Method target = null;
130                String blank = " ";
131                try {
132                    target = t.getClass().getMethod("getTargetException",
133                            (java.lang.Class<?>[]) null);
134                } catch (Exception ee) {
135                // OK: getTargetException method could be there or not
136                }
137                System.out.println(blank + t.getClass() + "==>" + t.getMessage());
138                while (target != null) {
139                    try {
140                        t = (Exception) target.invoke(t,
141                                (java.lang.Object[]) null);
142                    } catch (Exception ee) {
143                        t = null;
144                    }
145                    try {
146                        if (t != null) {
147                            blank = blank + "  ";
148                            System.out.println(blank + t.getClass() + "==>" +
149                                    t.getMessage());
150                            try {
151                                target =
152                                        t.getClass().getMethod("getTargetException",
153                                        (java.lang.Class<?>[]) null);
154                            } catch (Exception ee) {
155                            // OK: getTargetException method could be there or not                            }
156                            }
157                        } else {
158                            target = null;
159                        }
160                    } catch (Exception ee) {
161                        target = null;
162                    }
163                }
164
165                // We may have exceptions wrapping an Error then it is
166                // getTargetError that is likely to be called
167                try {
168                    target = ((Exception) theThro).getClass().getMethod("getTargetError",
169                            (java.lang.Class<?>[]) null);
170                } catch (Exception ee) {
171                // OK: getTargetError method could be there or not
172                }
173                Throwable err = theThro;
174                while (target != null) {
175                    try {
176                        err = (Error) target.invoke(err,
177                                (java.lang.Object[]) null);
178                    } catch (Exception ee) {
179                        err = null;
180                    }
181                    try {
182                        if (err != null) {
183                            blank = blank + "  ";
184                            System.out.println(blank + err.getClass() + "==>" +
185                                    err.getMessage());
186                            if (withStack) {
187                                err.printStackTrace(System.out);
188                            }
189                            try {
190                                target = err.getClass().getMethod("getTargetError",
191                                        (java.lang.Class<?>[]) null);
192                            } catch (Exception ee) {
193                            // OK: getTargetError method could be there or not
194                            }
195                        } else {
196                            target = null;
197                        }
198                    } catch (Exception ee) {
199                        target = null;
200                    }
201                }
202            } else {
203                System.out.println("Throwable is : " + theThro);
204            }
205        } catch (Throwable x) {
206            System.out.println("Exception : raised in printException : " + x);
207        }
208    }
209
210    /**
211     * Wait up to maxTimeInSeconds second(s) the given JMX connector server
212     * comes up (which means isActive returns true).
213     * If it fails to do so we throw a RunTime exception.
214     */
215    public static void waitReady(JMXConnectorServerMBean server,
216                                 int maxTimeInSeconds) throws Exception {
217        int elapsed = 0;
218
219        while (!server.isActive() && elapsed < maxTimeInSeconds) {
220            Thread.sleep(1000);
221            elapsed++;
222        }
223
224        if (server.isActive()) {
225            String message = "Utils::waitReady: JMX connector server came up";
226            if ( elapsed == 0) {
227                message += " immediately";
228            } else {
229                message += " after " + elapsed + " seconds";
230            }
231            message += " [" + server.getAddress() + "]";
232            Utils.debug(DEBUG_STANDARD, message);
233        } else {
234            String message = "Utils::waitReady: (ERROR) JMX connector" +
235                    " server didn't come up after " + elapsed + " seconds [" +
236                    server.getAddress() + "]";
237            System.out.println(message);
238            throw new RuntimeException(message);
239        }
240    }
241}
242