1 /* 2 * JBoss, Home of Professional Open Source 3 * Copyright 2014, Red Hat, Inc. and/or its affiliates, and individual 4 * contributors by the @authors tag. See the copyright.txt in the 5 * distribution for a full listing of individual contributors. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.jboss.as.quickstarts.servlet.filterlistener; 18 19 import java.io.ByteArrayOutputStream; 20 import java.io.IOException; 21 import java.util.Collections; 22 import java.util.Enumeration; 23 import java.util.HashMap; 24 import java.util.Map; 25 26 import javax.servlet.Filter; 27 import javax.servlet.FilterChain; 28 import javax.servlet.FilterConfig; 29 import javax.servlet.ServletContext; 30 import javax.servlet.ServletException; 31 import javax.servlet.ServletRequest; 32 import javax.servlet.ServletResponse; 33 import javax.servlet.annotation.WebFilter; 34 import javax.servlet.http.HttpServletRequest; 35 import javax.servlet.http.HttpServletRequestWrapper; 36 import javax.servlet.http.HttpSession; 37 38 /** 39 * A silly Servlet Filter that removes the letters a, e, i, o, and u (but not <a 40 * href="http://oxforddictionaries.com/page/200">sometimes y</a>) from all request parameter values. To achieve this, a wrapper 41 * is placed around the request object. This wrapper returns a different set of parameters than those that the JBoss AS 42 * container parsed from the original HTTP request. 43 * <p> 44 * This is just one simple example of what you can do with a filter. In real life, you will find filters useful for these kinds 45 * of things: 46 * <ul> 47 * <li>Accepting or rejecting requests based on security requirements (by calling {@link HttpServletRequest#getUserPrincipal()} 48 * or examining attributes of the {@link HttpSession} to see if the user is authenticated) 49 * <li>Logging access to certain resources (this could also be done with a Request Listener) 50 * <li>Caching responses (by wrapping the response's output stream in a {@link ByteArrayOutputStream} on cache miss, and 51 * replaying saved responses on cache hit) 52 * <li>Performing compression on request or response data (again, by wrapping the request's input stream or the response's 53 * output stream) 54 * </ul> 55 * <p> 56 * Note that this application also employs a {@linkplain ParameterDumpingRequestListener Request Listener}, which will see all 57 * requests before this Filter sees them. 58 * 59 * @author Jonathan Fuerth <jfuerth@redhat.com> 60 */ 61 @WebFilter("/*") 62 public class VowelRemoverFilter implements Filter { 63 64 private ServletContext servletContext; 65 66 @Override 67 public void init(FilterConfig filterConfig) throws ServletException { 68 69 // It is common to save a reference to the ServletContext here in case it is needed 70 // in the destroy() call. 71 servletContext = filterConfig.getServletContext(); 72 73 // To see this log message at run time, check out the terminal window where you started JBoss AS. 74 servletContext.log("VowelRemoverFilter initialized"); 75 } 76 77 @Override 78 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, 79 ServletException { 80 81 final Map<String, String[]> filteredParams = Collections.unmodifiableMap(removeVowels(request.getParameterMap())); 82 83 // Here, we wrap the request so that the servlet (and other filters further down the chain) 84 // will see our filteredParams rather than the original request's parameters. Wrappers can be 85 // as benign or as crazy as you like. Use your imagination! 86 HttpServletRequestWrapper wrappedRequest = new HttpServletRequestWrapper((HttpServletRequest) request) { 87 @Override 88 public Map<String, String[]> getParameterMap() { 89 return filteredParams; 90 } 91 92 @Override 93 public String getParameter(String name) { 94 return filteredParams.get(name) == null ? null : filteredParams.get(name)[0]; 95 } 96 97 @Override 98 public Enumeration<String> getParameterNames() { 99 return Collections.enumeration(filteredParams.keySet()); 100 } 101 102 @Override 103 public String[] getParameterValues(String name) { 104 return filteredParams.get(name); 105 } 106 }; 107 108 // Some notes on other filter use cases: 109 // 1. We could have also wrapped the response object if we wanted to capture 110 // or manipulate the output 111 // 2. If we just wanted to examine the request or session, we could do that in 112 // a filter or in a Request Listener (see ParameterDumpingRequestListener) 113 // 3. You don't have to wrap the request or response at all if you just want 114 // to set request or session attributes 115 // 4. You don't have to call chain.doFilter(). The filter can handle the request 116 // directly (for example, to forward to a login page or send a "403 Forbidden" 117 // response if the user is not logged in) 118 119 try { 120 servletContext.log("VowelRemoverFilter invoking filter chain..."); 121 122 // This is where other filters, and ultimately the servlet or JSP, get a chance to handle the request 123 chain.doFilter(wrappedRequest, response); 124 125 } finally { 126 127 // The try .. finally is important here because another filter or the 128 // servlet itself may throw an exception 129 servletContext.log("VowelRemoverFilter done filtering request"); 130 } 131 } 132 133 /** 134 * Performs the vowel removal work of this filter. 135 * 136 * @param parameterMap the map of parameter names and values in the original request. 137 * @return A copy of the original map with all the same keys, but whose values do not contain vowels. 138 */ 139 private Map<String, String[]> removeVowels(Map<String, String[]> parameterMap) { 140 Map<String, String[]> m = new HashMap<String, String[]>(); 141 for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) { 142 String[] orig = entry.getValue(); 143 String[] vowelless = new String[orig.length]; 144 for (int i = 0; i < orig.length; i++) { 145 vowelless[i] = orig[i].replaceAll("[aeiou]", ""); 146 } 147 m.put(entry.getKey(), vowelless); 148 } 149 return m; 150 } 151 152 @Override 153 public void destroy() { 154 servletContext.log("VowelRemoverFilter destroyed"); 155 servletContext = null; 156 } 157 158 }