View Javadoc

1   /*
2    * Copyright (C) The Spice Group. All rights reserved.
3    *
4    * This software is published under the terms of the Spice
5    * Software License version 1.1, a copy of which has been included
6    * with this distribution in the LICENSE.txt file.
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                      //Ignore
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 }