1/*
2 * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 5039210
27 * @summary test on a client notification deadlock.
28 * @author Shanliang JIANG
29 *
30 * @run clean DeadLockTest
31 * @run build DeadLockTest
32 * @run main DeadLockTest
33 */
34
35import java.net.MalformedURLException;
36import java.io.IOException;
37import java.util.HashMap;
38
39import javax.management.*;
40import javax.management.remote.*;
41
42public class DeadLockTest {
43    private static final String[] protocols = {"rmi", "iiop", "jmxmp"};
44    private static final MBeanServer mbs = MBeanServerFactory.createMBeanServer();
45
46    public static void main(String[] args) {
47        System.out.println(">>> test on a client notification deadlock.");
48
49        boolean ok = true;
50        for (int i = 0; i < protocols.length; i++) {
51            try {
52                test(protocols[i]);
53            } catch (Exception e) {
54                System.out.println(">>> Test failed for " + protocols[i]);
55                e.printStackTrace(System.out);
56            }
57        }
58
59        System.out.println(">>> Test passed");
60    }
61
62    private static void test(String proto)
63            throws Exception {
64        System.out.println(">>> Test for protocol " + proto);
65
66        JMXServiceURL u = null;
67        JMXConnectorServer server = null;
68
69        HashMap env = new HashMap(2);
70        // server will close a client connection after 1 second
71        env.put("jmx.remote.x.server.connection.timeout", "1000");
72
73        // disable the client ping
74        env.put("jmx.remote.x.client.connection.check.period", "0");
75
76        try {
77            u = new JMXServiceURL(proto, null, 0);
78            server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs);
79        } catch (MalformedURLException e) {
80            System.out.println(">>> Skipping unsupported URL " + proto);
81        }
82
83        server.start();
84
85        JMXServiceURL addr = server.getAddress();
86
87        long st = 2000;
88        MyListener myListener;
89
90        // a cycle to make sure that we test the blocking problem.
91        do {
92            JMXConnector client = JMXConnectorFactory.connect(addr, env);
93            MBeanServerConnection conn = client.getMBeanServerConnection();
94            myListener = new MyListener(conn);
95            client.addConnectionNotificationListener(myListener, null, null);
96
97            // wait the server to close the client connection
98            Thread.sleep(st);
99
100            // makes the listener to do a remote request via the connection
101            // which should be closed by the server.
102            conn.getDefaultDomain();
103
104            // allow the listner to have time to work
105            Thread.sleep(100);
106
107            // get a closed notif, should no block.
108            client.close();
109            Thread.sleep(100);
110
111            st += 2000;
112
113        } while(!myListener.isDone());
114
115        server.stop();
116    }
117
118    private static class MyListener implements NotificationListener {
119        public MyListener(MBeanServerConnection conn) {
120            this.conn = conn;
121        }
122
123        public void handleNotification(Notification n, Object h) {
124            if (n instanceof JMXConnectionNotification) {
125                JMXConnectionNotification jcn = (JMXConnectionNotification)n;
126                final String type = jcn.getType();
127                System.out.println(">>> The listener receives notif with the type:"+type);
128
129                if (JMXConnectionNotification.CLOSED.equals(type) ||
130                    JMXConnectionNotification.FAILED.equals(type)) {
131
132                    synchronized(this) {
133                        done = false;
134                    }
135
136                    try {
137                        conn.getDefaultDomain();
138                    } catch (IOException ioe) {
139                        // Greate !
140                    }
141
142                    synchronized(this) {
143                        done = true;
144                    }
145
146                    System.out.println(">>> The listener is not blocked!");
147                }
148            }
149        }
150
151        public boolean isDone() {
152            synchronized(this) {
153                return done;
154            }
155        }
156
157        private boolean done = false;
158        private MBeanServerConnection conn;
159    }
160}
161