1 // Copyright (C) 1998-2001 by Jason Hunter <jhunter_AT_acm_DOT_org>.
2 // All rights reserved.  Use of this class is limited.
3 // Please see the LICENSE for more information.
4 
5 package com.oreilly.servlet;
6 
7 import java.io.*;
8 import java.util.*;
9 import javax.servlet.*;
10 
11 /**
12  * A class to simplify parameter handling.  It can return parameters of
13  * any primitive type (no casting or parsing required), can throw an
14  * exception when a parameter is not found (simplifying error handling),
15  * and can accept default values (eliminating error handling).
16  * <p>
17  * It is used like this:
18  * <blockquote><pre>
19  * ParameterParser parser = new ParameterParser(req);
20  * &nbsp;
21  * float ratio = parser.getFloatParameter("ratio", 1.0);
22  * &nbsp;
23  * int count = 0;
24  * try {
25  *   count = parser.getIntParameter("count");
26  * }
27  * catch (NumberFormatException e) {
28  *   handleMalformedCount();
29  * }
30  * catch (ParameterNotFoundException e) {
31  *   handleNoCount();
32  * }
33  * </pre></blockquote>
34  *
35  * There's also a capability to find out if any required parameters are
36  * missing from a request:
37  * <blockquote><pre>
38  * ParameterParser parser = new ParameterParser(req);
39  * String[] required = { "fname", "lname", "account" };
40  * String[] missing = parser.getMissingParameters(required);
41  * </pre></blockquote>
42  *
43  * The default charset for input parameters is ISO-8859-1 (Latin-1).
44  * If the parameter values are encoded in another format, specify that using
45  * setCharacterEncoding() before parsing.  The parameter names currently
46  * have to be in the Latin-1 character set:
47  * <blockquote><pre>
48  * ParameterParser parser = new ParameterParser(req);
49  * parser.setCharacterEncoding("Shift_JIS");
50  * String japaneseValue = parser.getStringParameter("latinName");
51  * </pre></blockquote>
52  *
53  * @see com.oreilly.servlet.ParameterNotFoundException
54  *
55  * @author <b>Jason Hunter</b>, Copyright &#169; 1998, 1999
56  * @version 1.4, 2000/12/14, better checking the selected encoding is valid in
57  *                           setCharacterEncoding() thanks to Dewayne McNair
58  * @version 1.3, 2000/05/17, added setCharacterEncoding()
59  * @version 1.2, 2000/05/17, getBooleanParameter() now recognizes "on" and "yes"
60  * @version 1.1, 1999/12/20, added getMissingParameters() method
61  * @version 1.0, 1998/09/18
62  */
63 public class ParameterParser {
64 
65   private ServletRequest req;
66   private String encoding;
67 
68   /**
69    * Constructs a new ParameterParser to handle the parameters of the
70    * given request.
71    *
72    * @param req the servlet request
73    */
ParameterParser(ServletRequest req)74   public ParameterParser(ServletRequest req) {
75     this.req = req;
76   }
77 
78   /**
79    * Sets the character encoding (charset) of the request to help the parser
80    * properly decode parameter values.  The default is to return undecoded values,
81    * the same as would be returned by getParameter().
82    *
83    * @param encoding the charset of the request
84    * @exception UnsupportedEncodingException if the charset is not supported
85    * on this sytem
86    */
setCharacterEncoding(String encoding)87   public void setCharacterEncoding(String encoding)
88                  throws UnsupportedEncodingException {
89     // Test the encoding is valid
90     new String("".getBytes("8859_1"), encoding);
91     // Getting here means we're valid, so set the encoding
92     this.encoding = encoding;
93   }
94 
95   /**
96    * Gets the named parameter value as a String
97    *
98    * @param name the parameter name
99    * @return the parameter value as a String
100    * @exception ParameterNotFoundException if the parameter was not found
101    * or was the empty string
102    */
getStringParameter(String name)103   public String getStringParameter(String name)
104       throws ParameterNotFoundException {
105     String[] values = req.getParameterValues(name);
106     if (values == null) {
107       throw new ParameterNotFoundException(name + " not found");
108     }
109     else if (values[0].length() == 0) {
110       throw new ParameterNotFoundException(name + " was empty");
111     }
112     else {
113       if (encoding == null) {
114         return values[0];
115       }
116       else {
117         try {
118           return new String(values[0].getBytes("8859_1"), encoding);
119         }
120         catch (UnsupportedEncodingException e) {
121           return values[0];  // should never happen
122         }
123       }
124     }
125   }
126 
127   /**
128    * Gets the named parameter value as a String, with a default.
129    * Returns the default value if the parameter is not found or
130    * is the empty string.
131    *
132    * @param name the parameter name
133    * @param def the default parameter value
134    * @return the parameter value as a String, or the default
135    */
getStringParameter(String name, String def)136   public String getStringParameter(String name, String def) {
137     try { return getStringParameter(name); }
138     catch (Exception e) { return def; }
139   }
140 
141   /**
142    * Gets the named parameter value as a boolean, with true indicated by
143    * "true", "on", or "yes" in any letter case, false indicated by "false",
144    * "off", or "no" in any letter case.
145    *
146    * @param name the parameter name
147    * @return the parameter value as a boolean
148    * @exception ParameterNotFoundException if the parameter was not found
149    * @exception NumberFormatException if the parameter could not be converted
150    * to a boolean
151    */
getBooleanParameter(String name)152   public boolean getBooleanParameter(String name)
153       throws ParameterNotFoundException, NumberFormatException {
154     String value = getStringParameter(name).toLowerCase();
155     if ((value.equalsIgnoreCase("true")) ||
156         (value.equalsIgnoreCase("on")) ||
157         (value.equalsIgnoreCase("yes"))) {
158         return true;
159     }
160     else if ((value.equalsIgnoreCase("false")) ||
161              (value.equalsIgnoreCase("off")) ||
162              (value.equalsIgnoreCase("no"))) {
163         return false;
164     }
165     else {
166       throw new NumberFormatException("Parameter " + name + " value " + value +
167                                       " is not a boolean");
168     }
169   }
170 
171   /**
172    * Gets the named parameter value as a boolean, with a default.
173    * Returns the default value if the parameter is not found.
174    *
175    * @param name the parameter name
176    * @param def the default parameter value
177    * @return the parameter value as a boolean, or the default
178    */
getBooleanParameter(String name, boolean def)179   public boolean getBooleanParameter(String name, boolean def) {
180     try { return getBooleanParameter(name); }
181     catch (Exception e) { return def; }
182   }
183 
184   /**
185    * Gets the named parameter value as a byte
186    *
187    * @param name the parameter name
188    * @return the parameter value as a byte
189    * @exception ParameterNotFoundException if the parameter was not found
190    * @exception NumberFormatException if the parameter value could not
191    * be converted to a byte
192    */
getByteParameter(String name)193   public byte getByteParameter(String name)
194       throws ParameterNotFoundException, NumberFormatException {
195     return Byte.parseByte(getStringParameter(name));
196   }
197 
198   /**
199    * Gets the named parameter value as a byte, with a default.
200    * Returns the default value if the parameter is not found or cannot
201    * be converted to a byte.
202    *
203    * @param name the parameter name
204    * @param def the default parameter value
205    * @return the parameter value as a byte, or the default
206    */
getByteParameter(String name, byte def)207   public byte getByteParameter(String name, byte def) {
208     try { return getByteParameter(name); }
209     catch (Exception e) { return def; }
210   }
211 
212   /**
213    * Gets the named parameter value as a char
214    *
215    * @param name the parameter name
216    * @return the parameter value as a char
217    * @exception ParameterNotFoundException if the parameter was not found
218    * or was the empty string
219    */
getCharParameter(String name)220   public char getCharParameter(String name)
221       throws ParameterNotFoundException {
222     String param = getStringParameter(name);
223     if (param.length() == 0)
224       throw new ParameterNotFoundException(name + " is empty string");
225     else
226       return (param.charAt(0));
227   }
228 
229   /**
230    * Gets the named parameter value as a char, with a default.
231    * Returns the default value if the parameter is not found.
232    *
233    * @param name the parameter name
234    * @param def the default parameter value
235    * @return the parameter value as a char, or the default
236    */
getCharParameter(String name, char def)237   public char getCharParameter(String name, char def) {
238     try { return getCharParameter(name); }
239     catch (Exception e) { return def; }
240   }
241 
242   /**
243    * Gets the named parameter value as a double
244    *
245    * @param name the parameter name
246    * @return the parameter value as a double
247    * @exception ParameterNotFoundException if the parameter was not found
248    * @exception NumberFormatException if the parameter could not be converted
249    * to a double
250    */
getDoubleParameter(String name)251   public double getDoubleParameter(String name)
252       throws ParameterNotFoundException, NumberFormatException {
253     return new Double(getStringParameter(name)).doubleValue();
254   }
255 
256   /**
257    * Gets the named parameter value as a double, with a default.
258    * Returns the default value if the parameter is not found.
259    *
260    * @param name the parameter name
261    * @param def the default parameter value
262    * @return the parameter value as a double, or the default
263    */
getDoubleParameter(String name, double def)264   public double getDoubleParameter(String name, double def) {
265     try { return getDoubleParameter(name); }
266     catch (Exception e) { return def; }
267   }
268 
269   /**
270    * Gets the named parameter value as a float
271    *
272    * @param name the parameter name
273    * @return the parameter value as a float
274    * @exception ParameterNotFoundException if the parameter was not found
275    * @exception NumberFormatException if the parameter could not be converted
276    * to a float
277    */
getFloatParameter(String name)278   public float getFloatParameter(String name)
279       throws ParameterNotFoundException, NumberFormatException {
280     return new Float(getStringParameter(name)).floatValue();
281   }
282 
283   /**
284    * Gets the named parameter value as a float, with a default.
285    * Returns the default value if the parameter is not found.
286    *
287    * @param name the parameter name
288    * @param def the default parameter value
289    * @return the parameter value as a float, or the default
290    */
getFloatParameter(String name, float def)291   public float getFloatParameter(String name, float def) {
292     try { return getFloatParameter(name); }
293     catch (Exception e) { return def; }
294   }
295 
296   /**
297    * Gets the named parameter value as a int
298    *
299    * @param name the parameter name
300    * @return the parameter value as a int
301    * @exception ParameterNotFoundException if the parameter was not found
302    * @exception NumberFormatException if the parameter could not be converted
303    * to a int
304    */
getIntParameter(String name)305   public int getIntParameter(String name)
306       throws ParameterNotFoundException, NumberFormatException {
307     return Integer.parseInt(getStringParameter(name));
308   }
309 
310   /**
311    * Gets the named parameter value as a int, with a default.
312    * Returns the default value if the parameter is not found.
313    *
314    * @param name the parameter name
315    * @param def the default parameter value
316    * @return the parameter value as a int, or the default
317    */
getIntParameter(String name, int def)318   public int getIntParameter(String name, int def) {
319     try { return getIntParameter(name); }
320     catch (Exception e) { return def; }
321   }
322 
323   /**
324    * Gets the named parameter value as a long
325    *
326    * @param name the parameter name
327    * @return the parameter value as a long
328    * @exception ParameterNotFoundException if the parameter was not found
329    * @exception NumberFormatException if the parameter could not be converted
330    * to a long
331    */
getLongParameter(String name)332   public long getLongParameter(String name)
333       throws ParameterNotFoundException, NumberFormatException {
334     return Long.parseLong(getStringParameter(name));
335   }
336 
337   /**
338    * Gets the named parameter value as a long, with a default.
339    * Returns the default value if the parameter is not found.
340    *
341    * @param name the parameter name
342    * @param def the default parameter value
343    * @return the parameter value as a long, or the default
344    */
getLongParameter(String name, long def)345   public long getLongParameter(String name, long def) {
346     try { return getLongParameter(name); }
347     catch (Exception e) { return def; }
348   }
349 
350   /**
351    * Gets the named parameter value as a short
352    *
353    * @param name the parameter name
354    * @return the parameter value as a short
355    * @exception ParameterNotFoundException if the parameter was not found
356    * @exception NumberFormatException if the parameter could not be converted
357    * to a short
358    */
getShortParameter(String name)359   public short getShortParameter(String name)
360       throws ParameterNotFoundException, NumberFormatException {
361     return Short.parseShort(getStringParameter(name));
362   }
363 
364   /**
365    * Gets the named parameter value as a short, with a default.
366    * Returns the default value if the parameter is not found.
367    *
368    * @param name the parameter name
369    * @param def the default parameter value
370    * @return the parameter value as a short, or the default
371    */
getShortParameter(String name, short def)372   public short getShortParameter(String name, short def) {
373     try { return getShortParameter(name); }
374     catch (Exception e) { return def; }
375   }
376 
377   /**
378    * Determines which of the required parameters were missing from the
379    * request.  Returns null if all the parameters are present.
380    *
381    * @param an array of required parameters
382    * @return an array of missing parameters, or null if none are missing
383    */
getMissingParameters(String[] required)384   public String[] getMissingParameters(String[] required) {
385     Vector missing = new Vector();
386     for (int i = 0; i < required.length; i++) {
387       String val = getStringParameter(required[i], null);
388       if (val == null) {
389         missing.addElement(required[i]);
390       }
391     }
392     if (missing.size() == 0) {
393       return null;
394     }
395     else {
396       String[] ret = new String[missing.size()];
397       missing.copyInto(ret);
398       return ret;
399     }
400   }
401 }
402