KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > core > StandardHostValve


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18
19 package org.apache.catalina.core;
20
21
22 import java.io.IOException JavaDoc;
23
24 import javax.servlet.RequestDispatcher JavaDoc;
25 import javax.servlet.ServletContext JavaDoc;
26 import javax.servlet.ServletException JavaDoc;
27 import javax.servlet.http.HttpServletResponse JavaDoc;
28
29 import org.apache.catalina.CometEvent;
30 import org.apache.catalina.Context;
31 import org.apache.catalina.Globals;
32 import org.apache.catalina.Wrapper;
33 import org.apache.catalina.connector.ClientAbortException;
34 import org.apache.catalina.connector.Request;
35 import org.apache.catalina.connector.Response;
36 import org.apache.catalina.deploy.ErrorPage;
37 import org.apache.catalina.util.RequestUtil;
38 import org.apache.catalina.util.StringManager;
39 import org.apache.catalina.valves.ValveBase;
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42
43
44 /**
45  * Valve that implements the default basic behavior for the
46  * <code>StandardHost</code> container implementation.
47  * <p>
48  * <b>USAGE CONSTRAINT</b>: This implementation is likely to be useful only
49  * when processing HTTP requests.
50  *
51  * @author Craig R. McClanahan
52  * @author Remy Maucherat
53  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
54  */

