jdk/test/java/rmi/server/Unmarshal/checkUnmarshalOnStopThread/CheckUnmarshalOnStopThread.java
changeset 2 90ce3da70b43
child 309 bda219d843f6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/server/Unmarshal/checkUnmarshalOnStopThread/CheckUnmarshalOnStopThread.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,197 @@
+/* 
+ * Copyright 1998-1999 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4118600 
+ * @summary RMI UnmarshallException, interaction on stopping a thread.
+ *
+ * @bug 4177704
+ * @summary RuntimeExceptions can corrupt call connections that may be reused.
+ *
+ * @author Laird Dornin
+ *
+ * @library ../../../testlibrary
+ * @build TestLibrary RMID JavaVM StreamPipe
+ * @build CheckUnmarshall PoisonPill RuntimeExceptionParameter
+ * @build CheckUnmarshalOnStopThread
+ * @build CheckUnmarshalOnStopThread_Stub
+ * @run main/othervm/timeout=480 CheckUnmarshalOnStopThread 
+ */
+
+import java.rmi.*;
+import java.rmi.server.*;
+import java.io.*;
+import java.rmi.registry.*;
+
+/**
+ * Description for 4118600: 
+ *
+ * If an rmi call thread is stopped while unmarshalling a return
+ * value), java.lang.ThreadDeath will be thrown during
+ * UnicastRef.invoke(...).  If rmi handles the Error properly, the
+ * remote method connection will not be reused.  Otherwise the
+ * connection can be freed and reused in a corrupted state, which will
+ * lead to the throwing of an UnmarshalException the next time the
+ * connection is used.
+ *
+ * To test RMI Error handling, the test invokes the remote call,
+ * getPoisonPill, a number of times.  This method returns an object
+ * which throws an Error on return value deserialization (from its
+ * readObject method). If RMI handles the error correctly, another
+ * remote call, ping, should execute correctly (i.e. with no
+ * exceptions).  The test fails if the ping method throws an
+ * UnmarshalException.
+ *
+ * The old way that the test used to operate:
+ *
+ * Iterate a large number of times: each iteration spawns a thread
+ * that makes multiple rmi calls, sleep for 10 milliseconds, then stop
+ * the thread that is making the rmi calls (hopefully during return
+ * value Unmarshalling).
+ *
+ * Count the number of UnmarshalExceptions that occur during test
+ * iterations.  If this number is > 10, then the test fails.
+ *
+ * Note: Even if rmi is catching java.lang.ThreadDeath properly, other
+ * types of exceptions (often related to monitor state, etc.) can
+ * occur.  This test is only written to track UnmarshalExceptions;
+ * success/failure does not depend on other types of problems.
+ *
+ * Description for 4177704: 
+ * 
+ * Similar situation as for 4177704 except that instead of just
+ * ensuring that RMI properly handles Errors, the second part of the
+ * test ensures that RMI deals with RuntimeExceptions correctly.
+ *
+ * Test also ensures that call connections are freed without reuse
+ * when RuntimeExceptions are thrown during the marshalling of call
+ * parameters.  An object that throws a RuntimeException in its
+ * writeObject method helps to carry out this part of the test.
+ */
+public class CheckUnmarshalOnStopThread 
+    extends UnicastRemoteObject 
+    implements CheckUnmarshal 
+{
+    final static int RUNTIME_PILL = 1;
+    public static int typeToThrow = 0;
+
+    /*
+     * remote object implementation 
+     */
+
+    CheckUnmarshalOnStopThread() throws RemoteException { }
+
+    public PoisonPill getPoisonPill() throws RemoteException {
+	return new PoisonPill(new Integer(0));
+    }
+
+    public Object ping() throws RemoteException {
+	return (Object) new Integer(0);
+    }
+
+    public void passRuntimeExceptionParameter(
+        RuntimeExceptionParameter rep) throws RemoteException 
+    {
+	// will never be called
+    }
+
+    public static void main(String [] args) {
+
+	Object dummy = new Object();
+	CheckUnmarshal cu = null;
+	CheckUnmarshalOnStopThread cuonst = null;
+
+	System.err.println("\nregression test for bugs: " + 
+			   "4118600 and 4177704\n");
+
+	try {
+	    cuonst = new CheckUnmarshalOnStopThread();
+	    cu = (CheckUnmarshal) UnicastRemoteObject.toStub(cuonst);
+
+	    // make sure that RMI will free connections appropriately
+	    // under several situations:
+
+	    // when Errors are thrown during parameter unmarshalling
+	    System.err.println("testing to see if RMI will handle errors");
+	    ensureConnectionsAreFreed(cu, true);
+
+	    // when RuntimeExceptions are thrown during parameter unmarshalling
+	    System.err.println("testing to see if RMI will handle " + 
+			       "runtime exceptions");
+	    typeToThrow = RUNTIME_PILL;
+	    ensureConnectionsAreFreed(cu, true);
+
+	    // when RuntimeExceptions are thrown during parameter marshalling
+	    System.err.println("testing to see if RMI will handle " + 
+			       "runtime exceptions thrown during " + 
+			       "parameter marshalling");
+	    ensureConnectionsAreFreed(cu, false);
+
+	    System.err.println
+		("\nsuccess: CheckUnmarshalOnStopThread test passed ");
+
+	} catch (Exception e) {
+	    TestLibrary.bomb(e);
+	} finally {
+	    cu = null;
+	    deactivate(cuonst);
+	}
+    }
+    
+    static void ensureConnectionsAreFreed(CheckUnmarshal cu, boolean getPill) 
+	throws Exception
+    {
+	// invoke a remote call that will corrupt a call connection
+	// that will not be freed (if the bug is not fixed)
+
+	for (int i = 0 ; i < 250 ; i++) {
+	    try {
+		Object test = cu.ping();
+		if (getPill) {
+		    cu.getPoisonPill();
+		} else {
+		    cu.passRuntimeExceptionParameter(
+		        new RuntimeExceptionParameter());
+		}
+	    } catch (Error e) {
+		// expect an Error from call unmarshalling, ignore it
+	    } catch (RuntimeException e) {
+		// " RuntimeException "
+	    }
+	}
+
+	System.err.println("remote calls passed, received no " + 
+			   "unmarshal exceptions\n\n");
+    }
+
+    static void deactivate(RemoteServer r) {
+	// make sure that the object goes away
+	try {
+	    System.err.println("deactivating object.");
+	    UnicastRemoteObject.unexportObject(r, true);
+	} catch (Exception e) {
+	    e.getMessage();
+	    e.printStackTrace();
+	}
+    }
+}