View Javadoc

1   // 
2   // Copyright (c) 2003, 2004, Caltha - Gajda, Krzewski, Mach, Potempski Sp.J. 
3   // All rights reserved. 
4   // 
5   // Redistribution and use in source and binary forms, with or without modification,  
6   // are permitted provided that the following conditions are met: 
7   //  
8   // * Redistributions of source code must retain the above copyright notice,  
9   //   this list of conditions and the following disclaimer. 
10  // * Redistributions in binary form must reproduce the above copyright notice,  
11  //   this list of conditions and the following disclaimer in the documentation  
12  //   and/or other materials provided with the distribution. 
13  // * Neither the name of the Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.  
14  //   nor the names of its contributors may be used to endorse or promote products  
15  //   derived from this software without specific prior written permission. 
16  // 
17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
18  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
19  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
20  // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  
21  // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  
22  // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
23  // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
24  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
25  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
26  // POSSIBILITY OF SUCH DAMAGE. 
27  // 
28  
29  package org.objectledge.parameters;
30  
31  import java.io.UnsupportedEncodingException;
32  import java.net.URLDecoder;
33  import java.util.Enumeration;
34  import java.util.HashMap;
35  import java.util.HashSet;
36  import java.util.LinkedHashMap;
37  import java.util.Map;
38  import java.util.Set;
39  import java.util.StringTokenizer;
40  
41  import javax.servlet.http.HttpServletRequest;
42  
43  import org.objectledge.context.Context;
44  import org.objectledge.web.mvc.tools.LinkTool;
45  
46  /***
47   * Request parameters contain parameters from the request sorted by their names.
48   *
49   * <p>TODO: figure out a way to discover URL parameters encoding, now UTF-8 is used, but
50   * browsers encode GET form parameters using form page encoding thus rendering UTF-8 decoding
51   * useless. Problems:</p>
52   * <ul>
53   * <li>browsers encode URLs using UTF-8 by default (URLs typed in th location bar)</li>
54   * <li>browsers do not send any information on parameters encoding</li>
55   * </ul>
56   *
57   * @author <a href="mailto:dgajda@caltha.pl">Damian Gajda</a>
58   * @author <a href="mailto:pablo@caltha.pl">Pawel Potempski</a>
59   * @version $Id: RequestParameters.java,v 1.17 2005/08/05 12:48:27 rafal Exp $
60   */
61  public class RequestParameters extends SortedParameters
62  {
63      private Set<String> pathParams = new HashSet<String>();
64      private Set<String> queryParams = new HashSet<String>();
65      private Set<String> postParams = new HashSet<String>();    
66      
67  	/***
68  	 * Usefull method to retrieve parameters from context.
69  	 *
70  	 * @param context the context.
71  	 * @return the request parameters.
72  	 */
73  	public static RequestParameters getRequestParameters(Context context)
74  	{
75  		return (RequestParameters)context.getAttribute(RequestParameters.class);
76  	}
77  	
78      /***
79       * No arg constructor for mocking.
80       */
81      protected RequestParameters()
82      {
83          // intentionally left blank
84      }
85      
86      /***
87       * Create the parameter container with parameters found in http request.
88       * 
89       * @param request the request
90       * @throws IllegalArgumentException if illegal escape sequences appears.
91       */
92      public RequestParameters(HttpServletRequest request)
93      	throws IllegalArgumentException
94      {
95          super();
96          
97          // get query string parameters 
98          addURLParams(request.getQueryString(), "&=");
99  
100         // copy querystring params to extract only post params from request params parsed by the
101         // servlet container
102         HashMap queryStringParams = new HashMap();
103         queryStringParams.putAll(this.map);
104         queryParams.addAll(queryStringParams.keySet());
105         
106         // post parameters
107         Enumeration names = request.getParameterNames();
108         while (names.hasMoreElements())
109         {
110             String name = (String)names.nextElement();
111             String[] values = request.getParameterValues(name);
112             // avoid duplicate parameters from queryString
113             int start = 0;
114             if(queryStringParams.containsKey(name))
115             {
116                 start = ((String[])(queryStringParams.get(name))).length;
117             }
118             for (int i = start; i < values.length; i++)
119             {
120                 add(name, values[i]);
121             }
122         }
123         postParams.addAll(map.keySet());
124         for(String name : map.keySet())
125         {
126             if(queryStringParams.containsKey(name)
127                 && ((String[])queryStringParams.get(name)).length == getStrings(name).length)
128             {
129                 postParams.remove(name);
130             }
131         }
132 
133         // get path info parameters
134         addURLParams(request.getPathInfo(), "/");
135         pathParams.addAll(map.keySet());
136         pathParams.removeAll(queryParams);
137         pathParams.removeAll(postParams);        
138 
139         // speed up sorted parameters retrieval
140         Map tmp = new LinkedHashMap(map);
141         map = tmp;
142     }
143     
144     private static final int START = 0;
145     private static final int NAME = 1;
146     private static final int SEPARATOR_AFTER_NAME = 2;
147     private static final int VALUE = 3;
148     private static final int SEPARATOR_AFTER_VALUE = 4;
149     
150     private void addURLParams(String urlPart, String separator)
151     {       
152         if (urlPart == null)
153         {
154             return;
155         }
156         
157         try
158         {
159             StringTokenizer st = new StringTokenizer(urlPart, separator, true);
160             int state = START;
161             String name = null;
162             while (st.hasMoreTokens())
163             {
164                 String token = st.nextToken();
165                 // separators
166                 if(token.length() == 1 && separator.indexOf(token.charAt(0)) > -1 )
167                 {
168                     switch(state)
169                     {
170                         case START:
171                             state = NAME;
172                             break;
173                         case SEPARATOR_AFTER_NAME:
174                             state = VALUE;
175                             break;
176                         case SEPARATOR_AFTER_VALUE:
177                             state = NAME;
178                             break;
179                         case VALUE:
180                             add(name, "");
181                             name = null;
182                             state = NAME;
183                             break;
184                         case NAME:
185                             throw new IllegalStateException("empty parameter name");
186                         default:
187                             throw new IllegalStateException(
188                                 "illegal state while parsing params");
189                     }
190                 }
191                 // names and values
192                 else
193                 {
194                     switch(state)
195                     {
196                         case START:
197                         case NAME:
198                             name = URLDecoder.decode(token, LinkTool.PARAMETER_ENCODING);
199                             state = SEPARATOR_AFTER_NAME;
200                             break;
201                         case VALUE:
202                             add(name, URLDecoder.decode(token, LinkTool.PARAMETER_ENCODING));
203                             name = null;
204                             state = SEPARATOR_AFTER_VALUE;
205                             break;
206                         default:
207                             break;  
208                     }
209                 }
210             }
211         }
212         ///CLOVER:OFF
213         catch (UnsupportedEncodingException e)
214         {
215             throw new IllegalArgumentException("Unsupported encoding exception " + e.getMessage());
216         }
217         ///CLOVER:ON
218     }
219     
220     /***
221      * Checks if the parameter was passed in through request path info.
222      * 
223      * @param name name of the parameter.
224      * @return <code>true</code> if the parameter was passed in through path info.
225      */
226     public boolean isPathInfoParameter(String name)
227     {
228         return pathParams.contains(name);
229     }
230 
231     /***
232      * Checks if the parameter was passed in through request query string.
233      * 
234      * @param name name of the parameter.
235      * @return <code>true</code> if the parameter was passed in through request query string.
236      */
237     public boolean isQueryStringParameter(String name)
238     {
239         return queryParams.contains(name);
240     }
241     
242     /***
243      * Checks if the parameter was passed in through POST request body.
244      * 
245      * @param name name of the parameter.
246      * @return <code>true</code> if the parameter was passed through POST request body.
247      */
248     public boolean isPOSTParameter(String name)
249     {
250         return postParams.contains(name);
251     }
252     
253     /***
254      * To be used by FileUploadValve, that handles multipart/form-data POSTs.
255      * 
256      * @param name of the parameter.
257      * @param value value of the parameter.
258      */
259     public void addPOSTParameter(String name, String value)
260     {
261         super.add(name, value);
262         postParams.add(name);
263     }
264 }