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 
  34 import java.util.Map ;
  35 import java.util.HashMap;
  36 import java.util.Set;
  37 import java.util.HashSet;
  38 import java.util.Iterator;
  39 import java.util.Properties;
  40 import java.lang.reflect.Method;
  41 
  42 import java.lang.management.ManagementFactory;
  43 import javax.management.MBeanServer;
  44 import javax.management.MBeanServerFactory;
  45 import javax.management.MBeanServerConnection;
  46 import javax.management.ObjectInstance;
  47 import javax.management.ObjectName ;
  48 import javax.management.QueryExp;
  49 
  50 import javax.management.remote.JMXConnector;
  51 import javax.management.remote.JMXConnectorFactory;
  52 import javax.management.remote.JMXConnectorServer;
  53 import javax.management.remote.JMXConnectorServerFactory;
  54 import javax.management.remote.JMXServiceURL;
  55 
  56 public 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 }