1 /***
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Exoffice Technologies. For written permission,
18 * please contact info@exolab.org.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Exoffice Technologies. Exolab is a registered
23 * trademark of Exoffice Technologies.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.exolab.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: DisconnectionTestCase.java,v 1.4 2006/12/16 12:37:17 tanderson Exp $
44 */
45 package org.exolab.jms.net.invoke;
46
47 import java.rmi.RemoteException;
48 import java.util.Map;
49 import java.util.HashMap;
50
51 import EDU.oswego.cs.dl.util.concurrent.Latch;
52
53 import org.exolab.jms.net.Callback;
54 import org.exolab.jms.net.CallbackService;
55 import org.exolab.jms.net.CallbackServiceImpl;
56 import org.exolab.jms.net.connector.Caller;
57 import org.exolab.jms.net.connector.CallerListener;
58 import org.exolab.jms.net.orb.ORB;
59 import org.exolab.jms.net.proxy.Proxy;
60 import org.exolab.jms.net.registry.Registry;
61
62
63 /***
64 * Tests disconnection.
65 *
66 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
67 * @version $Revision: 1.4 $ $Date: 2006/12/16 12:37:17 $
68 */
69 public class DisconnectionTestCase extends ORBTestCase {
70
71 /***
72 * Construct a new <code>DisconnectionTestCase</code>.
73 *
74 * @param name the name of test case
75 * @param uri the server export URI
76 */
77 public DisconnectionTestCase(String name, String uri) {
78 super(name, uri);
79 }
80
81 /***
82 * Construct a new <code>DisconnectionTestCase</code>.
83 *
84 * @param name the name of test case
85 * @param uri the server export URI
86 * @param properties connection properties. May be <code>null</code>
87 */
88 public DisconnectionTestCase(String name, String uri, Map properties) {
89 super(name, uri, properties);
90 }
91
92 /***
93 * Construct a new <code>DisconnectionTestCase</code>.
94 *
95 * @param name the name of test case
96 * @param uri the server export URI
97 * @param routeURI the route URI
98 */
99 public DisconnectionTestCase(String name, String uri, String routeURI) {
100 super(name, uri, routeURI);
101 }
102
103 /***
104 * Construct a new <code>DisconnectionTestCase</code>.
105 *
106 * @param name the name of test case
107 * @param uri the export URI
108 * @param routeURI the route URI
109 * @param connectionProps connection properties. May be <code>null</code>
110 * @param acceptorProps acceptor properites. May be <code>null</code>
111 */
112 public DisconnectionTestCase(String name, String uri, String routeURI,
113 Map connectionProps, Map acceptorProps) {
114 super(name, uri, routeURI, connectionProps, acceptorProps);
115 }
116
117 /***
118 * Verifies that the client is notified when the server is shut down.
119 *
120 * @throws Exception for any error
121 */
122 public void testServerDisconnect() throws Exception {
123 final Latch latch = new Latch();
124 CallerListener listener = new CallerListener() {
125 public void disconnected(Caller caller) {
126 latch.release();
127 }
128 };
129 ORB client = getClientORB();
130 client.addCallerListener(getServerURI(), listener);
131
132 ORB server = getORB();
133 server.getRegistry();
134
135
136
137 Registry registry = getRegistry();
138 assertNotNull(registry);
139
140 server.shutdown();
141
142 if (!latch.attempt(10 * 1000)) {
143 fail("CallerListener not notified of disconnection");
144 }
145 }
146
147 /***
148 * Verifies that the server is notified when the client is shut down.
149 *
150 * @throws Exception for any error
151 */
152 public void testClientDisconnect() throws Exception {
153 Latch latch = new Latch();
154 ORB server = getORB();
155 CallbackServer serviceImpl = new CallbackServer(server, latch);
156
157 Proxy proxy = server.exportObject(serviceImpl);
158 server.getRegistry().bind("service", proxy);
159
160 ORB client = getClientORB();
161 Registry registry = client.getRegistry(getConnectionProperties());
162 CallbackService service = (CallbackService) registry.lookup("service");
163
164 LoggingCallback callback = new LoggingCallback();
165 Callback callbackProxy = (Callback) client.exportObjectTo(callback,
166 getServerURI());
167 service.addCallback(callbackProxy);
168
169 assertNull(serviceImpl.getException());
170 client.shutdown();
171
172 if (!latch.attempt(10 * 1000)) {
173 fail("CallerListener not notified of disconnection");
174 }
175 assertNull(serviceImpl.getException());
176 }
177
178 /***
179 * Verifies that the client is notified when the connection is closed
180 * through inactivity.
181 *
182 * @throws Exception for any error
183 */
184 public void testInactive() throws Exception {
185 final Latch latch = new Latch();
186 CallerListener listener = new CallerListener() {
187 public void disconnected(Caller caller) {
188 latch.release();
189 }
190 };
191
192 ORB server = getORB();
193 CallbackServer serviceImpl = new CallbackServer(server, latch);
194
195 Proxy proxy = server.exportObject(serviceImpl);
196 server.getRegistry().bind("service", proxy);
197
198 ORB client = getClientORB();
199 client.addCallerListener(getServerURI(), listener);
200
201 Registry registry = getRegistry();
202 assertNotNull(registry);
203 CallbackService service = (CallbackService) registry.lookup("service");
204 assertNotNull(service);
205
206
207
208 for (int i = 0; i < 10; ++i) {
209 Runtime.getRuntime().gc();
210 if (latch.attempt(1000)) {
211 break;
212 }
213 }
214 if (latch.attempt(0)) {
215 fail("Connection terminated when there were active proxies");
216 }
217
218
219
220
221
222 registry = null;
223 for (int i = 0; i < 10; ++i) {
224 Runtime.getRuntime().gc();
225 if (latch.attempt(1000)) {
226 break;
227 }
228 }
229 if (latch.attempt(0)) {
230 fail("Connection terminated when there were active proxies");
231 }
232
233
234 service = null;
235
236
237 for (int i = 0; i < 10; ++i) {
238 Runtime.getRuntime().gc();
239 if (latch.attempt(1000)) {
240 break;
241 }
242 }
243 if (!latch.attempt(0)) {
244 fail("CallerListener not notified of disconnection");
245 }
246 }
247
248 /***
249 * Returns properties for configuring the client ORB.
250 * This configures the default connection pool to reap connections every
251 * 5 seconds.
252 *
253 * @return the properties for configuring the client ORB.
254 */
255 protected Map getClientProperties() {
256 Map properties = super.getClientProperties();
257 return addReapIntervalProperty(properties);
258 }
259
260 /***
261 * Returns the acceptor properties to use when accepting connections.
262 * This configures the default connection pool to reap connections every
263 * 5 seconds.
264 *
265 * @return the acceptor properties, or <code>null</code> if the default
266 * connection properties should be used
267 * @throws Exception for any error
268 */
269 protected Map getAcceptorProperties() throws Exception {
270 Map properties = super.getAcceptorProperties();
271 return addReapIntervalProperty(properties);
272 }
273
274 /***
275 * Adds a 5 second reap interval property to ORB configuration properties.
276 *
277 * @param properties the properties to add to. May be <code>null</code>
278 * @return the updated configuration properties
279 */
280 private Map addReapIntervalProperty(Map properties) {
281 if (properties == null) {
282 properties = new HashMap();
283 }
284 properties.put("org.exolab.jms.net.pool.reapInterval", "5");
285 return properties;
286 }
287
288 /***
289 * {@link CallbackService} implementation that detects disconnection of its
290 * client.
291 */
292 private static class CallbackServer extends CallbackServiceImpl
293 implements CallerListener {
294
295 /***
296 * The ORB.
297 */
298 private final ORB _orb;
299
300 /***
301 * The latch to notify when disconnect() is invoked.
302 */
303 private final Latch _latch;
304
305 /***
306 * Any exception raised during the test. Should be null.
307 */
308 private Exception _exception;
309
310
311 /***
312 * Construct a new <code>CallbackServer</code>.
313 *
314 * @param orb the ORB to use
315 * @param latch the latch to notify when disconnect() is invoked.
316 */
317 public CallbackServer(ORB orb, Latch latch) {
318 _orb = orb;
319 _latch = latch;
320 }
321
322 /***
323 * Register a callback.
324 *
325 * @param callback the callback to register
326 */
327 public synchronized void addCallback(Callback callback) {
328 super.addCallback(callback);
329 try {
330 Caller caller = _orb.getCaller();
331 _orb.addCallerListener(caller.getRemoteURI().toString(), this);
332 } catch (RemoteException exception) {
333 _exception = exception;
334 }
335 }
336
337 /***
338 * Notifies that a caller has been disconnected.
339 *
340 * @param caller the caller that was disconnected
341 */
342 public void disconnected(Caller caller) {
343 try {
344 _latch.release();
345 _orb.removeCallerListener(caller.getRemoteURI().toString(),
346 this);
347 } catch (RemoteException exception) {
348 _exception = exception;
349 }
350 }
351
352 /***
353 * Returns any exception raised.
354 *
355 * @return any exception raised, or <code>null</code>
356 */
357 public Exception getException() {
358 return _exception;
359 }
360 }
361 }