55
56 final class StandardHostValve
57     extends ValveBase {
58
59
60     private static Log log = LogFactory.getLog(StandardHostValve.class);
61
62     // ----------------------------------------------------- Instance Variables
63

64
65     /**
66      * The descriptive information related to this implementation.
67      */

68     private static final String JavaDoc info =
69         "org.apache.catalina.core.StandardHostValve/1.0";
70
71
72     /**
73      * The string manager for this package.
74      */

75     private static final StringManager sm =
76         StringManager.getManager(Constants.Package);
77
78
79     // ------------------------------------------------------------- Properties
80

81
82     /**
83      * Return descriptive information about this Valve implementation.
84      */

85     public String JavaDoc getInfo() {
86
87         return (info);
88
89     }
90
91
92     // --------------------------------------------------------- Public Methods
93

94
95     /**
96      * Select the appropriate child Context to process this request,
97      * based on the specified request URI. If no matching Context can
98      * be found, return an appropriate HTTP error.
99      *
100      * @param request Request to be processed
101      * @param response Response to be produced
102      * @param valveContext Valve context used to forward to the next Valve
103      *
104      * @exception IOException if an input/output error occurred
105      * @exception ServletException if a servlet error occurred
106      */

107     public final void invoke(Request request, Response JavaDoc response)
108         throws IOException JavaDoc, ServletException JavaDoc {
109
110         // Select the Context to be used for this Request
111
Context JavaDoc context = request.getContext();
112         if (context == null) {
113             response.sendError
114                 (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
115                  sm.getString("standardHost.noContext"));
116             return;
117         }
118
119         // Bind the context CL to the current thread
120
if( context.getLoader() != null ) {
121             // Not started - it should check for availability first
122
// This should eventually move to Engine, it's generic.
123
Thread.currentThread().setContextClassLoader
124                     (context.getLoader().getClassLoader());
125         }
126
127         // Ask this Context to process this request
128
context.getPipeline().getFirst().invoke(request, response);
129
130         // Access a session (if present) to update last accessed time, based on a
131
// strict interpretation of the specification
132
if (Globals.STRICT_SERVLET_COMPLIANCE) {
133             request.getSession(false);
134         }
135
136         // Error page processing
137
response.setSuspended(false);
138
139         Throwable JavaDoc t = (Throwable JavaDoc) request.getAttribute(Globals.EXCEPTION_ATTR);
140
141         if (t != null) {
142             throwable(request, response, t);
143         } else {
144             status(request, response);
145         }
146
147         // Restore the context classloader
148
Thread.currentThread().setContextClassLoader
149             (StandardHostValve.class.getClassLoader());
150
151     }
152
153
154     /**
155      * Process Comet event.
156      *
157      * @param request Request to be processed
158      * @param response Response to be produced
159      * @param valveContext Valve context used to forward to the next Valve
160      *
161      * @exception IOException if an input/output error occurred
162      * @exception ServletException if a servlet error occurred
163      */

164     public final void event(Request request, Response JavaDoc response, CometEvent event)
165         throws IOException JavaDoc, ServletException JavaDoc {
166
167         // Select the Context to be used for this Request
168
Context JavaDoc context = request.getContext();
169
170         // Bind the context CL to the current thread
171
if( context.getLoader() != null ) {
172             // Not started - it should check for availability first
173
// This should eventually move to Engine, it's generic.
174
Thread.currentThread().setContextClassLoader
175                     (context.getLoader().getClassLoader());
176         }
177
178         // Ask this Context to process this request
179
context.getPipeline().getFirst().event(request, response, event);
180
181         // Access a session (if present) to update last accessed time, based on a
182
// strict interpretation of the specification
183
if (Globals.STRICT_SERVLET_COMPLIANCE) {
184             request.getSession(false);
185         }
186
187         // Error page processing
188
response.setSuspended(false);
189
190         Throwable JavaDoc t = (Throwable JavaDoc) request.getAttribute(Globals.EXCEPTION_ATTR);
191
192         if (t != null) {
193             throwable(request, response, t);
194         } else {
195             status(request, response);
196         }
197
198         // Restore the context classloader
199
Thread.currentThread().setContextClassLoader
200             (StandardHostValve.class.getClassLoader());
201
202     }
203
204
205     // ------------------------------------------------------ Protected Methods
206

207
208     /**
209      * Handle the specified Throwable encountered while processing
210      * the specified Request to produce the specified Response. Any
211      * exceptions that occur during generation of the exception report are
212      * logged and swallowed.
213      *
214      * @param request The request being processed
215      * @param response The response being generated
216      * @param throwable The exception that occurred (which possibly wraps
217      * a root cause exception
218      */

219     protected void throwable(Request request, Response JavaDoc response,
220                              Throwable JavaDoc throwable) {
221         Context JavaDoc context = request.getContext();
222         if (context == null)
223             return;
224
225         Throwable JavaDoc realError = throwable;
226
227         if (realError instanceof ServletException JavaDoc) {
228             realError = ((ServletException JavaDoc) realError).getRootCause();
229             if (realError == null) {
230                 realError = throwable;
231             }
232         }
233
234         // If this is an aborted request from a client just log it and return
235
if (realError instanceof ClientAbortException ) {
236             if (log.isDebugEnabled()) {
237                 log.debug
238                     (sm.getString("standardHost.clientAbort",
239                         realError.getCause().getMessage()));
240             }
241             return;
242         }
243
244         ErrorPage errorPage = findErrorPage(context, throwable);
245         if ((errorPage == null) && (realError != throwable)) {
246             errorPage = findErrorPage(context, realError);
247         }
248
249         if (errorPage != null) {
250             response.setAppCommitted(false);
251             request.setAttribute
252                 (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
253                  errorPage.getLocation());
254             request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
255                               new Integer JavaDoc(ApplicationFilterFactory.ERROR));
256             request.setAttribute
257                 (Globals.STATUS_CODE_ATTR,
258                  new Integer JavaDoc(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
259             request.setAttribute(Globals.ERROR_MESSAGE_ATTR,
260                               throwable.getMessage());
261             request.setAttribute(Globals.EXCEPTION_ATTR,
262                               realError);
263             Wrapper wrapper = request.getWrapper();
264             if (wrapper != null)
265                 request.setAttribute(Globals.SERVLET_NAME_ATTR,
266                                   wrapper.getName());
267             request.setAttribute(Globals.EXCEPTION_PAGE_ATTR,
268                                  request.getRequestURI());
269             request.setAttribute(Globals.EXCEPTION_TYPE_ATTR,
270                               realError.getClass());
271             if (custom(request, response, errorPage)) {
272                 try {
273                     response.flushBuffer();
274                 } catch (IOException JavaDoc e) {
275                     container.getLogger().warn("Exception Processing " + errorPage, e);
276                 }
277             }
278         } else {
279             // A custom error-page has not been defined for the exception
280
// that was thrown during request processing. Check if an
281
// error-page for error code 500 was specified and if so,
282
// send that page back as the response.
283
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
284             // The response is an error
285
response.setError();
286
287             status(request, response);
288         }
289
290
291     }
292
293
294     /**
295      * Handle the HTTP status code (and corresponding message) generated
296      * while processing the specified Request to produce the specified
297      * Response. Any exceptions that occur during generation of the error
298      * report are logged and swallowed.
299      *
300      * @param request The request being processed
301      * @param response The response being generated
302      */

303     protected void status(Request request, Response JavaDoc response) {
304
305         int statusCode = response.getStatus();
306
307         // Handle a custom error page for this status code
308
Context JavaDoc context = request.getContext();
309         if (context == null)
310             return;
311
312         /* Only look for error pages when isError() is set.
313          * isError() is set when response.sendError() is invoked. This
314          * allows custom error pages without relying on default from
315          * web.xml.
316          */

317         if (!response.isError())
318             return;
319
320         ErrorPage errorPage = context.findErrorPage(statusCode);
321         if (errorPage != null) {
322             response.setAppCommitted(false);
323             request.setAttribute(Globals.STATUS_CODE_ATTR,
324                               new Integer JavaDoc(statusCode));
325
326             String JavaDoc message = RequestUtil.filter(response.getMessage());
327             if (message == null)
328                 message = "";
329             request.setAttribute(Globals.ERROR_MESSAGE_ATTR, message);
330             request.setAttribute
331                 (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
332                  errorPage.getLocation());
333             request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
334                               new Integer JavaDoc(ApplicationFilterFactory.ERROR));
335
336
337             Wrapper wrapper = request.getWrapper();
338             if (wrapper != null)
339                 request.setAttribute(Globals.SERVLET_NAME_ATTR,
340                                   wrapper.getName());
341             request.setAttribute(Globals.EXCEPTION_PAGE_ATTR,
342                                  request.getRequestURI());
343             if (custom(request, response, errorPage)) {
344                 try {
345                     response.flushBuffer();
346                 } catch (IOException JavaDoc e) {
347                     container.getLogger().warn("Exception Processing " + errorPage, e);
348                 }
349             }
350         }
351
352     }
353
354
355     /**
356      * Find and return the ErrorPage instance for the specified exception's
357      * class, or an ErrorPage instance for the closest superclass for which
358      * there is such a definition. If no associated ErrorPage instance is
359      * found, return <code>null</code>.
360      *
361      * @param context The Context in which to search
362      * @param exception The exception for which to find an ErrorPage
363      */

364     protected static ErrorPage findErrorPage
365         (Context JavaDoc context, Throwable JavaDoc exception) {
366
367         if (exception == null)
368             return (null);
369         Class JavaDoc clazz = exception.getClass();
370         String JavaDoc name = clazz.getName();
371         while (!Object JavaDoc.class.equals(clazz)) {
372             ErrorPage errorPage = context.findErrorPage(name);
373             if (errorPage != null)
374                 return (errorPage);
375             clazz = clazz.getSuperclass();
376             if (clazz == null)
377                 break;
378             name = clazz.getName();
379         }
380         return (null);
381
382     }
383
384
385     /**
386      * Handle an HTTP status code or Java exception by forwarding control
387      * to the location included in the specified errorPage object. It is
388      * assumed that the caller has already recorded any request attributes
389      * that are to be forwarded to this page. Return <code>true</code> if
390      * we successfully utilized the specified error page location, or
391      * <code>false</code> if the default error report should be rendered.
392      *
393      * @param request The request being processed
394      * @param response The response being generated
395      * @param errorPage The errorPage directive we are obeying
396      */

397     protected boolean custom(Request request, Response JavaDoc response,
398                              ErrorPage errorPage) {
399
400         if (container.getLogger().isDebugEnabled())
401             container.getLogger().debug("Processing " + errorPage);
402
403         request.setPathInfo(errorPage.getLocation());
404
405         try {
406
407             // Reset the response if possible (else IllegalStateException)
408
//hres.reset();
409
// Reset the response (keeping the real error code and message)
410
Integer JavaDoc statusCodeObj =
411                 (Integer JavaDoc) request.getAttribute(Globals.STATUS_CODE_ATTR);
412             int statusCode = statusCodeObj.intValue();
413             String JavaDoc message =
414                 (String JavaDoc) request.getAttribute(Globals.ERROR_MESSAGE_ATTR);
415             response.reset(statusCode, message);
416
417             // Forward control to the specified location
418
ServletContext JavaDoc servletContext =
419                 request.getContext().getServletContext();
420             RequestDispatcher JavaDoc rd =
421                 servletContext.getRequestDispatcher(errorPage.getLocation());
422             rd.forward(request.getRequest(), response.getResponse());
423
424             // If we forward, the response is suspended again
425
response.setSuspended(false);
426
427             // Indicate that we have successfully processed this custom page
428
return (true);
429
430         } catch (Throwable JavaDoc t) {
431
432             // Report our failure to process this custom page
433
container.getLogger().error("Exception Processing " + errorPage, t);
434             return (false);
435
436         }
437
438     }
439
440
441 }
442
Popular Tags