KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  *
21  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
22  *
23  * Portions Copyright Apache Software Foundation.
24  */

25
26
27 package org.apache.catalina.core;
28
29 import java.io.*;
30
31 import javax.servlet.*;
32 import javax.servlet.http.*;
33
34 import org.apache.catalina.Context;
35 import org.apache.catalina.Globals;
36 import org.apache.catalina.Wrapper;
37 import org.apache.catalina.connector.ClientAbortException;
38 import org.apache.catalina.connector.ResponseFacade;
39 import org.apache.catalina.deploy.ErrorPage;
40 import org.apache.catalina.util.RequestUtil;
41 import org.apache.catalina.util.ResponseUtil;
42 import org.apache.catalina.util.StringManager;
43 import org.apache.catalina.valves.ErrorReportValve;
44 import org.apache.coyote.tomcat5.CoyoteResponseFacade;
45
46 import com.sun.org.apache.commons.logging.Log;
47 import com.sun.org.apache.commons.logging.LogFactory;
48
49 /**
50  * Class responsible for processing the result of a RD.forward() invocation
51  * before committing the response.
52  *
53  * If sendError() was called during RD.forward(), an attempt is made to match
54  * the status code against the error pages of the RD's associated context, or
55  * those of the host on which the context has been deployed.
56  *
57  * The response contents are then committed, to comply with SRV.8.4
58  * ("The Forward Method"):
59  *
60  * Before the forward method of the RequestDispatcher interface returns, the
61  * response content must be sent and committed, and closed by the servlet
62  * container
63  */

