1 /*
2 * $Id: FacesServlet.java,v 1.38 2008/01/25 16:36:32 edburns Exp $
3 */
4
5 /*
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
7 *
8 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
9 *
10 * The contents of this file are subject to the terms of either the GNU
11 * General Public License Version 2 only ("GPL") or the Common Development
12 * and Distribution License("CDDL") (collectively, the "License"). You
13 * may not use this file except in compliance with the License. You can obtain
14 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
15 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
16 * language governing permissions and limitations under the License.
17 *
18 * When distributing the software, include this License Header Notice in each
19 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
20 * Sun designates this particular file as subject to the "Classpath" exception
21 * as provided by Sun in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the License
23 * Header, with the fields enclosed by brackets [] replaced by your own
24 * identifying information: "Portions Copyrighted [year]
25 * [name of copyright owner]"
26 *
27 * Contributor(s):
28 *
29 * If you wish your version of this file to be governed by only the CDDL or
30 * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 * elects to include this software in this distribution under the [CDDL or GPL
32 * Version 2] license." If you don't indicate a single choice of license, a
33 * recipient has the option to distribute your version of this file under
34 * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 * its licensees as provided above. However, if you add GPL Version 2 code
36 * and therefore, elected the GPL Version 2 license, then the option applies
37 * only if the new code is made subject to such option by the copyright
38 * holder.
39 */
40
41 package javax.faces.webapp;
42
43
44 import java.io.IOException;
45 import java.util.ResourceBundle;
46 import java.util.logging.Level;
47 import java.util.logging.Logger;
48
49 import javax.faces.FacesException;
50 import javax.faces.FactoryFinder;
51 import javax.faces.application.ResourceHandler;
52 import javax.faces.context.FacesContext;
53 import javax.faces.context.FacesContextFactory;
54 import javax.faces.lifecycle.Lifecycle;
55 import javax.faces.lifecycle.LifecycleFactory;
56 import javax.servlet.Servlet;
57 import javax.servlet.ServletConfig;
58 import javax.servlet.ServletException;
59 import javax.servlet.ServletRequest;
60 import javax.servlet.ServletResponse;
61 import javax.servlet.UnavailableException;
62 import javax.servlet.http.HttpServletRequest;
63 import javax.servlet.http.HttpServletResponse;
64
65
66 /**
67 * <p><strong class="changed_modified_2_0">FacesServlet</strong> is a
68 * servlet that manages the request processing lifecycle for web
69 * applications that are utilizing JavaServer Faces to construct the
70 * user interface.</p>
71 */
72
73 public final class FacesServlet implements Servlet {
74
75
76 /**
77 * <p>Context initialization parameter name for a comma delimited list
78 * of context-relative resource paths (in addition to
79 * <code>/WEB-INF/faces-config.xml</code> which is loaded automatically
80 * if it exists) containing JavaServer Faces configuration information.</p>
81 */
82 public static final String CONFIG_FILES_ATTR =
83 "javax.faces.CONFIG_FILES";
84
85
86 /**
87 * <p>Context initialization parameter name for the lifecycle identifier
88 * of the {@link Lifecycle} instance to be utilized.</p>
89 */
90 public static final String LIFECYCLE_ID_ATTR =
91 "javax.faces.LIFECYCLE_ID";
92
93
94 /**
95 * The <code>Logger</code> for this class.
96 */
97 private static final Logger LOGGER =
98 Logger.getLogger("javax.faces.webapp", "javax.faces.LogStrings");
99
100
101 /**
102 * <p>Factory for {@link FacesContext} instances.</p>
103 */
104 private FacesContextFactory facesContextFactory = null;
105
106
107 /**
108 * <p>The {@link Lifecycle} instance to use for request processing.</p>
109 */
110 private Lifecycle lifecycle = null;
111
112
113 /**
114 * <p>The <code>ServletConfig</code> instance for this servlet.</p>
115 */
116 private ServletConfig servletConfig = null;
117
118
119 /**
120 * <p>Release all resources acquired at startup time.</p>
121 */
122 public void destroy() {
123
124 facesContextFactory = null;
125 lifecycle = null;
126 servletConfig = null;
127
128 }
129
130
131 /**
132 * <p>Return the <code>ServletConfig</code> instance for this servlet.</p>
133 */
134 public ServletConfig getServletConfig() {
135
136 return (this.servletConfig);
137
138 }
139
140
141 /**
142 * <p>Return information about this Servlet.</p>
143 */
144 public String getServletInfo() {
145
146 return (this.getClass().getName());
147
148 }
149
150
151 /**
152 * <p>Acquire the factory instances we will require.</p>
153 *
154 * @throws ServletException if, for any reason, the startup of
155 * this Faces application failed. This includes errors in the
156 * config file that is parsed before or during the processing of
157 * this <code>init()</code> method.
158 */
159 public void init(ServletConfig servletConfig) throws ServletException {
160
161 // Save our ServletConfig instance
162 this.servletConfig = servletConfig;
163
164 // Acquire our FacesContextFactory instance
165 try {
166 facesContextFactory = (FacesContextFactory)
167 FactoryFinder.getFactory
168 (FactoryFinder.FACES_CONTEXT_FACTORY);
169 } catch (FacesException e) {
170 ResourceBundle rb = LOGGER.getResourceBundle();
171 String msg = rb.getString("severe.webapp.facesservlet.init_failed");
172 Throwable rootCause = (e.getCause() != null) ? e.getCause() : e;
173 LOGGER.log(Level.SEVERE, msg, rootCause);
174 throw new UnavailableException(msg);
175 }
176
177 // Acquire our Lifecycle instance
178 try {
179 LifecycleFactory lifecycleFactory = (LifecycleFactory)
180 FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
181 String lifecycleId ;
182
183 // First look in the servlet init-param set
184 if (null == (lifecycleId = servletConfig.getInitParameter(LIFECYCLE_ID_ATTR))) {
185 // If not found, look in the context-param set
186 lifecycleId = servletConfig.getServletContext().getInitParameter
187 (LIFECYCLE_ID_ATTR);
188 }
189
190 if (lifecycleId == null) {
191 lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
192 }
193 lifecycle = lifecycleFactory.getLifecycle(lifecycleId);
194 } catch (FacesException e) {
195 Throwable rootCause = e.getCause();
196 if (rootCause == null) {
197 throw e;
198 } else {
199 throw new ServletException(e.getMessage(), rootCause);
200 }
201 }
202
203 }
204
205
206 /**
207 * <p class="changed_modified_2_0">Process an incoming request, and create the
208 * corresponding response according to the following
209 * specification.</p>
210 *
211 * <div class="changed_modified_2_0">
212 *
213 * <p>If the <code>request</code> and <code>response</code>
214 * arguments to this method are not instances of
215 * <code>HttpServletRequest</code> and
216 * <code>HttpServletResponse</code>, respectively, the results of
217 * invoking this method are undefined.</p>
218 *
219 * <p>This method must respond to requests that start with the
220 * following strings by invoking the <code>sendError</code> method
221 * on the response argument (cast to
222 * <code>HttpServletResponse</code>), passing the code
223 * <code>HttpServletResponse.SC_NOT_FOUND</code> as the
224 * argument. </p>
225 *
226 * <ul>
227 *
228 <pre><code>
229 /WEB-INF/
230 /WEB-INF
231 /META-INF/
232 /META-INF
233 </code></pre>
234 *
235 * </ul>
236 *
237
238 * <p>If none of the cases described above in the specification for
239 * this method apply to the servicing of this request, the following
240 * action must be taken to service the request.</p>
241
242 * <p>Acquire a {@link FacesContext} instance for this request.</p>
243
244 * <p>Acquire the <code>ResourceHandler</code> for this request by
245 * calling {@link
246 * javax.faces.application.Application#getResourceHandler}. Call
247 * {@link
248 * javax.faces.application.ResourceHandler#isResourceRequest}. If
249 * this returns <code>true</code> call {@link
250 * javax.faces.application.ResourceHandler#handleResourceRequest}.
251 * If this returns <code>false</code>, call {@link
252 * javax.faces.lifecycle.Lifecycle#execute} followed by {@link
253 * javax.faces.lifecycle.Lifecycle#render}. If a {@link
254 * javax.faces.FacesException} is thrown in either case, extract the
255 * cause from the <code>FacesException</code>. If the cause is
256 * <code>null</code> extract the message from the
257 * <code>FacesException</code>, put it inside of a new
258 * <code>ServletException</code> instance, and pass the
259 * <code>FacesException</code> instance as the root cause, then
260 * rethrow the <code>ServletException</code> instance. If the cause
261 * is an instance of <code>ServletException</code>, rethrow the
262 * cause. If the cause is an instance of <code>IOException</code>,
263 * rethrow the cause. Otherwise, create a new
264 * <code>ServletException</code> instance, passing the message from
265 * the cause, as the first argument, and the cause itself as the
266 * second argument.</p>
267
268 * In a finally block, {@link
269 * javax.faces.context.FacesContext#release} must be called.
270
271 * </div>
272 *
273 * @param request The servlet request we are processing
274 * @param response The servlet response we are creating
275 *
276 * @throws IOException if an input/output error occurs during processing
277 * @throws ServletException if a servlet error occurs during processing
278
279 */
280 public void service(ServletRequest request,
281 ServletResponse response)
282 throws IOException, ServletException {
283
284 // If prefix mapped, then ensure requests for /WEB-INF are
285 // not processed.
286 String pathInfo = ((HttpServletRequest) request).getPathInfo();
287 if (pathInfo != null) {
288 pathInfo = pathInfo.toUpperCase();
289 if (pathInfo.startsWith("/WEB-INF/")
290 || pathInfo.equals("/WEB-INF")
291 || pathInfo.startsWith("/META-INF/")
292 || pathInfo.equals("/META-INF")) {
293 ((HttpServletResponse) response).
294 sendError(HttpServletResponse.SC_NOT_FOUND);
295 return;
296 }
297 }
298
299 // Acquire the FacesContext instance for this request
300 FacesContext context = facesContextFactory.getFacesContext
301 (servletConfig.getServletContext(), request, response, lifecycle);
302
303 // Execute the request processing lifecycle for this request
304 try {
305 ResourceHandler handler =
306 context.getApplication().getResourceHandler();
307 if (handler.isResourceRequest(context)) {
308 handler.handleResourceRequest(context);
309 } else {
310 lifecycle.execute(context);
311 lifecycle.render(context);
312 }
313 } catch (FacesException e) {
314 Throwable t = e.getCause();
315 if (t == null) {
316 throw new ServletException(e.getMessage(), e);
317 } else {
318 if (t instanceof ServletException) {
319 throw ((ServletException) t);
320 } else if (t instanceof IOException) {
321 throw ((IOException) t);
322 } else {
323 throw new ServletException(t.getMessage(), t);
324 }
325 }
326 }
327 finally {
328 // Release the FacesContext instance for this request
329 context.release();
330 }
331 }
332
333 }