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 2004-2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42   *
43   * $Id: ManagedConnectionTestCase.java,v 1.3 2006/12/16 12:37:17 tanderson Exp $
44   */
45  package org.exolab.jms.net.connector;
46  
47  import junit.framework.TestCase;
48  
49  import java.security.Principal;
50  
51  
52  /***
53   * Tests the {@link ManagedConnectionFactory} interface.
54   *
55   * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
56   * @version $Revision: 1.3 $ $Date: 2006/12/16 12:37:17 $
57   */
58  public abstract class ManagedConnectionTestCase extends TestCase {
59  
60      /***
61       * The managed connection factory.
62       */
63      private ManagedConnectionFactory _factory;
64  
65  
66      /***
67       * Construct an instance of this class for a specific test case.
68       *
69       * @param name the name of test case
70       */
71      public ManagedConnectionTestCase(String name) {
72          super(name);
73      }
74  
75      /***
76       * Tests {@link ManagedConnection#getConnection}.
77       *
78       * @throws Exception for any error
79       */
80      public void testGetConnection() throws Exception {
81          Principal principal = null;
82  
83          // set up an acceptor to handle the connection request
84          ManagedConnectionAcceptor acceptor = createAcceptor(principal);
85          InvocationHandler handler = new TestInvocationHandler();
86          TestAcceptorEventListener listener = new TestAcceptorEventListener(
87                  handler);
88          acceptor.accept(listener);
89  
90          // create the managed connection
91          ConnectionRequestInfo info = getManagedConnectionRequestInfo();
92          ManagedConnection managed = _factory.createManagedConnection(
93                  principal, info);
94  
95          // verify that getConnection() fails if no InvocationHandler
96          // is registered
97          try {
98              managed.getConnection();
99              fail("Expected " + IllegalStateException.class.getName()
100                     + " to be thrown");
101         } catch (IllegalStateException exception) {
102             // the expected behaviour
103         } catch (Exception exception) {
104             fail("Expected " + IllegalStateException.class.getName()
105                     + " to be thrown, but got exception="
106                     + exception.getClass().getName()
107                     + ", message=" + exception.getMessage());
108         }
109 
110         // register an InvocationHandler and verify that getConnection()
111         // succeeds
112         managed.setInvocationHandler(new TestInvocationHandler());
113 
114         Connection connection = managed.getConnection();
115         assertNotNull(connection);
116 
117         // clean up
118         managed.destroy();
119         listener.destroy();
120         acceptor.close();
121     }
122 
123     /***
124      * Verifies that an <code>InvocationHandler</code> can be registered,
125      * and that <code>IllegalStateException</code> is thrown if
126      * {@link ManagedConnection#setInvocationHandler} is invoked more
127      * than once.
128      *
129      * @throws Exception for any error
130      */
131     public void testSetInvocationHandler() throws Exception {
132         Principal principal = null;
133 
134         // set up an acceptor to handle the connection request
135         ManagedConnectionAcceptor acceptor = createAcceptor(principal);
136         InvocationHandler handler = new TestInvocationHandler();
137         TestAcceptorEventListener listener = new TestAcceptorEventListener(
138                 handler);
139         acceptor.accept(listener);
140 
141         // create the managed connection
142         ManagedConnection managed = createConnection(principal);
143         try {
144             managed.setInvocationHandler(null);
145             fail("Expected " + IllegalStateException.class.getName()
146                     + " to be thrown");
147         } catch (IllegalStateException exception) {
148             // the expected behaviour
149         } catch (Exception exception) {
150             fail("Expected " + IllegalStateException.class.getName()
151                     + " to be thrown, but got exception="
152                     + exception.getClass().getName()
153                     + ", message=" + exception.getMessage());
154         }
155 
156         try {
157             managed.setInvocationHandler(new TestInvocationHandler());
158             fail("Expected " + IllegalStateException.class.getName()
159                     + " to be thrown");
160         } catch (IllegalStateException exception) {
161             // the expected behaviour
162         } catch (Exception exception) {
163             fail("Expected " + IllegalStateException.class.getName()
164                     + " to be thrown, but got exception="
165                     + exception.getClass().getName()
166                     + ", message=" + exception.getMessage());
167         }
168 
169         // clean up
170         managed.destroy();
171         listener.destroy();
172         acceptor.close();
173     }
174 
175     /***
176      * Tests {@link ManagedConnection#ping}, from the client perspective.
177      *
178      * @throws Exception for any error
179      */
180     public void testClientIsAlive() throws Exception {
181         Principal principal = null;
182 
183         // set up an acceptor to handle the connection request
184         ManagedConnectionAcceptor acceptor = createAcceptor(principal);
185         InvocationHandler handler = new TestInvocationHandler();
186         TestAcceptorEventListener listener = new TestAcceptorEventListener(
187                 handler);
188         acceptor.accept(listener);
189 
190         // create the client connection
191         ManagedConnection client = createConnection(principal);
192         TestConnectionEventListener mcListener
193                 = new TestConnectionEventListener();
194         client.setConnectionEventListener(mcListener);
195 
196         client.ping();
197         Thread.sleep(1000);
198         assertEquals(1, mcListener.getPinged());
199 
200         // destroy the server connection, and verify its dead from the
201         // client perspective
202         ManagedConnection server = listener.getConnection();
203         assertNotNull(server);
204         server.destroy();
205 
206         try {
207             client.ping();
208             Thread.sleep(1000);
209             assertEquals(1, mcListener.getPinged());
210         } catch (ResourceException alternative) {
211             // ping could also throw an exception
212         }
213 
214         // destroy the client
215         client.destroy();
216 
217         try {
218             client.ping();
219             fail("Expected IllegalStateException to be thrown");
220         } catch (IllegalStateException expected) {
221             // expected behaviour
222         }
223 
224         // clean up
225         acceptor.close();
226     }
227 
228     /***
229      * Tests {@link ManagedConnection#ping}, from the server perspective.
230      *
231      * @throws Exception for any error
232      */
233     public void testServerIsAlive() throws Exception {
234         Principal principal = null;
235 
236         // set up an acceptor to handle the connection request
237         ManagedConnectionAcceptor acceptor = createAcceptor(principal);
238         InvocationHandler handler = new TestInvocationHandler();
239         TestAcceptorEventListener listener = new TestAcceptorEventListener(
240                 handler);
241         acceptor.accept(listener);
242 
243         // create the client connection
244         ManagedConnection client = createConnection(principal);
245 
246         // delay to enable the listener to get notified
247         Thread.sleep(1000);
248 
249         // get the server connection
250         ManagedConnection server = listener.getConnection();
251         assertNotNull(server);
252         TestConnectionEventListener mcListener
253                 = new TestConnectionEventListener();
254         server.setConnectionEventListener(mcListener);
255 
256         server.ping();
257         Thread.sleep(1000);
258         assertEquals(1, mcListener.getPinged());
259 
260         // destroy the client connection, and verify its dead from the
261         // server perspective
262         client.destroy();
263 
264         try {
265             server.ping();
266             Thread.sleep(1000);
267             assertEquals(1, mcListener.getPinged());
268         } catch (ResourceException alternative) {
269             // ping could also throw an exception
270         }
271 
272         // destroy the server connection
273         server.destroy();
274 
275         try {
276             server.ping();
277         } catch (IllegalStateException expected) {
278             // the expected behaviour
279         }
280 
281         // clean up
282         acceptor.close();
283     }
284 
285     /***
286      * Sets up the test case.
287      *
288      * @throws Exception for any error
289      */
290     protected void setUp() throws Exception {
291         _factory = createManagedConnectionFactory();
292     }
293 
294     /***
295      * Creates a managed connection factory.
296      *
297      * @return the new managed connection factory
298      * @throws Exception for any error
299      */
300     protected abstract ManagedConnectionFactory
301             createManagedConnectionFactory() throws Exception;
302 
303     /***
304      * Returns connection request info suitable for creating a managed
305      * connection.
306      *
307      * @return connection request info for creating a managed connection
308      * @throws Exception for any error
309      */
310     protected abstract ConnectionRequestInfo getManagedConnectionRequestInfo()
311             throws Exception;
312 
313     /***
314      * Returns connection request info suitable for creating a managed
315      * connection acceptor.
316      *
317      * @return connection request info for creating a managed connection
318      *         acceptor
319      * @throws Exception for any error
320      */
321     protected abstract ConnectionRequestInfo getAcceptorConnectionRequestInfo()
322             throws Exception;
323 
324     /***
325      * Helper to return the cached managed connection factory
326      *
327      * @return the cached managed connection factory
328      */
329     protected ManagedConnectionFactory getManagedConnectionFactory() {
330         return _factory;
331     }
332 
333     /***
334      * Helper to create a managed connection.
335      *
336      * @param principal the principal to use. May be <code>null</code>
337      * @throws Exception for any error
338      */
339     protected ManagedConnection createConnection(Principal principal)
340             throws Exception {
341         ConnectionRequestInfo info = getManagedConnectionRequestInfo();
342         ManagedConnection connection = _factory.createManagedConnection(
343                 principal, info);
344         connection.setInvocationHandler(new TestInvocationHandler());
345         return connection;
346     }
347 
348     /***
349      * Helper to create a managed connection acceptor.
350      *
351      * @param principal the principal to use. May be <code>null</code>
352      * @throws Exception for any error
353      */
354     protected ManagedConnectionAcceptor createAcceptor(Principal principal)
355             throws Exception {
356         ConnectionRequestInfo info = getAcceptorConnectionRequestInfo();
357         Authenticator authenticator = new TestAuthenticator(principal);
358         return _factory.createManagedConnectionAcceptor(authenticator, info);
359     }
360 
361     private class TestConnectionEventListener
362             implements ManagedConnectionListener {
363 
364         /***
365          * Determines the no. of times the connection has been pinged.
366          */
367         private int _pinged;
368 
369         /***
370          * Notifies closure of a connection. The <code>ManagedConnection</code>
371          * instance invokes this to notify its registered listeners when
372          * the peer closes the connection.
373          *
374          * @param source the managed connection that is the source of the event
375          */
376         public void closed(ManagedConnection source) {
377             //To change body of implemented methods use File | Settings | File Templates.
378         }
379 
380         /***
381          * Notifies a connection related error. The <code>ManagedConnection</code>
382          * instance invokes this to notify its registered listeners of the
383          * occurrence of a physical connection-related error.
384          *
385          * @param source    the managed connection that is the source of the event
386          * @param throwable the error
387          */
388         public void error(ManagedConnection source, Throwable throwable) {
389             //To change body of implemented methods use File | Settings | File Templates.
390         }
391 
392         /***
393          * Notifies of a successful ping.
394          *
395          * @param source the managed connection that is the source of the event
396          */
397         public synchronized void pinged(ManagedConnection source) {
398             ++_pinged;
399         }
400 
401         /***
402          * Returns the no. of times a ping has been replied to.
403          *
404          * @return the no. of times a ping has been replied to
405          */
406         public synchronized int getPinged() {
407             return _pinged;
408         }
409     }
410 
411 }