KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > exolab > jms > net > socket > SocketManagedConnectionAcceptor


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: SocketManagedConnectionAcceptor.java,v 1.6 2005/06/13 14:48:11 tanderson Exp $
44  */

45 package org.exolab.jms.net.socket;
46
47 import java.io.IOException JavaDoc;
48 import java.net.InetAddress JavaDoc;
49 import java.net.ServerSocket JavaDoc;
50 import java.net.Socket JavaDoc;
51
52 import org.apache.commons.logging.Log;
53 import org.apache.commons.logging.LogFactory;
54 import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
55
56 import org.exolab.jms.net.connector.Authenticator;
57 import org.exolab.jms.net.connector.ManagedConnection;
58 import org.exolab.jms.net.connector.ManagedConnectionAcceptor;
59 import org.exolab.jms.net.connector.ManagedConnectionAcceptorListener;
60 import org.exolab.jms.net.connector.ResourceException;
61 import org.exolab.jms.net.connector.URIRequestInfo;
62 import org.exolab.jms.net.uri.URI;
63 import org.exolab.jms.net.util.ThreadPool;
64
65
66 /**
67  * A {@link ManagedConnectionAcceptor} for accepting socket connections.
68  *
69  * @author <a HREF="mailto:tma@netspace.net.au">Tim Anderson</a>
70  * @version $Revision: 1.6 $ $Date: 2005/06/13 14:48:11 $
71  */

