View Javadoc
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 }