1/*
2 * Copyright (c) 2001, 2017, 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/* @test
25 * @bug 4308492
26 * @summary In addition to keeping the VM alive (with a non-daeman thread)
27 * while there are remote objects exported, the RMI runtime should also
28 * keep it alive while there remain calls in progress (to remote objects
29 * the have presumably been unexported), so that a remote object can more
30 * conveniently implement a graceful remote shutdown method (that unexports
31 * the object).
32 * @author Peter Jones
33 *
34 * @library ../../../testlibrary
35 * @modules java.rmi/sun.rmi.registry
36 *          java.rmi/sun.rmi.server
37 *          java.rmi/sun.rmi.transport
38 *          java.rmi/sun.rmi.transport.tcp
39 * @build TestLibrary JavaVM KeepAliveDuringCall_Stub
40 *     ShutdownMonitor Shutdown ShutdownImpl ShutdownImpl_Stub
41 * @run main/othervm KeepAliveDuringCall
42 */
43
44import java.rmi.Remote;
45import java.rmi.RemoteException;
46import java.rmi.registry.LocateRegistry;
47import java.rmi.registry.Registry;
48import java.rmi.server.UnicastRemoteObject;
49
50public class KeepAliveDuringCall implements ShutdownMonitor {
51
52    public static final String BINDING = "KeepAliveDuringCall";
53    private static final int TIMEOUT = 20000;
54
55    private Object lock = new Object();
56    private Shutdown shutdown = null;
57    private boolean stillAlive = false;
58
59    public void submitShutdown(Shutdown shutdown) {
60        synchronized (lock) {
61            this.shutdown = shutdown;
62            lock.notifyAll();
63        }
64    }
65
66    public void declareStillAlive() {
67        synchronized (lock) {
68            stillAlive = true;
69            lock.notifyAll();
70        }
71    }
72
73    public static void main(String[] args) {
74
75        System.err.println("\nRegression test for bug 4308492\n");
76
77        KeepAliveDuringCall obj = new KeepAliveDuringCall();
78        JavaVM jvm = null;
79
80        try {
81            UnicastRemoteObject.exportObject(obj);
82            System.err.println("exported shutdown monitor");
83
84            Registry localRegistry = TestLibrary.createRegistryOnEphemeralPort();
85            int registryPort = TestLibrary.getRegistryPort(localRegistry);
86            System.err.println("created local registry");
87
88            localRegistry.bind(BINDING, obj);
89            System.err.println("bound shutdown monitor in local registry");
90
91            System.err.println("starting remote ShutdownImpl VM...");
92            jvm = new JavaVM("ShutdownImpl",
93                        "-Drmi.registry.port=" +
94                        registryPort, "");
95            jvm.start();
96
97            Shutdown s;
98            synchronized (obj.lock) {
99                System.err.println(
100                    "waiting for submission of object to shutdown...");
101                while ((s = obj.shutdown) == null) {
102                    obj.lock.wait(TIMEOUT);
103                }
104                if (s == null) {
105                    throw new RuntimeException(
106                        "TEST FAILED: timeout waiting for shutdown object " +
107                        "to make initial contact");
108                }
109                System.err.println("shutdown object submitted: " + s);
110            }
111
112            try {
113                s.shutdown();
114            } catch (RemoteException e) {
115                throw new RuntimeException(
116                    "TEST FAILED: shutdown method threw remote exception", e);
117            }
118
119            synchronized (obj.lock) {
120                if (!obj.stillAlive) {
121                    throw new RuntimeException("TEST FAILED: " +
122                        "shutdown object not detected alive after unexport");
123                }
124            }
125
126            System.err.println("TEST PASSED: " +
127                "shutdown object detected still alive after unexport");
128
129        } catch (Exception e) {
130            if (e instanceof RuntimeException) {
131                throw (RuntimeException) e;
132            } else {
133                throw new RuntimeException(
134                    "TEST FAILED: unexpected exception", e);
135            }
136        } finally {
137            if (jvm != null) {
138                jvm.destroy();
139            }
140            try {
141                UnicastRemoteObject.unexportObject(obj, true);
142            } catch (RemoteException e) {
143            }
144        }
145    }
146}
147