/* * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import sun.management.jmxremote.ConnectorBootstrap; import java.io.File; import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.IOException; import java.net.BindException; import java.rmi.server.ExportException; import java.util.Properties; import java.util.Iterator; import java.util.Set; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Enumeration; import javax.management.remote.*; import javax.management.*; import jdk.internal.agent.AgentConfigurationError; import java.security.Security; /** *

This class implements unit test for RMI Bootstrap. * When called with no arguments main() looks in the directory indicated * by the "test.src" system property for files called management*ok.properties * or management*ko.properties. The *ok.properties files are assumed to be * valid Java M&M config files for which the bootstrap should succeed. * The *ko.properties files are assumed to be configurations for which the * bootstrap & connection test will fail.

* *

The rmi port number can be specified with the "rmi.port" system property. * If not, this test will use the first available port

* *

When called with some argument, the main() will interprete its args to * be Java M&M configuration file names. The filenames are expected to end * with ok.properties or ko.properties - and are interpreted as above.

* *

Note that a limitation of the RMI registry (bug 4267864) prevent * this test from succeeding if more than 1 configuration is used. * As long as 4267864 isn't fix, this test must be called as many times * as needed but with a single argument (no arguments, or several arguments * will fail).

* *

Debug traces are logged in "sun.management.test"

**/ public class RmiBootstrapTest { // the number of consecutive ports to test for availability private static int MAX_GET_FREE_PORT_TRIES = 10; static TestLogger log = new TestLogger("RmiBootstrapTest"); /** * Default values for RMI configuration properties. **/ public static interface DefaultValues { public static final String PORT="0"; public static final String CONFIG_FILE_NAME="management.properties"; public static final String USE_SSL="true"; public static final String USE_AUTHENTICATION="true"; public static final String PASSWORD_FILE_NAME="jmxremote.password"; public static final String ACCESS_FILE_NAME="jmxremote.access"; public static final String KEYSTORE="keystore"; public static final String KEYSTORE_PASSWD="password"; public static final String TRUSTSTORE="truststore"; public static final String TRUSTSTORE_PASSWD="trustword"; public static final String SSL_NEED_CLIENT_AUTH="false"; } /** * Names of RMI configuration properties. **/ public static interface PropertyNames { public static final String PORT= "com.sun.management.jmxremote.port"; public static final String CONFIG_FILE_NAME= "com.sun.management.config.file"; public static final String USE_SSL= "com.sun.management.jmxremote.ssl"; public static final String USE_AUTHENTICATION= "com.sun.management.jmxremote.authenticate"; public static final String PASSWORD_FILE_NAME= "com.sun.management.jmxremote.password.file"; public static final String ACCESS_FILE_NAME= "com.sun.management.jmxremote.access.file"; public static final String INSTRUMENT_ALL= "com.sun.management.instrumentall"; public static final String CREDENTIALS = "jmx.remote.credentials"; public static final String KEYSTORE= "javax.net.ssl.keyStore"; public static final String KEYSTORE_PASSWD= "javax.net.ssl.keyStorePassword"; public static final String TRUSTSTORE= "javax.net.ssl.trustStore"; public static final String TRUSTSTORE_PASSWD= "javax.net.ssl.trustStorePassword"; public static final String SSL_ENABLED_CIPHER_SUITES = "com.sun.management.jmxremote.ssl.enabled.cipher.suites"; public static final String SSL_ENABLED_PROTOCOLS = "com.sun.management.jmxremote.ssl.enabled.protocols"; public static final String SSL_NEED_CLIENT_AUTH = "com.sun.management.jmxremote.ssl.need.client.auth"; public static final String SSL_CLIENT_ENABLED_CIPHER_SUITES = "javax.rmi.ssl.client.enabledCipherSuites"; } /** * A filter to find all filenames who match *. * Note that and can overlap. **/ private static class ConfigFilenameFilter implements FilenameFilter { final String suffix; final String prefix; ConfigFilenameFilter(String prefix, String suffix) { this.suffix=suffix; this.prefix=prefix; } public boolean accept(File dir, String name) { return (name.startsWith(prefix) && name.endsWith(suffix)); } } /** * Get all "management*ok.properties" files in the directory * indicated by the "test.src" management property. **/ private static File[] findConfigurationFilesOk() { final String testSrc = System.getProperty("test.src"); final File dir = new File(testSrc); final FilenameFilter filter = new ConfigFilenameFilter("management_test","ok.properties"); return dir.listFiles(filter); } /** * Get all "management*ko.properties" files in the directory * indicated by the "test.src" management property. **/ private static File[] findConfigurationFilesKo() { final String testSrc = System.getProperty("test.src"); final File dir = new File(testSrc); final FilenameFilter filter = new ConfigFilenameFilter("management_test","ko.properties"); return dir.listFiles(filter); } /** * List all MBeans and their attributes. Used to test communication * with the Java M&M MBean Server. * @return the number of queried MBeans. */ public static int listMBeans(MBeanServerConnection server) throws IOException { return listMBeans(server,null,null); } /** * List all matching MBeans and their attributes. * Used to test communication with the Java M&M MBean Server. * @return the number of matching MBeans. */ public static int listMBeans(MBeanServerConnection server, ObjectName pattern, QueryExp query) throws IOException { final Set names = server.queryNames(pattern,query); for (final Iterator i=names.iterator(); i.hasNext(); ) { ObjectName name = (ObjectName)i.next(); log.trace("listMBeans","Got MBean: "+name); try { MBeanInfo info = server.getMBeanInfo((ObjectName)name); MBeanAttributeInfo[] attrs = info.getAttributes(); if (attrs == null) continue; for (int j=0; j, }. * If the password file does not exists, return an empty list. * (File not found = empty file). **/ private ArrayList readCredentials(String passwordFileName) throws IOException { final Properties pws = new Properties(); final ArrayList result = new ArrayList(); final File f = new File(passwordFileName); if (!f.exists()) return result; FileInputStream fin = new FileInputStream(passwordFileName); try {pws.load(fin);}finally{fin.close();} for (Enumeration en=pws.propertyNames();en.hasMoreElements();) { final String[] cred = new String[2]; cred[0]=(String)en.nextElement(); cred[1]=pws.getProperty(cred[0]); result.add(cred); } return result; } /** * Connect with the given url, using all given credentials in turn. * A null entry in the useCredentials arrays indicate a connection * where no credentials are used. * @param url JMXServiceURL of the server. * @param useCredentials An array of credentials (a credential * is a two String array, so this is an array of arrays * of strings: * useCredentials[i][0]=subject * useCredentials[i][1]=password * if useCredentials[i] == null means no credentials. * @param expectConnectOk true if connection is expected to succeed * Note: if expectConnectOk=false and the test fails to connect * the number of failure is not incremented. Conversely, * if expectConnectOk=false and the test does not fail to * connect the number of failure is incremented. * @param expectReadOk true if communication (listMBeans) is expected * to succeed. * Note: if expectReadOk=false and the test fails to read MBeans * the number of failure is not incremented. Conversely, * if expectReadOk=false and the test does not fail to * read MBeans the number of failure is incremented. * @return number of failure. **/ public int connectAndRead(JMXServiceURL url, Object[] useCredentials, boolean expectConnectOk, boolean expectReadOk) throws IOException { int errorCount = 0; for (int i=0 ; i 0) { final String err = "Test " + confname + " failed with " + errorCount + " error(s)"; log.debug("testCommunication",err); throw new RuntimeException(err); } } /** * Test the configuration indicated by `file'. * Sets the appropriate System properties for config file and * port and then calls ConnectorBootstrap.initialize(). * eventually cleans up by calling ConnectorBootstrap.terminate(). * @return null if the test succeeds, an error message otherwise. **/ private String testConfiguration(File file) throws IOException, InterruptedException { for (int i = 0; i < MAX_GET_FREE_PORT_TRIES; i++) { try { int port = jdk.test.lib.Utils.getFreePort(); final String path; try { path=(file==null)?null:file.getCanonicalPath(); } catch(IOException x) { final String err = "Failed to test configuration " + file + ": " + x; log.trace("testConfiguration",err); log.debug("testConfiguration",x); return err; } final String config = (path==null)?"Default config file":path; System.out.println("***"); System.out.println("*** Testing configuration (port=" + port + "): " + path); System.out.println("***"); System.setProperty("com.sun.management.jmxremote.port", Integer.toString(port)); if (path != null) System.setProperty("com.sun.management.config.file", path); else System.getProperties().remove("com.sun.management.config.file"); log.trace("testConfiguration","com.sun.management.jmxremote.port="+port); if (path != null && log.isDebugOn()) log.trace("testConfiguration", "com.sun.management.config.file="+path); checkSslConfiguration(); final JMXConnectorServer cs; try { cs = ConnectorBootstrap.initialize(); } catch (AgentConfigurationError x) { if (x.getCause() instanceof ExportException) { if (x.getCause().getCause() instanceof BindException) { throw (BindException)x.getCause().getCause(); } } final String err = "Failed to initialize connector:" + "\n\tcom.sun.management.jmxremote.port=" + port + ((path!=null)?"\n\tcom.sun.management.config.file="+path: "\n\t"+config) + "\n\tError is: " + x; log.trace("testConfiguration",err); log.debug("testConfiguration",x); return err; } catch (Exception x) { log.debug("testConfiguration",x); return x.toString(); } try { JMXServiceURL url = new JMXServiceURL("rmi",null,0,"/jndi/rmi://localhost:"+ port+"/jmxrmi"); try { testCommunication(url); } catch (Exception x) { final String err = "Failed to connect to agent {url="+url+ "}: " + x; log.trace("testConfiguration",err); log.debug("testConfiguration",x); return err; } } catch (Exception x) { final String err = "Failed to test configuration "+config+ ": "+x; log.trace("testConfiguration",err); log.debug("testConfiguration",x); return err; } finally { try { cs.stop(); } catch (Exception x) { final String err = "Failed to terminate: "+x; log.trace("testConfiguration",err); log.debug("testConfiguration",x); } } System.out.println("Configuration " + config + " successfully tested"); return null; } catch(BindException ex) { } } System.err.println("Cannot find a free port after " + MAX_GET_FREE_PORT_TRIES + " tries"); return "Failed: cannot find a free port after " + MAX_GET_FREE_PORT_TRIES + " tries"; } /** * Test a configuration file which should make the bootstrap fail. * The test is assumed to have succeeded if the bootstrap fails. * @return null if the test succeeds, an error message otherwise. **/ private String testConfigurationKo(File conf) throws InterruptedException, IOException { String errStr = null; errStr = testConfiguration(conf); if (errStr == null) { return "Configuration " + conf + " should have failed!"; } System.out.println("Configuration " + conf + " failed as expected"); log.debug("runko", "Error was: " + errStr); return null; } /** * Test a configuration file. Determines whether the bootstrap * should succeed or fail depending on the file name: * *ok.properties: bootstrap should succeed. * *ko.properties: bootstrap or connection should fail. * @return null if the test succeeds, an error message otherwise. **/ private String testConfigurationFile(String fileName) throws InterruptedException, IOException { File file = new File(fileName); if (fileName.endsWith("ok.properties")) { String errStr = null; errStr = testConfiguration(file); return errStr; } if (fileName.endsWith("ko.properties")) { return testConfigurationKo(file); } return fileName + ": test file suffix must be one of [ko|ok].properties"; } /** * Find all *ko.property files and test them. * (see findConfigurationFilesKo() and testConfigurationKo()) * @throws RuntimeException if the test fails. **/ public void runko() throws InterruptedException, IOException { final File[] conf = findConfigurationFilesKo(); if ((conf == null)||(conf.length == 0)) throw new RuntimeException("No configuration found"); String errStr; for (int i=0;i