64 class ApplicationDispatcherForward {
65
66     private static Log log = LogFactory.getLog(
67         ApplicationDispatcherForward.class);
68
69     private static final StringManager sm =
70         StringManager.getManager(org.apache.catalina.valves.Constants.Package);
71
72
73     static void commit(HttpServletRequest request,
74                        HttpServletResponse response,
75                        Context context,
76                        Wrapper wrapper)
77             throws IOException, ServletException {
78
79         int statusCode = getStatus(response);
80         if (statusCode >= 400
81                 && request.getAttribute(Globals.EXCEPTION_ATTR) == null) {
82             boolean matchFound = status(request, response, context, wrapper,
83                                         statusCode);
84             if (!matchFound) {
85                 serveDefaultErrorPage(request, response, statusCode);
86             }
87         }
88
89         try {
90             PrintWriter writer = response.getWriter();
91             writer.close();
92         } catch (IllegalStateException JavaDoc e) {
93             try {
94                 ServletOutputStream stream = response.getOutputStream();
95                 stream.close();
96             } catch (IllegalStateException JavaDoc f) {
97                 ;
98             } catch (IOException f) {
99                 ;
100             }
101         } catch (IOException e) {
102             ;
103         }
104     }
105
106
107     /*
108      * Searches and processes a custom error page for the given status code.
109      *
110      * This method attempts to map the given status code to an error page,
111      * using the mappings of the given context or those of the host on which
112      * the given context has been deployed.
113      *
114      * If a match is found using the context mappings, the request is forwarded
115      * to the error page. Otherwise, if a match is found using the host
116      * mappings, the contents of the error page are returned. If no match is
117      * found, no action is taken.
118      *
119      * @return true if a matching error page was found, false otherwise
120      */

121     private static boolean status(HttpServletRequest request,
122                                   HttpServletResponse response,
123                                   Context context,
124                                   Wrapper wrapper,
125                                   int statusCode) {
126
127         boolean matchFound = false;
128
129         ErrorPage errorPage = context.findErrorPage(statusCode);
130         if (errorPage != null) {
131
132             matchFound = true;
133
134             // Prevent infinite loop
135
String JavaDoc requestPath = (String JavaDoc) request.getAttribute(
136                 ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR);
137             if (requestPath == null
138                     || !requestPath.equals(errorPage.getLocation())) {
139                 String JavaDoc message = RequestUtil.filter(getMessage(response));
140                 if (message == null) {
141                     message = "";
142                 }
143                 prepareRequestForDispatch(request,
144                                           wrapper,
145                                           errorPage.getLocation(),
146                                           statusCode,
147                                           message);
148                 custom(request, response, errorPage, context);
149             }
150         } else {
151             errorPage = ((StandardHost) context.getParent()).findErrorPage(
152                                             statusCode);
153             if (errorPage != null) {
154                 matchFound = true;
155                 try {
156                     serveErrorPage(response, errorPage, statusCode);
157                 } catch (Exception JavaDoc e) {
158                     log.warn("Exception processing " + errorPage, e);
159                 }
160             }
161         }
162
163         return matchFound;
164     }
165
166
167     /**
168      * Handles an HTTP status code or exception by forwarding control
169      * to the location included in the specified errorPage object.
170      */

171     private static void custom(HttpServletRequest request,
172                                HttpServletResponse response,
173                                ErrorPage errorPage,
174                                Context context) {
175         try {
176             // Forward control to the specified error page
177
if (response.isCommitted()) {
178                 /*
179                  * If the target of the RD.forward() has called
180                  * response.sendError(), the response will have been committed,
181                  * and any attempt to RD.forward() the response to the error
182                  * page will cause an IllegalStateException.
183                  * Uncommit the response.
184                  */

185                 resetResponse(response);
186             }
187             ServletContext servletContext = context.getServletContext();
188             RequestDispatcher rd =
189                 servletContext.getRequestDispatcher(errorPage.getLocation());
190             rd.forward(request, response);
191         } catch (IllegalStateException JavaDoc ise) {
192             log.warn("Exception processing " + errorPage, ise);
193         } catch (Throwable JavaDoc t) {
194             log.warn("Exception processing " + errorPage, t);
195         }
196     }
197
198
199     /**
200      * Adds request attributes in preparation for RD.forward().
201      */

202     private static void prepareRequestForDispatch(HttpServletRequest request,
203                                                   Wrapper errorServlet,
204                                                   String JavaDoc errorPageLocation,
205                                                   int errorCode,
206                                                   String JavaDoc errorMessage) {
207         request.setAttribute(
208             ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
209             new Integer JavaDoc(ApplicationFilterFactory.ERROR));
210
211         request.setAttribute(
212             Globals.EXCEPTION_PAGE_ATTR,
213             request.getRequestURI());
214
215         if (errorServlet != null) {
216             // Save the logical name of the servlet in which the error occurred
217
request.setAttribute(Globals.SERVLET_NAME_ATTR,
218                                  errorServlet.getName());
219         }
220
221         request.setAttribute(
222             ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
223             errorPageLocation);
224
225         request.setAttribute(Globals.STATUS_CODE_ATTR, new Integer JavaDoc(errorCode));
226
227         request.setAttribute(Globals.ERROR_MESSAGE_ATTR, errorMessage);
228     }
229
230     /**
231      * Copies the contents of the given error page to the response.
232      */

233     private static void serveErrorPage(HttpServletResponse response,
234                                        ErrorPage errorPage,
235                                        int statusCode)
236             throws Exception JavaDoc {
237
238         ServletOutputStream ostream = null;
239         PrintWriter writer = null;
240         FileReader reader = null;
241         BufferedInputStream istream = null;
242         IOException ioe = null;
243
244         String JavaDoc message = errorPage.getReason();
245         if (message != null && !response.isCommitted()) {
246             response.reset();
247             response.setStatus(statusCode, message);
248         }
249          
250         try {
251             ostream = response.getOutputStream();
252         } catch (IllegalStateException JavaDoc e) {
253             // If it fails, we try to get a Writer instead if we're
254
// trying to serve a text file
255
writer = response.getWriter();
256         }
257
258         if (writer != null) {
259             reader = new FileReader(errorPage.getLocation());
260             ioe = ResponseUtil.copy(reader, writer);
261             try {
262                 reader.close();
263             } catch (Throwable JavaDoc t) {
264                 ;
265             }
266         } else {
267             istream = new BufferedInputStream(
268                 new FileInputStream(errorPage.getLocation()));
269             ioe = ResponseUtil.copy(istream, ostream);
270             try {
271                 istream.close();
272             } catch (Throwable JavaDoc t) {
273                 ;
274             }
275         }
276
277         // Rethrow any exception that may have occurred
278
if (ioe != null) {
279             throw ioe;
280         }
281     }
282
283
284     /**
285      * Renders the default error page.
286      */

287     private static void serveDefaultErrorPage(HttpServletRequest request,
288                                               HttpServletResponse response,
289                                               int statusCode)
290             throws IOException, ServletException {
291
292         // Do nothing on a 1xx, 2xx and 3xx status
293
if (response.isCommitted() || statusCode < 400) {
294             return;
295         }
296
297         String JavaDoc message = RequestUtil.filter(getMessage(response));
298         if (message == null) {
299             message = "";
300         }
301
302         // Do nothing if there is no report for the specified status code
303
String JavaDoc report = null;
304         try {
305             report = sm.getString("http." + statusCode, message);
306         } catch (Throwable JavaDoc t) {
307             ;
308         }
309         if (report == null) {
310             return;
311         }
312
313         String JavaDoc responseContents =
314             ErrorReportValve.makeErrorPage(statusCode, message, null, null,
315                                            report, response);
316         // START SJSAS 6412710
317
response.setLocale(sm.getResourceBundleLocale(response.getLocale()));
318         // END SJSAS 6412710
319

320         try {
321             response.setContentType("text/html");
322             response.getWriter().write(responseContents);
323         } catch (Throwable JavaDoc t) {
324             log.warn("Exception sending default error page", t);
325         }
326     }
327
328
329     private static int getStatus(ServletResponse response) {
330    
331         while (response instanceof ServletResponseWrapper) {
332             response = ((ServletResponseWrapper) response).getResponse();
333         }
334
335         return ((CoyoteResponseFacade) response).getStatus();
336     }
337
338
339     private static String JavaDoc getMessage(ServletResponse response) {
340    
341         while (response instanceof ServletResponseWrapper) {
342             response = ((ServletResponseWrapper) response).getResponse();
343         }
344
345         return ((CoyoteResponseFacade) response).getMessage();
346     }
347
348
349     private static void resetResponse(ServletResponse response) {
350    
351         while (response instanceof ServletResponseWrapper) {
352             response = ((ServletResponseWrapper) response).getResponse();
353         }
354
355         ((CoyoteResponseFacade) response).setSuspended(false);
356         ((CoyoteResponseFacade) response).setAppCommitted(false);
357     }
358
359 }
360
Popular Tags