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