1/*
2 * Copyright (c) 2002, 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 4526514
26 * @summary rmid does not handle group restart for latecomer objects
27 * @author Ann Wollrath
28 *
29 * @library ../../../testlibrary
30 * @modules java.rmi/sun.rmi.registry
31 *          java.rmi/sun.rmi.server
32 *          java.rmi/sun.rmi.transport
33 *          java.rmi/sun.rmi.transport.tcp
34 *          java.base/sun.nio.ch
35 * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary
36 *     RestartLatecomer RestartLatecomer_Stub
37 * @run main/othervm/policy=security.policy/timeout=240 RestartLatecomer
38 */
39
40import java.io.*;
41import java.rmi.*;
42import java.rmi.activation.*;
43import java.rmi.server.*;
44import java.rmi.registry.*;
45import java.util.Vector;
46import java.util.Properties;
47
48public class RestartLatecomer
49        implements ActivateMe, Runnable
50{
51
52    private ActivationID id;
53    private static Object lock = new Object();
54    private Vector responders = new Vector();
55
56    private static final String RESTARTABLE = "restartable";
57    private static final String ACTIVATABLE = "activatable";
58
59
60    public RestartLatecomer(ActivationID id, MarshalledObject mobj)
61        throws ActivationException, RemoteException
62    {
63        this.id = id;
64        Activatable.exportObject(this, id, 0);
65        ActivateMe obj;
66        String responder;
67        try {
68            Object[] stuff = (Object[]) mobj.get();
69            responder = (String) stuff[0];
70            System.err.println(responder + " service started");
71            obj = (ActivateMe) stuff[1];
72        } catch (Exception e) {
73            System.err.println("unable to obtain stub from marshalled object");
74            return;
75        }
76
77        /*
78         * Call back object in the test VM to notify it that
79         * this object has been activated or restarted.
80         */
81        obj.callback(responder);
82    }
83
84    public RestartLatecomer() throws RemoteException {
85        UnicastRemoteObject.exportObject(this, 0);
86    }
87
88    private void waitFor(String responder) throws Exception {
89        synchronized (lock) {
90            for (int i = 0; i < 15; i++) {
91                if (responders.contains(responder) != true) {
92                    lock.wait(5000);
93                    if (responders.contains(responder) == true) {
94                        return;
95                    }
96                } else {
97                    return;
98                }
99            }
100        }
101
102        throw new RuntimeException(
103            "TEST FAILED: service not restarted by timeout");
104    }
105
106    private void clearResponders() {
107        synchronized (lock) {
108            responders.clear();
109        }
110    }
111
112
113    /**
114     * Notifies the receiver that the object denoted by "responder"
115     * has activated or restarted.
116     */
117    public void callback(String responder) {
118        System.err.println(
119            "RestartLatecomer: received callback from " + responder);
120        /*
121         * Notify waiter that callback has been received and
122         * test can proceed.
123         */
124        synchronized (lock) {
125            responders.add(responder);
126            lock.notifyAll();
127        }
128    }
129
130    /**
131     * Pings object (to activate it).
132     */
133    public void ping() {
134        System.err.println("RestartLatecomer: recevied ping");
135    }
136
137    /**
138     * Spawns a thread to deactivate the object.
139     */
140    public void shutdown() {
141        System.err.println("RestartLatecomer: received shutdown request");
142        (new Thread(this,"RestartLatecomer")).start();
143    }
144
145    public ActivationID getID() {
146        return id;
147    }
148
149    /**
150     * Thread to deactivate object. First attempts to make object
151     * inactive (via the inactive method).  If that fails (the
152     * object may still have pending/executing calls), then
153     * unexport the object forcibly.
154     */
155    public void run() {
156        System.exit(0);
157    }
158
159    public static void main(String[] args) {
160
161        System.out.println("\nRegression test for bug 4526514\n");
162
163        TestLibrary.suggestSecurityManager("java.rmi.RMISecurityManager");
164
165        RMID rmid = null;
166        RestartLatecomer callbackObj = null;
167
168        try {
169            RMID.removeLog();
170            rmid = RMID.createRMIDOnEphemeralPort();
171            rmid.start();
172
173            /* Cause activation groups to have a security policy that will
174             * allow security managers to be downloaded and installed
175             */
176            Properties p = new Properties();
177            // this test must always set policies/managers in its
178            // activation groups
179            p.put("java.security.policy",
180                  TestParams.defaultGroupPolicy);
181            p.put("java.security.manager",
182                  TestParams.defaultSecurityManager);
183
184            /*
185             * Create unicast object to be contacted when service is activated.
186             */
187            callbackObj = new RestartLatecomer();
188            /*
189             * Create and register descriptors for a restartable and
190             * non-restartable service (respectively) in a group other than
191             * this VM's group.
192             */
193            System.err.println("Creating descriptors");
194
195            Object[] stuff = new Object[] { RESTARTABLE, callbackObj };
196            MarshalledObject restartMobj = new MarshalledObject(stuff);
197            ActivationGroupDesc groupDesc =
198                new ActivationGroupDesc(p, null);
199
200            stuff[0] = ACTIVATABLE;
201            MarshalledObject activateMobj = new MarshalledObject(stuff);
202            ActivationGroupID groupID =
203                ActivationGroup.getSystem().registerGroup(groupDesc);
204
205            ActivationDesc activatableDesc =
206                new ActivationDesc(groupID, "RestartLatecomer", null,
207                                   activateMobj, false);
208            ActivationDesc restartableDesc =
209                new ActivationDesc(groupID, "RestartLatecomer", null,
210                                   restartMobj, true);
211
212
213            System.err.println("Register activatable object's descriptor");
214            ActivateMe activatableObj =
215                (ActivateMe) Activatable.register(activatableDesc);
216
217            System.err.println("Activate object (starts group VM)");
218            activatableObj.ping();
219
220            callbackObj.waitFor(ACTIVATABLE);
221            callbackObj.clearResponders();
222            System.err.println("Callback from activatable object received");
223
224            System.err.println("Register restartable object's descriptor");
225            ActivateMe restartableObj =
226                (ActivateMe) Activatable.register(restartableDesc);
227
228            System.err.println("Shutdown object (exits group VM)");
229            try {
230                activatableObj.shutdown();
231            } catch (RemoteException ignore) {
232                /*
233                 * Since the shutdown method spawns a thread to call
234                 * System.exit, the group's VM may exit, closing all
235                 * connections, before this call had returned.  If that
236                 * happens, then a RemoteException will be caught
237                 * here.
238                 */
239            }
240
241            System.err.println("Pause for shutdown to happen...");
242            Thread.sleep(5000);
243
244            /*
245             * Wait for "latecomer" restartable service to be
246             * automatically restarted.
247             */
248            callbackObj.waitFor(RESTARTABLE);
249            System.err.println(
250                "TEST PASSED: rmid restarted latecomer service");
251
252        } catch (Exception e) {
253            TestLibrary.bomb(e);
254        } finally {
255            rmid.cleanup();
256            TestLibrary.unexport(callbackObj);
257        }
258    }
259
260
261}
262
263
264interface ActivateMe extends Remote {
265    public void ping() throws RemoteException;
266    public void callback(String responder) throws RemoteException;
267    public void shutdown() throws RemoteException;
268}
269