1/*
2 * Copyright (c) 2006, 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 6417044
27 * @summary Test deadlock in MBeanRegistration.postRegister method
28 * @author Eamonn McManus, Daniel Fuchs
29 *
30 * @run clean PostRegisterDeadlockTest
31 * @run build PostRegisterDeadlockTest
32 * @run main PostRegisterDeadlockTest
33 */
34
35import java.lang.Thread.State;
36import java.util.concurrent.*;
37import javax.management.*;
38
39public class PostRegisterDeadlockTest {
40    public static interface BlibbyMBean {}
41
42    public static class Blibby implements BlibbyMBean, MBeanRegistration {
43        public Blibby(MBeanServer mbs, ObjectName otherName) {
44            this.mbs = mbs;
45            this.otherName = otherName;
46        }
47
48        public ObjectName preRegister(MBeanServer mbs, ObjectName on) {
49            return on;
50        }
51
52        public void preDeregister() {}
53
54        public void postRegister(Boolean done) {
55            // If no other MBean was registered
56            // do nothing.
57            //
58            if (otherName == null) return;
59
60            // Check that we can unregister
61            // other MBean
62            try {
63                Thread t = new Thread() {
64                    public void run() {
65                        try {
66                            try {
67                                mbs.unregisterMBean(otherName);
68                            } catch (InstanceNotFoundException x) {
69                                 // Race condition!
70                                 System.out.println(otherName+
71                                         " was unregistered by main thread.");
72                            }
73                        } catch (Throwable e) {
74                            e.printStackTrace(System.out);
75                            fail(e.toString());
76                        }
77                    }
78                };
79                t.start();
80                t.join(5000L);
81                if (t.isAlive()) {
82                    if (t.getState().equals(State.BLOCKED))
83                        fail("Deadlock detected");
84                    else
85                        fail("Test not conclusive: "+
86                             "Thread is alive but not blocked.");
87                }
88            } catch (Throwable e) {
89                e.printStackTrace(System.out);
90                fail(e.toString());
91            }
92        }
93
94        public void postDeregister() {}
95
96        private final MBeanServer mbs;
97        private final ObjectName otherName;
98    }
99
100    public static void main(String[] args) throws Exception {
101        String previous = null;
102        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
103        ObjectName on1 = new ObjectName("a:type=Blibby,name=\"1\"");
104        ObjectName on2 = new ObjectName("a:type=Blibby,name=\"2\"");
105
106
107        // Test 1:
108        // 1 MBean is registered with on1
109        // Another MBean is registered with on1, postRegister(FALSE) is
110        // called, and the second MBean attempts to unregister first MBean in
111        // postRegister:
112        // postRegister starts a thread which unregisters the first MBean:
113        // this must not deadlock
114        //
115        System.out.println("\n****  TEST #1 ****\n");
116        System.out.println("Registering Blibby #1 with name: " + on1);
117        mbs.registerMBean(new Blibby(mbs, null), on1);
118        try {
119            System.out.println("Registering Blibby #2 with same name: " + on1);
120            mbs.registerMBean(new Blibby(mbs, on1), on1);
121        } catch (InstanceAlreadyExistsException x) {
122            System.out.println("Received expected exception: " + x);
123        }
124        if (mbs.isRegistered(on1)) {
125            try {
126                mbs.unregisterMBean(on1);
127                if (failure == null)
128                    fail(on1+" should have been unregistered");
129            } catch (InstanceNotFoundException x) {
130                // Race condition!
131                System.out.println(on1+" was unregistered by mbean thread.");
132            }
133        }  else {
134            System.out.println(on1+" was correctly unregistered.");
135        }
136
137        if (failure == previous)
138            System.out.println("\n****  TEST #1 PASSED ****\n");
139
140        previous = failure;
141
142        // Test 2:
143        // 1 MBean is registered with on1
144        // Another MBean is registered with on2, postRegister(TRUE) is
145        // called, and the second MBean attempts to unregister first MBean in
146        // postRegister:
147        // postRegister starts a thread which unregisters the first MBean:
148        // this must not deadlock
149        //
150        System.out.println("\n****  TEST #2 ****\n");
151        System.out.println("Registering Blibby #1 with name: " + on1);
152        mbs.registerMBean(new Blibby(mbs, null), on1);
153        System.out.println("Registering Blibby #2 with other name: " + on2);
154        mbs.registerMBean(new Blibby(mbs, on1), on2);
155        if (mbs.isRegistered(on1)) {
156            try {
157                mbs.unregisterMBean(on1);
158                if (failure == null)
159                    fail(on1+" should have been unregistered");
160            } catch (InstanceNotFoundException x) {
161                // Race condition!
162                System.out.println(on1+" was unregistered by mbean thread.");
163            }
164        }  else {
165            System.out.println(on1+" was correctly unregistered.");
166        }
167
168        System.out.println("unregistering "+on2);
169        mbs.unregisterMBean(on2);
170        if (failure == previous)
171            System.out.println("\n****  TEST #2 PASSED ****\n");
172        previous = failure;
173
174        if (failure == null)
175            System.out.println("OK: Test passed");
176        else
177            throw new Exception("TEST FAILED: " + failure);
178    }
179
180    private static void fail(String why) {
181        System.out.println("FAILED: " + why);
182        failure = (failure == null)?why:(failure+",\n"+why);
183    }
184
185    private static volatile String failure;
186}
187