| /* |
| * Copyright (c) 1998, 2012, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.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 |
| * @modules java.rmi/sun.rmi.registry |
| * java.rmi/sun.rmi.server |
| * java.rmi/sun.rmi.transport |
| * java.rmi/sun.rmi.transport.tcp |
| * @build TestLibrary CheckUnmarshal CheckUnmarshalOnStopThread_Stub |
| * PoisonPill RuntimeExceptionParameter |
| * @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(); |
| } |
| } |
| } |