1 /* 2 * Copyright (c) 1999, 2014, 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 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 * @build TestLibrary RMID 32 * TestSecurityManager RegisteringActivatable ShutdownGracefully_Stub 33 * @run main/othervm/policy=security.policy/timeout=700 ShutdownGracefully 34 */ 35 36 import java.rmi.activation.*; 37 import java.rmi.*; 38 import java.util.Properties; 39 40 /** 41 * The test creates an rmid with a special security manager. After 42 * rmid makes two registrations (which is greater than rmid's 43 * snapshotInterval) the security manager stops allowing rmid to write 44 * to update and snapshot log files in rmid's log directory. The Test 45 * registers an Activatable object twice with different group ids. 46 * The second registration will cause rmid to have to write to a 47 * LogFile (it causes a snapshot) and the security manager will not 48 * allow the file write to happen. The test makes sure that rmid 49 * shuts down in a graceful manner without any explicit request to do 50 * so. The test will not exit for 400 seconds if rmid does not exit 51 * (after that time, the test will fail). 52 */ 53 public class ShutdownGracefully 54 extends Activatable implements Runnable, RegisteringActivatable 55 { 56 private static RegisteringActivatable registering = null; 57 58 private final static long SHUTDOWN_TIMEOUT = 400 * 1000; 59 60 public static void main(String args[]) { 61 62 RMID rmid = null; 63 64 System.err.println("\nRegression test for bug/rfe 4183169\n"); 65 66 try { 67 TestLibrary.suggestSecurityManager( 68 "java.rmi.RMISecurityManager"); 69 70 // start an rmid. 71 RMID.removeLog(); 72 rmid = RMID.createRMID(); 73 74 // rmid needs to run with a security manager that 75 // simulates a log problem; rmid should also snapshot 76 // quickly. 77 rmid.addOptions(new String[] { 78 "-Djava.security.manager=TestSecurityManager", 79 "-Dsun.rmi.activation.snapshotInterval=1"}); 80 81 // rmid.addArguments(new String[] { 82 // "-C-Djava.rmi.server.logCalls=true"}); 83 84 rmid.start(); 85 86 // Ensure that activation groups run with the correct 87 // security manager. 88 // 89 Properties p = new Properties(); 90 p.put("java.security.policy", 91 TestParams.defaultGroupPolicy); 92 p.put("java.security.manager", 93 "java.lang.SecurityManager"); 94 95 System.err.println("activation group will be created " + 96 "in a new VM"); 97 ActivationGroupDesc groupDesc = 98 new ActivationGroupDesc(p, null); 99 ActivationSystem system = ActivationGroup.getSystem(); 100 if(system == null) { 101 //Set a 5 seconds timeout 102 long stopTime = System.currentTimeMillis() + 5000; 103 do { 104 try { 105 Thread.sleep(200); 106 } catch (InterruptedException ignore) { 107 } 108 if((system = ActivationGroup.getSystem()) != null) { 109 break; 110 } 111 } while (System.currentTimeMillis() < stopTime); 112 if (system == null) { 113 TestLibrary.bomb("\nfailure: Can't acquire ActivationSystem"); 114 } 115 } 116 ActivationGroupID groupID = system.registerGroup(groupDesc); 117 118 System.err.println("registering activatable"); 119 ActivationDesc desc = new ActivationDesc 120 (groupID, "ShutdownGracefully", null, null); 121 registering = (RegisteringActivatable) 122 Activatable.register(desc); 123 124 System.err.println("activate and deactivate object " + 125 "via method call"); 126 registering.shutdown(); 127 128 /* 129 * the security manager rmid is running with will stop 130 * rmid from writing to its log files; in 1.2.x this would 131 * have caused rmid to have thrown a runtime exception and 132 * continue running in an unstable state. With the fix 133 * for 4183169, rmid should shutdown gracefully instead. 134 */ 135 136 /* 137 * register another activatable with a new group id; rmid 138 * should not recover from this... I use two 139 * registrations to more closely simulate the environment 140 * in which the bug was found. In java versions with out 141 * the appropriate bug fix, rmid would hide a 142 * NullPointerException in this circumstance. 143 */ 144 p.put("dummyname", "dummyvalue"); 145 groupDesc = new ActivationGroupDesc(p, null); 146 ActivationGroupID secondGroupID = 147 system.registerGroup(groupDesc); 148 desc = new ActivationDesc(secondGroupID, 149 "ShutdownGracefully", null, null); 150 151 try { 152 registering = (RegisteringActivatable) 153 Activatable.register(desc); 154 155 System.err.println("second activate and deactivate " + 156 "object via method call"); 157 } catch (ActivationException e) { 158 System.err.println("received exception from registration " + 159 "call that should have failed..."); 160 } 161 162 /* 163 * no longer needed because the security manager 164 * throws an exception during snapshot 165 */ 166 /* 167 try { 168 registering.shutdown(); 169 170 System.err.println("received exception from remote " + 171 "call that should have failed..."); 172 } catch (RemoteException e) { 173 } 174 */ 175 176 } catch (Exception e) { 177 TestLibrary.bomb("\nfailure: unexpected exception ", e); 178 } finally { 179 try { 180 Thread.sleep(4000); 181 } catch (InterruptedException e) { 182 } 183 184 registering = null; 185 186 // Need to make sure that rmid goes away by itself 187 JavaVM rmidProcess = rmid; 188 if (rmidProcess != null) { 189 try { 190 Runnable waitThread = 191 new ShutdownDetectThread(rmidProcess); 192 193 synchronized (waitThread) { 194 (new Thread(waitThread)).start(); 195 waitThread.wait(SHUTDOWN_TIMEOUT); 196 System.err.println("rmid has shutdown"); 197 198 if (!rmidDone) { 199 // ensure that this rmid does not infect 200 // other tests. 201 rmidProcess.destroy(); 202 TestLibrary.bomb("rmid did not shutdown " + 203 "gracefully in time"); 204 } 205 } 206 } catch (Exception e) { 207 TestLibrary.bomb("exception waiting for rmid " + 208 "to shut down"); 209 } 210 } 211 // else rmid should be down 212 } 213 214 System.err.println 215 ("\nsuccess: ShutdownGracefully test passed "); 216 } 217 218 private static boolean rmidDone = false; 219 220 /** 221 * class that waits for rmid to exit 222 */ 223 private static class ShutdownDetectThread implements Runnable { 224 private JavaVM rmidProcess = null; 225 226 ShutdownDetectThread(JavaVM rmidProcess) { 227 this.rmidProcess = rmidProcess; 228 } 229 public void run() { 230 System.err.println("waiting for rmid to shutdown"); 231 232 try { 233 rmidProcess.waitFor(); 234 } catch (InterruptedException e) { 235 // should not happen 236 } 237 238 synchronized (this) { 239 // notify parent thread when rmid has exited 240 this.notify(); 241 rmidDone = true; 242 } 243 244 RMID.removeLog(); 245 } 246 } 247 248 /** 249 * implementation of RegisteringActivatable 250 */ 251 public ShutdownGracefully 252 (ActivationID id, MarshalledObject mo) throws RemoteException 253 { 254 // register/export anonymously 255 super(id, 0); 256 } 257 258 /** 259 * Spawns a thread to deactivate the object. 260 */ 261 public void shutdown() throws Exception { 262 (new Thread(this, "ShutdownGracefully")).start(); 263 } 264 265 /** 266 * Thread to deactivate object. First attempts to make object 267 * inactive (via the inactive method). If that fails (the 268 * object may still have pending/executing calls), then 269 * unexport the object forcibly. 270 */ 271 public void run() { 272 try { 273 Thread.sleep(50 * 1000); 274 } catch (InterruptedException e) { 275 } 276 ActivationLibrary.deactivate(this, getID()); 277 } 278 }