KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > winstone > RequestHandlerThread


1 /*
2  * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
3  * Distributed under the terms of either:
4  * - the common development and distribution license (CDDL), v1.0; or
5  * - the GNU Lesser General Public License, v2.1 or later
6  */

7 package winstone;
8
9 import java.io.IOException JavaDoc;
10 import java.io.InputStream JavaDoc;
11 import java.io.InterruptedIOException JavaDoc;
12 import java.io.OutputStream JavaDoc;
13 import java.net.Socket JavaDoc;
14 import java.net.SocketException JavaDoc;
15
16 import javax.servlet.ServletException JavaDoc;
17 import javax.servlet.ServletRequestEvent JavaDoc;
18 import javax.servlet.ServletRequestListener JavaDoc;
19
20 /**
21  * The threads to which incoming requests get allocated.
22  *
23  * @author <a HREF="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
24  * @version $Id: RequestHandlerThread.java,v 1.20 2006/08/25 17:04:59 rickknowles Exp $
25  */

26 public class RequestHandlerThread implements Runnable JavaDoc {
27     private Thread JavaDoc thread;
28     private ObjectPool objectPool;
29     private WinstoneInputStream inData;
30     private WinstoneOutputStream outData;
31     private WinstoneRequest req;
32     private WinstoneResponse rsp;
33     private Listener listener;
34     private Socket JavaDoc socket;
35     private String JavaDoc threadName;
36     private long requestStartTime;
37     private boolean simulateModUniqueId;
38     private boolean saveSessions;
39 // private Object processingMonitor = new Boolean(true);
40

41     /**
42      * Constructor - this is called by the handler pool, and just sets up for
43      * when a real request comes along.
44      */

45     public RequestHandlerThread(ObjectPool objectPool, int threadIndex,
46             boolean simulateModUniqueId, boolean saveSessions) {
47         this.objectPool = objectPool;
48         this.simulateModUniqueId = simulateModUniqueId;
49         this.saveSessions = saveSessions;
50         this.threadName = Launcher.RESOURCES.getString(
51                 "RequestHandlerThread.ThreadName", "" + threadIndex);
52
53         // allocate a thread to run on this object
54
this.thread = new Thread JavaDoc(this, threadName);
55         this.thread.setDaemon(true);
56     }
57
58     /**
59      * The main thread execution code.
60      */

61     public void run() {
62         
63         boolean interrupted = false;
64         while (!interrupted) {
65             // Start request processing
66
InputStream JavaDoc inSocket = null;
67             OutputStream JavaDoc outSocket = null;
68             boolean iAmFirst = true;
69             try {
70                 // Get input/output streams
71
inSocket = socket.getInputStream();
72                 outSocket = socket.getOutputStream();
73
74                 // The keep alive loop - exiting from here means the connection has closed
75
boolean continueFlag = true;
76                 while (continueFlag && !interrupted) {
77                     try {
78                         long requestId = System.currentTimeMillis();
79                         this.listener.allocateRequestResponse(socket, inSocket,
80                                 outSocket, this, iAmFirst);
81                         if (this.req == null) {
82                             // Dead request - happens sometimes with ajp13 - discard
83
this.listener.deallocateRequestResponse(this, req,
84                                     rsp, inData, outData);
85                             continue;
86                         }
87                         String JavaDoc servletURI = this.listener.parseURI(this,
88                                 this.req, this.rsp, this.inData, this.socket,
89                                 iAmFirst);
90                         if (servletURI == null) {
91                             Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
92                                     "RequestHandlerThread.KeepAliveTimedOut", this.threadName);
93                             
94                             // Keep alive timed out - deallocate and go into wait state
95
this.listener.deallocateRequestResponse(this, req,
96                                     rsp, inData, outData);
97                             continueFlag = false;
98                             continue;
99                         }
100                         
101                         if (this.simulateModUniqueId) {
102                             req.setAttribute("UNIQUE_ID", "" + requestId);
103                         }
104                         long headerParseTime = getRequestProcessTime();
105                         iAmFirst = false;
106
107                         HostConfiguration hostConfig = req.getHostGroup().getHostByName(req.getServerName());
108                         Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
109                                 "RequestHandlerThread.StartRequest",
110                                 new String JavaDoc[] {"" + requestId, hostConfig.getHostname()});
111
112                         // Get the URI from the request, check for prefix, then
113
// match it to a requestDispatcher
114
WebAppConfiguration webAppConfig = hostConfig.getWebAppByURI(servletURI);
115                         if (webAppConfig == null) {
116                             webAppConfig = hostConfig.getWebAppByURI("/");
117                         }
118                         if (webAppConfig == null) {
119                             Logger.log(Logger.WARNING, Launcher.RESOURCES,
120                                     "RequestHandlerThread.UnknownWebapp",
121                                     new String JavaDoc[] { servletURI });
122                             rsp.sendError(WinstoneResponse.SC_NOT_FOUND,
123                                     Launcher.RESOURCES.getString("RequestHandlerThread.UnknownWebappPage", servletURI));
124                             rsp.flushBuffer();
125                             req.discardRequestBody();
126                             writeToAccessLog(servletURI, req, rsp, null);
127
128                             // Process keep-alive
129
continueFlag = this.listener.processKeepAlive(req, rsp, inSocket);
130                             this.listener.deallocateRequestResponse(this, req, rsp, inData, outData);
131                             Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestHandlerThread.FinishRequest",
132                                     "" + requestId);
133                             Logger.log(Logger.SPEED, Launcher.RESOURCES, "RequestHandlerThread.RequestTime",
134                                     new String JavaDoc[] { servletURI, "" + headerParseTime, "" + getRequestProcessTime() });
135                             continue;
136                         }
137                         req.setWebAppConfig(webAppConfig);
138
139                         // Now we've verified it's in the right webapp, send
140
// request in scope notify
141
ServletRequestListener JavaDoc reqLsnrs[] = webAppConfig.getRequestListeners();
142                         for (int n = 0; n < reqLsnrs.length; n++) {
143                             ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
144                             Thread.currentThread().setContextClassLoader(webAppConfig.getLoader());
145                             reqLsnrs[n].requestInitialized(new ServletRequestEvent JavaDoc(webAppConfig, req));
146                             Thread.currentThread().setContextClassLoader(cl);
147                         }
148
149                         // Lookup a dispatcher, then process with it
150
processRequest(webAppConfig, req, rsp,
151                                 webAppConfig.getServletURIFromRequestURI(servletURI));
152                         writeToAccessLog(servletURI, req, rsp, webAppConfig);
153
154                         this.outData.finishResponse();
155                         this.inData.finishRequest();
156
157                         Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
158                                 "RequestHandlerThread.FinishRequest",
159                                 "" + requestId);
160
161                         // Process keep-alive
162
continueFlag = this.listener.processKeepAlive(req, rsp, inSocket);
163
164                         // Set last accessed time on session as start of this
165
// request
166
req.markSessionsAsRequestFinished(this.requestStartTime, this.saveSessions);
167
168                         // send request listener notifies
169
for (int n = 0; n < reqLsnrs.length; n++) {
170                             ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
171                             Thread.currentThread().setContextClassLoader(webAppConfig.getLoader());
172                             reqLsnrs[n].requestDestroyed(new ServletRequestEvent JavaDoc(webAppConfig, req));
173                             Thread.currentThread().setContextClassLoader(cl);
174                         }
175
176                         req.setWebAppConfig(null);
177                         rsp.setWebAppConfig(null);
178                         req.setRequestAttributeListeners(null);
179
180                         this.listener.deallocateRequestResponse(this, req, rsp, inData, outData);
181                         Logger.log(Logger.SPEED, Launcher.RESOURCES, "RequestHandlerThread.RequestTime",
182                                 new String JavaDoc[] { servletURI, "" + headerParseTime,
183                                                 "" + getRequestProcessTime() });
184                     } catch (InterruptedIOException JavaDoc errIO) {
185                         continueFlag = false;
186                         Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
187                                 "RequestHandlerThread.SocketTimeout", errIO);
188                     } catch (SocketException JavaDoc errIO) {
189                         continueFlag = false;
190                     }
191                 }
192                 this.listener.deallocateRequestResponse(this, req, rsp, inData, outData);
193                 this.listener.releaseSocket(this.socket, inSocket, outSocket); // shut sockets
194
} catch (Throwable JavaDoc err) {
195                 try {
196                     this.listener.deallocateRequestResponse(this, req, rsp, inData, outData);
197                 } catch (Throwable JavaDoc errClose) {
198                 }
199                 try {
200                     this.listener.releaseSocket(this.socket, inSocket,
201                             outSocket); // shut sockets
202
} catch (Throwable JavaDoc errClose) {
203                 }
204                 Logger.log(Logger.ERROR, Launcher.RESOURCES,
205                         "RequestHandlerThread.RequestError", err);
206             }
207
208             this.objectPool.releaseRequestHandler(this);
209
210             if (!interrupted) {
211                 // Suspend this thread until we get assigned and woken up
212
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
213                         "RequestHandlerThread.EnterWaitState");
214                 try {
215                     synchronized (this) {
216                         this.wait();
217                     }
218                 } catch (InterruptedException JavaDoc err) {
219                     interrupted = true;
220                 }
221                 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
222                         "RequestHandlerThread.WakingUp");
223             }
224         }
225         Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestHandlerThread.ThreadExit");
226     }
227
228     /**
229      * Actually process the request. This takes the request and response, and feeds
230      * them to the desired servlet, which then processes them or throws them off to
231      * another servlet.
232      */

