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: SocketManagedConnectionFactoryTestCase.java,v 1.4 2005/12/01 13:44:39 tanderson Exp $
44   */
45  package org.exolab.jms.net.socket;
46  
47  import java.net.InetAddress;
48  import java.util.ArrayList;
49  import java.util.List;
50  
51  import org.apache.commons.logging.Log;
52  import org.apache.commons.logging.LogFactory;
53  
54  import org.exolab.jms.net.connector.ConnectionRequestInfo;
55  import org.exolab.jms.net.connector.ManagedConnection;
56  import org.exolab.jms.net.connector.ManagedConnectionAcceptor;
57  import org.exolab.jms.net.connector.ManagedConnectionFactory;
58  import org.exolab.jms.net.connector.ManagedConnectionFactoryTestCase;
59  import org.exolab.jms.net.connector.ResourceException;
60  import org.exolab.jms.net.connector.TestAcceptorEventListener;
61  import org.exolab.jms.net.connector.TestInvocationHandler;
62  import org.exolab.jms.net.uri.URI;
63  import org.exolab.jms.net.uri.URIHelper;
64  
65  
66  /***
67   * Tests the {@link SocketManagedConnectionFactory}.
68   *
69   * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
70   * @version $Revision: 1.4 $ $Date: 2005/12/01 13:44:39 $
71   */
72  public abstract class SocketManagedConnectionFactoryTestCase extends
73          ManagedConnectionFactoryTestCase {
74  
75      /***
76       * The acceptor URI.
77       */
78      private final URI _uri;
79  
80      /***
81       * The logger.
82       */
83      static final Log _log
84              = LogFactory.getLog(SocketManagedConnectionFactoryTestCase.class);
85  
86  
87      /***
88       * Construct an instance of this class for a specific test case.
89       *
90       * @param name the name of test case
91       * @param uri  the acceptor URI
92       * @throws Exception for any error
93       */
94      public SocketManagedConnectionFactoryTestCase(String name, String uri)
95              throws Exception {
96          super(name);
97          _uri = new URI(uri);
98      }
99  
100     /***
101      * Verifies that clients can connect via the the alternative URI specified
102      * by {@link SocketRequestInfo#getAlternativeHost()}, if the primary URI
103      * cannot be reached.
104      *
105      * @throws Exception for any error
106      */
107     public void testAlternativeURI() throws Exception {
108         URI uri = new URI(_uri);
109         uri.setHost("anonexistenthost1");
110         checkAlternativeURI(uri, _uri.getHost());
111     }
112 
113     /***
114      * Verifies that clients can connect via the the alternative URI specified
115      * by {@link SocketRequestInfo#getAlternativeHost()}, if the primary URI
116      * cannot be reached.
117      * In this case, a SecurityException is thrown when attempting to connect
118      * to the primary URI.
119      *
120      * @throws Exception for any error
121      */
122     public void testAlternativeURIWithSecMgr() throws Exception {
123         final URI uri= new URI(_uri);
124         uri.setHost("anonexistenthost2");
125 
126         SecurityManager manager = new SecurityManager() {
127             public void checkConnect(String host, int port) {
128                 if (host.equals(uri.getHost()) && port == uri.getPort()) {
129                     throw new SecurityException(
130                             "Cant connect to " + host + ":" + port);
131                 }
132                 // let everthing else connect
133             }
134         };
135         SecurityManager original = System.getSecurityManager();
136         System.setSecurityManager(manager);
137         try {
138             checkAlternativeURI(uri, _uri.getHost());
139         } finally {
140             System.setSecurityManager(original);
141         }
142     }
143 
144     /***
145      * Tests the behaviour of setting {@link SocketRequestInfo#getBindAll} to
146      * <code>false</code> to restrict connections to a single address.
147      *
148      * @throws Exception for any error
149      */
150     public void testBindSingle() throws Exception {
151         String scheme = _uri.getScheme();
152         int port = _uri.getPort();
153 
154         // set up the acceptor to only accept connections via
155         // "127.0.0.1"
156         final String loopbackIP = "127.0.0.1";
157         if (InetAddress.getLocalHost().getHostAddress().equals(loopbackIP)) {
158             fail("Local host address must not be the same as "
159                  + loopbackIP + " in order for this test case to run");
160 
161         }
162         URI loopback = URIHelper.create(scheme, loopbackIP, port);
163         SocketRequestInfo acceptInfo = getSocketRequestInfo(loopback);
164         acceptInfo.setBindAll(false);
165 
166         // create the acceptor
167         ManagedConnectionAcceptor acceptor
168                 = createAcceptor(null, acceptInfo);
169         TestAcceptorEventListener listener = new TestAcceptorEventListener(
170                 new TestInvocationHandler());
171         acceptor.accept(listener);
172 
173         // connections to this should fail
174         String host = InetAddress.getLocalHost().getHostName();
175         URI localhost = URIHelper.create(scheme, host, port);
176         SocketRequestInfo failInfo = getSocketRequestInfo(localhost);
177 
178         // verify that a connection can't be established
179         try {
180             createConnection(null, failInfo);
181             fail("Expected connection to " + localhost + " to fail");
182         } catch (ResourceException exception) {
183             // the expected behaviour
184         }
185 
186         // verify that a connection can be established via the loopback URI
187         SocketRequestInfo info = getSocketRequestInfo(loopback);
188         ManagedConnection connection = null;
189         try {
190             connection = createConnection(null, info);
191         } catch (Exception exception) {
192             fail("Expected connections to " + loopback + " to succeed:" +
193                  exception);
194         }
195 
196         // clean up
197         connection.destroy();
198 
199         // NB: the ServerSocket doesn't seem to close down under JDK 1.3.1
200         //  and 1.4.1 if the accepted sockets aren't closed first.
201         // This only happens when the ServerSocket is bound to a single address
202         listener.destroy();
203 
204         acceptor.close();
205     }
206 
207     /***
208      * Tests connection matching when the alternative URI is used.
209      *
210      * @throws Exception for any error
211      */
212     public void testMatchManagedConnectionsWithAlternativeURI()
213             throws Exception {
214         // create the acceptor
215         SocketRequestInfo info = getSocketRequestInfo(_uri);
216         ManagedConnectionAcceptor acceptor = createAcceptor(null, info);
217         TestAcceptorEventListener listener = new TestAcceptorEventListener(
218                 new TestInvocationHandler());
219         acceptor.accept(listener);
220 
221         // create a connection
222         List connections = new ArrayList();
223         ManagedConnection connection = connection = createConnection(null, info);
224         connections.add(connection);
225 
226         // verify connection matching
227         ManagedConnectionFactory factory = getManagedConnectionFactory();
228         ManagedConnection match = null;
229 
230         // make sure that the created connection matches the info used
231         // to establish it
232         match = factory.matchManagedConnections(connections, null, info);
233         assertEquals(connection, match);
234 
235         // make sure connection matching works when the alternative URI
236         // is the same as the acceptors.
237         URI failURI = getUnusedURI();
238         SocketRequestInfo altInfo = getSocketRequestInfo(failURI);
239         altInfo.setAlternativeHost(_uri.getHost());
240 
241         // make sure there is no match when none of the URIs are the same.
242         SocketRequestInfo failInfo = getSocketRequestInfo(failURI);
243         match = factory.matchManagedConnections(connections, null, failInfo);
244         assertNull(match);
245 
246         // clean up
247         acceptor.close();
248         listener.destroy();
249         connection.destroy();
250     }
251 
252     /***
253      * Returns connection request info suitable for creating a managed
254      * connection.
255      *
256      * @return connection request info for creating a managed connection
257      * @throws Exception for any error
258      */
259     protected ConnectionRequestInfo getManagedConnectionRequestInfo()
260             throws Exception {
261         return getSocketRequestInfo(_uri);
262     }
263 
264     /***
265      * Returns connection request info suitable for creating a managed
266      * connection acceptor.
267      * <p/>
268      * This implementation returns that returned by {@link
269      * #getManagedConnectionRequestInfo()}.
270      *
271      * @return connection request info for creating a managed connection
272      *         acceptor
273      * @throws Exception for any error
274      */
275     protected ConnectionRequestInfo getAcceptorConnectionRequestInfo()
276             throws Exception {
277         return getManagedConnectionRequestInfo();
278     }
279 
280     /***
281      * Returns socket request info, for the specified URI, suitable for creating
282      * a managed connection and connection acceptor.
283      *
284      * @return socket request info for creating a managed connection
285      * @throws Exception for any error
286      */
287     protected SocketRequestInfo getSocketRequestInfo(URI uri)
288             throws Exception {
289         return new SocketRequestInfo(uri);
290     }
291 
292     /***
293      * Returns a unused acceptor URI, for use by the {@link
294      * #testAlternativeURI()} test case.
295      * <p/>
296      * This implementation uses the acceptor URI supplied at construction,
297      * with an invalid host name
298      *
299      * @return an unused acceptor URI
300      * @throws Exception for any error
301      */
302     protected URI getUnusedURI() throws Exception {
303         URI result = new URI(_uri);
304         result.setHost("someinvalidhostname");
305         return result;
306     }
307 
308     /***
309      * Verifies that clients can connect via the the alternative URI determined
310      * by {@link SocketRequestInfo#getAlternativeHost()}, if the primary URI
311      * cannot be reached.
312      *
313      * @param uri an URI with host that cannot be connected to
314      * @param alternativeHost the alternative host to connect to
315      * @throws Exception for any error
316      */
317     private void checkAlternativeURI(URI uri, String alternativeHost)
318             throws Exception {
319         URI successURI = new URI(uri);
320         successURI.setHost(alternativeHost);
321         SocketRequestInfo acceptInfo = getSocketRequestInfo(successURI);
322 
323         SocketRequestInfo failInfo = getSocketRequestInfo(uri);
324         // connections to this should fail
325 
326         SocketRequestInfo successInfo = getSocketRequestInfo(uri);
327         successInfo.setAlternativeHost(successURI.getHost());
328         // connections to this should succeed (on second attempt)
329 
330         // create the acceptor
331         ManagedConnectionAcceptor acceptor = createAcceptor(null, acceptInfo);
332         TestAcceptorEventListener listener = new TestAcceptorEventListener(
333                 new TestInvocationHandler());
334         acceptor.accept(listener);
335 
336         // verify that a connection can't be established to uri
337         try {
338             createConnection(null, failInfo);
339             fail("Expected connection to " + uri + " to fail");
340         } catch (ResourceException exception) {
341             // the expected behaviour
342         }
343 
344         // verify that a connection can be established via the alternative URI
345         ManagedConnection connection = null;
346         try {
347             connection = createConnection(null, successInfo);
348         } catch (Exception exception) {
349             fail("Expected connections to " + successURI + " to succeed:" +
350                  exception);
351         }
352 
353         // clean up
354         connection.destroy();
355         acceptor.close();
356     }
357 
358 }