Path: blob/master/test/jdk/sun/management/jmxremote/bootstrap/JMXAgentInterfaceBinding.java
41153 views
/*1* Copyright (c) 2015, Red Hat Inc2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.IOException;24import java.net.InetAddress;25import java.net.InetSocketAddress;26import java.net.MalformedURLException;27import java.net.Socket;28import java.net.SocketAddress;29import java.net.UnknownHostException;30import java.nio.charset.StandardCharsets;31import java.util.HashMap;32import java.util.Map;33import java.util.concurrent.CountDownLatch;34import java.util.concurrent.TimeUnit;35import java.util.regex.Matcher;36import java.util.regex.Pattern;3738import javax.management.remote.JMXConnector;39import javax.management.remote.JMXConnectorFactory;40import javax.management.remote.JMXServiceURL;41import javax.management.remote.rmi.RMIConnectorServer;42import javax.net.ssl.SSLSocket;43import javax.net.ssl.SSLSocketFactory;44import javax.rmi.ssl.SslRMIClientSocketFactory;4546/**47* Tests client connections to the JDK's built-in JMX agent server on the given48* ports/interface combinations.49*50* @see JMXInterfaceBindingTest51*52* @author Severin Gehwolf <[email protected]>53*54* Usage:55*56* SSL:57* java -Dcom.sun.management.jmxremote.ssl.need.client.auth=true \58* -Dcom.sun.management.jmxremote.host=127.0.0.1 \59* -Dcom.sun.management.jmxremote.port=9111 \60* -Dcom.sun.management.jmxremote.rmi.port=9112 \61* -Dcom.sun.management.jmxremote.authenticate=false \62* -Dcom.sun.management.jmxremote.ssl=true \63* -Dcom.sun.management.jmxremote.registry.ssl=true64* -Djavax.net.ssl.keyStore=... \65* -Djavax.net.ssl.keyStorePassword=... \66* JMXAgentInterfaceBinding 127.0.0.1 9111 9112 true67*68* Non-SSL:69* java -Dcom.sun.management.jmxremote.host=127.0.0.1 \70* -Dcom.sun.management.jmxremote.port=9111 \71* -Dcom.sun.management.jmxremote.rmi.port=9112 \72* -Dcom.sun.management.jmxremote.authenticate=false \73* -Dcom.sun.management.jmxremote.ssl=false \74* JMXAgentInterfaceBinding 127.0.0.1 9111 9112 false75*76*/77public class JMXAgentInterfaceBinding {7879private final MainThread mainThread;8081public JMXAgentInterfaceBinding(InetAddress bindAddress,82int jmxPort,83int rmiPort,84boolean useSSL) {85this.mainThread = new MainThread(bindAddress, jmxPort, rmiPort, useSSL);86}8788public void startEndpoint() {89mainThread.start();90try {91mainThread.join();92} catch (InterruptedException e) {93throw new RuntimeException("Test failed", e);94}95if (mainThread.isFailed()) {96mainThread.rethrowException();97}98}99100public static void main(String[] args) {101if (args.length != 4) {102throw new RuntimeException(103"Test failed. usage: java JMXInterfaceBindingTest <BIND_ADDRESS> <JMX_PORT> <RMI_PORT> {true|false}");104}105int jmxPort = parsePortFromString(args[1]);106int rmiPort = parsePortFromString(args[2]);107boolean useSSL = Boolean.parseBoolean(args[3]);108String strBindAddr = args[0];109System.out.println(110"DEBUG: Running test for triplet (hostname,jmxPort,rmiPort) = ("111+ strBindAddr + "," + jmxPort + "," + rmiPort + "), useSSL = " + useSSL);112InetAddress bindAddress;113try {114bindAddress = InetAddress.getByName(args[0]);115} catch (UnknownHostException e) {116throw new RuntimeException("Test failed. Unknown ip: " + args[0]);117}118JMXAgentInterfaceBinding test = new JMXAgentInterfaceBinding(bindAddress,119jmxPort, rmiPort, useSSL);120test.startEndpoint(); // Expect for main test to terminate process121}122123private static int parsePortFromString(String port) {124try {125return Integer.parseInt(port);126} catch (NumberFormatException e) {127throw new RuntimeException(128"Invalid port specified. Not an integer! Value was: "129+ port);130}131}132133private static class JMXConnectorThread extends Thread {134135private final String addr;136private final int jmxPort;137private final int rmiPort;138private final boolean useSSL;139private final CountDownLatch latch;140private volatile boolean failed;141private volatile boolean jmxConnectWorked;142private volatile boolean rmiConnectWorked;143144private JMXConnectorThread(String addr,145int jmxPort,146int rmiPort,147boolean useSSL,148CountDownLatch latch) {149this.addr = addr;150this.jmxPort = jmxPort;151this.rmiPort = rmiPort;152this.latch = latch;153this.useSSL = useSSL;154}155156@Override157public void run() {158try {159connect();160} catch (IOException e) {161e.printStackTrace();162failed = true;163}164}165166private void connect() throws IOException {167System.out.println(168"JMXConnectorThread: Attempting JMX connection on: "169+ addr + " on port " + jmxPort);170JMXServiceURL url;171try {172url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://"173+ addr + ":" + jmxPort + "/jmxrmi");174} catch (MalformedURLException e) {175throw new RuntimeException("Test failed.", e);176}177Map<String, Object> env = new HashMap<>();178if (useSSL) {179SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();180env.put("com.sun.jndi.rmi.factory.socket", csf);181env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);182}183// connect and immediately close184JMXConnector c = JMXConnectorFactory.connect(url, env);185c.close();186System.out.println("JMXConnectorThread: connection to JMX worked");187jmxConnectWorked = true;188checkRmiSocket();189latch.countDown(); // signal we are done.190}191192private void checkRmiSocket() throws IOException {193Socket rmiConnection;194if (useSSL) {195rmiConnection = SSLSocketFactory.getDefault().createSocket();196} else {197rmiConnection = new Socket();198}199SocketAddress target = new InetSocketAddress(addr, rmiPort);200rmiConnection.connect(target);201if (useSSL) {202((SSLSocket)rmiConnection).startHandshake();203}204System.out.println(205"JMXConnectorThread: connection to rmi socket worked host/port = "206+ addr + "/" + rmiPort);207rmiConnectWorked = true;208// Closing the channel without sending any data will cause an209// java.io.EOFException on the server endpoint. We don't care about this210// though, since we only want to test if we can connect.211rmiConnection.close();212}213214public boolean isFailed() {215return failed;216}217218public boolean jmxConnectionWorked() {219return jmxConnectWorked;220}221222public boolean rmiConnectionWorked() {223return rmiConnectWorked;224}225}226227private static class MainThread extends Thread {228229private static final String EXP_TERM_MSG_REG = "Exit: ([0-9]+)";230private static final Pattern EXIT_PATTERN = Pattern.compile(EXP_TERM_MSG_REG);231private static final String COOP_EXIT = "MainThread: Cooperative Exit";232private static final int WAIT_FOR_JMX_AGENT_TIMEOUT_MS = 20_000;233private final String addr;234private final int jmxPort;235private final int rmiPort;236private final boolean useSSL;237private boolean jmxAgentStarted = false;238private volatile Exception excptn;239240private MainThread(InetAddress bindAddress, int jmxPort, int rmiPort, boolean useSSL) {241this.addr = wrapAddress(bindAddress.getHostAddress());242this.jmxPort = jmxPort;243this.rmiPort = rmiPort;244this.useSSL = useSSL;245}246247@Override248public void run() {249try {250waitUntilReadyForConnections();251252// Wait for termination message253String actualTerm = new String(System.in.readAllBytes(), StandardCharsets.UTF_8).trim();254System.err.println("DEBUG: MainThread: actualTerm: '" + actualTerm + "'");255Matcher matcher = EXIT_PATTERN.matcher(actualTerm);256if (matcher.matches()) {257int expExitCode = Integer.parseInt(matcher.group(1));258System.out.println(COOP_EXIT);259System.exit(expExitCode); // The main test expects this exit value260}261} catch (Exception e) {262this.excptn = e;263}264}265266private void waitUntilReadyForConnections() {267CountDownLatch latch = new CountDownLatch(1);268JMXConnectorThread connectionTester = new JMXConnectorThread(269addr, jmxPort, rmiPort, useSSL, latch);270connectionTester.start();271boolean expired = false;272try {273expired = !latch.await(WAIT_FOR_JMX_AGENT_TIMEOUT_MS, TimeUnit.MILLISECONDS);274System.out.println(275"MainThread: Finished waiting for JMX agent to become available: expired == "276+ expired);277jmxAgentStarted = !expired;278} catch (InterruptedException e) {279throw new RuntimeException("Test failed", e);280}281if (!jmxAgentStarted) {282throw new RuntimeException(283"Test failed. JMX server agents not becoming available.");284}285if (connectionTester.isFailed()286|| !connectionTester.jmxConnectionWorked()287|| !connectionTester.rmiConnectionWorked()) {288throw new RuntimeException(289"Test failed. JMX agent does not seem ready. See log output for details.");290}291// The main test expects this exact message being printed292System.out.println("MainThread: Ready for connections");293}294295private boolean isFailed() {296return excptn != null;297}298299private void rethrowException() throws RuntimeException {300throw new RuntimeException(excptn);301}302}303304/**305* Will wrap IPv6 address in '[]'306*/307static String wrapAddress(String address) {308if (address.contains(":")) {309return "[" + address + "]";310}311return address;312}313}314315316