233     private void processRequest(WebAppConfiguration webAppConfig, WinstoneRequest req,
234             WinstoneResponse rsp, String JavaDoc path) throws IOException JavaDoc, ServletException JavaDoc {
235         RequestDispatcher rd = null;
236         javax.servlet.RequestDispatcher JavaDoc rdError = null;
237         try {
238             rd = webAppConfig.getInitialDispatcher(path, req, rsp);
239
240             // Null RD means an error or we have been redirected to a welcome page
241
if (rd != null) {
242                 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
243                         "RequestHandlerThread.HandlingRD", rd.getName());
244                 rd.forward(req, rsp);
245             }
246             // if null returned, assume we were redirected
247
} catch (Throwable JavaDoc err) {
248             Logger.log(Logger.WARNING, Launcher.RESOURCES,
249                     "RequestHandlerThread.UntrappedError", err);
250             rdError = webAppConfig.getErrorDispatcherByClass(err);
251         }
252
253         // If there was any kind of error, execute the error dispatcher here
254
if (rdError != null) {
255             try {
256                 if (rsp.isCommitted()) {
257                     rdError.include(req, rsp);
258                 } else {
259                     rsp.resetBuffer();
260                     rdError.forward(req, rsp);
261                 }
262             } catch (Throwable JavaDoc err) {
263                 Logger.log(Logger.ERROR, Launcher.RESOURCES, "RequestHandlerThread.ErrorInErrorServlet", err);
264             }
265 // rsp.sendUntrappedError(err, req, rd != null ? rd.getName() : null);
266
}
267         rsp.flushBuffer();
268         req.discardRequestBody();
269     }
270
271     /**
272      * Assign a socket to the handler
273      */

