1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package javax.faces.webapp;
20
21 import java.io.IOException;
22 import java.util.logging.Level;
23 import java.util.logging.Logger;
24
25 import javax.faces.FacesException;
26 import javax.faces.FactoryFinder;
27 import javax.faces.application.ResourceHandler;
28 import javax.faces.context.FacesContext;
29 import javax.faces.context.FacesContextFactory;
30 import javax.faces.lifecycle.Lifecycle;
31 import javax.faces.lifecycle.LifecycleFactory;
32 import javax.servlet.Servlet;
33 import javax.servlet.ServletConfig;
34 import javax.servlet.ServletException;
35 import javax.servlet.ServletRequest;
36 import javax.servlet.ServletResponse;
37 import javax.servlet.http.HttpServletRequest;
38 import javax.servlet.http.HttpServletResponse;
39
40 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
41 /**
42 * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
43 *
44 * @author Manfred Geiler (latest modification by $Author: struberg $)
45 * @version $Revision: 1188235 $ $Date: 2011-10-24 12:09:33 -0500 (Mon, 24 Oct 2011) $
46 */
47 public final class FacesServlet implements Servlet
48 {
49 //private static final Log log = LogFactory.getLog(FacesServlet.class);
50 private static final Logger log = Logger.getLogger(FacesServlet.class.getName());
51
52 /**
53 * Comma separated list of URIs of (additional) faces config files.
54 * (e.g. /WEB-INF/my-config.xml)See JSF 1.0 PRD2, 10.3.2
55 * Attention: You do not need to put /WEB-INF/faces-config.xml in here.
56 */
57 @JSFWebConfigParam(since="1.1")
58 public static final String CONFIG_FILES_ATTR = "javax.faces.CONFIG_FILES";
59
60 /**
61 * Identify the Lifecycle instance to be used.
62 */
63 @JSFWebConfigParam(since="1.1")
64 public static final String LIFECYCLE_ID_ATTR = "javax.faces.LIFECYCLE_ID";
65
66 private static final String SERVLET_INFO = "FacesServlet of the MyFaces API implementation";
67
68 private ServletConfig _servletConfig;
69 private FacesContextFactory _facesContextFactory;
70 private Lifecycle _lifecycle;
71
72 public FacesServlet()
73 {
74 super();
75 }
76
77 public void destroy()
78 {
79 _servletConfig = null;
80 _facesContextFactory = null;
81 _lifecycle = null;
82 if (log.isLoggable(Level.FINEST))
83 {
84 log.finest("destroy");
85 }
86 }
87
88 public ServletConfig getServletConfig()
89 {
90 return _servletConfig;
91 }
92
93 public String getServletInfo()
94 {
95 return SERVLET_INFO;
96 }
97
98 private String getLifecycleId()
99 {
100 // 1. check for Servlet's init-param
101 // 2. check for global context parameter
102 // 3. use default Lifecycle Id, if none of them was provided
103 String serLifecycleId = _servletConfig.getInitParameter(LIFECYCLE_ID_ATTR);
104 String appLifecycleId = _servletConfig.getServletContext().getInitParameter(LIFECYCLE_ID_ATTR);
105 appLifecycleId = serLifecycleId == null ? appLifecycleId : serLifecycleId;
106 return appLifecycleId != null ? appLifecycleId : LifecycleFactory.DEFAULT_LIFECYCLE;
107 }
108
109 public void init(ServletConfig servletConfig) throws ServletException
110 {
111 if (log.isLoggable(Level.FINEST))
112 {
113 log.finest("init begin");
114 }
115 _servletConfig = servletConfig;
116 _facesContextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
117 // TODO: null-check for Weblogic, that tries to initialize Servlet before ContextListener
118
119 // Javadoc says: Lifecycle instance is shared across multiple simultaneous requests, it must be implemented in a
120 // thread-safe manner.
121 // So we can acquire it here once:
122 LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
123 _lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
124 if (log.isLoggable(Level.FINEST))
125 {
126 log.finest("init end");
127 }
128 }
129
130 public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException
131 {
132 // If the request and response arguments to this method are not instances of HttpServletRequest and
133 // HttpServletResponse, respectively, the results of invoking this method are undefined.
134 // In this case ClassCastException
135 HttpServletRequest httpRequest = (HttpServletRequest)request;
136 String pathInfo = httpRequest.getPathInfo();
137
138 // if it is a prefix mapping ...
139
140 /*
141 * This method must respond to requests that start with the following strings by invoking the sendError
142 * method on the response argument (cast to HttpServletResponse), passing the code
143 * HttpServletResponse.SC_NOT_FOUND as the argument.
144 *
145 * /WEB-INF/
146 * /WEB-INF
147 * /META-INF/
148 * /META-INF
149 */
150 if (pathInfo != null && (pathInfo.startsWith("/WEB-INF") || pathInfo.startsWith("/META-INF")))
151 {
152 StringBuffer buffer = new StringBuffer();
153
154 buffer.append(" Someone is trying to access a secure resource : ").append(pathInfo);
155 buffer.append("\n remote address is ").append(httpRequest.getRemoteAddr());
156 buffer.append("\n remote host is ").append(httpRequest.getRemoteHost());
157 buffer.append("\n remote user is ").append(httpRequest.getRemoteUser());
158 buffer.append("\n request URI is ").append(httpRequest.getRequestURI());
159
160 log.warning(buffer.toString());
161
162 // Why does RI return a 404 and not a 403, SC_FORBIDDEN ?
163
164 ((HttpServletResponse)response).sendError(HttpServletResponse.SC_NOT_FOUND);
165 return;
166 }
167
168 // If none of the cases described above in the specification for this method apply to the servicing of this
169 // request, the following action must be taken to service the request:
170 if (log.isLoggable(Level.FINEST))
171 {
172 log.finest("service begin");
173 }
174
175 // Acquire a FacesContext instance for this request.
176 FacesContext facesContext = prepareFacesContext(request, response);
177
178 try
179 {
180 // jsf 2.0 : get the current ResourceHandler and
181 // check if it is a resource request, if true
182 // delegate to ResourceHandler, else continue with
183 // the lifecycle.
184 // Acquire the ResourceHandler for this request by calling Application.getResourceHandler().
185 ResourceHandler resourceHandler = facesContext.getApplication().getResourceHandler();
186
187 // Call ResourceHandler.isResourceRequest(javax.faces.context.FacesContext).
188 if (resourceHandler.isResourceRequest(facesContext))
189 {
190 // If this returns true call ResourceHandler.handleResourceRequest(javax.faces.context.FacesContext).
191 resourceHandler.handleResourceRequest(facesContext);
192 }
193 else
194 {
195 // If this returns false, handle as follows:
196 // call Lifecycle.execute(javax.faces.context.FacesContext)
197 _lifecycle.execute(facesContext);
198 // followed by Lifecycle.render(javax.faces.context.FacesContext).
199 _lifecycle.render(facesContext);
200 }
201 }
202 catch (FacesException e)
203 {
204 // If a FacesException is thrown in either case
205
206 // extract the cause from the FacesException
207 Throwable cause = e.getCause();
208 if (cause == null)
209 {
210 // If the cause is null extract the message from the FacesException, put it inside of a new
211 // ServletException instance, and pass the FacesException instance as the root cause, then
212 // rethrow the ServletException instance.
213 throw new ServletException(e.getLocalizedMessage(), e);
214 }
215 else if (cause instanceof ServletException)
216 {
217 // If the cause is an instance of ServletException, rethrow the cause.
218 throw (ServletException)cause;
219 }
220 else if (cause instanceof IOException)
221 {
222 // If the cause is an instance of IOException, rethrow the cause.
223 throw (IOException)cause;
224 }
225 else
226 {
227 // Otherwise, create a new ServletException instance, passing the message from the cause,
228 // as the first argument, and the cause itself as the second argument.
229 throw new ServletException(cause.getLocalizedMessage(), cause);
230 }
231 }
232 finally
233 {
234 // In a finally block, FacesContext.release() must be called.
235 facesContext.release();
236 }
237 if (log.isLoggable(Level.FINEST))
238 {
239 log.finest("service end");
240 }
241 }
242
243 private FacesContext prepareFacesContext(ServletRequest request, ServletResponse response)
244 {
245 FacesContext facesContext =
246 _facesContextFactory.getFacesContext(_servletConfig.getServletContext(), request, response, _lifecycle);
247 return facesContext;
248 }
249 }