001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.portlet.bind;
018
019import javax.portlet.PortletRequest;
020
021/**
022 * Parameter extraction methods, for an approach distinct from data binding,
023 * in which parameters of specific types are required.
024 *
025 * <p>This approach is very useful for simple submissions, where binding
026 * request parameters to a command object would be overkill.
027 *
028 * @author Juergen Hoeller
029 * @author Keith Donald
030 * @author John A. Lewis
031 * @since 2.0
032 */
033public abstract class PortletRequestUtils {
034
035        private static final IntParser INT_PARSER = new IntParser();
036
037        private static final LongParser LONG_PARSER = new LongParser();
038
039        private static final FloatParser FLOAT_PARSER = new FloatParser();
040
041        private static final DoubleParser DOUBLE_PARSER = new DoubleParser();
042
043        private static final BooleanParser BOOLEAN_PARSER = new BooleanParser();
044
045        private static final StringParser STRING_PARSER = new StringParser();
046
047
048        /**
049         * Get an Integer parameter, or {@code null} if not present.
050         * Throws an exception if it the parameter value isn't a number.
051         * @param request current portlet request
052         * @param name the name of the parameter
053         * @return the Integer value, or {@code null} if not present
054         * @throws PortletRequestBindingException a subclass of PortletException,
055         * so it doesn't need to be caught
056         */
057        public static Integer getIntParameter(PortletRequest request, String name)
058                        throws PortletRequestBindingException {
059
060                if (request.getParameter(name) == null) {
061                        return null;
062                }
063                return getRequiredIntParameter(request, name);
064        }
065
066        /**
067         * Get an int parameter, with a fallback value. Never throws an exception.
068         * Can pass a distinguished value as default to enable checks of whether it was supplied.
069         * @param request current portlet request
070         * @param name the name of the parameter
071         * @param defaultVal the default value to use as fallback
072         */
073        public static int getIntParameter(PortletRequest request, String name, int defaultVal) {
074                if (request.getParameter(name) == null) {
075                        return defaultVal;
076                }
077                try {
078                        return getRequiredIntParameter(request, name);
079                }
080                catch (PortletRequestBindingException ex) {
081                        return defaultVal;
082                }
083        }
084
085        /**
086         * Get an array of int parameters, return an empty array if not found.
087         * @param request current portlet request
088         * @param name the name of the parameter with multiple possible values
089         */
090        public static int[] getIntParameters(PortletRequest request, String name) {
091                try {
092                        return getRequiredIntParameters(request, name);
093                }
094                catch (PortletRequestBindingException ex) {
095                        return new int[0];
096                }
097        }
098
099        /**
100         * Get an int parameter, throwing an exception if it isn't found or isn't a number.
101         * @param request current portlet request
102         * @param name the name of the parameter
103         * @throws PortletRequestBindingException a subclass of PortletException,
104         * so it doesn't need to be caught
105         */
106        public static int getRequiredIntParameter(PortletRequest request, String name)
107                        throws PortletRequestBindingException {
108
109                return INT_PARSER.parseInt(name, request.getParameter(name));
110        }
111
112        /**
113         * Get an array of int parameters, throwing an exception if not found or one is not a number..
114         * @param request current portlet request
115         * @param name the name of the parameter with multiple possible values
116         * @throws PortletRequestBindingException a subclass of PortletException,
117         * so it doesn't need to be caught
118         */
119        public static int[] getRequiredIntParameters(PortletRequest request, String name)
120                        throws PortletRequestBindingException {
121
122                return INT_PARSER.parseInts(name, request.getParameterValues(name));
123        }
124
125
126        /**
127         * Get a Long parameter, or {@code null} if not present.
128         * Throws an exception if it the parameter value isn't a number.
129         * @param request current portlet request
130         * @param name the name of the parameter
131         * @return the Long value, or {@code null} if not present
132         * @throws PortletRequestBindingException a subclass of PortletException,
133         * so it doesn't need to be caught
134         */
135        public static Long getLongParameter(PortletRequest request, String name)
136                        throws PortletRequestBindingException {
137
138                if (request.getParameter(name) == null) {
139                        return null;
140                }
141                return getRequiredLongParameter(request, name);
142        }
143
144        /**
145         * Get a long parameter, with a fallback value. Never throws an exception.
146         * Can pass a distinguished value as default to enable checks of whether it was supplied.
147         * @param request current portlet request
148         * @param name the name of the parameter
149         * @param defaultVal the default value to use as fallback
150         */
151        public static long getLongParameter(PortletRequest request, String name, long defaultVal) {
152                if (request.getParameter(name) == null) {
153                        return defaultVal;
154                }
155                try {
156                        return getRequiredLongParameter(request, name);
157                }
158                catch (PortletRequestBindingException ex) {
159                        return defaultVal;
160                }
161        }
162
163        /**
164         * Get an array of long parameters, return an empty array if not found.
165         * @param request current portlet request
166         * @param name the name of the parameter with multiple possible values
167         */
168        public static long[] getLongParameters(PortletRequest request, String name) {
169                try {
170                        return getRequiredLongParameters(request, name);
171                }
172                catch (PortletRequestBindingException ex) {
173                        return new long[0];
174                }
175        }
176
177        /**
178         * Get a long parameter, throwing an exception if it isn't found or isn't a number.
179         * @param request current portlet request
180         * @param name the name of the parameter
181         * @throws PortletRequestBindingException a subclass of PortletException,
182         * so it doesn't need to be caught
183         */
184        public static long getRequiredLongParameter(PortletRequest request, String name)
185                        throws PortletRequestBindingException {
186
187                return LONG_PARSER.parseLong(name, request.getParameter(name));
188        }
189
190        /**
191         * Get an array of long parameters, throwing an exception if not found or one is not a number.
192         * @param request current portlet request
193         * @param name the name of the parameter with multiple possible values
194         * @throws PortletRequestBindingException a subclass of PortletException,
195         * so it doesn't need to be caught
196         */
197        public static long[] getRequiredLongParameters(PortletRequest request, String name)
198                        throws PortletRequestBindingException {
199
200                return LONG_PARSER.parseLongs(name, request.getParameterValues(name));
201        }
202
203
204        /**
205         * Get a Float parameter, or {@code null} if not present.
206         * Throws an exception if it the parameter value isn't a number.
207         * @param request current portlet request
208         * @param name the name of the parameter
209         * @return the Float value, or {@code null} if not present
210         * @throws PortletRequestBindingException a subclass of PortletException,
211         * so it doesn't need to be caught
212         */
213        public static Float getFloatParameter(PortletRequest request, String name)
214                        throws PortletRequestBindingException {
215
216                if (request.getParameter(name) == null) {
217                        return null;
218                }
219                return getRequiredFloatParameter(request, name);
220        }
221
222        /**
223         * Get a float parameter, with a fallback value. Never throws an exception.
224         * Can pass a distinguished value as default to enable checks of whether it was supplied.
225         * @param request current portlet request
226         * @param name the name of the parameter
227         * @param defaultVal the default value to use as fallback
228         */
229        public static float getFloatParameter(PortletRequest request, String name, float defaultVal) {
230                if (request.getParameter(name) == null) {
231                        return defaultVal;
232                }
233                try {
234                        return getRequiredFloatParameter(request, name);
235                }
236                catch (PortletRequestBindingException ex) {
237                        return defaultVal;
238                }
239        }
240
241        /**
242         * Get an array of float parameters, return an empty array if not found.
243         * @param request current portlet request
244         * @param name the name of the parameter with multiple possible values
245         */
246        public static float[] getFloatParameters(PortletRequest request, String name) {
247                try {
248                        return getRequiredFloatParameters(request, name);
249                }
250                catch (PortletRequestBindingException ex) {
251                        return new float[0];
252                }
253        }
254
255        /**
256         * Get a float parameter, throwing an exception if it isn't found or isn't a number.
257         * @param request current portlet request
258         * @param name the name of the parameter
259         * @throws PortletRequestBindingException a subclass of PortletException,
260         * so it doesn't need to be caught
261         */
262        public static float getRequiredFloatParameter(PortletRequest request, String name)
263                        throws PortletRequestBindingException {
264
265                return FLOAT_PARSER.parseFloat(name, request.getParameter(name));
266        }
267
268        /**
269         * Get an array of float parameters, throwing an exception if not found or one is not a number.
270         * @param request current portlet request
271         * @param name the name of the parameter with multiple possible values
272         * @throws PortletRequestBindingException a subclass of PortletException,
273         * so it doesn't need to be caught
274         */
275        public static float[] getRequiredFloatParameters(PortletRequest request, String name)
276                        throws PortletRequestBindingException {
277
278                return FLOAT_PARSER.parseFloats(name, request.getParameterValues(name));
279        }
280
281
282        /**
283         * Get a Double parameter, or {@code null} if not present.
284         * Throws an exception if it the parameter value isn't a number.
285         * @param request current portlet request
286         * @param name the name of the parameter
287         * @return the Double value, or {@code null} if not present
288         * @throws PortletRequestBindingException a subclass of PortletException,
289         * so it doesn't need to be caught
290         */
291        public static Double getDoubleParameter(PortletRequest request, String name)
292                        throws PortletRequestBindingException {
293
294                if (request.getParameter(name) == null) {
295                        return null;
296                }
297                return getRequiredDoubleParameter(request, name);
298        }
299
300        /**
301         * Get a double parameter, with a fallback value. Never throws an exception.
302         * Can pass a distinguished value as default to enable checks of whether it was supplied.
303         * @param request current portlet request
304         * @param name the name of the parameter
305         * @param defaultVal the default value to use as fallback
306         */
307        public static double getDoubleParameter(PortletRequest request, String name, double defaultVal) {
308                if (request.getParameter(name) == null) {
309                        return defaultVal;
310                }
311                try {
312                        return getRequiredDoubleParameter(request, name);
313                }
314                catch (PortletRequestBindingException ex) {
315                        return defaultVal;
316                }
317        }
318
319        /**
320         * Get an array of double parameters, return an empty array if not found.
321         * @param request current portlet request
322         * @param name the name of the parameter with multiple possible values
323         */
324        public static double[] getDoubleParameters(PortletRequest request, String name) {
325                try {
326                        return getRequiredDoubleParameters(request, name);
327                }
328                catch (PortletRequestBindingException ex) {
329                        return new double[0];
330                }
331        }
332
333        /**
334         * Get a double parameter, throwing an exception if it isn't found or isn't a number.
335         * @param request current portlet request
336         * @param name the name of the parameter
337         * @throws PortletRequestBindingException a subclass of PortletException,
338         * so it doesn't need to be caught
339         */
340        public static double getRequiredDoubleParameter(PortletRequest request, String name)
341                        throws PortletRequestBindingException {
342
343                return DOUBLE_PARSER.parseDouble(name, request.getParameter(name));
344        }
345
346        /**
347         * Get an array of double parameters, throwing an exception if not found or one is not a number.
348         * @param request current portlet request
349         * @param name the name of the parameter with multiple possible values
350         * @throws PortletRequestBindingException a subclass of PortletException,
351         * so it doesn't need to be caught
352         */
353        public static double[] getRequiredDoubleParameters(PortletRequest request, String name)
354                        throws PortletRequestBindingException {
355
356                return DOUBLE_PARSER.parseDoubles(name, request.getParameterValues(name));
357        }
358
359
360        /**
361         * Get a Boolean parameter, or {@code null} if not present.
362         * Throws an exception if it the parameter value isn't a boolean.
363         * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true;
364         * treats every other non-empty value as false (i.e. parses leniently).
365         * @param request current portlet request
366         * @param name the name of the parameter
367         * @return the Boolean value, or {@code null} if not present
368         * @throws PortletRequestBindingException a subclass of PortletException,
369         * so it doesn't need to be caught
370         */
371        public static Boolean getBooleanParameter(PortletRequest request, String name)
372                        throws PortletRequestBindingException {
373
374                if (request.getParameter(name) == null) {
375                        return null;
376                }
377                return (getRequiredBooleanParameter(request, name));
378        }
379
380        /**
381         * Get a boolean parameter, with a fallback value. Never throws an exception.
382         * Can pass a distinguished value as default to enable checks of whether it was supplied.
383         * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true;
384         * treats every other non-empty value as false (i.e. parses leniently).
385         * @param request current portlet request
386         * @param name the name of the parameter
387         * @param defaultVal the default value to use as fallback
388         */
389        public static boolean getBooleanParameter(PortletRequest request, String name, boolean defaultVal) {
390                if (request.getParameter(name) == null) {
391                        return defaultVal;
392                }
393                try {
394                        return getRequiredBooleanParameter(request, name);
395                }
396                catch (PortletRequestBindingException ex) {
397                        return defaultVal;
398                }
399        }
400
401        /**
402         * Get an array of boolean parameters, return an empty array if not found.
403         * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true;
404         * treats every other non-empty value as false (i.e. parses leniently).
405         * @param request current portlet request
406         * @param name the name of the parameter with multiple possible values
407         */
408        public static boolean[] getBooleanParameters(PortletRequest request, String name) {
409                try {
410                        return getRequiredBooleanParameters(request, name);
411                }
412                catch (PortletRequestBindingException ex) {
413                        return new boolean[0];
414                }
415        }
416
417        /**
418         * Get a boolean parameter, throwing an exception if it isn't found
419         * or isn't a boolean.
420         * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true;
421         * treats every other non-empty value as false (i.e. parses leniently).
422         * @param request current portlet request
423         * @param name the name of the parameter
424         * @throws PortletRequestBindingException a subclass of PortletException,
425         * so it doesn't need to be caught
426         */
427        public static boolean getRequiredBooleanParameter(PortletRequest request, String name)
428                        throws PortletRequestBindingException {
429
430                return BOOLEAN_PARSER.parseBoolean(name, request.getParameter(name));
431        }
432
433        /**
434         * Get an array of boolean parameters, throwing an exception if not found
435         * or one isn't a boolean.
436         * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true;
437         * treats every other non-empty value as false (i.e. parses leniently).
438         * @param request current portlet request
439         * @param name the name of the parameter
440         * @throws PortletRequestBindingException a subclass of PortletException,
441         * so it doesn't need to be caught
442         */
443        public static boolean[] getRequiredBooleanParameters(PortletRequest request, String name)
444                        throws PortletRequestBindingException {
445
446                return BOOLEAN_PARSER.parseBooleans(name, request.getParameterValues(name));
447        }
448
449
450        /**
451         * Get a String parameter, or {@code null} if not present.
452         * Throws an exception if it the parameter value is empty.
453         * @param request current portlet request
454         * @param name the name of the parameter
455         * @return the String value, or {@code null} if not present
456         * @throws PortletRequestBindingException a subclass of PortletException,
457         * so it doesn't need to be caught
458         */
459        public static String getStringParameter(PortletRequest request, String name)
460                        throws PortletRequestBindingException {
461
462                if (request.getParameter(name) == null) {
463                        return null;
464                }
465                return getRequiredStringParameter(request, name);
466        }
467
468        /**
469         * Get a String parameter, with a fallback value. Never throws an exception.
470         * Can pass a distinguished value to default to enable checks of whether it was supplied.
471         * @param request current portlet request
472         * @param name the name of the parameter
473         * @param defaultVal the default value to use as fallback
474         */
475        public static String getStringParameter(PortletRequest request, String name, String defaultVal) {
476                String val = request.getParameter(name);
477                return (val != null ? val : defaultVal);
478        }
479
480        /**
481         * Get an array of String parameters, return an empty array if not found.
482         * @param request current portlet request
483         * @param name the name of the parameter with multiple possible values
484         */
485        public static String[] getStringParameters(PortletRequest request, String name) {
486                try {
487                        return getRequiredStringParameters(request, name);
488                }
489                catch (PortletRequestBindingException ex) {
490                        return new String[0];
491                }
492        }
493
494        /**
495         * Get a String parameter, throwing an exception if it isn't found or is empty.
496         * @param request current portlet request
497         * @param name the name of the parameter
498         * @throws PortletRequestBindingException a subclass of PortletException,
499         * so it doesn't need to be caught
500         */
501        public static String getRequiredStringParameter(PortletRequest request, String name)
502                        throws PortletRequestBindingException {
503
504                return STRING_PARSER.validateRequiredString(name, request.getParameter(name));
505        }
506
507        /**
508         * Get an array of String parameters, throwing an exception if not found or one is empty.
509         * @param request current portlet request
510         * @param name the name of the parameter
511         * @throws PortletRequestBindingException a subclass of PortletException,
512         * so it doesn't need to be caught
513         */
514        public static String[] getRequiredStringParameters(PortletRequest request, String name)
515                        throws PortletRequestBindingException {
516
517                return STRING_PARSER.validateRequiredStrings(name, request.getParameterValues(name));
518        }
519
520
521        private abstract static class ParameterParser<T> {
522
523                protected final T parse(String name, String parameter) throws PortletRequestBindingException {
524                        validateRequiredParameter(name, parameter);
525                        try {
526                                return doParse(parameter);
527                        }
528                        catch (NumberFormatException ex) {
529                                throw new PortletRequestBindingException(
530                                                "Required " + getType() + " parameter '" + name + "' with value of '" +
531                                                parameter + "' is not a valid number", ex);
532                        }
533                }
534
535                protected final void validateRequiredParameter(String name, Object parameter)
536                                throws PortletRequestBindingException {
537
538                        if (parameter == null) {
539                                throw new MissingPortletRequestParameterException(name, getType());
540                        }
541                }
542
543                protected abstract String getType();
544
545                protected abstract T doParse(String parameter) throws NumberFormatException;
546        }
547
548
549        private static class IntParser extends ParameterParser<Integer> {
550
551                @Override
552                protected String getType() {
553                        return "int";
554                }
555
556                @Override
557                protected Integer doParse(String s) throws NumberFormatException {
558                        return Integer.valueOf(s);
559                }
560
561                public int parseInt(String name, String parameter) throws PortletRequestBindingException {
562                        return parse(name, parameter);
563                }
564
565                public int[] parseInts(String name, String[] values) throws PortletRequestBindingException {
566                        validateRequiredParameter(name, values);
567                        int[] parameters = new int[values.length];
568                        for (int i = 0; i < values.length; i++) {
569                                parameters[i] = parseInt(name, values[i]);
570                        }
571                        return parameters;
572                }
573        }
574
575
576        private static class LongParser extends ParameterParser<Long> {
577
578                @Override
579                protected String getType() {
580                        return "long";
581                }
582
583                @Override
584                protected Long doParse(String parameter) throws NumberFormatException {
585                        return Long.valueOf(parameter);
586                }
587
588                public long parseLong(String name, String parameter) throws PortletRequestBindingException {
589                        return parse(name, parameter);
590                }
591
592                public long[] parseLongs(String name, String[] values) throws PortletRequestBindingException {
593                        validateRequiredParameter(name, values);
594                        long[] parameters = new long[values.length];
595                        for (int i = 0; i < values.length; i++) {
596                                parameters[i] = parseLong(name, values[i]);
597                        }
598                        return parameters;
599                }
600        }
601
602
603        private static class FloatParser extends ParameterParser<Float> {
604
605                @Override
606                protected String getType() {
607                        return "float";
608                }
609
610                @Override
611                protected Float doParse(String parameter) throws NumberFormatException {
612                        return Float.valueOf(parameter);
613                }
614
615                public float parseFloat(String name, String parameter) throws PortletRequestBindingException {
616                        return parse(name, parameter);
617                }
618
619                public float[] parseFloats(String name, String[] values) throws PortletRequestBindingException {
620                        validateRequiredParameter(name, values);
621                        float[] parameters = new float[values.length];
622                        for (int i = 0; i < values.length; i++) {
623                                parameters[i] = parseFloat(name, values[i]);
624                        }
625                        return parameters;
626                }
627        }
628
629
630        private static class DoubleParser extends ParameterParser<Double> {
631
632                @Override
633                protected String getType() {
634                        return "double";
635                }
636
637                @Override
638                protected Double doParse(String parameter) throws NumberFormatException {
639                        return Double.valueOf(parameter);
640                }
641
642                public double parseDouble(String name, String parameter) throws PortletRequestBindingException {
643                        return parse(name, parameter);
644                }
645
646                public double[] parseDoubles(String name, String[] values) throws PortletRequestBindingException {
647                        validateRequiredParameter(name, values);
648                        double[] parameters = new double[values.length];
649                        for (int i = 0; i < values.length; i++) {
650                                parameters[i] = parseDouble(name, values[i]);
651                        }
652                        return parameters;
653                }
654        }
655
656
657        private static class BooleanParser extends ParameterParser<Boolean> {
658
659                @Override
660                protected String getType() {
661                        return "boolean";
662                }
663
664                @Override
665                protected Boolean doParse(String parameter) throws NumberFormatException {
666                        return (parameter.equalsIgnoreCase("true") || parameter.equalsIgnoreCase("on") ||
667                                        parameter.equalsIgnoreCase("yes") || parameter.equals("1"));
668                }
669
670                public boolean parseBoolean(String name, String parameter) throws PortletRequestBindingException {
671                        return parse(name, parameter);
672                }
673
674                public boolean[] parseBooleans(String name, String[] values) throws PortletRequestBindingException {
675                        validateRequiredParameter(name, values);
676                        boolean[] parameters = new boolean[values.length];
677                        for (int i = 0; i < values.length; i++) {
678                                parameters[i] = parseBoolean(name, values[i]);
679                        }
680                        return parameters;
681                }
682        }
683
684
685        private static class StringParser extends ParameterParser<String> {
686
687                @Override
688                protected String getType() {
689                        return "string";
690                }
691
692                @Override
693                protected String doParse(String parameter) throws NumberFormatException {
694                        return parameter;
695                }
696
697                public String validateRequiredString(String name, String value) throws PortletRequestBindingException {
698                        validateRequiredParameter(name, value);
699                        return value;
700                }
701
702                public String[] validateRequiredStrings(String name, String[] values) throws PortletRequestBindingException {
703                        validateRequiredParameter(name, values);
704                        for (String value : values) {
705                                validateRequiredParameter(name, value);
706                        }
707                        return values;
708                }
709        }
710
711}