274     public void commenceRequestHandling(Socket JavaDoc socket, Listener listener) {
275         this.listener = listener;
276         this.socket = socket;
277         if (this.thread.isAlive())
278             synchronized (this) {
279                 this.notifyAll();
280             }
281         else
282             this.thread.start();
283     }
284
285     public void setRequest(WinstoneRequest request) {
286         this.req = request;
287     }
288
289     public void setResponse(WinstoneResponse response) {
290         this.rsp = response;
291     }
292
293     public void setInStream(WinstoneInputStream inStream) {
294         this.inData = inStream;
295     }
296
297     public void setOutStream(WinstoneOutputStream outStream) {
298         this.outData = outStream;
299     }
300
301     public void setRequestStartTime() {
302         this.requestStartTime = System.currentTimeMillis();
303     }
304
305     public long getRequestProcessTime() {
306         return System.currentTimeMillis() - this.requestStartTime;
307     }
308
309     /**
310      * Trigger the thread destruction for this handler
311      */

312     public void destroy() {
313         if (this.thread.isAlive()) {
314             this.thread.interrupt();
315         }
316     }
317     
318     protected void writeToAccessLog(String JavaDoc originalURL, WinstoneRequest request, WinstoneResponse response,
319             WebAppConfiguration webAppConfig) {
320         if (webAppConfig != null) {
321             // Log a row containing appropriate data
322
AccessLogger logger = webAppConfig.getAccessLogger();
323             if (logger != null) {
324                 logger.log(originalURL, request, response);
325             }
326         }
327     }
328 }
329
Popular Tags