package onlinefrontlines.web; import onlinefrontlines.Constants; import onlinefrontlines.auth.AutoAuth; import onlinefrontlines.profiler.Profiler; import onlinefrontlines.profiler.Sampler; import onlinefrontlines.utils.Tools; import java.util.HashMap; import java.util.Enumeration; import java.io.IOException; import javax.servlet.*; import javax.servlet.http.*; import org.w3c.dom.*; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; /** * Filters all incoming action requests * * @author jorrit * * Copyright (C) 2009-2013 Jorrit Rouwe * * This file is part of Online Frontlines. * * Online Frontlines is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Online Frontlines is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Online Frontlines. If not, see <http://www.gnu.org/licenses/>. */ public class RequestFilter implements Filter { /** * List of registered actions */ private HashMap<String, WebActionConfig> registeredActions = new HashMap<String, WebActionConfig>(); /** * Stored servlet context */ private ServletContext servletContext; /** * Wrapper for the request */ private static class RequestWrapper extends HttpServletRequestWrapper { private WebAction action; /** * Constructor */ RequestWrapper(HttpServletRequest request, WebAction action) { super(request); this.action = action; } /** * Override get attribute to search in actions fields */ @Override public Object getAttribute(String name) { // Try as attribute Object attribute = super.getAttribute(name); if (attribute != null) return attribute; // Ignore system attributes if (name.startsWith("javax.servlet.") || name.startsWith("org.apache.")) return null; // Try as field attribute = action.config.getField(action, name); super.setAttribute(name, attribute); return attribute; } } /** * Fill in action config object * * @param action Action node from actions.xml * @param actionConfig Action config object to fill in */ public void getActionConfig(Node action, WebActionConfig actionConfig) throws Exception { // Get class loader ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Get attributes NamedNodeMap actionAttrs = action.getAttributes(); // Get action class Node actionClassNode = actionAttrs.getNamedItem("class"); if (actionClassNode != null) actionConfig.action = classLoader.loadClass(actionClassNode.getNodeValue()); // Get method Node methodNode = actionAttrs.getNamedItem("method"); if (methodNode != null) { String method = methodNode.getNodeValue().toLowerCase(); if (method.equals("input")) actionConfig.method = WebActionConfig.ActionMethod.INPUT; else if (method.equals("execute")) actionConfig.method = WebActionConfig.ActionMethod.EXECUTE; else throw new Exception("Invalid method " + method); } NodeList actionChildren = action.getChildNodes(); for (int j = 0; j < actionChildren.getLength(); ++j) { Node child = actionChildren.item(j); String childName = child.getNodeName().toLowerCase(); if (childName.equals("interceptor")) { // Create interceptor String interceptorClass = child.getFirstChild().getNodeValue(); actionConfig.interceptor = (WebInterceptor)classLoader.loadClass(interceptorClass).newInstance(); } else if (childName.equals("result")) { // Get type Node resultTypeNode = child.getAttributes().getNamedItem("type"); String resultType = resultTypeNode != null? resultTypeNode.getNodeValue().toLowerCase() : "jsp"; // Get name Node resultNameNode = child.getAttributes().getNamedItem("name"); String resultName = resultNameNode != null? resultNameNode.getNodeValue().toLowerCase() : "success"; // Get url String resultUrl = child.getFirstChild().getNodeValue(); // Create view WebView view; if (resultType.equals("jsp")) view = new WebViewJsp(resultUrl); else if (resultType.equals("redirect")) view = new WebViewRedirect(resultUrl); else throw new Exception("Invalid view type " + resultType); // Fill in correct entry if (resultName.equals("input")) actionConfig.inputView = view; else if (resultName.equals("success")) actionConfig.successView = view; else if (resultName.equals("error")) actionConfig.errorView = view; else if (resultName.equals("redirect")) actionConfig.redirectView = view; else throw new Exception("Invalid name " + resultName); } } } /** * {@inheritDoc} */ public void init(FilterConfig config) { // Store servletcontext servletContext = config.getServletContext(); try { // Open actions.xml config file DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); Document doc = docBuilder.parse(servletContext.getResourceAsStream("/WEB-INF/classes/actions.xml")); if (doc == null) throw new Exception("Config file 'actions.xml' not found."); // Normalize text representation doc.getDocumentElement().normalize(); // Load default action NodeList defaultAction = doc.getElementsByTagName("default-action"); if (defaultAction == null || defaultAction.getLength() != 1) throw new Exception("Need a default action"); WebActionConfig defaultActionConfig = new WebActionConfig(); getActionConfig(defaultAction.item(0), defaultActionConfig); // Load actions NodeList actions = doc.getElementsByTagName("action"); if (actions == null) throw new Exception("Need at least one action"); for (int i = 0; i < actions.getLength(); ++i) { // Get action node Node action = actions.item(i); // Get name String actionName = action.getAttributes().getNamedItem("name").getNodeValue(); // Get config WebActionConfig actionConfig = new WebActionConfig(defaultActionConfig); getActionConfig(action, actionConfig); // Register action registeredActions.put("/OnlineFrontlines/" + actionName + ".do", actionConfig); } } catch (Exception e) { // Log error Tools.logException(e); } } /** * {@inheritDoc} */ public void destroy() { } /** * Override doFilter method */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // Get request String requestURI = ((HttpServletRequest)request).getRequestURI(); Sampler sampler = Profiler.getInstance().startSampler(Profiler.CATEGORY_HTTP_REQUEST, requestURI); try { // Set encoding request.setCharacterEncoding("UTF-8"); // Don't cache this WebUtils.setNoCacheHeaders((HttpServletResponse)response); // Find action WebActionConfig actionConfig = registeredActions.get(requestURI); if (actionConfig == null) { WebView view = new WebViewJsp("/WEB-INF/jsp/NotFound.jsp"); view.execute((HttpServletRequest)request, (HttpServletResponse)response); return; } // Create action WebAction action = null; try { action = (WebAction)actionConfig.action.newInstance(); } catch (Exception e) { // Log exceptions Tools.logException(e); // Send error WebView view = actionConfig.errorView; view.execute((HttpServletRequest)request, (HttpServletResponse)response); return; } // Create wrappers RequestWrapper req = new RequestWrapper((HttpServletRequest)request, action); // Set constants on action action.config = actionConfig; action.servletContext = servletContext; action.request = req; action.response = (HttpServletResponse)response; // Set constants on request req.setAttribute(Constants.CURRENT_ACTION, action); // Set user on request AutoAuth.AuthResult result = AutoAuth.getAuthenticatedUser(action.request, action.response); if (result != null) { action.user = result.user; action.facebookAccessToken = result.facebookAccessToken; } // Set parameters on action Enumeration<?> params = request.getParameterNames(); while (params.hasMoreElements()) { String name = (String)params.nextElement(); String value = request.getParameter(name); action.config.setField(action, name, value); } // Execute action WebView view; try { view = actionConfig.interceptor.intercept(action); } catch (Exception e) { // Log exceptions Tools.logException(e); // Send error action.addActionError(action.getText("unexpectedError")); view = action.getErrorView(); } try { // Execute view view.execute(req, (HttpServletResponse)response); } catch (Exception e) { // Log exception Tools.logException(e); // Send internal server error ((HttpServletResponse)response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } finally { sampler.stop(); } } }