1 /*
2  * Copyright (c) 1999, 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 4183169 8032050
26  * @summary Minor problem with the way ReliableLog handles IOExceptions.
27  *
28  * @author Laird Dornin; code borrowed from Ann Wollrath
29  *
30  * @library ../../../testlibrary
31  * @modules java.rmi/sun.rmi.registry
32  *          java.rmi/sun.rmi.server
33  *          java.rmi/sun.rmi.transport
34  *          java.rmi/sun.rmi.transport.tcp
35  *          java.base/sun.nio.ch
36  * @build TestLibrary RMID RMIDSelectorProvider
37  *     TestSecurityManager RegisteringActivatable ShutdownGracefully_Stub
38  * @run main/othervm/policy=security.policy/timeout=700 ShutdownGracefully
39  */
40 
41 import java.rmi.activation.*;
42 import java.rmi.*;
43 import java.util.Properties;
44 import java.util.concurrent.TimeoutException;
45 
46 /**
47  * The test creates an rmid with a special security manager.  After
48  * rmid makes two registrations (which is greater than rmid's
49  * snapshotInterval) the security manager stops allowing rmid to write
50  * to update and snapshot log files in rmid's log directory.  The Test
51  * registers an Activatable object twice with different group ids.
52  * The second registration will cause rmid to have to write to a
53  * LogFile (it causes a snapshot) and the security manager will not
54  * allow the file write to happen.  The test makes sure that rmid
55  * shuts down in a graceful manner without any explicit request to do
56  * so.  The test will not exit for 400 seconds if rmid does not exit
57  * (after that time, the test will fail).
58  */
59 public class ShutdownGracefully
60     extends Activatable implements RegisteringActivatable
61 {
62     private static RegisteringActivatable registering = null;
63 
64     private final static long SHUTDOWN_TIMEOUT = 400 * 1000;
65 
main(String args[])66     public static void main(String args[]) {
67 
68         RMID rmid = null;
69 
70         // Save exception if there is a exception or expected behavior
71         Exception exception = null;
72         System.err.println("\nRegression test for bug/rfe 4183169\n");
73 
74         try {
75             TestLibrary.suggestSecurityManager(
76                 "java.rmi.RMISecurityManager");
77 
78             // start an rmid.
79             RMID.removeLog();
80             rmid = RMID.createRMIDOnEphemeralPort();
81 
82             // rmid needs to run with a security manager that
83             // simulates a log problem; rmid should also snapshot
84             // quickly.
85             rmid.addOptions(new String[] {
86                 "-Djava.security.manager=TestSecurityManager",
87                 "-Dsun.rmi.activation.snapshotInterval=1"});
88 
89             //      rmid.addArguments(new String[] {
90             //          "-C-Djava.rmi.server.logCalls=true"});
91 
92             rmid.start();
93 
94             // Ensure that activation groups run with the correct
95             // security manager.
96             //
97             Properties p = new Properties();
98             p.put("java.security.policy",
99                   TestParams.defaultGroupPolicy);
100             p.put("java.security.manager",
101                   "java.lang.SecurityManager");
102 
103             System.err.println("activation group will be created " +
104                                "in a new VM");
105             ActivationGroupDesc groupDesc =
106                 new ActivationGroupDesc(p, null);
107             ActivationSystem system = ActivationGroup.getSystem();
108             ActivationGroupID groupID = system.registerGroup(groupDesc);
109 
110             System.err.println("registering activatable");
111             ActivationDesc desc = new ActivationDesc
112                 (groupID, "ShutdownGracefully", null, null);
113             registering = (RegisteringActivatable)
114                 Activatable.register(desc);
115 
116             System.err.println("activate and deactivate object " +
117                                "via method call");
118             registering.shutdown();
119 
120             /*
121              * the security manager rmid is running with will stop
122              * rmid from writing to its log files; in 1.2.x this would
123              * have caused rmid to have thrown a runtime exception and
124              * continue running in an unstable state.  With the fix
125              * for 4183169, rmid should shutdown gracefully instead.
126              */
127 
128             /*
129              * register another activatable with a new group id; rmid
130              * should not recover from this...  I use two
131              * registrations to more closely simulate the environment
132              * in which the bug was found.  In java versions with out
133              * the appropriate bug fix, rmid would hide a
134              * NullPointerException in this circumstance.
135              */
136             p.put("dummyname", "dummyvalue");
137             groupDesc = new ActivationGroupDesc(p, null);
138             ActivationGroupID secondGroupID =
139                 system.registerGroup(groupDesc);
140             desc = new ActivationDesc(secondGroupID,
141                 "ShutdownGracefully", null, null);
142 
143             /*
144              * registration request is expected to be failed. succeeded case
145              * should be recorded. And raise error after clean up  rmid.
146              */
147             try {
148                 registering = (RegisteringActivatable)
149                     Activatable.register(desc);
150                 System.err.println("The registration request succeeded unexpectedly");
151                 exception = new RuntimeException("The registration request succeeded unexpectedly");
152             } catch (ActivationException e) {
153                 System.err.println("received exception from registration " +
154                                    "call that should have failed...");
155                 // Need wait rmid process terminates.
156                 try {
157                     int exitCode = rmid.waitFor(SHUTDOWN_TIMEOUT);
158                     System.err.println("RMID has exited gracefully with exitcode:" + exitCode);
159                     rmid = null;
160                 } catch (TimeoutException te) {
161                     System.err.println("RMID process has not exited in given time");
162                     exception = te;
163                 }
164             }
165         } catch (Exception e) {
166             System.err.println("Exception thrown:" + e);
167             exception = e;
168         } finally {
169             if (rmid != null)
170                 rmid.cleanup();
171         }
172         if (exception != null)
173             TestLibrary.bomb("\nexception thrown in test: ", exception);
174     }
175 
176     /**
177      * implementation of RegisteringActivatable
178      */
ShutdownGracefully(ActivationID id, MarshalledObject mo)179     public ShutdownGracefully
180         (ActivationID id, MarshalledObject mo) throws RemoteException
181     {
182         // register/export anonymously
183         super(id, 0);
184     }
185 
186     /**
187      * Deactivates the object. We need to unexport forcibly because this call
188      * in-progress on this object, which is the same object that we are trying
189      * to deactivate.
190      */
shutdown()191     public void shutdown() throws Exception {
192         Activatable.unexportObject(this, true);
193         ActivationLibrary.deactivate(this, getID());
194     }
195 }
196