72 public abstract class SocketManagedConnectionAcceptor
73         implements ManagedConnectionAcceptor {
74
75     /**
76      * The connection authenticator.
77      */

78     private Authenticator _authenticator;
79
80     /**
81      * The underlying socket.
82      */

83     private ServerSocket JavaDoc _socket;
84
85     /**
86      * The URI denoting this acceptor.
87      */

88     private final URI _uri;
89
90     /**
91      * The thread pool for handling invocation requests.
92      */

93     private PooledExecutor _pool;
94
95     /**
96      * The thread group for all threads associated with this.
97      */

98     private final ThreadGroup JavaDoc _group;
99
100     /**
101      * The connection dispatcher.
102      */

103     private Dispatcher _dispatcher;
104
105     /**
106      * The connection request info used to match acceptors.
107      */

108     private final SocketRequestInfo _info;
109
110
111     /**
112      * The logger.
113      */

114     private static final Log _log =
115             LogFactory.getLog(SocketManagedConnectionAcceptor.class);
116
117
118     /**
119      * Construct a new <code>SocketManagedConnectionAcceptor</code>.
120      * <p/>
121      * This creates a server socket with the specified port and listen backlog.
122      * <p/>
123      * If {@link SocketRequestInfo#getBindAll()} flag can be used on multi-homed
124      * hosts to limit the addresses on which connections are accepted.
125      * If <code>false</code>, the socket will only accept connections on the
126      * address specified by {@link SocketRequestInfo#getHostAddress}.
127      * If <code>true</code> it will accept connections on all local addresses.
128      * <p/>
129      * The port returned by {@link URIRequestInfo#getPort} must be between 0 and
130      * 65535, inclusive
131      *
132      * @param authenticator the connection authenticator
133      * @param info the connection request info
134      * @throws ResourceException if a server socket cannot be created
135      */

136     public SocketManagedConnectionAcceptor(Authenticator authenticator,
137                                            SocketRequestInfo info)
138             throws ResourceException {
139
140         if (authenticator == null) {
141             throw new IllegalArgumentException JavaDoc(
142                     "Argument 'authenticator' is null");
143         }
144         if (info == null) {
145             throw new IllegalArgumentException JavaDoc("Argument 'info' is null");
146         }
147
148         _authenticator = authenticator;
149         _uri = info.getURI();
150         _info = info;
151         int port = info.getPort();
152         try {
153             InetAddress JavaDoc host = null;
154             if (!info.getBindAll()) {
155                 host = info.getHostAddress();
156             }
157             int backlog = info.getConnectionRequestQueueSize();
158             _socket = createServerSocket(port, backlog, host);
159         } catch (IOException JavaDoc exception) {
160             throw new ResourceException(
161                     "Failed to create server socket for URI=" + info.getURI(),
162                     exception);
163         }
164
165         _group = new ThreadGroup JavaDoc(_uri.toString());
166         StringBuffer JavaDoc name = new StringBuffer JavaDoc();
167         name.append(_uri.toString());
168         name.append("[server]");
169         _pool = new ThreadPool(_group, name.toString(), info.getMaxThreads());
170     }
171
172     /**
173      * Start accepting connections.
174      *
175      * @param listener the listener to delegate accepted connections to
176      * @throws ResourceException if connections cannot be accepted
177      */

178     public synchronized void accept(ManagedConnectionAcceptorListener listener)
179             throws ResourceException {
180         if (_dispatcher != null) {
181             throw new ResourceException(
182                     "Acceptor is already accepting connections on URI=" + _uri);
183         }
184
185         _dispatcher = new Dispatcher(listener);
186         _dispatcher.start();
187         if (_log.isDebugEnabled()) {
188             _log.debug("Acceptor accepting requests at URI=" + _uri);
189         }
190     }
191
192     /**
193      * Returns the connection request info used to construct this.
194      *
195      * @return the connection request info
196      */

197     public SocketRequestInfo getRequestInfo() {
198         return _info;
199     }
200
201     /**
202      * Returns the URI that this acceptor is accepting connections on.
203      *
204      * @return the URI that this acceptor is accepting connections on
205      */

206     public URI getURI() {
207         return _uri;
208     }
209
210     /**
211      * Stop accepting connection requests, and clean up any allocated
212      * resources.
213      *
214      * @throws ResourceException generic exception if the operation fails
215      */

216     public synchronized void close() throws ResourceException {
217         if (_log.isDebugEnabled()) {
218             _log.debug("Acceptor shutting down at URI=" + _uri);
219         }
220         _pool.shutdownNow();
221         if (_dispatcher != null) {
222             // dispatcher responsible for closing socket
223
_dispatcher.close();
224             if (Thread.currentThread() != _dispatcher) {
225                 try {
226                     _dispatcher.join(); // wait for the dispatcher to terminate
227
} catch (InterruptedException JavaDoc ignore) {
228                     // don't care.
229
}
230             }
231             _dispatcher = null;
232             _socket = null;
233         } else if (_socket != null) {
234             try {
235                 _socket.close();
236                 _socket = null;
237             } catch (IOException JavaDoc exception) {
238                 throw new ResourceException("Failed to close socket",
239                                             exception);
240             }
241         }
242     }
243
244     /**
245      * Create a new server socket.
246      *
247      * @param port the port to listen on
248      * @param backlog the listen backlog
249      * @param host if non-null, specifies to only accept connections to the
250      * specified address. If null, accept connections on any/all
251      * local addresses.
252      * @return a new server socket, listening on <code>port</code>
253      * @throws IOException if the socket can't be created
254      */

255     protected ServerSocket JavaDoc createServerSocket(int port, int backlog,
256                                               InetAddress JavaDoc host)
257             throws IOException JavaDoc {
258         return new ServerSocket JavaDoc(port, backlog, host);
259     }
260
261     /**
262      * Create a new server-side <code>ManagedConnection</code> for an accepted
263      * socket connection.
264      *
265      * @param uri the URI denoting this acceptor
266      * @param socket the accepted socket connection
267      * @param authenticator the connection authenticator
268      * @param pool the thread pool for handling invocation requests
269      * @return a new server-side managed connection
270      * @throws ResourceException if the managed connection can't be created
271      */

272     protected abstract ManagedConnection createManagedConnection(
273             URI uri, Socket JavaDoc socket, Authenticator authenticator,
274             PooledExecutor pool)
275             throws ResourceException;
276
277     /**
278      * Accepts connections.
279      */

280     private class Dispatcher extends Thread JavaDoc {
281
282         /**
283          * The listener to delegate accepted connections to.
284          */

285         private final ManagedConnectionAcceptorListener _listener;
286
287         /**
288          * Determines if the dispatcher is closed.
289          */

290         private volatile boolean _closed = false;
291
292         /**
293          * Construct a new <code>Dispatcher</code>.
294          *
295          * @param listener the listener to delegate accepted connections to
296          */

297         public Dispatcher(ManagedConnectionAcceptorListener listener) {
298             super(_group, getURI() + "[acceptor]");
299             _listener = listener;
300         }
301
302         /**
303          * Close the dispatcher.
304          */

305         public void close() {
306             _closed = true;
307             try {
308                 _socket.close();
309             } catch (IOException JavaDoc exception) {
310                 _log.debug(exception);
311             }
312         }
313
314         /**
315          * Accept connections.
316          */

317         public void run() {
318             while (!_closed) {
319                 try {
320                     Socket JavaDoc socket = _socket.accept();
321                     ManagedConnection connection = createManagedConnection(
322                             _uri, socket, _authenticator, _pool);
323                     _listener.accepted(SocketManagedConnectionAcceptor.this,
324                                        connection);
325                 } catch (Exception JavaDoc exception) {
326                     if (!_closed) {
327                         _listener.error(SocketManagedConnectionAcceptor.this,
328                                         exception);
329                     }
330                     break;
331                 }
332             }
333         }
334     }
335 }
336
Popular Tags