1/*
2 * Copyright (c) 1998, 2012, 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 4118600
26 * @summary RMI UnmarshallException, interaction on stopping a thread.
27 *
28 * @bug 4177704
29 * @summary RuntimeExceptions can corrupt call connections that may be reused.
30 *
31 * @author Laird Dornin
32 *
33 * @library ../../../testlibrary
34 * @modules java.rmi/sun.rmi.registry
35 *          java.rmi/sun.rmi.server
36 *          java.rmi/sun.rmi.transport
37 *          java.rmi/sun.rmi.transport.tcp
38 * @build TestLibrary CheckUnmarshal CheckUnmarshalOnStopThread_Stub
39 *     PoisonPill RuntimeExceptionParameter
40 * @run main/othervm/timeout=480 CheckUnmarshalOnStopThread
41 */
42
43import java.rmi.*;
44import java.rmi.server.*;
45import java.io.*;
46import java.rmi.registry.*;
47
48/**
49 * Description for 4118600:
50 *
51 * If an rmi call thread is stopped while unmarshalling a return
52 * value), java.lang.ThreadDeath will be thrown during
53 * UnicastRef.invoke(...).  If rmi handles the Error properly, the
54 * remote method connection will not be reused.  Otherwise the
55 * connection can be freed and reused in a corrupted state, which will
56 * lead to the throwing of an UnmarshalException the next time the
57 * connection is used.
58 *
59 * To test RMI Error handling, the test invokes the remote call,
60 * getPoisonPill, a number of times.  This method returns an object
61 * which throws an Error on return value deserialization (from its
62 * readObject method). If RMI handles the error correctly, another
63 * remote call, ping, should execute correctly (i.e. with no
64 * exceptions).  The test fails if the ping method throws an
65 * UnmarshalException.
66 *
67 * The old way that the test used to operate:
68 *
69 * Iterate a large number of times: each iteration spawns a thread
70 * that makes multiple rmi calls, sleep for 10 milliseconds, then stop
71 * the thread that is making the rmi calls (hopefully during return
72 * value Unmarshalling).
73 *
74 * Count the number of UnmarshalExceptions that occur during test
75 * iterations.  If this number is > 10, then the test fails.
76 *
77 * Note: Even if rmi is catching java.lang.ThreadDeath properly, other
78 * types of exceptions (often related to monitor state, etc.) can
79 * occur.  This test is only written to track UnmarshalExceptions;
80 * success/failure does not depend on other types of problems.
81 *
82 * Description for 4177704:
83 *
84 * Similar situation as for 4177704 except that instead of just
85 * ensuring that RMI properly handles Errors, the second part of the
86 * test ensures that RMI deals with RuntimeExceptions correctly.
87 *
88 * Test also ensures that call connections are freed without reuse
89 * when RuntimeExceptions are thrown during the marshalling of call
90 * parameters.  An object that throws a RuntimeException in its
91 * writeObject method helps to carry out this part of the test.
92 */
93public class CheckUnmarshalOnStopThread
94    extends UnicastRemoteObject
95    implements CheckUnmarshal
96{
97    final static int RUNTIME_PILL = 1;
98    public static int typeToThrow = 0;
99
100    /*
101     * remote object implementation
102     */
103
104    CheckUnmarshalOnStopThread() throws RemoteException { }
105
106    public PoisonPill getPoisonPill() throws RemoteException {
107        return new PoisonPill(new Integer(0));
108    }
109
110    public Object ping() throws RemoteException {
111        return (Object) new Integer(0);
112    }
113
114    public void passRuntimeExceptionParameter(
115        RuntimeExceptionParameter rep) throws RemoteException
116    {
117        // will never be called
118    }
119
120    public static void main(String [] args) {
121
122        Object dummy = new Object();
123        CheckUnmarshal cu = null;
124        CheckUnmarshalOnStopThread cuonst = null;
125
126        System.err.println("\nregression test for bugs: " +
127                           "4118600 and 4177704\n");
128
129        try {
130            cuonst = new CheckUnmarshalOnStopThread();
131            cu = (CheckUnmarshal) UnicastRemoteObject.toStub(cuonst);
132
133            // make sure that RMI will free connections appropriately
134            // under several situations:
135
136            // when Errors are thrown during parameter unmarshalling
137            System.err.println("testing to see if RMI will handle errors");
138            ensureConnectionsAreFreed(cu, true);
139
140            // when RuntimeExceptions are thrown during parameter unmarshalling
141            System.err.println("testing to see if RMI will handle " +
142                               "runtime exceptions");
143            typeToThrow = RUNTIME_PILL;
144            ensureConnectionsAreFreed(cu, true);
145
146            // when RuntimeExceptions are thrown during parameter marshalling
147            System.err.println("testing to see if RMI will handle " +
148                               "runtime exceptions thrown during " +
149                               "parameter marshalling");
150            ensureConnectionsAreFreed(cu, false);
151
152            System.err.println
153                ("\nsuccess: CheckUnmarshalOnStopThread test passed ");
154
155        } catch (Exception e) {
156            TestLibrary.bomb(e);
157        } finally {
158            cu = null;
159            deactivate(cuonst);
160        }
161    }
162
163    static void ensureConnectionsAreFreed(CheckUnmarshal cu, boolean getPill)
164        throws Exception
165    {
166        // invoke a remote call that will corrupt a call connection
167        // that will not be freed (if the bug is not fixed)
168
169        for (int i = 0 ; i < 250 ; i++) {
170            try {
171                Object test = cu.ping();
172                if (getPill) {
173                    cu.getPoisonPill();
174                } else {
175                    cu.passRuntimeExceptionParameter(
176                        new RuntimeExceptionParameter());
177                }
178            } catch (Error e) {
179                // expect an Error from call unmarshalling, ignore it
180            } catch (RuntimeException e) {
181                // " RuntimeException "
182            }
183        }
184
185        System.err.println("remote calls passed, received no " +
186                           "unmarshal exceptions\n\n");
187    }
188
189    static void deactivate(RemoteServer r) {
190        // make sure that the object goes away
191        try {
192            System.err.println("deactivating object.");
193            UnicastRemoteObject.unexportObject(r, true);
194        } catch (Exception e) {
195            e.getMessage();
196            e.printStackTrace();
197        }
198    }
199}
200