Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/management/remote/mandatory/connection/ConnectionTest.java
38867 views
/*1* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.2* 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*/2223/*24* @test25* @bug 486539726* @summary Tests remote JMX connections27* @author Eamonn McManus28* @run clean ConnectionTest29* @run build ConnectionTest30* @run main ConnectionTest31*/3233import java.io.IOException;34import java.net.MalformedURLException;35import java.util.Collections;36import java.util.HashMap;37import java.util.HashSet;38import java.util.Iterator;39import java.util.LinkedList;40import java.util.List;41import java.util.Map;42import java.util.Set;43import java.util.StringTokenizer;4445import java.security.Principal;46import java.util.regex.Pattern;47import javax.security.auth.Subject;4849import javax.management.MBeanServer;50import javax.management.MBeanServerConnection;51import javax.management.MBeanServerFactory;52import javax.management.Notification;53import javax.management.NotificationListener;54import javax.management.ObjectName;5556import javax.management.remote.JMXAuthenticator;57import javax.management.remote.JMXConnectionNotification;58import javax.management.remote.JMXConnector;59import javax.management.remote.JMXConnectorFactory;60import javax.management.remote.JMXConnectorServer;61import javax.management.remote.JMXConnectorServerFactory;62import javax.management.remote.JMXPrincipal;63import javax.management.remote.JMXServiceURL;6465public class ConnectionTest {6667public static void main(String[] args) {68// System.setProperty("java.util.logging.config.file",69// "../../../../logging.properties");70// // we are in <workspace>/build/test/JTwork/scratch71// java.util.logging.LogManager.getLogManager().readConfiguration();72boolean ok = true;73String[] protocols = {"rmi", "iiop", "jmxmp"};74if (args.length > 0)75protocols = args;76for (int i = 0; i < protocols.length; i++) {77final String proto = protocols[i];78System.out.println("Testing for protocol " + proto);79try {80ok &= test(proto);81} catch (Exception e) {82System.err.println("Unexpected exception: " + e);83e.printStackTrace();84ok = false;85}86}8788if (ok)89System.out.println("Test passed");90else {91System.out.println("TEST FAILED");92System.exit(1);93}94}9596private static boolean test(String proto) throws Exception {97ObjectName serverName = ObjectName.getInstance("d:type=server");98MBeanServer mbs = MBeanServerFactory.newMBeanServer();99JMXAuthenticator authenticator = new BogusAuthenticator();100Map env = Collections.singletonMap("jmx.remote.authenticator",101authenticator);102JMXServiceURL url = new JMXServiceURL("service:jmx:" + proto + "://");103JMXConnectorServer server;104try {105server =106JMXConnectorServerFactory.newJMXConnectorServer(url, env,107null);108} catch (MalformedURLException e) {109System.out.println("Protocol " + proto +110" not supported, ignoring");111return true;112}113System.out.println("Created connector server");114mbs.registerMBean(server, serverName);115System.out.println("Registered connector server in MBean server");116mbs.addNotificationListener(serverName, logListener, null, null);117mbs.invoke(serverName, "start", null, null);118System.out.println("Started connector server");119JMXServiceURL address =120(JMXServiceURL) mbs.getAttribute(serverName, "Address");121System.out.println("Retrieved address: " + address);122123if (address.getHost().length() == 0) {124System.out.println("Generated address has empty hostname");125return false;126}127128JMXConnector client = JMXConnectorFactory.connect(address);129System.out.println("Client connected");130131String clientConnId = client.getConnectionId();132System.out.println("Got connection ID on client: " + clientConnId);133boolean ok = checkConnectionId(proto, clientConnId);134if (!ok)135return false;136System.out.println("Connection ID is OK");137138// 4901826: connection ids need some time to be updated using jmxmp139// we don't get the notif immediately either140// this was originally timeout 1ms, which was not enough141Notification notif = waitForNotification(1000);142System.out.println("Server got notification: " + notif);143144ok = mustBeConnectionNotification(notif, clientConnId,145JMXConnectionNotification.OPENED);146if (!ok)147return false;148149client.close();150System.out.println("Closed client");151152notif = waitForNotification(1000);153System.out.println("Got notification: " + notif);154155ok = mustBeConnectionNotification(notif, clientConnId,156JMXConnectionNotification.CLOSED);157if (!ok)158return false;159160client = JMXConnectorFactory.connect(address);161System.out.println("Second client connected");162163String clientConnId2 = client.getConnectionId();164if (clientConnId.equals(clientConnId2)) {165System.out.println("Same connection ID for two connections: " +166clientConnId2);167return false;168}169System.out.println("Second client connection ID is different");170171notif = waitForNotification(1);172ok = mustBeConnectionNotification(notif, clientConnId2,173JMXConnectionNotification.OPENED);174if (!ok)175return false;176177MBeanServerConnection mbsc = client.getMBeanServerConnection();178Map attrs = (Map) mbsc.getAttribute(serverName, "Attributes");179System.out.println("Server attributes received by client: " + attrs);180181server.stop();182System.out.println("Server stopped");183184notif = waitForNotification(1000);185System.out.println("Server got connection-closed notification: " +186notif);187188ok = mustBeConnectionNotification(notif, clientConnId2,189JMXConnectionNotification.CLOSED);190if (!ok)191return false;192193try {194mbsc.getDefaultDomain();195System.out.println("Connection still working but should not be");196return false;197} catch (IOException e) {198System.out.println("Connection correctly got exception: " + e);199}200201try {202client = JMXConnectorFactory.connect(address);203System.out.println("Connector server still working but should " +204"not be");205return false;206} catch (IOException e) {207System.out.println("New connection correctly got exception: " + e);208}209210return true;211}212213private static boolean214mustBeConnectionNotification(Notification notif,215String requiredConnId,216String requiredType) {217218if (!(notif instanceof JMXConnectionNotification)) {219System.out.println("Should have been a " +220"JMXConnectionNotification: " +221notif.getClass());222return false;223}224225JMXConnectionNotification cnotif = (JMXConnectionNotification) notif;226if (!cnotif.getType().equals(requiredType)) {227System.out.println("Wrong type notif: is \"" + cnotif.getType() +228"\", should be \"" + requiredType + "\"");229return false;230}231232if (!cnotif.getConnectionId().equals(requiredConnId)) {233System.out.println("Wrong connection id: is \"" +234cnotif.getConnectionId() + "\", should be \"" +235requiredConnId);236return false;237}238239return true;240}241242private static final String IPV4_PTN = "^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}(\\:[1-9][0-9]{3})?$";243244/**245* Checks the connection id for validity.246* The {@link247* javax.management.remote package description} describes the248* conventions for connection IDs.249* @param proto Connection protocol250* @param clientConnId The connection ID251* @return Returns {@code true} if the connection id conforms to the specification; {@code false} otherwise.252* @throws Exception253*/254private static boolean checkConnectionId(String proto, String clientConnId)255throws Exception {256StringTokenizer tok = new StringTokenizer(clientConnId, " ", true);257String s;258s = tok.nextToken();259if (!s.startsWith(proto + ":")) {260System.out.println("Expected \"" + proto + ":\", found \"" + s +261"\"");262return false;263}264265int hostAddrInd = s.indexOf("//");266if (hostAddrInd > -1) {267s = s.substring(hostAddrInd + 2);268if (!Pattern.matches(IPV4_PTN, s)) {269if (!s.startsWith("[") || !s.endsWith("]")) {270System.out.println("IPv6 address must be enclosed in \"[]\"");271return false;272}273}274}275s = tok.nextToken();276if (!s.equals(" ")) {277System.out.println("Expected \" \", found \"" + s + "\"");278return false;279}280s = tok.nextToken();281StringTokenizer tok2 = new StringTokenizer(s, ";", true);282Set principalNames = new HashSet();283String s2;284s2 = tok2.nextToken();285if (s2.equals(";")) {286System.out.println("In identity \"" + s +287"\", expected name, found \";\"");288return false;289}290principalNames.add(s2);291s2 = tok2.nextToken();292if (!s2.equals(";"))293throw new Exception("Can't happen");294s2 = tok2.nextToken();295if (s2.equals(";")) {296System.out.println("In identity \"" + s +297"\", expected name, found \";\"");298return false;299}300principalNames.add(s2);301if (tok2.hasMoreTokens()) {302System.out.println("In identity \"" + s + "\", too many tokens");303return false;304}305if (principalNames.size() != bogusPrincipals.size()) {306System.out.println("Wrong number of principal names: " +307principalNames.size() + " != " +308bogusPrincipals.size());309return false;310}311for (Iterator it = bogusPrincipals.iterator(); it.hasNext(); ) {312Principal p = (Principal) it.next();313if (!principalNames.contains(p.getName())) {314System.out.println("Principal names don't contain \"" +315p.getName() + "\"");316return false;317}318}319s = tok.nextToken();320if (!s.equals(" ")) {321System.out.println("Expected \" \", found \"" + s + "\"");322return false;323}324return true;325}326327private static Notification waitForNotification(long timeout)328throws InterruptedException {329synchronized (log) {330if (log.isEmpty()) {331long remainingTime = timeout;332final long startTime = System.currentTimeMillis();333334while (log.isEmpty() && remainingTime >0) {335log.wait(remainingTime);336remainingTime = timeout - (System.currentTimeMillis() - startTime);337}338339if (log.isEmpty()) {340throw new InterruptedException("Timed out waiting for " +341"notification!");342}343}344return (Notification) log.remove(0);345}346}347348private static class LogListener implements NotificationListener {349LogListener(List log) {350this.log = log;351}352353public void handleNotification(Notification n, Object h) {354synchronized (log) {355log.add(n);356log.notifyAll();357}358}359360private final List log;361}362363private static List log = new LinkedList();364private static NotificationListener logListener = new LogListener(log);365366private static class BogusAuthenticator implements JMXAuthenticator {367public Subject authenticate(Object credentials) {368Subject subject =369new Subject(true, bogusPrincipals,370Collections.EMPTY_SET, Collections.EMPTY_SET);371System.out.println("Authenticator returns: " + subject);372return subject;373}374}375376private static final Set bogusPrincipals = new HashSet();377static {378bogusPrincipals.add(new JMXPrincipal("foo"));379bogusPrincipals.add(new JMXPrincipal("bar"));380}381}382383384