1 /* 2 * Copyright (c) 2003, 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 import sun.management.jmxremote.ConnectorBootstrap; 24 25 import java.io.File; 26 import java.io.FileInputStream; 27 import java.io.FilenameFilter; 28 import java.io.IOException; 29 import java.net.BindException; 30 import java.rmi.server.ExportException; 31 32 import java.util.Properties; 33 import java.util.Iterator; 34 import java.util.Set; 35 import java.util.ArrayList; 36 import java.util.HashMap; 37 import java.util.Map; 38 import java.util.Enumeration; 39 40 import javax.management.remote.*; 41 import javax.management.*; 42 43 import jdk.internal.agent.AgentConfigurationError; 44 45 import java.security.Security; 46 47 /** 48 * <p>This class implements unit test for RMI Bootstrap. 49 * When called with no arguments main() looks in the directory indicated 50 * by the "test.src" system property for files called management*ok.properties 51 * or management*ko.properties. The *ok.properties files are assumed to be 52 * valid Java M&M config files for which the bootstrap should succeed. 53 * The *ko.properties files are assumed to be configurations for which the 54 * bootstrap & connection test will fail.</p> 55 * 56 * <p>The rmi port number can be specified with the "rmi.port" system property. 57 * If not, this test will use the first available port</p> 58 * 59 * <p>When called with some argument, the main() will interprete its args to 60 * be Java M&M configuration file names. The filenames are expected to end 61 * with ok.properties or ko.properties - and are interpreted as above.</p> 62 * 63 * <p>Note that a limitation of the RMI registry (bug 4267864) prevent 64 * this test from succeeding if more than 1 configuration is used. 65 * As long as 4267864 isn't fix, this test must be called as many times 66 * as needed but with a single argument (no arguments, or several arguments 67 * will fail).</p> 68 * 69 * <p>Debug traces are logged in "sun.management.test"</p> 70 **/ 71 public class RmiBootstrapTest { 72 // the number of consecutive ports to test for availability 73 private static int MAX_GET_FREE_PORT_TRIES = 10; 74 static TestLogger log = 75 new TestLogger("RmiBootstrapTest"); 76 77 /** 78 * Default values for RMI configuration properties. 79 **/ 80 public static interface DefaultValues { 81 public static final String PORT="0"; 82 public static final String CONFIG_FILE_NAME="management.properties"; 83 public static final String USE_SSL="true"; 84 public static final String USE_AUTHENTICATION="true"; 85 public static final String PASSWORD_FILE_NAME="jmxremote.password"; 86 public static final String ACCESS_FILE_NAME="jmxremote.access"; 87 public static final String KEYSTORE="keystore"; 88 public static final String KEYSTORE_PASSWD="password"; 89 public static final String TRUSTSTORE="truststore"; 90 public static final String TRUSTSTORE_PASSWD="trustword"; 91 public static final String SSL_NEED_CLIENT_AUTH="false"; 92 } 93 94 /** 95 * Names of RMI configuration properties. 96 **/ 97 public static interface PropertyNames { 98 public static final String PORT= 99 "com.sun.management.jmxremote.port"; 100 public static final String CONFIG_FILE_NAME= 101 "com.sun.management.config.file"; 102 public static final String USE_SSL= 103 "com.sun.management.jmxremote.ssl"; 104 public static final String USE_AUTHENTICATION= 105 "com.sun.management.jmxremote.authenticate"; 106 public static final String PASSWORD_FILE_NAME= 107 "com.sun.management.jmxremote.password.file"; 108 public static final String ACCESS_FILE_NAME= 109 "com.sun.management.jmxremote.access.file"; 110 public static final String INSTRUMENT_ALL= 111 "com.sun.management.instrumentall"; 112 public static final String CREDENTIALS = 113 "jmx.remote.credentials"; 114 public static final String KEYSTORE= 115 "javax.net.ssl.keyStore"; 116 public static final String KEYSTORE_PASSWD= 117 "javax.net.ssl.keyStorePassword"; 118 public static final String TRUSTSTORE= 119 "javax.net.ssl.trustStore"; 120 public static final String TRUSTSTORE_PASSWD= 121 "javax.net.ssl.trustStorePassword"; 122 public static final String SSL_ENABLED_CIPHER_SUITES = 123 "com.sun.management.jmxremote.ssl.enabled.cipher.suites"; 124 public static final String SSL_ENABLED_PROTOCOLS = 125 "com.sun.management.jmxremote.ssl.enabled.protocols"; 126 public static final String SSL_NEED_CLIENT_AUTH = 127 "com.sun.management.jmxremote.ssl.need.client.auth"; 128 public static final String SSL_CLIENT_ENABLED_CIPHER_SUITES = 129 "javax.rmi.ssl.client.enabledCipherSuites"; 130 } 131 132 /** 133 * A filter to find all filenames who match <prefix>*<suffix>. 134 * Note that <prefix> and <suffix> can overlap. 135 **/ 136 private static class ConfigFilenameFilter implements FilenameFilter { 137 final String suffix; 138 final String prefix; 139 ConfigFilenameFilter(String prefix, String suffix) { 140 this.suffix=suffix; 141 this.prefix=prefix; 142 } 143 public boolean accept(File dir, String name) { 144 return (name.startsWith(prefix) && name.endsWith(suffix)); 145 } 146 } 147 148 /** 149 * Get all "management*ok.properties" files in the directory 150 * indicated by the "test.src" management property. 151 **/ 152 private static File[] findConfigurationFilesOk() { 153 final String testSrc = System.getProperty("test.src"); 154 final File dir = new File(testSrc); 155 final FilenameFilter filter = 156 new ConfigFilenameFilter("management_test","ok.properties"); 157 return dir.listFiles(filter); 158 } 159 160 /** 161 * Get all "management*ko.properties" files in the directory 162 * indicated by the "test.src" management property. 163 **/ 164 private static File[] findConfigurationFilesKo() { 165 final String testSrc = System.getProperty("test.src"); 166 final File dir = new File(testSrc); 167 final FilenameFilter filter = 168 new ConfigFilenameFilter("management_test","ko.properties"); 169 return dir.listFiles(filter); 170 } 171 172 /** 173 * List all MBeans and their attributes. Used to test communication 174 * with the Java M&M MBean Server. 175 * @return the number of queried MBeans. 176 */ 177 public static int listMBeans(MBeanServerConnection server) 178 throws IOException { 179 return listMBeans(server,null,null); 180 } 181 182 /** 183 * List all matching MBeans and their attributes. 184 * Used to test communication with the Java M&M MBean Server. 185 * @return the number of matching MBeans. 186 */ 187 public static int listMBeans(MBeanServerConnection server, 188 ObjectName pattern, QueryExp query) 189 throws IOException { 190 191 final Set names = server.queryNames(pattern,query); 192 for (final Iterator i=names.iterator(); i.hasNext(); ) { 193 ObjectName name = (ObjectName)i.next(); 194 log.trace("listMBeans","Got MBean: "+name); 195 try { 196 MBeanInfo info = 197 server.getMBeanInfo((ObjectName)name); 198 MBeanAttributeInfo[] attrs = info.getAttributes(); 199 if (attrs == null) continue; 200 for (int j=0; j<attrs.length; j++) { 201 if (attrs[j].isReadable()) { 202 try { 203 Object o = 204 server.getAttribute(name,attrs[j].getName()); 205 if (log.isDebugOn()) 206 log.debug("listMBeans","\t\t" + 207 attrs[j].getName() + 208 " = "+o); 209 } catch (Exception x) { 210 log.trace("listMBeans","JmxClient failed to get " + 211 attrs[j].getName() + ": " + x); 212 final IOException io = 213 new IOException("JmxClient failed to get " + 214 attrs[j].getName()); 215 io.initCause(x); 216 throw io; 217 } 218 } 219 } 220 } catch (Exception x) { 221 log.trace("listMBeans", 222 "JmxClient failed to get MBeanInfo: " + x); 223 final IOException io = 224 new IOException("JmxClient failed to get MBeanInfo: "+x); 225 io.initCause(x); 226 throw io; 227 } 228 } 229 return names.size(); 230 } 231 232 /** 233 * Compute the full path name for a default file. 234 * @param basename basename (with extension) of the default file. 235 * @return ${JRE}/conf/management/${basename} 236 **/ 237 private static String getDefaultFileName(String basename) { 238 final String fileSeparator = File.separator; 239 final StringBuffer defaultFileName = 240 new StringBuffer(System.getProperty("java.home")). 241 append(fileSeparator).append("conf").append(fileSeparator). 242 append("management").append(fileSeparator). 243 append(basename); 244 return defaultFileName.toString(); 245 } 246 247 /** 248 * Compute the full path name for a default file. 249 * @param basename basename (with extension) of the default file. 250 * @return ${JRE}/conf/management/${basename} 251 **/ 252 private static String getDefaultStoreName(String basename) { 253 final String fileSeparator = File.separator; 254 final StringBuffer defaultFileName = 255 new StringBuffer(System.getProperty("test.src")). 256 append(fileSeparator).append("ssl").append(fileSeparator). 257 append(basename); 258 return defaultFileName.toString(); 259 } 260 261 262 /** 263 * Parses the password file to read the credentials. 264 * Returns an ArrayList of arrays of 2 string: 265 * {<subject>, <password>}. 266 * If the password file does not exists, return an empty list. 267 * (File not found = empty file). 268 **/ 269 private ArrayList readCredentials(String passwordFileName) 270 throws IOException { 271 final Properties pws = new Properties(); 272 final ArrayList result = new ArrayList(); 273 final File f = new File(passwordFileName); 274 if (!f.exists()) return result; 275 FileInputStream fin = new FileInputStream(passwordFileName); 276 try {pws.load(fin);}finally{fin.close();} 277 for (Enumeration en=pws.propertyNames();en.hasMoreElements();) { 278 final String[] cred = new String[2]; 279 cred[0]=(String)en.nextElement(); 280 cred[1]=pws.getProperty(cred[0]); 281 result.add(cred); 282 } 283 return result; 284 } 285 286 287 /** 288 * Connect with the given url, using all given credentials in turn. 289 * A null entry in the useCredentials arrays indicate a connection 290 * where no credentials are used. 291 * @param url JMXServiceURL of the server. 292 * @param useCredentials An array of credentials (a credential 293 * is a two String array, so this is an array of arrays 294 * of strings: 295 * useCredentials[i][0]=subject 296 * useCredentials[i][1]=password 297 * if useCredentials[i] == null means no credentials. 298 * @param expectConnectOk true if connection is expected to succeed 299 * Note: if expectConnectOk=false and the test fails to connect 300 * the number of failure is not incremented. Conversely, 301 * if expectConnectOk=false and the test does not fail to 302 * connect the number of failure is incremented. 303 * @param expectReadOk true if communication (listMBeans) is expected 304 * to succeed. 305 * Note: if expectReadOk=false and the test fails to read MBeans 306 * the number of failure is not incremented. Conversely, 307 * if expectReadOk=false and the test does not fail to 308 * read MBeans the number of failure is incremented. 309 * @return number of failure. 310 **/ 311 public int connectAndRead(JMXServiceURL url, 312 Object[] useCredentials, 313 boolean expectConnectOk, 314 boolean expectReadOk) 315 throws IOException { 316 317 int errorCount = 0; 318 319 for (int i=0 ; i<useCredentials.length ; i++) { 320 final Map m = new HashMap(); 321 final String[] credentials = (String[])useCredentials[i]; 322 final String crinfo; 323 if (credentials != null) { 324 crinfo = "{"+credentials[0] + ", " + credentials[1] + "}"; 325 m.put(PropertyNames.CREDENTIALS,credentials); 326 } else { 327 crinfo="no credentials"; 328 } 329 log.trace("testCommunication","using credentials: " + crinfo); 330 331 final JMXConnector c; 332 try { 333 c = JMXConnectorFactory.connect(url,m); 334 } catch (IOException x ) { 335 if (expectConnectOk) { 336 final String err = "Connection failed for " + crinfo + 337 ": " + x; 338 System.out.println(err); 339 log.trace("testCommunication",err); 340 log.debug("testCommunication",x); 341 errorCount++; 342 continue; 343 } else { 344 System.out.println("Connection failed as expected for " + 345 crinfo + ": " + x); 346 continue; 347 } 348 } catch (RuntimeException x ) { 349 if (expectConnectOk) { 350 final String err = "Connection failed for " + crinfo + 351 ": " + x; 352 System.out.println(err); 353 log.trace("testCommunication",err); 354 log.debug("testCommunication",x); 355 errorCount++; 356 continue; 357 } else { 358 System.out.println("Connection failed as expected for " + 359 crinfo + ": " + x); 360 continue; 361 } 362 } 363 try { 364 MBeanServerConnection conn = 365 c.getMBeanServerConnection(); 366 if (log.isDebugOn()) { 367 log.debug("testCommunication","Connection is:" + conn); 368 log.debug("testCommunication","Server domain is: " + 369 conn.getDefaultDomain()); 370 } 371 final ObjectName pattern = 372 new ObjectName("java.lang:type=Memory,*"); 373 final int count = listMBeans(conn,pattern,null); 374 if (count == 0) 375 throw new Exception("Expected at least one matching "+ 376 "MBean for "+pattern); 377 if (expectReadOk) { 378 System.out.println("Communication succeeded " + 379 "as expected for "+ 380 crinfo + ": found " + count 381 + ((count<2)?"MBean":"MBeans")); 382 } else { 383 final String err = "Expected failure didn't occur for " + 384 crinfo; 385 System.out.println(err); 386 errorCount++; 387 } 388 } catch (IOException x ) { 389 if (expectReadOk) { 390 final String err = "Communication failed with " + crinfo + 391 ": " + x; 392 System.out.println(err); 393 log.trace("testCommunication",err); 394 log.debug("testCommunication",x); 395 errorCount++; 396 continue; 397 } else { 398 System.out.println("Communication failed as expected for "+ 399 crinfo + ": " + x); 400 continue; 401 } 402 } catch (RuntimeException x ) { 403 if (expectReadOk) { 404 final String err = "Communication failed with " + crinfo + 405 ": " + x; 406 System.out.println(err); 407 log.trace("testCommunication",err); 408 log.debug("testCommunication",x); 409 errorCount++; 410 continue; 411 } else { 412 System.out.println("Communication failed as expected for "+ 413 crinfo + ": " + x); 414 } 415 } catch (Exception x) { 416 final String err = "Failed to read MBeans with " + crinfo + 417 ": " + x; 418 System.out.println(err); 419 log.trace("testCommunication",err); 420 log.debug("testCommunication",x); 421 errorCount++; 422 continue; 423 } finally { 424 c.close(); 425 } 426 } 427 return errorCount; 428 } 429 430 431 private void setSslProperties(String clientEnabledCipherSuites) { 432 final String defaultKeyStore = 433 getDefaultStoreName(DefaultValues.KEYSTORE); 434 final String defaultTrustStore = 435 getDefaultStoreName(DefaultValues.TRUSTSTORE); 436 437 final String keyStore = 438 System.getProperty(PropertyNames.KEYSTORE, defaultKeyStore); 439 System.setProperty(PropertyNames.KEYSTORE,keyStore); 440 log.trace("setSslProperties",PropertyNames.KEYSTORE+"="+keyStore); 441 442 final String password = 443 System.getProperty(PropertyNames.KEYSTORE_PASSWD, 444 DefaultValues.KEYSTORE_PASSWD); 445 System.setProperty(PropertyNames.KEYSTORE_PASSWD,password); 446 log.trace("setSslProperties", 447 PropertyNames.KEYSTORE_PASSWD+"="+password); 448 449 final String trustStore = 450 System.getProperty(PropertyNames.TRUSTSTORE, 451 defaultTrustStore); 452 System.setProperty(PropertyNames.TRUSTSTORE,trustStore); 453 log.trace("setSslProperties", 454 PropertyNames.TRUSTSTORE+"="+trustStore); 455 456 final String trustword = 457 System.getProperty(PropertyNames.TRUSTSTORE_PASSWD, 458 DefaultValues.TRUSTSTORE_PASSWD); 459 System.setProperty(PropertyNames.TRUSTSTORE_PASSWD,trustword); 460 log.trace("setSslProperties", 461 PropertyNames.TRUSTSTORE_PASSWD+"="+trustword); 462 463 if (clientEnabledCipherSuites != null) { 464 System.setProperty("javax.rmi.ssl.client.enabledCipherSuites", 465 clientEnabledCipherSuites); 466 } else { 467 System.clearProperty("javax.rmi.ssl.client.enabledCipherSuites"); 468 } 469 } 470 471 private void checkSslConfiguration() { 472 try { 473 final String defaultConf = 474 getDefaultFileName(DefaultValues.CONFIG_FILE_NAME); 475 final String confname = 476 System.getProperty(PropertyNames.CONFIG_FILE_NAME,defaultConf); 477 478 final Properties props = new Properties(); 479 final File conf = new File(confname); 480 if (conf.exists()) { 481 FileInputStream fin = new FileInputStream(conf); 482 try {props.load(fin);} finally {fin.close();} 483 } 484 485 // Do we use SSL? 486 final String useSslStr = 487 props.getProperty(PropertyNames.USE_SSL, 488 DefaultValues.USE_SSL); 489 final boolean useSsl = 490 Boolean.valueOf(useSslStr).booleanValue(); 491 492 log.debug("checkSslConfiguration", 493 PropertyNames.USE_SSL+"="+useSsl+ 494 ": setting SSL"); 495 // Do we use SSL client authentication? 496 final String useSslClientAuthStr = 497 props.getProperty(PropertyNames.SSL_NEED_CLIENT_AUTH, 498 DefaultValues.SSL_NEED_CLIENT_AUTH); 499 final boolean useSslClientAuth = 500 Boolean.valueOf(useSslClientAuthStr).booleanValue(); 501 502 log.debug("checkSslConfiguration", 503 PropertyNames.SSL_NEED_CLIENT_AUTH+"="+useSslClientAuth); 504 505 // Do we use customized SSL cipher suites? 506 final String sslCipherSuites = 507 props.getProperty(PropertyNames.SSL_ENABLED_CIPHER_SUITES); 508 509 log.debug("checkSslConfiguration", 510 PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" + 511 sslCipherSuites); 512 513 // Do we use customized SSL protocols? 514 final String sslProtocols = 515 props.getProperty(PropertyNames.SSL_ENABLED_PROTOCOLS); 516 517 log.debug("checkSslConfiguration", 518 PropertyNames.SSL_ENABLED_PROTOCOLS + "=" + 519 sslProtocols); 520 521 if (useSsl) { 522 setSslProperties(props.getProperty( 523 PropertyNames.SSL_CLIENT_ENABLED_CIPHER_SUITES)); 524 } 525 } catch (Exception x) { 526 System.out.println("Failed to setup SSL configuration: " + x); 527 log.debug("checkSslConfiguration",x); 528 } 529 } 530 531 /** 532 * Tests the server bootstraped at the given URL. 533 * Uses the system properties to determine which config file is used. 534 * Loads the config file to determine which password file is used. 535 * Loads the password file to find out wich credentials to use. 536 * Also checks that unregistered user/passwords are not allowed to 537 * connect when a password file is used. 538 * 539 * This method calls connectAndRead(). 540 **/ 541 public void testCommunication(JMXServiceURL url) 542 throws IOException { 543 544 final String defaultConf = 545 getDefaultFileName(DefaultValues.CONFIG_FILE_NAME); 546 final String confname = 547 System.getProperty(PropertyNames.CONFIG_FILE_NAME,defaultConf); 548 549 final Properties props = new Properties(); 550 final File conf = new File(confname); 551 if (conf.exists()) { 552 FileInputStream fin = new FileInputStream(conf); 553 try {props.load(fin);} finally {fin.close();} 554 } 555 556 // Do we use authentication? 557 final String useAuthenticationStr = 558 props.getProperty(PropertyNames.USE_AUTHENTICATION, 559 DefaultValues.USE_AUTHENTICATION); 560 final boolean useAuthentication = 561 Boolean.valueOf(useAuthenticationStr).booleanValue(); 562 563 // Get Password File 564 final String defaultPasswordFileName = Utils.convertPath( 565 getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME)); 566 final String passwordFileName = Utils.convertPath( 567 props.getProperty(PropertyNames.PASSWORD_FILE_NAME, 568 defaultPasswordFileName)); 569 570 // Get Access File 571 final String defaultAccessFileName = Utils.convertPath( 572 getDefaultFileName(DefaultValues.ACCESS_FILE_NAME)); 573 final String accessFileName = Utils.convertPath( 574 props.getProperty(PropertyNames.ACCESS_FILE_NAME, 575 defaultAccessFileName)); 576 577 if (useAuthentication) { 578 System.out.println("PasswordFileName: " + passwordFileName); 579 System.out.println("accessFileName: " + accessFileName); 580 } 581 582 final Object[] allCredentials; 583 final Object[] noCredentials = { null }; 584 if (useAuthentication) { 585 final ArrayList l = readCredentials(passwordFileName); 586 if (l.size() == 0) allCredentials = null; 587 else allCredentials = l.toArray(); 588 } else allCredentials = noCredentials; 589 590 int errorCount = 0; 591 if (allCredentials!=null) { 592 // Tests that the registered user/passwords are allowed to 593 // connect & read 594 // 595 errorCount += connectAndRead(url,allCredentials,true,true); 596 } else { 597 // Tests that no one is allowed 598 // connect & read 599 // 600 final String[][] someCredentials = { 601 null, 602 { "modify", "R&D" }, 603 { "measure", "QED" } 604 }; 605 errorCount += connectAndRead(url,someCredentials,false,false); 606 } 607 608 if (useAuthentication && allCredentials != noCredentials) { 609 // Tests that the registered user/passwords are not allowed to 610 // connect & read 611 // 612 final String[][] badCredentials = { 613 { "bad.user", "R&D" }, 614 { "measure", "bad.password" } 615 }; 616 errorCount += connectAndRead(url,badCredentials,false,false); 617 } 618 if (errorCount > 0) { 619 final String err = "Test " + confname + " failed with " + 620 errorCount + " error(s)"; 621 log.debug("testCommunication",err); 622 throw new RuntimeException(err); 623 } 624 } 625 626 627 /** 628 * Test the configuration indicated by `file'. 629 * Sets the appropriate System properties for config file and 630 * port and then calls ConnectorBootstrap.initialize(). 631 * eventually cleans up by calling ConnectorBootstrap.terminate(). 632 * @return null if the test succeeds, an error message otherwise. 633 **/ 634 private String testConfiguration(File file) throws IOException, InterruptedException { 635 636 for (int i = 0; i < MAX_GET_FREE_PORT_TRIES; i++) { 637 try { 638 int port = jdk.testlibrary.Utils.getFreePort(); 639 final String path; 640 try { 641 path=(file==null)?null:file.getCanonicalPath(); 642 } catch(IOException x) { 643 final String err = "Failed to test configuration " + file + 644 ": " + x; 645 log.trace("testConfiguration",err); 646 log.debug("testConfiguration",x); 647 return err; 648 } 649 final String config = (path==null)?"Default config file":path; 650 651 System.out.println("***"); 652 System.out.println("*** Testing configuration (port=" + port + "): " 653 + path); 654 System.out.println("***"); 655 656 System.setProperty("com.sun.management.jmxremote.port", 657 Integer.toString(port)); 658 if (path != null) 659 System.setProperty("com.sun.management.config.file", path); 660 else 661 System.getProperties().remove("com.sun.management.config.file"); 662 663 log.trace("testConfiguration","com.sun.management.jmxremote.port="+port); 664 if (path != null && log.isDebugOn()) 665 log.trace("testConfiguration", 666 "com.sun.management.config.file="+path); 667 668 checkSslConfiguration(); 669 670 final JMXConnectorServer cs; 671 try { 672 cs = ConnectorBootstrap.initialize(); 673 } catch (AgentConfigurationError x) { 674 if (x.getCause() instanceof ExportException) { 675 if (x.getCause().getCause() instanceof BindException) { 676 throw (BindException)x.getCause().getCause(); 677 } 678 } 679 final String err = "Failed to initialize connector:" + 680 "\n\tcom.sun.management.jmxremote.port=" + port + 681 ((path!=null)?"\n\tcom.sun.management.config.file="+path: 682 "\n\t"+config) + 683 "\n\tError is: " + x; 684 log.trace("testConfiguration",err); 685 log.debug("testConfiguration",x); 686 return err; 687 } catch (Exception x) { 688 log.debug("testConfiguration",x); 689 return x.toString(); 690 } 691 692 try { 693 JMXServiceURL url = 694 new JMXServiceURL("rmi",null,0,"/jndi/rmi://localhost:"+ 695 port+"/jmxrmi"); 696 697 try { 698 testCommunication(url); 699 } catch (Exception x) { 700 final String err = "Failed to connect to agent {url="+url+ 701 "}: " + x; 702 log.trace("testConfiguration",err); 703 log.debug("testConfiguration",x); 704 return err; 705 } 706 } catch (Exception x) { 707 final String err = "Failed to test configuration "+config+ 708 ": "+x; 709 log.trace("testConfiguration",err); 710 log.debug("testConfiguration",x); 711 return err; 712 } finally { 713 try { 714 cs.stop(); 715 } catch (Exception x) { 716 final String err = "Failed to terminate: "+x; 717 log.trace("testConfiguration",err); 718 log.debug("testConfiguration",x); 719 } 720 } 721 System.out.println("Configuration " + config + " successfully tested"); 722 return null; 723 } catch(BindException ex) { 724 } 725 } 726 System.err.println("Cannot find a free port after " + MAX_GET_FREE_PORT_TRIES + " tries"); 727 return "Failed: cannot find a free port after " + MAX_GET_FREE_PORT_TRIES + " tries"; 728 } 729 730 /** 731 * Test a configuration file which should make the bootstrap fail. 732 * The test is assumed to have succeeded if the bootstrap fails. 733 * @return null if the test succeeds, an error message otherwise. 734 **/ 735 private String testConfigurationKo(File conf) throws InterruptedException, IOException { 736 String errStr = null; 737 errStr = testConfiguration(conf); 738 if (errStr == null) { 739 return "Configuration " + 740 conf + " should have failed!"; 741 } 742 System.out.println("Configuration " + 743 conf + " failed as expected"); 744 log.debug("runko", "Error was: " + errStr); 745 return null; 746 } 747 748 /** 749 * Test a configuration file. Determines whether the bootstrap 750 * should succeed or fail depending on the file name: 751 * *ok.properties: bootstrap should succeed. 752 * *ko.properties: bootstrap or connection should fail. 753 * @return null if the test succeeds, an error message otherwise. 754 **/ 755 private String testConfigurationFile(String fileName) throws InterruptedException, IOException { 756 File file = new File(fileName); 757 758 if (fileName.endsWith("ok.properties")) { 759 String errStr = null; 760 errStr = testConfiguration(file); 761 return errStr; 762 } 763 if (fileName.endsWith("ko.properties")) { 764 return testConfigurationKo(file); 765 } 766 return fileName + 767 ": test file suffix must be one of [ko|ok].properties"; 768 } 769 770 /** 771 * Find all *ko.property files and test them. 772 * (see findConfigurationFilesKo() and testConfigurationKo()) 773 * @throws RuntimeException if the test fails. 774 **/ 775 public void runko() throws InterruptedException, IOException { 776 final File[] conf = findConfigurationFilesKo(); 777 if ((conf == null)||(conf.length == 0)) 778 throw new RuntimeException("No configuration found"); 779 780 String errStr; 781 for (int i=0;i<conf.length;i++) { 782 errStr = testConfigurationKo(conf[i]); 783 if (errStr != null) { 784 throw new RuntimeException(errStr); 785 } 786 } 787 788 } 789 790 /** 791 * Find all *ok.property files and test them. 792 * (see findConfigurationFilesOk() and testConfiguration()) 793 * @throws RuntimeException if the test fails. 794 **/ 795 public void runok() throws InterruptedException, IOException { 796 final File[] conf = findConfigurationFilesOk(); 797 if ((conf == null)||(conf.length == 0)) 798 throw new RuntimeException("No configuration found"); 799 800 String errStr = null; 801 for (int i=0;i<conf.length;i++) { 802 errStr = testConfiguration(conf[i]); 803 if (errStr != null) { 804 throw new RuntimeException(errStr); 805 } 806 } 807 808 // FIXME: No jmxremote.password is not installed in JRE by default. 809 // - disable the following test case. 810 // 811 // Test default config 812 // 813 // errStr = testConfiguration(null,port+testPort++); 814 // if (errStr != null) { 815 // throw new RuntimeException(errStr); 816 // } 817 } 818 819 /** 820 * Finds all configuration files (*ok.properties and *ko.properties) 821 * and tests them. 822 * (see runko() and runok()). 823 * @throws RuntimeException if the test fails. 824 **/ 825 public void run() throws InterruptedException, IOException { 826 runok(); 827 runko(); 828 } 829 830 /** 831 * Tests the specified configuration files. 832 * If args[] is not empty, each element in args[] is expected to be 833 * a filename ending either by ok.properties or ko.properties. 834 * Otherwise, the configuration files will be automatically determined 835 * by looking at all *.properties files located in the directory 836 * indicated by the System property "test.src". 837 * @throws RuntimeException if the test fails. 838 **/ 839 public void run(String args[]) throws InterruptedException, IOException { 840 if (args.length == 0) { 841 run() ; return; 842 } 843 for (int i=0; i<args.length; i++) { 844 final String errStr =testConfigurationFile(args[i]); 845 if (errStr != null) { 846 throw new RuntimeException(errStr); 847 } 848 } 849 } 850 851 /** 852 * Calls run(args[]). 853 * exit(1) if the test fails. 854 **/ 855 public static void main(String args[]) throws Exception { 856 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 857 858 try { 859 MAX_GET_FREE_PORT_TRIES = Integer.parseInt(System.getProperty("test.getfreeport.max.tries", "10")); 860 } catch (NumberFormatException ex) { 861 } 862 863 RmiBootstrapTest manager = new RmiBootstrapTest(); 864 try { 865 manager.run(args); 866 } catch (RuntimeException r) { 867 System.out.println("Test Failed: "+ r.getMessage()); 868 System.exit(1); 869 } catch (Throwable t) { 870 System.out.println("Test Failed: "+ t); 871 t.printStackTrace(); 872 System.exit(2); 873 } 874 System.out.println("**** Test RmiBootstrap Passed ****"); 875 } 876 877 }