1/*
2 * Copyright (c) 2006, 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
24/*
25 * @test
26 * @bug 8058865
27 * @summary Tests most of the existing query types.
28 * @author Olivier Lagneau
29 * @modules java.management.rmi
30 * @compile TestQuery.java
31 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SupportedQueryTypesTest -mbeanClassName TestQuery
32 */
33
34import java.util.Map ;
35import java.util.HashMap;
36import java.util.Set;
37import java.util.HashSet;
38import java.util.Iterator;
39import java.util.Properties;
40import java.lang.reflect.Method;
41
42import java.lang.management.ManagementFactory;
43import javax.management.MBeanServer;
44import javax.management.MBeanServerFactory;
45import javax.management.MBeanServerConnection;
46import javax.management.ObjectInstance;
47import javax.management.ObjectName ;
48import javax.management.QueryExp;
49
50import javax.management.remote.JMXConnector;
51import javax.management.remote.JMXConnectorFactory;
52import javax.management.remote.JMXConnectorServer;
53import javax.management.remote.JMXConnectorServerFactory;
54import javax.management.remote.JMXServiceURL;
55
56public class SupportedQueryTypesTest {
57
58    protected String mbeanClassName = null;
59
60    private MBeanServerConnection mbsc = null;
61
62
63    /*
64     * First Debug properties and arguments are collect in expected
65     * map  (argName, value) format, then calls original test's run method.
66     */
67    public static void main(String args[]) throws Exception {
68
69        System.out.println("=================================================");
70
71        // Parses parameters
72        Utils.parseDebugProperties();
73        Map<String, Object> map = Utils.parseParameters(args) ;
74
75        // Run test
76        SupportedQueryTypesTest test = new SupportedQueryTypesTest();
77        test.run(map);
78
79    }
80
81    public void run(Map<String, Object> args) {
82        int errorCount = 0;
83
84        ObjectName on = null;
85        ObjectName serverDelegateObjectName = null;
86
87        JMXConnectorServer cs = null;
88        JMXConnector cc = null;
89
90        System.out.println("SupportedQueryTypesTest::run: Start") ;
91        try {
92            // JMX MbeanServer used inside single VM as if remote.
93            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
94
95            JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
96            cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
97            cs.start();
98
99            JMXServiceURL addr = cs.getAddress();
100            cc = JMXConnectorFactory.connect(addr);
101            mbsc = cc.getMBeanServerConnection();
102
103
104            // Create and register the ServerDelegate MBean on the remote MBeanServer
105            String serverDelegateClassName = ServerDelegate.class.getName();
106            serverDelegateObjectName =
107                    new ObjectName("defaultDomain:class=" + serverDelegateClassName);
108            mbsc.createMBean(serverDelegateClassName, serverDelegateObjectName);
109
110            // Retrieve the MBean class name
111            mbeanClassName = (String) args.get("-mbeanClassName") ;
112            on = new ObjectName("defaultDomain:class=" + mbeanClassName);
113
114            // Create and register the MBean on the remote MBeanServer
115            System.out.println("SupportedQueryTypesTest::run: CREATE " +
116                    mbeanClassName + " on the remote MBeanServer with name "
117                    + on);
118            mbsc.createMBean(mbeanClassName, on);
119
120            // Create a QueryFactory and setup which query we'll use.
121            QueryFactory queries = new QueryFactory(mbeanClassName);
122            queries.buildQueries();
123            int maxIndex = queries.getSize();
124            int minIndex = 1;
125
126            // Create a reference Set<ObjectName> to check later on
127            // the queryNames() results
128            Set<ObjectName> referenceNameSet = new HashSet<ObjectName>();
129            referenceNameSet.add(on);
130
131            // Create a reference Set<ObjectInstance> to check later on
132            // the queryMBeans() results
133            ObjectInstance oi = new ObjectInstance(on, mbeanClassName);
134            Set<ObjectInstance> referenceInstanceSet =
135                    new HashSet<ObjectInstance>();
136            referenceInstanceSet.add(oi);
137
138            // Perform the queryNames and queryMBeans requests
139            for (int i = minIndex; i <= maxIndex; i++ ) {
140                QueryExp query = queries.getQuery(i);
141                System.out.println("----");
142                System.out.println("SupportedQueryTypesTest::run: Query # " + i);
143                System.out.println("query " + query);
144                errorCount +=
145                    doQueryNames(query, referenceNameSet);
146                errorCount +=
147                    doQueryMBeans(query, referenceInstanceSet);
148            }
149
150        } catch(Exception e) {
151            Utils.printThrowable(e, true);
152            errorCount++;
153
154        } finally {
155            // Do unregister the MBean
156            try {
157                if (mbsc.isRegistered(on)) {
158                    mbsc.unregisterMBean(on);
159                }
160                if (mbsc.isRegistered(serverDelegateObjectName)) {
161                    mbsc.unregisterMBean(serverDelegateObjectName);
162                }
163            } catch (Exception e) {
164                Utils.printThrowable(e, true) ;
165                errorCount++;
166            }
167
168            try {
169                // Close JMX Connector Client
170                cc.close();
171                // Stop connertor server
172                cs.stop();
173
174            } catch (Exception e) {
175                Utils.printThrowable(e, true) ;
176                errorCount++;
177            }
178        }
179
180        System.out.println("");
181        System.out.println("SupportedQueryTypesTest::run: Done") ;
182
183        // Handle result
184        if (errorCount == 0) {
185            System.out.println("SupportedQueryTypesTest::run: (OK)");
186        } else {
187            String message = "SupportedQueryTypesTest::run: (ERROR) Got " +
188                    + errorCount + " error(s)";
189            System.out.println(message);
190            throw new RuntimeException(message);
191        }
192    }
193
194
195    private int doQueryNames(QueryExp query, Set<ObjectName> referenceSet) {
196        int errorCount = 0;
197        System.out.println(" <*> Perform queryNames call ");
198
199        try {
200            // Call queryNames on the remote MBeanServer
201            Set<ObjectName> remoteSet =  mbsc.queryNames(null, query);
202
203            // Compare the 2 Set<ObjectName>
204            errorCount += checkSet(remoteSet, referenceSet);
205
206            // Cleaning
207            remoteSet.clear();
208
209        } catch (Exception e) {
210            Utils.printThrowable(e, true);
211            errorCount++;
212        }
213
214        if ( errorCount == 0 ) {
215            System.out.println("\t(OK)");
216        } else {
217            System.out.println("\t(ERROR) Query failed");
218        }
219
220        return errorCount;
221    }
222
223
224    private int doQueryMBeans(QueryExp query, Set<ObjectInstance> referenceSet) {
225        int errorCount = 0;
226        System.out.println(" <*> Perform queryMBeans call ");
227
228        try {
229            // Call queryMBeans on the remote MBeanServer
230            Set<ObjectInstance> remoteSet =  mbsc.queryMBeans(null, query);
231
232            // Compare the 2 Set<ObjectInstance>
233            errorCount += checkSet(remoteSet, referenceSet);
234
235            // Cleaning
236            remoteSet.clear();
237
238        } catch (Exception e) {
239            Utils.printThrowable(e, true);
240            errorCount++;
241        }
242
243        if ( errorCount == 0 ) {
244            System.out.println("\t(OK)");
245        } else {
246            System.out.println("\t(ERROR) Query failed");
247        }
248
249        return errorCount;
250    }
251
252    /**
253     * Pretty print of a Set content.
254     * When the Set isn't empty, toString() is called on each element.
255     * <br>The variable's name used to hold that Set is given via the setName
256     * parameter and used in the output.
257     */
258    private static void printSet(Set<?> printableSet, String setName) {
259        if ( printableSet.size() == 0 ) {
260            System.out.println("The Set " + setName + " is empty");
261        } else {
262            System.out.println("The Set " + setName + " contains :");
263
264            for (Iterator<?> it = printableSet.iterator(); it.hasNext();) {
265                Object elem = it.next();
266                System.out.println("\t" + elem.toString());
267            }
268        }
269    }
270
271
272    /**
273     * This method check the Set remoteSet is equal to
274     * the reference Set referenceSet,
275     * which means same size and content (order doesn't matter).
276     * <br>It returns 0 when the check is fine, otherwise 1.
277     */
278    private int checkSet(Set<?> remoteSet, Set<?> referenceSet) {
279        if ( !  remoteSet.equals(referenceSet) ) {
280            System.out.println("SupportedQueryTypesTest::checkSet:"
281                    + " (ERROR) Set aren't as expected");
282            printSet(remoteSet, "remoteSet");
283            printSet(referenceSet, "referenceSet");
284            return 1;
285        } else {
286            return 0;
287        }
288    }
289
290    // Utility inner class coming from JMX Tonga test suite.
291    private static class Utils {
292
293        // DEBUG is printed depending on the DEBUG and DEBUG_LEVEL JAVA property
294        static final String DEBUG_HEADER = "[debug] ";
295
296        // DEBUG levels
297        static int selectedDebugLevel = 0;
298        static final int DEBUG_STANDARD = 1;
299        static final int DEBUG_VERBOSE = 2;  // Mainly used for stress tests
300        static final int DEBUG_ALL = DEBUG_STANDARD | DEBUG_VERBOSE;
301
302        static void parseDebugProperties() {
303            int level = 0;
304            Properties p = System.getProperties();
305
306            // get selected levels
307            if (p.getProperty("DEBUG_STANDARD") != null) {
308                level |= DEBUG_STANDARD;
309            }
310
311            if (p.getProperty("DEBUG_VERBOSE") != null) {
312                level |= DEBUG_VERBOSE;
313            }
314
315            if (p.getProperty("DEBUG_ALL") != null) {
316                level |= DEBUG_ALL;
317            }
318
319            selectedDebugLevel = level;
320        }
321
322        /**
323         * Reproduces the original parsing and collection of test parameters
324         * from the DTonga JMX test suite.
325         *
326         * Collects passed args and returns them in a map(argname, value) structure,
327         * which will be then propagated as necessary to various called methods.
328         */
329        static Map<String, Object> parseParameters(String args[])
330        throws Exception {
331            debug(DEBUG_STANDARD, "TestRoot::parseParameters: Start");
332            HashMap<String, Object> map = new HashMap<>();
333
334            for ( int i = 0; i < args.length; i++ ) {
335                if ( args[i].trim().startsWith("-") ) {
336                    if ((i+1) < args.length && !args[i+1].startsWith("-") ) {
337                        debug(DEBUG_STANDARD,
338                            "TestRoot::parseParameters: added in map = " +
339                            args[i] +
340                            " with value " +
341                            args[i+1]) ;
342                        map.put(args[i].trim(), args[i+1].trim()) ;
343                    } else if ((i+1) < args.length && args[i+1].startsWith("-") ||
344                               (i+1) == args.length ) {
345                        debug(DEBUG_STANDARD,
346                                "TestRoot::parseParameters: added in map = " +
347                                args[i] +
348                                " with null value") ;
349                        map.put(args[i].trim(), null) ;
350                    } else {
351                        System.out.println(
352                            "TestRoot::parseParameters: (WARNING) not added in map = " +
353                            args[i]) ;
354                    }
355                }
356            }
357
358            debug(DEBUG_STANDARD, "TestRoot::parseParameters: Done") ;
359            return map ;
360        }
361
362        /**
363         * This method is to be used in all tests to print anything
364         * that is temporary.
365         * Printing is done only when debug is activated by the property DEBUG.
366         * Printing depends also on the DEBUG_LEVEL property.
367         * Here it encapsulates a System.out.println.
368         */
369        static void debug(int level, String line) {
370            if ((selectedDebugLevel & level) != 0) {
371                System.out.println(DEBUG_HEADER + line);
372            }
373        }
374
375        /**
376         * Do print stack trace when withStack is true.
377         * Does try to call getTargetException() and getTargetError() then
378         * print embedded stacks in the case of an Exception wrapping
379         * another Exception or an Error. Recurse until no more wrapping
380         * is found.
381         */
382        static void printThrowable(Throwable theThro, boolean withStack) {
383            try {
384                if (withStack) {
385                    theThro.printStackTrace(System.out);
386                }
387                if (theThro instanceof Exception) {
388                    Exception t = (Exception) theThro;
389                    Method target = null;
390                    String blank = " ";
391                    try {
392                        target = t.getClass().getMethod("getTargetException",
393                                (java.lang.Class<?>[]) null);
394                    } catch (Exception ee) {
395                    // OK: getTargetException method could be there or not
396                    }
397                    System.out.println(blank + t.getClass() + "==>" + t.getMessage());
398                    while (target != null) {
399                        try {
400                            t = (Exception) target.invoke(t,
401                                    (java.lang.Object[]) null);
402                        } catch (Exception ee) {
403                            t = null;
404                        }
405                        try {
406                            if (t != null) {
407                                blank = blank + "  ";
408                                System.out.println(blank + t.getClass() + "==>" +
409                                        t.getMessage());
410                                try {
411                                    target =
412                                            t.getClass().getMethod("getTargetException",
413                                            (java.lang.Class<?>[]) null);
414                                } catch (Exception ee) {
415                                // OK: getTargetException method could be there or not                            }
416                                }
417                            } else {
418                                target = null;
419                            }
420                        } catch (Exception ee) {
421                            target = null;
422                        }
423                    }
424
425                    // We may have exceptions wrapping an Error then it is
426                    // getTargetError that is likely to be called
427                    try {
428                        target = ((Exception) theThro).getClass().getMethod("getTargetError",
429                                (java.lang.Class<?>[]) null);
430                    } catch (Exception ee) {
431                    // OK: getTargetError method could be there or not
432                    }
433                    Throwable err = theThro;
434                    while (target != null) {
435                        try {
436                            err = (Error) target.invoke(err,
437                                    (java.lang.Object[]) null);
438                        } catch (Exception ee) {
439                            err = null;
440                        }
441                        try {
442                            if (err != null) {
443                                blank = blank + "  ";
444                                System.out.println(blank + err.getClass() + "==>" +
445                                        err.getMessage());
446                                if (withStack) {
447                                    err.printStackTrace(System.out);
448                                }
449                                try {
450                                    target = err.getClass().getMethod("getTargetError",
451                                            (java.lang.Class<?>[]) null);
452                                } catch (Exception ee) {
453                                // OK: getTargetError method could be there or not
454                                }
455                            } else {
456                                target = null;
457                            }
458                        } catch (Exception ee) {
459                            target = null;
460                        }
461                    }
462                } else {
463                    System.out.println("Throwable is : " + theThro);
464                }
465            } catch (Throwable x) {
466                System.out.println("Exception : raised in printException : " + x);
467            }
468        }
469    }
470
471}
472