Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/management/remote/mandatory/connection/BrokenConnectionTest.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 4940957 802520526* @summary Tests behaviour when connections break27* @author Eamonn McManus28* @run clean BrokenConnectionTest29* @run build BrokenConnectionTest30* @run main BrokenConnectionTest31*/3233import java.io.*;34import java.lang.reflect.*;35import java.nio.channels.ServerSocketChannel;36import java.net.*;37import java.rmi.server.*;38import java.util.*;3940import java.rmi.UnmarshalException;4142import javax.management.*;43import javax.management.remote.*;44import javax.management.remote.rmi.*;4546// resolve ambiguity47import java.lang.reflect.Proxy;4849public class BrokenConnectionTest {50private static ObjectName DELEGATE_NAME;51private static ObjectName BREAK_NAME;52private static ObjectName LISTENER_NAME;53public static void main(String[] args) throws Exception {54DELEGATE_NAME =55new ObjectName("JMImplementation:type=MBeanServerDelegate");56BREAK_NAME = new ObjectName("test:type=Break");57LISTENER_NAME = new ObjectName("test:type=Listener");5859String failed = "";6061final String[] protos = {"rmi", "jmxmp"};6263for (int i = 0; i < protos.length; i++) {64final String proto = protos[i];65System.out.println();66System.out.println("------- Testing for " + proto + " -------");67try {68if (!test(proto))69failed += " " + proto;70} catch (Exception e) {71System.out.println("FAILED WITH EXCEPTION:");72e.printStackTrace(System.out);73failed += " " + proto;74}75}7677System.out.println();7879if (failed.length() > 0) {80System.out.println("TEST FAILED FOR:" + failed);81System.exit(1);82}8384System.out.println("Test passed");85}8687private static boolean test(String proto) throws Exception {88if (proto.equals("rmi"))89return rmiTest();90else if (proto.equals("jmxmp"))91return jmxmpTest();92else93throw new AssertionError(proto);94}9596private static interface Breakable {97public JMXConnectorServer createConnectorServer(MBeanServer mbs)98throws IOException;99public void setBroken(boolean broken);100}101102private static interface TestAction {103public String toString();104public boolean test(MBeanServerConnection mbsc, Breakable breakable)105throws Exception;106}107108private static abstract class Operation implements TestAction {109public String toString() {110return opName() + ", break, " + opName();111}112void init(MBeanServerConnection mbsc) throws Exception {}113abstract String opName();114public boolean test(MBeanServerConnection mbsc, Breakable breakable)115throws Exception {116init(mbsc);117operation(mbsc);118System.out.println("Client ran " + opName() + " OK");119breakable.setBroken(true);120System.out.println("Broke connection, run " + opName() + " again");121try {122operation(mbsc);123System.out.println("TEST FAILED: " + opName() +124" should fail!");125return false;126} catch (IOException e) {127System.out.println("Got IOException as expected (" + e + ")");128}129return true;130}131abstract void operation(MBeanServerConnection mbsc) throws Exception;132}133134private static TestAction[] tests = {135new Operation() {136String opName() {137return "getDefaultDomain";138}139void operation(MBeanServerConnection mbsc) throws Exception {140mbsc.getDefaultDomain();141}142},143new Operation() {144String opName() {145return "addNotificationListener(NL)";146}147void operation(MBeanServerConnection mbsc) throws Exception {148mbsc.addNotificationListener(DELEGATE_NAME,149new CountListener(), null, null);150}151},152new Operation() {153String opName() {154return "addNotificationListener(MB)";155}156void init(MBeanServerConnection mbsc) throws Exception {157mbsc.createMBean(CountListener.class.getName(),158LISTENER_NAME);159}160void operation(MBeanServerConnection mbsc) throws Exception {161mbsc.addNotificationListener(DELEGATE_NAME, LISTENER_NAME,162null, null);163}164},165new Operation() {166String opName() {167return "removeNotificationListener(NL)";168}169void init(MBeanServerConnection mbsc) throws Exception {170for (int i = 0; i < NLISTENERS; i++) {171NotificationListener l = new CountListener();172mbsc.addNotificationListener(DELEGATE_NAME, l, null, null);173listeners.add(l);174}175}176void operation(MBeanServerConnection mbsc) throws Exception {177NotificationListener l = (NotificationListener)178listeners.remove(0);179mbsc.removeNotificationListener(DELEGATE_NAME, l, null, null);180}181static final int NLISTENERS = 2;182List/*<NotificationListener>*/ listeners = new ArrayList();183},184new Operation() {185String opName() {186return "removeNotificationListener(MB)";187}188void init(MBeanServerConnection mbsc) throws Exception {189mbsc.createMBean(CountListener.class.getName(),190LISTENER_NAME);191}192void operation(MBeanServerConnection mbsc) throws Exception {193try {194mbsc.removeNotificationListener(DELEGATE_NAME,195LISTENER_NAME,196null, null);197throw new IllegalArgumentException("removeNL should not " +198"have worked!");199} catch (ListenerNotFoundException e) {200// normal - there isn't one!201}202}203},204new Operation() {205String opName() {206return "createMBean(className, objectName)";207}208void operation(MBeanServerConnection mbsc) throws Exception {209ObjectName name =210new ObjectName("test:instance=" + nextInstance());211mbsc.createMBean(CountListener.class.getName(), name);212}213private synchronized int nextInstance() {214return ++instance;215}216private int instance;217},218new Operation() {219String opName() {220return "getAttribute";221}222void operation(MBeanServerConnection mbsc) throws Exception {223mbsc.getAttribute(DELEGATE_NAME, "ImplementationName");224}225},226new Operation() {227String opName() {228return "getAttributes";229}230void operation(MBeanServerConnection mbsc) throws Exception {231mbsc.getAttribute(DELEGATE_NAME, "ImplementationName");232}233},234new Operation() {235String opName() {236return "getDomains";237}238void operation(MBeanServerConnection mbsc) throws Exception {239mbsc.getDomains();240}241},242new Operation() {243String opName() {244return "getMBeanCount";245}246void operation(MBeanServerConnection mbsc) throws Exception {247mbsc.getMBeanCount();248}249},250new Operation() {251String opName() {252return "getMBeanInfo";253}254void operation(MBeanServerConnection mbsc) throws Exception {255mbsc.getMBeanInfo(DELEGATE_NAME);256}257},258new Operation() {259String opName() {260return "getObjectInstance";261}262void operation(MBeanServerConnection mbsc) throws Exception {263mbsc.getObjectInstance(DELEGATE_NAME);264}265},266new Operation() {267String opName() {268return "invoke";269}270void operation(MBeanServerConnection mbsc) throws Exception {271mbsc.invoke(BREAK_NAME, "doNothing", new Object[0],272new String[0]);273}274},275new Operation() {276String opName() {277return "isInstanceOf";278}279void operation(MBeanServerConnection mbsc) throws Exception {280mbsc.isInstanceOf(DELEGATE_NAME, "whatsit");281}282},283new Operation() {284String opName() {285return "isRegistered";286}287void operation(MBeanServerConnection mbsc) throws Exception {288mbsc.isRegistered(DELEGATE_NAME);289}290},291new Operation() {292String opName() {293return "queryMBeans";294}295void operation(MBeanServerConnection mbsc) throws Exception {296mbsc.queryMBeans(new ObjectName("*:*"), null);297}298},299new Operation() {300String opName() {301return "queryNames";302}303void operation(MBeanServerConnection mbsc) throws Exception {304mbsc.queryNames(new ObjectName("*:*"), null);305}306},307new Operation() {308String opName() {309return "setAttribute";310}311void operation(MBeanServerConnection mbsc) throws Exception {312mbsc.setAttribute(BREAK_NAME,313new Attribute("Nothing", null));314}315},316new Operation() {317String opName() {318return "setAttributes";319}320void operation(MBeanServerConnection mbsc) throws Exception {321AttributeList attrs = new AttributeList();322attrs.add(new Attribute("Nothing", null));323mbsc.setAttributes(BREAK_NAME, attrs);324}325},326new Operation() {327String opName() {328return "unregisterMBean";329}330void init(MBeanServerConnection mbsc) throws Exception {331for (int i = 0; i < NBEANS; i++) {332ObjectName name = new ObjectName("test:instance=" + i);333mbsc.createMBean(CountListener.class.getName(), name);334names.add(name);335}336}337void operation(MBeanServerConnection mbsc) throws Exception {338ObjectName name = (ObjectName) names.remove(0);339mbsc.unregisterMBean(name);340}341private static final int NBEANS = 2;342private List/*<ObjectName>*/ names = new ArrayList();343},344new TestAction() {345public String toString() {346return "break during send for setAttribute";347}348public boolean test(MBeanServerConnection mbsc,349Breakable breakable) throws Exception {350Attribute attr =351new Attribute("Break", new BreakWhenSerialized(breakable));352try {353mbsc.setAttribute(BREAK_NAME, attr);354System.out.println("TEST FAILED: setAttribute with " +355"BreakWhenSerializable did not fail!");356return false;357} catch (IOException e) {358System.out.println("Got IOException as expected: " + e);359360return true;361}362}363},364new TestAction() {365public String toString() {366return "break during receive for getAttribute";367}368public boolean test(MBeanServerConnection mbsc,369Breakable breakable) throws Exception {370try {371mbsc.getAttribute(BREAK_NAME, "Break");372System.out.println("TEST FAILED: getAttribute of " +373"BreakWhenSerializable did not fail!");374return false;375} catch (IOException e) {376System.out.println("Got IOException as expected: " + e);377378return true;379}380}381},382};383384public static interface BreakMBean {385public BreakWhenSerialized getBreak();386public void setBreak(BreakWhenSerialized x);387// public void breakOnNotify();388public void doNothing();389public void setNothing(Object x);390}391392public static class Break393extends NotificationBroadcasterSupport implements BreakMBean {394public Break(Breakable breakable) {395this.breakable = breakable;396}397398public BreakWhenSerialized getBreak() {399return new BreakWhenSerialized(breakable);400}401402public void setBreak(BreakWhenSerialized x) {403throw new IllegalArgumentException("setBreak worked but " +404"should not!");405}406407// public void breakOnNotify() {408// Notification broken = new Notification("type", "source", 0L);409// broken.setUserData(new BreakWhenSerialized(breakable));410// sendNotification(broken);411// }412413public void doNothing() {}414415public void setNothing(Object x) {}416417private final Breakable breakable;418}419420private static class BreakWhenSerialized implements Serializable {421BreakWhenSerialized(Breakable breakable) {422this.breakable = breakable;423}424425private void writeObject(ObjectOutputStream out) throws IOException {426breakable.setBroken(true);427}428429private final transient Breakable breakable;430}431432private static class FailureNotificationFilter433implements NotificationFilter {434public boolean isNotificationEnabled(Notification n) {435System.out.println("Filter: " + n + " (" + n.getType() + ")");436437final String failed =438JMXConnectionNotification.FAILED;439return (n instanceof JMXConnectionNotification440&& n.getType().equals(JMXConnectionNotification.FAILED));441}442}443444public static interface CountListenerMBean {}445446public static class CountListener447implements CountListenerMBean, NotificationListener {448public synchronized void handleNotification(Notification n, Object h) {449count++;450}451452int count;453}454455private static boolean test(Breakable breakable)456throws Exception {457boolean alreadyMissedFailureNotif = false;458String failed = "";459for (int i = 1; i <= tests.length; i++) {460TestAction ta = tests[i - 1];461System.out.println();462System.out.println("Test " + i + ": " + ta);463MBeanServer mbs = MBeanServerFactory.newMBeanServer();464Break breakMBean = new Break(breakable);465mbs.registerMBean(breakMBean, BREAK_NAME);466JMXConnectorServer cs = breakable.createConnectorServer(mbs);467System.out.println("Created and started connector server");468JMXServiceURL addr = cs.getAddress();469JMXConnector cc = JMXConnectorFactory.connect(addr);470CountListener failureListener = new CountListener();471NotificationFilter failureFilter = new FailureNotificationFilter();472cc.addConnectionNotificationListener(failureListener,473failureFilter,474null);475MBeanServerConnection mbsc = cc.getMBeanServerConnection();476System.out.println("Client connected OK");477boolean thisok = ta.test(mbsc, breakable);478479try {480System.out.println("Stopping server");481cs.stop();482} catch (IOException e) {483System.out.println("Ignoring exception on stop: " + e);484}485if (thisok) {486System.out.println("Waiting for failure notif");487// pass or test timeout. see 8025205488do {489Thread.sleep(100);490} while (failureListener.count < 1);491492Thread.sleep(1000); // if more notif coming ...493if (failureListener.count > 1) {494System.out.println("Got too many failure notifs: " +495failureListener.count);496thisok = false;497}498}499if (!thisok)500failed = failed + " " + i;501System.out.println("Test " + i + (thisok ? " passed" : " FAILED"));502breakable.setBroken(false);503}504if (failed.equals(""))505return true;506else {507System.out.println("FAILING CASES:" + failed);508return false;509}510}511512private static class BreakableRMI implements Breakable {513public JMXConnectorServer createConnectorServer(MBeanServer mbs)514throws IOException {515JMXServiceURL url = new JMXServiceURL("rmi", null, 0);516Map env = new HashMap();517env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,518brssf);519JMXConnectorServer cs =520JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);521cs.start();522return cs;523}524525public void setBroken(boolean broken) {526brssf.setBroken(broken);527}528529private final BreakableRMIServerSocketFactory brssf =530new BreakableRMIServerSocketFactory();531}532533private static boolean rmiTest() throws Exception {534System.out.println("RMI broken connection test");535Breakable breakable = new BreakableRMI();536return test(breakable);537}538539private static class BreakableRMIServerSocketFactory540implements RMIServerSocketFactory {541542public synchronized ServerSocket createServerSocket(int port)543throws IOException {544if (broken)545throw new IOException("ServerSocket has been broken");546BreakableServerSocket bss = new BreakableServerSocket(port);547bssList.add(bss);548return bss;549}550551synchronized void setBroken(boolean broken) {552this.broken = broken;553// System.out.println("BRSSF.setBroken(" + broken + ")");554for (Iterator it = bssList.iterator(); it.hasNext(); ) {555BreakableServerSocket bss = (BreakableServerSocket) it.next();556// System.out.println((broken ? "" : "un") + "break " + bss);557bss.setBroken(broken);558}559}560561private final List/*<BreakableServerSocket>*/ bssList =562new ArrayList();563private boolean broken = false;564}565566private static class BreakableJMXMP implements Breakable {567BreakableJMXMP() throws IOException {568bss = new BreakableServerSocket(0);569}570571public JMXConnectorServer createConnectorServer(MBeanServer mbs)572throws IOException {573try {574InvocationHandler scsih =575new SocketConnectionServerInvocationHandler(bss);576final String mcs =577"javax.management.remote.generic.MessageConnectionServer";578final Class messageConnectionServerClass = Class.forName(mcs);579final Class[] proxyInterfaces = {messageConnectionServerClass};580Object socketConnectionServer =581Proxy.newProxyInstance(this.getClass().getClassLoader(),582proxyInterfaces,583scsih);584Map env = new HashMap();585env.put("jmx.remote.message.connection.server",586socketConnectionServer);587final String gcs =588"javax.management.remote.generic.GenericConnectorServer";589final Class genericConnectorServerClass = Class.forName(gcs);590final Class[] constrTypes = {Map.class, MBeanServer.class};591final Constructor constr =592genericConnectorServerClass.getConstructor(constrTypes);593JMXConnectorServer cs = (JMXConnectorServer)594constr.newInstance(new Object[] {env, mbs});595cs.start();596return cs;597} catch (Exception e) {598e.printStackTrace(System.out);599throw new AssertionError(e);600}601}602603public void setBroken(boolean broken) {604bss.setBroken(broken);605}606607private final BreakableServerSocket bss;608}609610private static boolean jmxmpTest() throws Exception {611System.out.println("JMXMP broken connection test");612try {613Class.forName("javax.management.remote.generic.GenericConnector");614} catch (ClassNotFoundException e) {615System.out.println("Optional classes not present, skipping test");616return true;617}618Breakable breakable = new BreakableJMXMP();619return test(breakable);620}621622private static class BreakableServerSocket extends ServerSocket {623BreakableServerSocket(int port) throws IOException {624super();625ss = new ServerSocket(port);626}627628synchronized void setBroken(boolean broken) {629this.broken = broken;630// System.out.println("BSS.setBroken(" + broken + ")");631if (!broken)632return;633for (Iterator it = sList.iterator(); it.hasNext(); ) {634Socket s = (Socket) it.next();635try {636// System.out.println("Break: " + s);637s.close();638} catch (IOException e) {639System.out.println("Unable to close socket: " + s +640", ignoring (" + e + ")");641}642it.remove();643}644}645646public void bind(SocketAddress endpoint) throws IOException {647ss.bind(endpoint);648}649650public void bind(SocketAddress endpoint, int backlog)651throws IOException {652ss.bind(endpoint, backlog);653}654655public InetAddress getInetAddress() {656return ss.getInetAddress();657}658659public int getLocalPort() {660return ss.getLocalPort();661}662663public SocketAddress getLocalSocketAddress() {664return ss.getLocalSocketAddress();665}666667public Socket accept() throws IOException {668// System.out.println("BSS.accept");669Socket s = ss.accept();670// System.out.println("BSS.accept returned: " + s);671if (broken)672s.close();673else674sList.add(s);675return s;676}677678public void close() throws IOException {679ss.close();680}681682public ServerSocketChannel getChannel() {683return ss.getChannel();684}685686public boolean isBound() {687return ss.isBound();688}689690public boolean isClosed() {691return ss.isClosed();692}693694public void setSoTimeout(int timeout) throws SocketException {695ss.setSoTimeout(timeout);696}697698public int getSoTimeout() throws IOException {699return ss.getSoTimeout();700}701702public void setReuseAddress(boolean on) throws SocketException {703ss.setReuseAddress(on);704}705706public boolean getReuseAddress() throws SocketException {707return ss.getReuseAddress();708}709710public String toString() {711return "BreakableServerSocket wrapping " + ss.toString();712}713714public void setReceiveBufferSize (int size) throws SocketException {715ss.setReceiveBufferSize(size);716}717718public int getReceiveBufferSize() throws SocketException {719return ss.getReceiveBufferSize();720}721722private final ServerSocket ss;723private final List/*<Socket>*/ sList = new ArrayList();724private boolean broken = false;725}726727/* We do a lot of messy reflection stuff here because we don't728want to reference the optional parts of the JMX Remote API in729an environment (J2SE) where they won't be present. */730731/* This class implements the logic that allows us to pretend that732we have a class that looks like this:733class SocketConnectionServer implements MessageConnectionServer {734public MessageConnection accept() throws IOException {...}735public JMXServiceURL getAddress() {...}736public void start(Map env) throws IOException {...}737public void stop() throws IOException {...}738}739*/740private static class SocketConnectionServerInvocationHandler741implements InvocationHandler {742SocketConnectionServerInvocationHandler(ServerSocket ss) {743this.ss = ss;744}745746public Object invoke(Object proxy, Method method, Object[] args)747throws Exception {748final String mname = method.getName();749try {750if (mname.equals("accept"))751return accept();752else if (mname.equals("getAddress"))753return getAddress();754else if (mname.equals("start"))755start((Map) args[0]);756else if (mname.equals("stop"))757stop();758else // probably a method inherited from Object759return method.invoke(this, args);760} catch (InvocationTargetException ite) {761Throwable t = ite.getCause();762if (t instanceof IOException) {763throw (IOException)t;764} else if (t instanceof RuntimeException) {765throw (RuntimeException)t;766} else {767throw ite;768}769}770771return null;772}773774private Object/*MessageConnection*/ accept() throws Exception {775System.out.println("SCSIH.accept()");776Socket s = ss.accept();777Class socketConnectionClass =778Class.forName("com.sun.jmx.remote.socket.SocketConnection");779Constructor constr =780socketConnectionClass.getConstructor(new Class[] {Socket.class});781return constr.newInstance(new Object[] {s});782// InvocationHandler scih = new SocketConnectionInvocationHandler(s);783// Class messageConnectionClass =784// Class.forName("javax.management.generic.MessageConnection");785// return Proxy.newProxyInstance(this.getClass().getClassLoader(),786// new Class[] {messageConnectionClass},787// scih);788}789790private JMXServiceURL getAddress() throws Exception {791System.out.println("SCSIH.getAddress()");792return new JMXServiceURL("jmxmp", null, ss.getLocalPort());793}794795private void start(Map env) throws IOException {796System.out.println("SCSIH.start(" + env + ")");797}798799private void stop() throws IOException {800System.out.println("SCSIH.stop()");801}802803private final ServerSocket ss;804}805}806807808