1
2
3
4
5
6
7
8 package org.codehaus.spice.netserve.connection.handlers;
9
10 import java.io.IOException;
11 import java.net.Socket;
12 import java.util.HashSet;
13 import java.util.Set;
14 import org.codehaus.spice.netserve.connection.RequestHandler;
15
16 /***
17 * Abstract base class for request handlers.
18 *
19 * @author Peter Donald
20 * @version $Revision: 1.2 $ $Date: 2004/03/21 23:42:58 $
21 */
22 public abstract class AbstractRequestHandler
23 implements RequestHandler
24 {
25 /***
26 * The set of active requests.
27 */
28 private final Set m_activeRequests = new HashSet();
29
30 /***
31 * True if shutdown() has been called.
32 */
33 private boolean m_shutdown;
34
35 /***
36 * Handle a connection.
37 *
38 * @param socket the socket
39 */
40 public void handleConnection( Socket socket )
41 {
42 performRequest( socket );
43 }
44
45 /***
46 * @see RequestHandler#shutdown
47 */
48 public void shutdown( final long timeout )
49 {
50 markAsShutdown();
51 final Thread[] threads;
52 synchronized( this )
53 {
54 threads = (Thread[])m_activeRequests.
55 toArray( new Thread[ m_activeRequests.size() ] );
56 }
57 for( int i = 0; i < threads.length; i++ )
58 {
59 final Thread thread = threads[ i ];
60 thread.interrupt();
61 }
62 final long now = System.currentTimeMillis();
63 final long then = now + timeout;
64
65 while( System.currentTimeMillis() < then || 0 == timeout )
66 {
67 synchronized( this )
68 {
69 if( 0 == m_activeRequests.size() )
70 {
71 return;
72 }
73 try
74 {
75 wait( timeout );
76 }
77 catch( final InterruptedException ie )
78 {
79
80 }
81 }
82 }
83 }
84
85 /***
86 * Mark request handler as shutdown.
87 */
88 protected void markAsShutdown()
89 {
90 m_shutdown = true;
91 }
92
93 /***
94 * Return true if handler has been shutdown.
95 *
96 * @return true if handler has been shutdown.
97 */
98 protected boolean isShutdown()
99 {
100 return m_shutdown;
101 }
102
103 /***
104 * Perform the request for socket by delegating to
105 * underlying handler.
106 *
107 * @param socket the socket to handle
108 */
109 protected void performRequest( final Socket socket )
110 {
111 synchronized( this )
112 {
113 m_activeRequests.add( Thread.currentThread() );
114 }
115 setupThreadName( socket );
116 try
117 {
118 doPerformRequest( socket );
119 }
120 catch( final Throwable t )
121 {
122 errorHandlingConnection( socket, t );
123 }
124 finally
125 {
126 endConnection( socket );
127 synchronized( this )
128 {
129 m_activeRequests.remove( Thread.currentThread() );
130 notifyAll();
131 }
132 }
133 }
134
135 /***
136 * Method implemented to actually do the work.
137 *
138 * @param socket the socket
139 * @throws Exception if an error occurs
140 */
141 protected abstract void doPerformRequest( Socket socket )
142 throws Exception;
143
144 /***
145 * Setup the name of the thread.
146 *
147 * @param socket the socket associated with request
148 */
149 protected void setupThreadName( final Socket socket )
150 {
151 final String name = getThreadName( socket );
152 Thread.currentThread().setName( name );
153 }
154
155 /***
156 * End connection for socket.
157 *
158 * @param socket the socket
159 */
160 protected void endConnection( final Socket socket )
161 {
162 if( socket.isConnected() )
163 {
164 try
165 {
166 socket.close();
167 }
168 catch( final IOException ioe )
169 {
170 errorClosingConnection( socket, ioe );
171 }
172 }
173 }
174
175 /***
176 * Create Runnable to perform the request.
177 *
178 * @param socket the socket to handle
179 * @return thee runnable
180 */
181 protected Runnable createRunnable( final Socket socket )
182 {
183 return new Runnable()
184 {
185 public void run()
186 {
187 performRequest( socket );
188 }
189 };
190 }
191
192 /***
193 * Return the name should be set for current thread.
194 *
195 * @param socket the socket being handled in thread
196 * @return the thread name.
197 */
198 protected String getThreadName( final Socket socket )
199 {
200 if( socket.isConnected() )
201 {
202 return "RequestHandler for " +
203 socket.getInetAddress().getHostAddress() + ":" +
204 socket.getPort();
205 }
206 else
207 {
208 return "RequestHandler for " + socket;
209 }
210 }
211
212 /***
213 * Notify handler of an error handling socket.
214 *
215 * @param socket the socket
216 * @param t the error
217 */
218 protected void errorHandlingConnection( final Socket socket,
219 final Throwable t )
220 {
221 }
222
223 /***
224 * Notify handler of an error closing socket.
225 *
226 * @param socket the socket
227 * @param t the error
228 */
229 protected void errorClosingConnection( final Socket socket,
230 final Throwable t )
231 {
232 errorHandlingConnection( socket, t );
233 }
234 }