001 /*
002 * Copyright 2004 The Apache Software Foundation.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.esupportail.commons.web.servlet;
017
018 import java.io.IOException;
019 import java.util.HashMap;
020 import java.util.Map;
021
022 import javax.faces.FactoryFinder;
023 import javax.faces.application.Application;
024 import javax.faces.application.ViewHandler;
025 import javax.faces.component.UIViewRoot;
026 import javax.faces.context.FacesContext;
027 import javax.faces.context.FacesContextFactory;
028 import javax.faces.el.VariableResolver;
029 import javax.faces.lifecycle.Lifecycle;
030 import javax.faces.lifecycle.LifecycleFactory;
031 import javax.servlet.ServletConfig;
032 import javax.servlet.ServletException;
033 import javax.servlet.http.HttpServlet;
034 import javax.servlet.http.HttpServletRequest;
035 import javax.servlet.http.HttpServletResponse;
036
037 import org.esupportail.commons.dao.HibernateUtils;
038 import org.esupportail.commons.exceptions.ConfigException;
039 import org.esupportail.commons.services.application.ApplicationService;
040 import org.esupportail.commons.services.application.ApplicationUtils;
041 import org.esupportail.commons.services.application.VersionningUtils;
042 import org.esupportail.commons.services.exceptionHandling.ExceptionService;
043 import org.esupportail.commons.services.exceptionHandling.ExceptionUtils;
044 import org.esupportail.commons.services.logging.Logger;
045 import org.esupportail.commons.services.logging.LoggerImpl;
046 import org.esupportail.commons.services.urlGeneration.AbstractUrlGenerator;
047 import org.esupportail.commons.services.urlGeneration.ServletUrlGeneratorImpl;
048 import org.esupportail.commons.web.deepLinking.AbstractDeepLinkingRedirector;
049 import org.esupportail.commons.web.deepLinking.DeepLinkingRedirector;
050 import org.springframework.util.StringUtils;
051
052 /**
053 * A JSF-based servlet that catches exception and gives them to an exception service.
054 * see Javadoc of <a href="http://java.sun.com/j2ee/javaserverfaces/1.1_01/docs/api/index.html">JSF Specification</a>
055 */
056 public class FacesServlet extends HttpServlet {
057
058 /**
059 * The id for serialization.
060 */
061 private static final long serialVersionUID = 6668301918264753450L;
062
063 /**
064 * The default name of the redirector.
065 */
066 private static final String DEFAULT_REDIRECTOR_NAME = "deepLinkingRedirector";
067
068 /**
069 * The name of the servlet parameter that gives the name of the redirector.
070 */
071 private static final String REDIRECTOR_NAME_PARAM = "deep-linking-redirector";
072
073 /**
074 * The default default view.
075 */
076 private static final String DEFAULT_DEFAULT_VIEW = "/stylesheets/welcome.faces";
077
078 /**
079 * The name of the servlet parameter that gives the name of the redirector.
080 */
081 private static final String DEFAULT_VIEW_PARAM = "default-view";
082
083 /**
084 * The servlet info.
085 */
086 private static final String SERVLET_INFO = "FacesServlet";
087
088 /**
089 * A logger.
090 */
091 private final Logger logger = new LoggerImpl(getClass());
092
093 /**
094 * The context factory.
095 */
096 private FacesContextFactory facesContextFactory;
097
098 /**
099 * The lifecycle.
100 */
101 private Lifecycle lifecycle;
102
103 /**
104 * The name of the redirector.
105 */
106 private String redirectorName;
107
108 /**
109 * The default view.
110 */
111 private String defaultView;
112
113 /**
114 * Constructor.
115 */
116 public FacesServlet() {
117 super();
118 }
119
120 /**
121 * @see javax.servlet.Servlet#destroy()
122 */
123 @Override
124 public void destroy() {
125 facesContextFactory = null;
126 lifecycle = null;
127 }
128
129 /**
130 * @see javax.servlet.Servlet#getServletInfo()
131 */
132 @Override
133 public String getServletInfo() {
134 return SERVLET_INFO;
135 }
136
137 private String getLifecycleId() {
138 String lifecycleId = getServletConfig().getInitParameter(javax.faces.webapp.FacesServlet.LIFECYCLE_ID_ATTR);
139 if (lifecycleId == null) {
140 lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
141 }
142 return lifecycleId;
143 }
144
145 /**
146 * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
147 */
148 @Override
149 public void init(final ServletConfig servletConfig) throws ServletException {
150 try {
151 super.init(servletConfig);
152 facesContextFactory =
153 (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
154 LifecycleFactory lifecycleFactory =
155 (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
156 lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
157 ApplicationService applicationService = ApplicationUtils.createApplicationService();
158 logger.info("starting " + applicationService.getName() + " v"
159 + applicationService.getVersion() + "...");
160 defaultView = servletConfig.getInitParameter(DEFAULT_VIEW_PARAM);
161 if (!StringUtils.hasText(defaultView)) {
162 defaultView = DEFAULT_DEFAULT_VIEW;
163 logger.warn("property " + DEFAULT_VIEW_PARAM
164 + " is not set, using default value [" + defaultView + "]");
165 }
166 redirectorName = servletConfig.getInitParameter(REDIRECTOR_NAME_PARAM);
167 if (!StringUtils.hasText(redirectorName)) {
168 redirectorName = DEFAULT_REDIRECTOR_NAME;
169 logger.warn("property " + REDIRECTOR_NAME_PARAM
170 + " is not set, using default value [" + redirectorName + "]");
171 }
172 } catch (Exception e) {
173 ExceptionUtils.catchException(e);
174 throw new ServletException(e);
175 }
176 }
177
178 /**
179 * Check the version of the application and throw a ConfigException
180 * if the servlet can not be executed (for instance if the version
181 * of the application and the one of the database do not match).
182 * @throws ConfigException
183 */
184 protected void checkVersion() throws ConfigException {
185 // This method can be overriden by particular implementations
186 VersionningUtils.checkVersion(true, false);
187 }
188
189 /**
190 * Wrap exceptions thrown when already catching an exception.
191 */
192 private void handleExceptionHandlingException(
193 final Exception e)
194 throws ServletException, IOException {
195 logger.error(
196 "An exception was thrown while already catching a previous exception:",
197 e);
198 if (e instanceof IOException) {
199 throw (IOException) e;
200 } else if (e instanceof ServletException) {
201 throw (ServletException) e;
202 } else if (e.getMessage() != null) {
203 throw new ServletException(e.getMessage(), e);
204 } else {
205 throw new ServletException(e);
206 }
207 }
208
209 /**
210 * Catch an exception.
211 * @param exception
212 * @param request
213 * @param response
214 * @throws ServletException
215 */
216 protected void catchException(
217 final Exception exception,
218 final HttpServletRequest request,
219 final HttpServletResponse response) throws ServletException, IOException {
220 ExceptionUtils.markExceptionCaught(request);
221 ExceptionService exceptionService = null;
222 try {
223 exceptionService = ExceptionUtils.catchException(getServletContext(), exception, request);
224 } catch (Exception e) {
225 handleExceptionHandlingException(e);
226 // never reached, prevent from warnings
227 return;
228 }
229 ExceptionUtils.markExceptionCaught(request, exceptionService);
230 try {
231 String exceptionUrl = request.getContextPath()
232 + exceptionService.getExceptionView().replace(".jsp", ".faces");
233 response.sendRedirect(exceptionUrl);
234 logger.info("redirected the browser to [" + exceptionUrl + "]");
235 return;
236 } catch (Exception e) {
237 handleExceptionHandlingException(e);
238 }
239 }
240
241 /**
242 * @return the redirector
243 */
244 private DeepLinkingRedirector getRedirector(
245 final FacesContext facesContext) {
246 VariableResolver vr = facesContext.getApplication().getVariableResolver();
247 DeepLinkingRedirector deepLinkingRedirector =
248 (DeepLinkingRedirector) vr.resolveVariable(facesContext, redirectorName);
249 if (deepLinkingRedirector == null) {
250 throw new ConfigException("bean [" + redirectorName + "] not found!");
251 }
252 return deepLinkingRedirector;
253 }
254
255 /**
256 * @return the parameters of the current request.
257 */
258 private Map<String, String> getParams(
259 final HttpServletRequest request) {
260 if (request == null) {
261 return null;
262 }
263 Map<String, String> params = AbstractUrlGenerator.decodeArgToParams(
264 request.getParameter(ServletUrlGeneratorImpl.ARGS_PARAM));
265 if (request.getParameter("enter") != null) {
266 if (params == null) {
267 params = new HashMap<String, String>();
268 }
269 params.put(AbstractDeepLinkingRedirector.ENTER_PARAM, "");
270 }
271 return params;
272 }
273
274 /**
275 * @see javax.servlet.http.HttpServlet#service(
276 * javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
277 */
278 @Override
279 public void service(final HttpServletRequest request,
280 final HttpServletResponse response)
281 throws IOException, ServletException {
282
283 FacesContext facesContext = null;
284 try {
285 String pathInfo = request.getPathInfo();
286
287 // if it is a prefix mapping ...
288 if (pathInfo != null && (pathInfo.startsWith("/WEB-INF") || pathInfo .startsWith("/META-INF"))) {
289 StringBuffer buffer = new StringBuffer();
290 buffer.append(" Someone is trying to access a secure resource : " + pathInfo);
291 buffer.append("\n remote address is " + request.getRemoteAddr());
292 buffer.append("\n remote host is " + request.getRemoteHost());
293 buffer.append("\n remote user is " + request.getRemoteUser());
294 buffer.append("\n request URI is " + request.getRequestURI());
295 logger.warn(buffer.toString());
296 response.sendError(HttpServletResponse.SC_NOT_FOUND);
297 return;
298 }
299 HibernateUtils.open(getServletContext());
300 if (!ExceptionUtils.exceptionAlreadyCaught(request)) {
301 VersionningUtils.checkVersion(getServletContext(), true, false);
302 }
303 facesContext = facesContextFactory.getFacesContext(
304 getServletConfig().getServletContext(), request, response, lifecycle);
305 Map<String, String> params = getParams(request);
306 if (params != null) {
307 String view = getRedirector(facesContext).redirect(params);
308 if (view == null) {
309 view = defaultView;
310 }
311 Application application = facesContext.getApplication();
312 ViewHandler viewHandler = application.getViewHandler();
313 UIViewRoot viewRoot = viewHandler.createView(facesContext, view);
314 viewRoot.setViewId(view);
315 facesContext.setViewRoot(viewRoot);
316 } else {
317 lifecycle.execute(facesContext);
318 }
319 lifecycle.render(facesContext);
320 HibernateUtils.close(true);
321 } catch (Exception e) {
322 HibernateUtils.close(false);
323 catchException(e, request, response);
324 } finally {
325 if (facesContext != null) {
326 facesContext.release();
327 }
328 }
329 }
330 }