Path: blob/master/test/jdk/javax/management/remote/mandatory/connection/BrokenConnectionTest.java
41159 views
/*1* Copyright (c) 2003, 2015, 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* @key intermittent27* @summary Tests behaviour when connections break28* @author Eamonn McManus29*30* @run clean BrokenConnectionTest31* @run build BrokenConnectionTest32* @run main BrokenConnectionTest33*/3435import java.io.*;36import java.lang.reflect.*;37import java.nio.channels.ServerSocketChannel;38import java.net.*;39import java.rmi.server.*;40import java.util.*;4142import java.rmi.UnmarshalException;4344import javax.management.*;45import javax.management.remote.*;46import javax.management.remote.rmi.*;4748// resolve ambiguity49import java.lang.reflect.Proxy;5051public class BrokenConnectionTest {52private static ObjectName DELEGATE_NAME;53private static ObjectName BREAK_NAME;54private static ObjectName LISTENER_NAME;55public static void main(String[] args) throws Exception {56DELEGATE_NAME =57new ObjectName("JMImplementation:type=MBeanServerDelegate");58BREAK_NAME = new ObjectName("test:type=Break");59LISTENER_NAME = new ObjectName("test:type=Listener");6061String failed = "";6263final String[] protos = {"rmi", "jmxmp"};6465for (int i = 0; i < protos.length; i++) {66final String proto = protos[i];67System.out.println();68System.out.println("------- Testing for " + proto + " -------");69try {70if (!test(proto))71failed += " " + proto;72} catch (Exception e) {73System.out.println("FAILED WITH EXCEPTION:");74e.printStackTrace(System.out);75failed += " " + proto;76}77}7879System.out.println();8081if (failed.length() > 0) {82System.out.println("TEST FAILED FOR:" + failed);83System.exit(1);84}8586System.out.println("Test passed");87}8889private static boolean test(String proto) throws Exception {90if (proto.equals("rmi"))91return rmiTest();92else if (proto.equals("jmxmp"))93return jmxmpTest();94else95throw new AssertionError(proto);96}9798private static interface Breakable {99public JMXConnectorServer createConnectorServer(MBeanServer mbs)100throws IOException;101public void setBroken(boolean broken);102}103104private static interface TestAction {105public String toString();106public boolean test(MBeanServerConnection mbsc, Breakable breakable)107throws Exception;108}109110private static abstract class Operation implements TestAction {111public String toString() {112return opName() + ", break, " + opName();113}114void init(MBeanServerConnection mbsc) throws Exception {}115abstract String opName();116public boolean test(MBeanServerConnection mbsc, Breakable breakable)117throws Exception {118init(mbsc);119operation(mbsc);120System.out.println("Client ran " + opName() + " OK");121breakable.setBroken(true);122System.out.println("Broke connection, run " + opName() + " again");123try {124operation(mbsc);125System.out.println("TEST FAILED: " + opName() +126" should fail!");127return false;128} catch (IOException e) {129System.out.println("Got IOException as expected (" + e + ")");130}131return true;132}133abstract void operation(MBeanServerConnection mbsc) throws Exception;134}135136private static TestAction[] tests = {137new Operation() {138String opName() {139return "getDefaultDomain";140}141void operation(MBeanServerConnection mbsc) throws Exception {142mbsc.getDefaultDomain();143}144},145new Operation() {146String opName() {147return "addNotificationListener(NL)";148}149void operation(MBeanServerConnection mbsc) throws Exception {150mbsc.addNotificationListener(DELEGATE_NAME,151new CountListener(), null, null);152}153},154new Operation() {155String opName() {156return "addNotificationListener(MB)";157}158void init(MBeanServerConnection mbsc) throws Exception {159mbsc.createMBean(CountListener.class.getName(),160LISTENER_NAME);161}162void operation(MBeanServerConnection mbsc) throws Exception {163mbsc.addNotificationListener(DELEGATE_NAME, LISTENER_NAME,164null, null);165}166},167new Operation() {168String opName() {169return "removeNotificationListener(NL)";170}171void init(MBeanServerConnection mbsc) throws Exception {172for (int i = 0; i < NLISTENERS; i++) {173NotificationListener l = new CountListener();174mbsc.addNotificationListener(DELEGATE_NAME, l, null, null);175listeners.add(l);176}177}178void operation(MBeanServerConnection mbsc) throws Exception {179NotificationListener l = (NotificationListener)180listeners.remove(0);181mbsc.removeNotificationListener(DELEGATE_NAME, l, null, null);182}183static final int NLISTENERS = 2;184List/*<NotificationListener>*/ listeners = new ArrayList();185},186new Operation() {187String opName() {188return "removeNotificationListener(MB)";189}190void init(MBeanServerConnection mbsc) throws Exception {191mbsc.createMBean(CountListener.class.getName(),192LISTENER_NAME);193}194void operation(MBeanServerConnection mbsc) throws Exception {195try {196mbsc.removeNotificationListener(DELEGATE_NAME,197LISTENER_NAME,198null, null);199throw new IllegalArgumentException("removeNL should not " +200"have worked!");201} catch (ListenerNotFoundException e) {202// normal - there isn't one!203}204}205},206new Operation() {207String opName() {208return "createMBean(className, objectName)";209}210void operation(MBeanServerConnection mbsc) throws Exception {211ObjectName name =212new ObjectName("test:instance=" + nextInstance());213mbsc.createMBean(CountListener.class.getName(), name);214}215private synchronized int nextInstance() {216return ++instance;217}218private int instance;219},220new Operation() {221String opName() {222return "getAttribute";223}224void operation(MBeanServerConnection mbsc) throws Exception {225mbsc.getAttribute(DELEGATE_NAME, "ImplementationName");226}227},228new Operation() {229String opName() {230return "getAttributes";231}232void operation(MBeanServerConnection mbsc) throws Exception {233mbsc.getAttribute(DELEGATE_NAME, "ImplementationName");234}235},236new Operation() {237String opName() {238return "getDomains";239}240void operation(MBeanServerConnection mbsc) throws Exception {241mbsc.getDomains();242}243},244new Operation() {245String opName() {246return "getMBeanCount";247}248void operation(MBeanServerConnection mbsc) throws Exception {249mbsc.getMBeanCount();250}251},252new Operation() {253String opName() {254return "getMBeanInfo";255}256void operation(MBeanServerConnection mbsc) throws Exception {257mbsc.getMBeanInfo(DELEGATE_NAME);258}259},260new Operation() {261String opName() {262return "getObjectInstance";263}264void operation(MBeanServerConnection mbsc) throws Exception {265mbsc.getObjectInstance(DELEGATE_NAME);266}267},268new Operation() {269String opName() {270return "invoke";271}272void operation(MBeanServerConnection mbsc) throws Exception {273mbsc.invoke(BREAK_NAME, "doNothing", new Object[0],274new String[0]);275}276},277new Operation() {278String opName() {279return "isInstanceOf";280}281void operation(MBeanServerConnection mbsc) throws Exception {282mbsc.isInstanceOf(DELEGATE_NAME, "whatsit");283}284},285new Operation() {286String opName() {287return "isRegistered";288}289void operation(MBeanServerConnection mbsc) throws Exception {290mbsc.isRegistered(DELEGATE_NAME);291}292},293new Operation() {294String opName() {295return "queryMBeans";296}297void operation(MBeanServerConnection mbsc) throws Exception {298mbsc.queryMBeans(new ObjectName("*:*"), null);299}300},301new Operation() {302String opName() {303return "queryNames";304}305void operation(MBeanServerConnection mbsc) throws Exception {306mbsc.queryNames(new ObjectName("*:*"), null);307}308},309new Operation() {310String opName() {311return "setAttribute";312}313void operation(MBeanServerConnection mbsc) throws Exception {314mbsc.setAttribute(BREAK_NAME,315new Attribute("Nothing", null));316}317},318new Operation() {319String opName() {320return "setAttributes";321}322void operation(MBeanServerConnection mbsc) throws Exception {323AttributeList attrs = new AttributeList();324attrs.add(new Attribute("Nothing", null));325mbsc.setAttributes(BREAK_NAME, attrs);326}327},328new Operation() {329String opName() {330return "unregisterMBean";331}332void init(MBeanServerConnection mbsc) throws Exception {333for (int i = 0; i < NBEANS; i++) {334ObjectName name = new ObjectName("test:instance=" + i);335mbsc.createMBean(CountListener.class.getName(), name);336names.add(name);337}338}339void operation(MBeanServerConnection mbsc) throws Exception {340ObjectName name = (ObjectName) names.remove(0);341mbsc.unregisterMBean(name);342}343private static final int NBEANS = 2;344private List/*<ObjectName>*/ names = new ArrayList();345},346new TestAction() {347public String toString() {348return "break during send for setAttribute";349}350public boolean test(MBeanServerConnection mbsc,351Breakable breakable) throws Exception {352Attribute attr =353new Attribute("Break", new BreakWhenSerialized(breakable));354try {355mbsc.setAttribute(BREAK_NAME, attr);356System.out.println("TEST FAILED: setAttribute with " +357"BreakWhenSerializable did not fail!");358return false;359} catch (IOException e) {360System.out.println("Got IOException as expected: " + e);361362return true;363}364}365},366new TestAction() {367public String toString() {368return "break during receive for getAttribute";369}370public boolean test(MBeanServerConnection mbsc,371Breakable breakable) throws Exception {372try {373mbsc.getAttribute(BREAK_NAME, "Break");374System.out.println("TEST FAILED: getAttribute of " +375"BreakWhenSerializable did not fail!");376return false;377} catch (IOException e) {378System.out.println("Got IOException as expected: " + e);379380return true;381}382}383},384};385386public static interface BreakMBean {387public BreakWhenSerialized getBreak();388public void setBreak(BreakWhenSerialized x);389// public void breakOnNotify();390public void doNothing();391public void setNothing(Object x);392}393394public static class Break395extends NotificationBroadcasterSupport implements BreakMBean {396public Break(Breakable breakable) {397this.breakable = breakable;398}399400public BreakWhenSerialized getBreak() {401return new BreakWhenSerialized(breakable);402}403404public void setBreak(BreakWhenSerialized x) {405throw new IllegalArgumentException("setBreak worked but " +406"should not!");407}408409// public void breakOnNotify() {410// Notification broken = new Notification("type", "source", 0L);411// broken.setUserData(new BreakWhenSerialized(breakable));412// sendNotification(broken);413// }414415public void doNothing() {}416417public void setNothing(Object x) {}418419private final Breakable breakable;420}421422private static class BreakWhenSerialized implements Serializable {423BreakWhenSerialized(Breakable breakable) {424this.breakable = breakable;425}426427private void writeObject(ObjectOutputStream out) throws IOException {428breakable.setBroken(true);429}430431private final transient Breakable breakable;432}433434private static class FailureNotificationFilter435implements NotificationFilter {436public boolean isNotificationEnabled(Notification n) {437System.out.println("Filter: " + n + " (" + n.getType() + ")");438439final String failed =440JMXConnectionNotification.FAILED;441return (n instanceof JMXConnectionNotification442&& n.getType().equals(JMXConnectionNotification.FAILED));443}444}445446public static interface CountListenerMBean {}447448public static class CountListener449implements CountListenerMBean, NotificationListener {450public synchronized void handleNotification(Notification n, Object h) {451count++;452}453454int count;455}456457private static boolean test(Breakable breakable)458throws Exception {459boolean alreadyMissedFailureNotif = false;460String failed = "";461for (int i = 1; i <= tests.length; i++) {462TestAction ta = tests[i - 1];463System.out.println();464System.out.println("Test " + i + ": " + ta);465MBeanServer mbs = MBeanServerFactory.newMBeanServer();466Break breakMBean = new Break(breakable);467mbs.registerMBean(breakMBean, BREAK_NAME);468JMXConnectorServer cs = breakable.createConnectorServer(mbs);469System.out.println("Created and started connector server");470JMXServiceURL addr = cs.getAddress();471JMXConnector cc = JMXConnectorFactory.connect(addr);472CountListener failureListener = new CountListener();473NotificationFilter failureFilter = new FailureNotificationFilter();474cc.addConnectionNotificationListener(failureListener,475failureFilter,476null);477MBeanServerConnection mbsc = cc.getMBeanServerConnection();478System.out.println("Client connected OK");479boolean thisok = ta.test(mbsc, breakable);480481try {482System.out.println("Stopping server");483cs.stop();484} catch (IOException e) {485System.out.println("Ignoring exception on stop: " + e);486}487if (thisok) {488System.out.println("Waiting for failure notif");489// pass or test timeout. see 8025205490do {491Thread.sleep(100);492} while (failureListener.count < 1);493494Thread.sleep(1000); // if more notif coming ...495if (failureListener.count > 1) {496System.out.println("Got too many failure notifs: " +497failureListener.count);498thisok = false;499}500}501if (!thisok)502failed = failed + " " + i;503System.out.println("Test " + i + (thisok ? " passed" : " FAILED"));504breakable.setBroken(false);505}506if (failed.equals(""))507return true;508else {509System.out.println("FAILING CASES:" + failed);510return false;511}512}513514private static class BreakableRMI implements Breakable {515public JMXConnectorServer createConnectorServer(MBeanServer mbs)516throws IOException {517JMXServiceURL url = new JMXServiceURL("rmi", null, 0);518Map env = new HashMap();519env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,520brssf);521JMXConnectorServer cs =522JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);523cs.start();524return cs;525}526527public void setBroken(boolean broken) {528brssf.setBroken(broken);529}530531private final BreakableRMIServerSocketFactory brssf =532new BreakableRMIServerSocketFactory();533}534535private static boolean rmiTest() throws Exception {536System.out.println("RMI broken connection test");537Breakable breakable = new BreakableRMI();538return test(breakable);539}540541private static class BreakableRMIServerSocketFactory542implements RMIServerSocketFactory {543544public synchronized ServerSocket createServerSocket(int port)545throws IOException {546if (broken)547throw new IOException("ServerSocket has been broken");548BreakableServerSocket bss = new BreakableServerSocket(port);549bssList.add(bss);550return bss;551}552553synchronized void setBroken(boolean broken) {554this.broken = broken;555// System.out.println("BRSSF.setBroken(" + broken + ")");556for (Iterator it = bssList.iterator(); it.hasNext(); ) {557BreakableServerSocket bss = (BreakableServerSocket) it.next();558// System.out.println((broken ? "" : "un") + "break " + bss);559bss.setBroken(broken);560}561}562563private final List/*<BreakableServerSocket>*/ bssList =564new ArrayList();565private boolean broken = false;566}567568private static class BreakableJMXMP implements Breakable {569BreakableJMXMP() throws IOException {570bss = new BreakableServerSocket(0);571}572573public JMXConnectorServer createConnectorServer(MBeanServer mbs)574throws IOException {575try {576InvocationHandler scsih =577new SocketConnectionServerInvocationHandler(bss);578final String mcs =579"javax.management.remote.generic.MessageConnectionServer";580final Class messageConnectionServerClass = Class.forName(mcs);581final Class[] proxyInterfaces = {messageConnectionServerClass};582Object socketConnectionServer =583Proxy.newProxyInstance(this.getClass().getClassLoader(),584proxyInterfaces,585scsih);586Map env = new HashMap();587env.put("jmx.remote.message.connection.server",588socketConnectionServer);589final String gcs =590"javax.management.remote.generic.GenericConnectorServer";591final Class genericConnectorServerClass = Class.forName(gcs);592final Class[] constrTypes = {Map.class, MBeanServer.class};593final Constructor constr =594genericConnectorServerClass.getConstructor(constrTypes);595JMXConnectorServer cs = (JMXConnectorServer)596constr.newInstance(new Object[] {env, mbs});597cs.start();598return cs;599} catch (Exception e) {600e.printStackTrace(System.out);601throw new AssertionError(e);602}603}604605public void setBroken(boolean broken) {606bss.setBroken(broken);607}608609private final BreakableServerSocket bss;610}611612private static boolean jmxmpTest() throws Exception {613System.out.println("JMXMP broken connection test");614try {615Class.forName("javax.management.remote.generic.GenericConnector");616} catch (ClassNotFoundException e) {617System.out.println("Optional classes not present, skipping test");618return true;619}620Breakable breakable = new BreakableJMXMP();621return test(breakable);622}623624private static class BreakableServerSocket extends ServerSocket {625BreakableServerSocket(int port) throws IOException {626super();627ss = new ServerSocket(port);628}629630synchronized void setBroken(boolean broken) {631this.broken = broken;632// System.out.println("BSS.setBroken(" + broken + ")");633if (!broken)634return;635for (Iterator it = sList.iterator(); it.hasNext(); ) {636Socket s = (Socket) it.next();637try {638// System.out.println("Break: " + s);639s.close();640} catch (IOException e) {641System.out.println("Unable to close socket: " + s +642", ignoring (" + e + ")");643}644it.remove();645}646}647648public void bind(SocketAddress endpoint) throws IOException {649ss.bind(endpoint);650}651652public void bind(SocketAddress endpoint, int backlog)653throws IOException {654ss.bind(endpoint, backlog);655}656657public InetAddress getInetAddress() {658return ss.getInetAddress();659}660661public int getLocalPort() {662return ss.getLocalPort();663}664665public SocketAddress getLocalSocketAddress() {666return ss.getLocalSocketAddress();667}668669public Socket accept() throws IOException {670// System.out.println("BSS.accept");671Socket s = ss.accept();672// System.out.println("BSS.accept returned: " + s);673if (broken)674s.close();675else676sList.add(s);677return s;678}679680public void close() throws IOException {681ss.close();682}683684public ServerSocketChannel getChannel() {685return ss.getChannel();686}687688public boolean isBound() {689return ss.isBound();690}691692public boolean isClosed() {693return ss.isClosed();694}695696public void setSoTimeout(int timeout) throws SocketException {697ss.setSoTimeout(timeout);698}699700public int getSoTimeout() throws IOException {701return ss.getSoTimeout();702}703704public void setReuseAddress(boolean on) throws SocketException {705ss.setReuseAddress(on);706}707708public boolean getReuseAddress() throws SocketException {709return ss.getReuseAddress();710}711712public String toString() {713return "BreakableServerSocket wrapping " + ss.toString();714}715716public void setReceiveBufferSize (int size) throws SocketException {717ss.setReceiveBufferSize(size);718}719720public int getReceiveBufferSize() throws SocketException {721return ss.getReceiveBufferSize();722}723724private final ServerSocket ss;725private final List/*<Socket>*/ sList = new ArrayList();726private boolean broken = false;727}728729/* We do a lot of messy reflection stuff here because we don't730want to reference the optional parts of the JMX Remote API in731an environment (J2SE) where they won't be present. */732733/* This class implements the logic that allows us to pretend that734we have a class that looks like this:735class SocketConnectionServer implements MessageConnectionServer {736public MessageConnection accept() throws IOException {...}737public JMXServiceURL getAddress() {...}738public void start(Map env) throws IOException {...}739public void stop() throws IOException {...}740}741*/742private static class SocketConnectionServerInvocationHandler743implements InvocationHandler {744SocketConnectionServerInvocationHandler(ServerSocket ss) {745this.ss = ss;746}747748public Object invoke(Object proxy, Method method, Object[] args)749throws Exception {750final String mname = method.getName();751try {752if (mname.equals("accept"))753return accept();754else if (mname.equals("getAddress"))755return getAddress();756else if (mname.equals("start"))757start((Map) args[0]);758else if (mname.equals("stop"))759stop();760else // probably a method inherited from Object761return method.invoke(this, args);762} catch (InvocationTargetException ite) {763Throwable t = ite.getCause();764if (t instanceof IOException) {765throw (IOException)t;766} else if (t instanceof RuntimeException) {767throw (RuntimeException)t;768} else {769throw ite;770}771}772773return null;774}775776private Object/*MessageConnection*/ accept() throws Exception {777System.out.println("SCSIH.accept()");778Socket s = ss.accept();779Class socketConnectionClass =780Class.forName("com.sun.jmx.remote.socket.SocketConnection");781Constructor constr =782socketConnectionClass.getConstructor(new Class[] {Socket.class});783return constr.newInstance(new Object[] {s});784// InvocationHandler scih = new SocketConnectionInvocationHandler(s);785// Class messageConnectionClass =786// Class.forName("javax.management.generic.MessageConnection");787// return Proxy.newProxyInstance(this.getClass().getClassLoader(),788// new Class[] {messageConnectionClass},789// scih);790}791792private JMXServiceURL getAddress() throws Exception {793System.out.println("SCSIH.getAddress()");794return new JMXServiceURL("jmxmp", null, ss.getLocalPort());795}796797private void start(Map env) throws IOException {798System.out.println("SCSIH.start(" + env + ")");799}800801private void stop() throws IOException {802System.out.println("SCSIH.stop()");803}804805private final ServerSocket ss;806}807}808809810