1/*
2 * Copyright (c) 1998, 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 4105080
26 * @summary Activation retry during a remote method call to an activatable
27 *          object can cause infinite recursion in some situations. The
28 *          RemoteRef contained in the ActivatableRef should never be
29 *          an ActivatableRef, but another type.
30 * (Needs /othervm to evade JavaTest security manager --aecolley)
31 * @author Ann Wollrath
32 *
33 * @bug 4164971
34 * @summary allow non-public activatable class and/or constructor
35 *          Main test class hasa non-public constructor to ensure
36 *          functionality is in place
37 *
38 * @library ../../../testlibrary
39 * @modules java.rmi/sun.rmi.registry
40 *          java.rmi/sun.rmi.server:+open
41 *          java.rmi/sun.rmi.transport
42 *          java.rmi/sun.rmi.transport.tcp
43 *          java.base/sun.nio.ch
44 * @build TestLibrary RMID RMIDSelectorProvider ActivateMe CheckActivateRef_Stub
45 * @run main/othervm/policy=security.policy/timeout=240 -Djava.rmi.server.ignoreStubClasses=true CheckActivateRef
46 * @run main/othervm/policy=security.policy/timeout=240 -Djava.rmi.server.ignoreStubClasses=false CheckActivateRef
47 * @key intermittent
48 */
49
50import java.io.*;
51import java.rmi.*;
52import java.rmi.server.*;
53import java.rmi.activation.*;
54import sun.rmi.server.ActivatableRef;
55import java.lang.reflect.*;
56import java.util.Properties;
57
58public class CheckActivateRef
59        extends Activatable
60        implements ActivateMe, Runnable
61{
62
63    private CheckActivateRef(ActivationID id, MarshalledObject obj)
64        throws ActivationException, RemoteException
65    {
66        super(id, 0);
67    }
68
69    public void ping()
70    {}
71
72    /**
73     * Spawns a thread to deactivate the object.
74     */
75    public void shutdown() throws Exception
76    {
77        (new Thread(this,"CheckActivateRef")).start();
78    }
79
80    /**
81     * Thread to deactivate object. First attempts to make object
82     * inactive (via the inactive method).  If that fails (the
83     * object may still have pending/executing calls), then
84     * unexport the object forcibly.
85     */
86    public void run() {
87        ActivationLibrary.deactivate(this, getID());
88    }
89
90    public static void main(String[] args)  {
91        /*
92         * The following line is required with the JDK 1.2 VM so that the
93         * VM can exit gracefully when this test completes.  Otherwise, the
94         * conservative garbage collector will find a handle to the server
95         * object on the native stack and not clear the weak reference to
96         * it in the RMI runtime's object table.
97         */
98        Object dummy = new Object();
99        RMID rmid = null;
100        ActivateMe obj;
101
102        // test should tolerate certain types of failures
103        int failures = 0;
104        int i = 0;
105
106        System.err.println("\nRegression test for bug 4105080\n");
107        System.err.println("java.security.policy = " +
108                           System.getProperty("java.security.policy",
109                                              "no policy"));
110
111
112        String propValue =
113            System.getProperty("java.rmi.server.useDynamicProxies", "false");
114        boolean useDynamicProxies = Boolean.parseBoolean(propValue);
115
116        CheckActivateRef server;
117        try {
118            TestLibrary.suggestSecurityManager(TestParams.defaultSecurityManager);
119
120            // start an rmid.
121            RMID.removeLog();
122            rmid = RMID.createRMIDOnEphemeralPort();
123            rmid.start();
124
125            /* Cause activation groups to have a security policy that will
126             * allow security managers to be downloaded and installed
127             */
128            Properties p = new Properties();
129            // this test must always set policies/managers in its
130            // activation groups
131            p.put("java.security.policy",
132                  TestParams.defaultGroupPolicy);
133            p.put("java.security.manager",
134                  TestParams.defaultSecurityManager);
135            p.put("java.rmi.server.useDynamicProxies", propValue);
136
137            /*
138             * Activate an object by registering its object
139             * descriptor and invoking a method on the
140             * stub returned from the register call.
141             */
142            System.err.println("Create activation group in this VM");
143            ActivationGroupDesc groupDesc =
144                new ActivationGroupDesc(p, null);
145            ActivationSystem system = ActivationGroup.getSystem();
146            ActivationGroupID groupID = system.registerGroup(groupDesc);
147            ActivationGroup.createGroup(groupID, groupDesc, 0);
148            System.err.println("Creating descriptor");
149            ActivationDesc desc =
150                new ActivationDesc("CheckActivateRef", null, null);
151            System.err.println("Registering descriptor");
152            obj = (ActivateMe) Activatable.register(desc);
153
154            System.err.println("proxy = " + obj);
155
156            if (useDynamicProxies && !Proxy.isProxyClass(obj.getClass()))
157            {
158                throw new RuntimeException("proxy is not dynamic proxy");
159            }
160
161            /*
162             * Loop a bunch of times to force activator to
163             * spawn VMs (groups)
164             */
165            try {
166                for (; i < 7; i++) {
167
168                    System.err.println("Activate object via method call");
169
170                    /*
171                     * Fix for 4277196: if we got an inactive group
172                     * exception, it is likely that we accidentally
173                     * invoked a method on an old activation
174                     * group. Give some time for the group to go away
175                     * and then retry the activation.
176                     */
177                    try {
178                        obj.ping();
179                    } catch (RemoteException e) {
180                        Exception detail = (Exception) e.detail;
181                        if ((detail != null) &&
182                            (detail instanceof ActivationException) &&
183                            (detail.getMessage().equals("group is inactive")))
184                        {
185                            try {
186                                Thread.sleep(5000);
187                            } catch (InterruptedException ex) {
188                            }
189                            obj.ping();
190
191                        } else {
192                            throw e;
193                        }
194                    }
195
196                    System.err.println("proxy = " + obj);
197
198                    /*
199                     * Now that object is activated, check to make sure that
200                     * the RemoteRef inside the stub's ActivatableRef
201                     * is *not* an ActivatableRef.
202                     */
203                    ActivatableRef aref;
204                    if (obj instanceof RemoteStub) {
205                        aref = (ActivatableRef) ((RemoteObject) obj).getRef();
206                    } else if (Proxy.isProxyClass(obj.getClass())) {
207                        RemoteObjectInvocationHandler handler =
208                            (RemoteObjectInvocationHandler)
209                            Proxy.getInvocationHandler(obj);
210                        aref = (ActivatableRef) handler.getRef();
211                    } else {
212                        throw new RuntimeException("unknown proxy type");
213                    }
214
215                    final ActivatableRef ref = aref;
216                    Field f = (Field)
217                        java.security.AccessController.doPrivileged
218                        (new java.security.PrivilegedExceptionAction() {
219                            public Object run() throws Exception {
220                                Field ff = ref.getClass().getDeclaredField("ref");
221                                ff.setAccessible(true);
222                                return ff;
223                            }
224                        });
225                    Object insideRef = f.get(ref);
226                    System.err.println("insideRef = " + insideRef);
227                    if (insideRef instanceof ActivatableRef) {
228                        TestLibrary.bomb("Embedded ref is an ActivatableRef");
229                    } else {
230                        System.err.println("ActivatableRef's embedded ref type: " +
231                                           insideRef.getClass().getName());
232                    }
233
234                    /*
235                     * Clean up object too.
236                     */
237                    System.err.println("Deactivate object via method call");
238                    obj.shutdown();
239
240                    try {
241                        // give activation group time to go away
242                        Thread.sleep(3000);
243                    } catch (InterruptedException e) {
244                    }
245                }
246            } catch (java.rmi.UnmarshalException ue) {
247                // account for test's activation race condition
248                if (ue.detail instanceof java.io.IOException) {
249                    if ((failures ++) >= 3) {
250                        throw ue;
251                    }
252                } else {
253                    throw ue;
254                }
255            }
256
257            System.err.println("\nsuccess: CheckActivateRef test passed ");
258
259        } catch (java.rmi.activation.ActivationException e) {
260            // test only needs to pass 3 times in 7
261            if (i < 4) {
262                TestLibrary.bomb(e);
263            }
264        } catch (Exception e) {
265            if (e instanceof java.security.PrivilegedActionException)
266                e = ((java.security.PrivilegedActionException)e).getException();
267            TestLibrary.bomb("\nfailure: unexpected exception " +
268                             e.getClass().getName(), e);
269
270        } finally {
271            rmid.cleanup();
272            obj = null;
273        }
274    }
275}
276