1 package org.apache.velocity.tools.view;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.lang.reflect.Array;
23 import java.util.Map;
24 import java.util.HashMap;
25 import java.util.Collection;
26 import java.util.Set;
27 import java.util.HashSet;
28 import javax.servlet.ServletRequest;
29 import org.apache.velocity.tools.Scope;
30 import org.apache.velocity.tools.config.DefaultKey;
31 import org.apache.velocity.tools.config.ValidScope;
32 import org.apache.velocity.tools.generic.ValueParser;
33
34 /**
35 * <p>Utility class for easy parsing of {@link ServletRequest} parameters.</p>
36 * <p><pre>
37 * Template example(s):
38 * $params.foo -> bar
39 * $params.getNumber('baz') -> 12.6
40 * $params.getInt('baz') -> 12
41 * $params.getNumbers('baz') -> [12.6]
42 *
43 * Toolbox configuration:
44 * <tools>
45 * <toolbox scope="request">
46 * <tool class="org.apache.velocity.tools.view.ParameterTool"/>
47 * </toolbox>
48 * </tools>
49 * </pre></p>
50 *
51 * <p>When used as a view tool, this should only be used in the request scope.
52 * This class is, however, quite useful in your application's controller, filter,
53 * or action code as well as in templates.</p>
54 *
55 * @author Nathan Bubna
56 * @version $Revision: 961796 $ $Date: 2010-07-08 17:18:15 +0200 (jeu., 08 juil. 2010) $
57 * @since VelocityTools 2.0
58 */
59 @DefaultKey("params")
60 @ValidScope(Scope.REQUEST)
61 public class ParameterTool extends ValueParser
62 {
63 private ServletRequest request;
64
65 /**
66 * Constructs a new instance
67 */
68 public ParameterTool()
69 {}
70
71 /**
72 * Constructs a new instance using the specified request.
73 *
74 * @param request the {@link ServletRequest} to be parsed
75 */
76 public ParameterTool(ServletRequest request)
77 {
78 setRequest(request);
79 }
80
81 @Override
82 protected void configure(ValueParser values)
83 {
84 super.configure(values);
85
86 ServletRequest req = (ServletRequest)values.getValue(ViewContext.REQUEST);
87 setRequest(req);
88 }
89
90 /**
91 * Sets the current {@link ServletRequest}
92 *
93 * @param request the {@link ServletRequest} to be parsed
94 */
95 public void setRequest(ServletRequest request)
96 {
97 this.request = request;
98 }
99
100 /**
101 * Returns the current {@link ServletRequest} for this instance.
102 *
103 * @return the current {@link ServletRequest}
104 * @throws UnsupportedOperationException if the request is null
105 */
106 protected ServletRequest getRequest()
107 {
108 if (request == null)
109 {
110 throw new UnsupportedOperationException("Request is null. ParameterTool must be initialized first!");
111 }
112 return request;
113 }
114
115 /**
116 * Overrides ValueParser.getValue(String key) to retrieve the
117 * value from the ServletRequest instead of an arbitrary Map.
118 *
119 * @param key the parameter's key
120 * @return parameter matching the specified key or
121 * <code>null</code> if there is no matching
122 * parameter
123 */
124 @Override
125 public Object getValue(String key)
126 {
127 return getRequest().getParameter(key);
128 }
129
130
131 /**
132 * Overrides ValueParser.getValues(String key) to retrieve
133 * Strings from the ServletRequest instead of an arbitrary Map.
134 *
135 * @param key the key for the desired parameter
136 * @return an array of String objects containing all of the values
137 * the given request parameter has, or <code>null</code>
138 * if the parameter does not exist
139 */
140 @Override
141 public Object[] getValues(String key)
142 {
143 String[] strings = getRequest().getParameterValues(key);
144 if (strings == null || strings.length == 0)
145 {
146 return null;
147 }
148 else if (strings.length == 1)
149 {
150 return parseStringList(strings[0]);
151 }
152 return strings;
153 }
154
155 /**
156 * Overrides ValueParser.setSource(Map source) to throw an
157 * UnsupportedOperationException, because this class uses
158 * a servlet request as its source, not a Map.
159 */
160 @Override
161 protected void setSource(Map source)
162 {
163 throw new UnsupportedOperationException();
164 }
165
166 /**
167 * Overrides ValueParser.getSource() to return the result
168 * of getRequest().getParameterMap() and expand singleton
169 * arrays within it first.
170 */
171 @Override
172 protected Map getSource()
173 {
174 Map source = super.getSource();
175 if (source == null)
176 {
177 source = expandSingletonArrays(getRequest().getParameterMap());
178 super.setSource(source);
179 }
180 return source;
181 }
182
183 /**
184 * Returns the map of all parameters available for the current request.
185 */
186 public Map getAll()
187 {
188 return getSource();
189 }
190
191 private boolean isSingletonArray(Object value)
192 {
193 return (value != null &&
194 value.getClass().isArray() &&
195 Array.getLength(value) == 1);
196 }
197
198 private Map<String,Object> expandSingletonArrays(Map<String,Object> original)
199 {
200 Map<String,Object> expanded = new HashMap<String,Object>(original);
201 for (Map.Entry<String,Object> entry : expanded.entrySet())
202 {
203 Object value = entry.getValue();
204 if (isSingletonArray(value))
205 {
206 entry.setValue(Array.get(value, 0));
207 }
208 }
209 return expanded;
210 }
211
212 }