1 /* 2 * Copyright (c) 2003, 2018, 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 package nsk.monitoring.share; 25 26 import nsk.share.log.Log; 27 import nsk.share.TestBug; 28 import nsk.share.ArgumentParser; 29 import java.lang.management.*; 30 31 /** 32 * Parser for JSR-174 test's arguments. 33 * <p> 34 * <code>ArgumentHandler</code> handles specific command line arguments 35 * related to way of execution of a test in addition to general arguments 36 * recognized by {@link ArgumentParser <code>ArgumentParser</code>}. 37 * <p> 38 * Following is the list of specific options for <code>ArgumentHandler</code>: 39 * <ul> 40 * <li><code>-testMode="<i>value</i>"</code>, where <i>value</i> may take 41 * one of the following values: <code>directly</code> -- to call methods in 42 * the MBean directly within the same JVM, <code>server</code> -- to call 43 * methods through MBeanServer, <code>proxy</code> -- to call methods 44 * through MBean proxy (not yet implemented). 45 * <li><code>-MBeanServer="<i>value</i>"</code>, where <i>value</i> may take 46 * one of the following values: <code>default</code> -- to execute test for 47 * default JMX implementation of MBeanServer or <code>custom</code> -- for 48 * implementation provided by NSK J2SE SQE Team. 49 * <li><code>-loadableClassCount=<i>value</i></code>, where <i>value</i> defines 50 * amount of loadable classes. Default values is <code>100</code>. 51 * <li><code>-loadersCount=<i>value</i></code>, where <i>value</i> defines 52 * amount of class loaders. Default values is <code>100</code>. 53 * <li><code>-singleClassloaderClass</code> specifies whether class loaders are 54 * instances of the same class. 55 * <li><code>-memory="<i>value</i>"</code>, where <i>value</i> may take 56 * one of the following values: <code>heap</code> -- to test heap memory, 57 * <code>nonheap</code> to test nonheap memory, <code>mixed</code> -- to 58 * test both heap and nonheap memory. 59 * <li><code>-invocationType="<i>value</i>"</code>, where <i>value</i> may take 60 * one of the following values: <code>java</code> -- to start java threads, 61 * <code>native</code> -- to start native threads, <code>mixed</code> -- to 62 * both java and native threads. 63 * <li><code>-monitoring="<i>value</i>"</code>, where <i>value</i> may take 64 * one of the following values: <code>polling</code> -- to start polling 65 * mechanism of monitoring, <code>notification</code> -- to start 66 * notification mechanism of monitoring. 67 * <li><code>-threshold="<i>value</i>"</code>, where <i>value</i> may take 68 * one of the following values: <code>usage</code> -- to test usage 69 * thresholds, <code>collection</code> -- to test collection usage 70 * thresholds. 71 * <li><code>-depth=<i>value</i></code>, where <i>value</i> defines 72 * depth of recursion. Default values is <code>1</code>. 73 * <li><code>-threadCount=<i>value</i></code>, where <i>value</i> defines 74 * number of threads to start. Default values is <code>1</code>. 75 * <li><code>-timeout=<i>value</i></code>, where <i>value</i> defines 76 * number of minutes to run the test. 77 * </ul> 78 * <p> 79 * See also list of basic options recognized by <code>ArgumentParser</code>. 80 * <p> 81 * See also comments to <code>ArgumentParser</code> how to work with 82 * command line arguments and options. 83 * 84 * @see ArgumentParser 85 */ 86 public class ArgumentHandler extends ArgumentParser { 87 static final String TEST_MODE = "testMode"; 88 static final String DIRECTLY_MODE = "directly"; 89 static final String SERVER_MODE = "server"; 90 static final String PROXY_MODE = "proxy"; 91 92 static final String SERVER_TYPE = "MBeanServer"; 93 static final String DEFAULT_TYPE = "default"; 94 static final String CUSTOM_TYPE = "custom"; 95 96 static final String LOADABLE_CLASSES_COUNT = "loadableClassCount"; 97 static final String LOADERS_COUNT = "loadersCount"; 98 static final String SINGLE_CLASSLOADER_CLASS = "singleClassloaderClass"; 99 100 static final String MEMORY_TYPE = "memory"; 101 static final String MT_HEAP = "heap"; 102 static final String MT_NONHEAP = "nonheap"; 103 static final String MT_MIXED = "mixed"; 104 105 static final String INVOCATION_TYPE = "invocationType"; 106 static final String JAVA_TYPE = "java"; 107 static final String NATIVE_TYPE = "native"; 108 static final String MIXED_TYPE = "mixed"; 109 110 static final String MONITORING = "monitoring"; 111 static final String MON_POLLING = "polling"; 112 static final String MON_NOTIF = "notification"; 113 114 static final String THRESHOLD = "threshold"; 115 static final String TH_USAGE = "usage"; 116 static final String TH_COLLECTION = "collection"; 117 118 static final String THREAD_DEPTH = "depth"; 119 static final String THREAD_COUNT = "threadCount"; 120 static final String TIMEOUT = "timeout"; 121 122 static final String SCENARIO_TYPE = "scenarioType"; 123 124 static final String ITERATIONS = "iterations"; 125 126 /** 127 * Keep a copy of raw command-line arguments and parse them; 128 * but throw an exception on parsing error. 129 * 130 * @param args Array of the raw command-line arguments. 131 * 132 * @throws BadOption If unknown option or illegal 133 * option value found 134 * 135 * @see ArgumentParser 136 */ ArgumentHandler(String args[])137 public ArgumentHandler(String args[]) { 138 super(args); 139 } 140 141 /** 142 * Returns the test mode. 143 * <p> 144 * To access the metrics directly, <code>testMode</code> option should 145 * be defined in command line <code>-testMode="directly"</code>. 146 * To access the metrics via MBeanServer, <code>"server"</code> should be 147 * assigned to <code>-testMode="directly"</code>. 148 * <p> 149 * If <code>testMode</code> is not defined by command line, a test is 150 * executed in <code>directly</code> mode. 151 * 152 * @return name of test mode. 153 * 154 */ getTestMode()155 public String getTestMode() { 156 return options.getProperty(TEST_MODE, DIRECTLY_MODE); 157 } 158 159 /** 160 * Returns a type of MBean server if any. 161 * Two kinds of MBean servers are allowed: default and custom servers. 162 * Default server is an implementation of {@link 163 * javax.management.MBeanServer <tt>javax.management.MBeanServer</tt>} 164 * interface provided by JMX. Custom server is an implementation provided 165 * by NSK J2SE SQE Team. Server type is defined by <tt>MBeanServer</tt> 166 * key in command line <code>-MBeanServer="default"</code> or 167 * <code>-MBeanServer="custom"</code> 168 * 169 * @return <i>MBeanServer</i> server type. 170 * 171 */ getServerType()172 public String getServerType() { 173 return options.getProperty(SERVER_TYPE, DEFAULT_TYPE); 174 } 175 176 /** 177 * Returns <i>true</i> if default implementation is used. 178 * 179 * @return <i>true</i> if default implementation is used. 180 * 181 * @see #getServerType() 182 */ isDefaultServer()183 public boolean isDefaultServer() { 184 return getServerType().equals(DEFAULT_TYPE); 185 } 186 187 /** 188 * Returns amount of class loaders. 189 * 190 * @return <i>loadersCount</i> as an integer value 191 */ getLoadersCount()192 public int getLoadersCount() { 193 String val = options.getProperty(LOADERS_COUNT, "100"); 194 int number; 195 try { 196 number = Integer.parseInt(val); 197 } catch (NumberFormatException e) { 198 throw new TestBug("Not integer value of \"" + LOADERS_COUNT 199 + "\" argument: " + val); 200 } 201 return number; 202 } 203 204 /** 205 * Returns <i>true</i> if class loaders, which perform class loading, are 206 * instances of the same class. If <code>-singleClassloaderClass</code> key 207 * is not set in command line options, then <i>false</i> is returned. 208 * 209 * @return if class loaders are instances of the same class. 210 * 211 */ singleClassloaderClass()212 public boolean singleClassloaderClass() { 213 return options.getProperty(SINGLE_CLASSLOADER_CLASS) != null; 214 } 215 216 /** 217 * Returns amount of loadable classes. If <code>-loadableClassesCount</code> 218 * key is not set with command line, <code>100</code> is returned. 219 * 220 * @return <i>loadableClassesCount</i> as an integer value 221 * 222 * @throws TestBug <i>loadableClassesCount</i> is non-numeric value. 223 * 224 */ getLoadableClassesCount()225 public int getLoadableClassesCount() { 226 String val = options.getProperty(LOADABLE_CLASSES_COUNT, "1"); 227 int number; 228 try { 229 number = Integer.parseInt(val); 230 } catch (NumberFormatException e) { 231 throw new TestBug("Not integer value of \"" + LOADABLE_CLASSES_COUNT 232 + "\" argument: " + val); 233 } 234 return number; 235 } 236 237 /** 238 * Returns invocation type. 239 * 240 * @return <i>invocationType</i> value 241 * 242 */ getInvocationType()243 public String getInvocationType() { 244 return options.getProperty(INVOCATION_TYPE, JAVA_TYPE); 245 } 246 247 /** 248 * Returns tested memory type. 249 * 250 * @return <i>memory</i> value 251 * 252 */ getTestedMemory()253 public String getTestedMemory() { 254 return options.getProperty(MEMORY_TYPE, MT_HEAP); 255 } 256 257 /** 258 * Returns timeout. 259 * 260 * @return <i>timeout</i> value 261 * 262 */ getTimeout()263 public int getTimeout() { 264 String value = options.getProperty(TIMEOUT, "30"); 265 266 try { 267 return Integer.parseInt(value); 268 } catch (NumberFormatException e) { 269 throw new TestBug("Not integer value of \"" + TIMEOUT 270 + "\" argument: " + value); 271 } 272 } 273 274 /** 275 * Returns recursion depth. 276 * 277 * @return <i>depth</i> value 278 * 279 */ getThreadDepth()280 public int getThreadDepth() { 281 String value = options.getProperty(THREAD_DEPTH, "1"); 282 283 try { 284 return Integer.parseInt(value); 285 } catch (NumberFormatException e) { 286 throw new TestBug("Not integer value of \"" + THREAD_DEPTH 287 + "\" argument: " + value); 288 } 289 } 290 291 /** 292 * Returns number of threads. 293 * 294 * @return <i>threadCount</i> value 295 * 296 */ getThreadCount()297 public int getThreadCount() { 298 String value = options.getProperty(THREAD_COUNT, "1"); 299 300 try { 301 return Integer.parseInt(value); 302 } catch (NumberFormatException e) { 303 throw new TestBug("Not integer value of \"" + THREAD_COUNT 304 + "\" argument: " + value); 305 } 306 } 307 308 /** 309 * Returns type of monitoring. 310 * 311 * @return <i>monitoring</i> value 312 * 313 */ getMonitoring()314 public String getMonitoring() { 315 return options.getProperty(MONITORING, MON_NOTIF); 316 } 317 318 /** 319 * Returns type of threshold. 320 * 321 * @return <i>threshold</i> value 322 * 323 */ getThreshold()324 public String getThreshold() { 325 return options.getProperty(THRESHOLD, TH_USAGE); 326 } 327 328 /** 329 * Returns thread type to create. 330 */ getScenarioType()331 public String getScenarioType() { 332 return options.getProperty(SCENARIO_TYPE, "running"); 333 } 334 getIterations()335 public int getIterations() { 336 return Integer.parseInt(options.getProperty(ITERATIONS, "3")); 337 } 338 339 /** 340 * Checks if an option is allowed and has proper value. 341 * This method is invoked by <code>parseArguments()</code> 342 * 343 * @param option option name 344 * @param value string representation of value 345 * (could be an empty string too) 346 * null if this option has no value 347 * @return <i>true</i> if option is allowed and has proper value 348 * <i>false</i> if otion is not admissible 349 * 350 * @throws <i>BadOption</i> if option has an illegal value 351 * 352 * @see nsk.share.ArgumentParser#parseArguments 353 */ checkOption(String option, String value)354 protected boolean checkOption(String option, String value) { 355 356 // defines directly, server or proxytest mode 357 if (option.equals(TEST_MODE)) { 358 if ( (!value.equals(DIRECTLY_MODE)) && 359 (!value.equals(SERVER_MODE)) && 360 (!value.equals(PROXY_MODE)) 361 ) { 362 throw new BadOption(option + ": must be one of: " 363 + "\"" + DIRECTLY_MODE + "\", " 364 + "\"" + SERVER_MODE + "\", " 365 + "\"" + PROXY_MODE + "\""); 366 } 367 return true; 368 } 369 370 // defines invocation type for stack filling 371 if (option.equals(INVOCATION_TYPE)) { 372 if ( (!value.equals(JAVA_TYPE)) && 373 (!value.equals(NATIVE_TYPE)) && 374 (!value.equals(MIXED_TYPE)) 375 ) { 376 throw new BadOption(option + ": must be one of: " 377 + "\"" + JAVA_TYPE + "\", " 378 + "\"" + NATIVE_TYPE + "\", " 379 + "\"" + MIXED_TYPE + "\""); 380 } 381 return true; 382 } 383 384 // defines default or custom MBean server 385 if (option.equals(SERVER_TYPE)) { 386 if ((!value.equals(DEFAULT_TYPE)) 387 && (!value.equals(CUSTOM_TYPE))) { 388 throw new BadOption(option + ": must be one of: \"" 389 + DEFAULT_TYPE + "\", \"" 390 + CUSTOM_TYPE + "\""); 391 } 392 393 return true; 394 } 395 396 // defines loadable classes and loaders counts 397 if (option.equals(LOADABLE_CLASSES_COUNT) || 398 option.equals(LOADERS_COUNT) || 399 option.equals(THREAD_DEPTH) || option.equals(THREAD_COUNT)) { 400 try { 401 int number = Integer.parseInt(value); 402 if (number < 0) { 403 throw new BadOption(option + ": value must be a positive " 404 + "integer"); 405 } 406 } catch (NumberFormatException e) { 407 throw new BadOption(option + ": value must be an integer"); 408 } 409 return true; 410 } 411 412 // defines timeout 413 if (option.equals(TIMEOUT)) { 414 try { 415 int number = Integer.parseInt(value); 416 417 if (number < 0) 418 throw new BadOption(option + ": value must be a positive " 419 + "integer"); 420 } catch (NumberFormatException e) { 421 throw new BadOption(option + ": value must be an integer"); 422 } 423 return true; 424 } 425 426 // defines if classloader class is single 427 if (option.equals(SINGLE_CLASSLOADER_CLASS)) { 428 if (!(value == null || value.length() <= 0)) { 429 throw new BadOption(option + ": no value must be specified"); 430 } 431 return true; 432 } 433 434 // defines memory types 435 if (option.equals(MEMORY_TYPE)) { 436 if ( (!value.equals(MT_HEAP)) && 437 (!value.equals(MT_NONHEAP)) && 438 (!value.equals(MT_MIXED)) 439 ) 440 throw new BadOption(option + ": must be one of: " 441 + "\"" + MT_HEAP + "\", " 442 + "\"" + MT_NONHEAP + "\", " 443 + "\"" + MT_MIXED + "\""); 444 return true; 445 } 446 447 // defines type of monitoring 448 if (option.equals(MONITORING)) { 449 if ( (!value.equals(MON_POLLING)) && 450 (!value.equals(MON_NOTIF)) 451 ) 452 throw new BadOption(option + ": must be one of: " 453 + "\"" + MON_POLLING + "\", " 454 + "\"" + MON_NOTIF + "\""); 455 return true; 456 } 457 458 // defines threshold 459 if (option.equals(THRESHOLD)) { 460 if ( (!value.equals(TH_USAGE)) && 461 (!value.equals(TH_COLLECTION)) 462 ) 463 throw new BadOption(option + ": must be one of: " 464 + "\"" + TH_USAGE + "\", " 465 + "\"" + TH_COLLECTION + "\""); 466 return true; 467 } 468 469 if (option.equals(SCENARIO_TYPE)) { 470 return true; 471 } 472 if (option.equals(ITERATIONS)) { 473 try { 474 int number = Integer.parseInt(value); 475 476 if (number < 0) 477 throw new BadOption(option + ": value must be a positive " 478 + "integer"); 479 return true; 480 } catch (NumberFormatException e) { 481 throw new BadOption(option + ": value must be an integer"); 482 } 483 484 } 485 return super.checkOption(option, value); 486 } 487 488 /** 489 * Check if the values of all options are consistent. 490 * This method is invoked by <code>parseArguments()</code> 491 * 492 * @throws <i>BadOption</i> if options have inconsistent values 493 * 494 * @see nsk.share.ArgumentParser#parseArguments 495 */ checkOptions()496 protected void checkOptions() { 497 super.checkOptions(); 498 } 499 dump(Log log)500 public void dump(Log log) { 501 log.info("Test mode: " + getTestMode()); 502 log.info("Server type: " + getServerType()); 503 log.info("loadableClassesCount: " + getLoadableClassesCount()); 504 log.info("loadersCount: " + getLoadersCount()); 505 log.info("singleClassloaderClass: " + singleClassloaderClass()); 506 } 507 } // ArgumentHandler 508