001package com.thetransactioncompany.util;
002
003
004import java.net.MalformedURLException;
005import java.net.URL;
006import java.util.Properties;
007
008
009/**
010 * Provides typed retrieval of {@link java.util.Properties} as {@code boolean}, 
011 * {@code int}, {@code long}, {@code float}, {@code double}, 
012 * {@link java.lang.String}, {@link java.net.URL} or {@code enum} values.
013 *
014 * @author Vladimir Dzhuvinov
015 */
016public class PropertyRetriever {
017
018        
019        /** 
020         * The property hashtable to parse. 
021         */
022        private Properties props;
023
024
025        /**
026         * Creates a new retriever for the specified properties.
027         *
028         * @param props The properties hasthtable.
029         */
030        public PropertyRetriever(final Properties props) {
031        
032                this.props = props;
033        }
034        
035        
036        /**
037         * Retrieves a boolean value.
038         *
039         * @param key The property name.
040         *
041         * @return The property as a boolean value.
042         *
043         * @throws PropertyParseException On a missing or invalid property.
044         */
045        public boolean getBoolean(final String key)
046                throws PropertyParseException {
047        
048                String value = props.getProperty(key);
049                
050                if (value == null)
051                        throw new PropertyParseException("Missing property", key);
052                
053                if (value.equalsIgnoreCase("true"))
054                        return true;
055                
056                else if (value.equalsIgnoreCase("false"))
057                        return false;
058                
059                else
060                        throw new PropertyParseException("Invalid boolean property", key, value);
061        }
062        
063        
064        /**
065         * Retrieves an optional boolean value.
066         *
067         * @param key The property name.
068         * @param def The default value if the property value is undefined or
069         *            empty.
070         *
071         * @return The property as a boolean.
072         *
073         * @throws PropertyParseException On an invalid property.
074         */
075        public boolean getOptBoolean(final String key, final boolean def)
076                throws PropertyParseException {
077        
078                String value = props.getProperty(key);
079                
080                if (value == null || value.trim().isEmpty())
081                        return def;
082                
083                if (value.equalsIgnoreCase("true"))
084                        return true;
085                
086                if (value.equalsIgnoreCase("false"))
087                        return false;
088                
089                throw new PropertyParseException("Invalid boolean property", key, value);
090        }
091        
092        
093        /**
094         * Retrieves an integer value.
095         *
096         * @param key The property name.
097         *
098         * @return The property as an integer.
099         *
100         * @throws PropertyParseException On a missing or invalid property.
101         */
102        public int getInt(final String key)
103                throws PropertyParseException {
104        
105                String value = props.getProperty(key);
106                
107                if (value == null)
108                        throw new PropertyParseException("Missing property", key);
109                
110                try {
111                        return Integer.parseInt(value);
112                
113                } catch (NumberFormatException e) {
114
115                        throw new PropertyParseException("Invalid int property", key, value);
116                }
117        }
118        
119        
120        /**
121         * Retrieves an optional integer value.
122         *
123         * @param key The property name.
124         * @param def The default value if the property value is undefined or
125         *            empty.
126         *
127         * @return The property as an integer.
128         *
129         * @throws PropertyParseException On an invalid property.
130         */
131        public int getOptInt(final String key, final int def)
132                throws PropertyParseException {
133        
134                String value = props.getProperty(key);
135                
136                if (value == null || value.trim().isEmpty())
137                        return def;
138                
139                try {
140                        return Integer.parseInt(value);
141                
142                } catch (NumberFormatException e) {
143
144                        throw new PropertyParseException("Invalid int property", key);
145                }
146        }
147        
148        
149        /**
150         * Retrieves a long value.
151         *
152         * @param key The property name.
153         *
154         * @return The property as a long.
155         *
156         * @throws PropertyParseException On a missing or invalid property.
157         */
158        public long getLong(final String key)
159                throws PropertyParseException {
160        
161                String value = props.getProperty(key);
162                
163                if (value == null)
164                        throw new PropertyParseException("Missing property", key);
165                
166                try {
167                        return Long.parseLong(value);
168                
169                } catch (NumberFormatException e) {
170
171                        throw new PropertyParseException("Invalid long property", key, value);
172                }
173        }
174        
175        
176        /**
177         * Retrieves an optional long value.
178         *
179         * @param key The property name.
180         * @param def The default value if the property value is undefined or
181         *            empty.
182         *
183         * @return The property as a long.
184         *
185         * @throws PropertyParseException On an invalid property.
186         */
187        public long getOptLong(final String key, final long def)
188                throws PropertyParseException {
189        
190                String value = props.getProperty(key);
191                
192                if (value == null || value.trim().isEmpty())
193                        return def;
194                
195                try {
196                        return Long.parseLong(value);
197                
198                } catch (NumberFormatException e) {
199
200                        throw new PropertyParseException("Invalid long property", key, value);
201                }
202        }
203        
204        
205        /**
206         * Retrieves a float value.
207         *
208         * @param key The property name.
209         *
210         * @return The property as a float.
211         *
212         * @throws PropertyParseException On a missing or invalid property.
213         */
214        public float getFloat(final String key)
215                throws PropertyParseException {
216        
217                String value = props.getProperty(key);
218                
219                if (value == null)
220                        throw new PropertyParseException("Missing property", key);
221                
222                try {
223                        return Float.parseFloat(value);
224                
225                } catch (NumberFormatException e) {
226
227                        throw new PropertyParseException("Invalid float property", key, value);
228                }
229        }
230        
231        
232        /**
233         * Retrieves an optional float value.
234         *
235         * @param key The property name.
236         * @param def The default value if the property value is undefined or
237         *            empty.
238         *
239         * @return The property as a float.
240         *
241         * @throws PropertyParseException On an invalid property.
242         */
243        public float getOptFloat(final String key, final float def)
244                throws PropertyParseException {
245        
246                String value = props.getProperty(key);
247                
248                if (value == null || value.trim().isEmpty())
249                        return def;
250                
251                try {
252                        return Float.parseFloat(value);
253                
254                } catch (NumberFormatException e) {
255
256                        throw new PropertyParseException("Invalid float property", key, value);
257                }
258        }
259        
260        
261        /**
262         * Retrieves a double value.
263         *
264         * @param key The property name.
265         *
266         * @return The property as a double.
267         *
268         * @throws PropertyParseException On a missing or invalid property.
269         */
270        public double getDouble(final String key)
271                throws PropertyParseException {
272        
273                String value = props.getProperty(key);
274                
275                if (value == null)
276                        throw new PropertyParseException("Missing property", key);
277                
278                try {
279                        return Double.parseDouble(value);
280                
281                } catch (NumberFormatException e) {
282
283                        throw new PropertyParseException("Invalid double property", key, value);
284                }
285        }
286        
287        
288        /**
289         * Retrieves an optional double value.
290         *
291         * @param key The property name.
292         * @param def The default value if the property value is undefined or
293         *            empty.
294         *
295         * @return The property as a double.
296         *
297         * @throws PropertyParseException On an invalid property.
298         */
299        public double getOptDouble(final String key, final double def)
300                throws PropertyParseException {
301        
302                String value = props.getProperty(key);
303                
304                if (value == null || value.trim().isEmpty())
305                        return def;
306                
307                try {
308                        return Double.parseDouble(value);
309                
310                } catch (NumberFormatException e) {
311
312                        throw new PropertyParseException("Invalid double property", key, value);
313                }
314        }
315        
316        
317        /**
318         * Retrieves a string value.
319         *
320         * @param key The property name.
321         *
322         * @return The property as a string.
323         *
324         * @throws PropertyParseException On a missing or invalid property.
325         */
326        public String getString(final String key)
327                throws PropertyParseException {
328        
329                String value = props.getProperty(key);
330                
331                if (value == null)
332                        throw new PropertyParseException("Missing property", key);
333                
334                return value;
335        }
336        
337        
338        /**
339         * Retrieves an optional string value.
340         *
341         * @param key The property name.
342         * @param def The default value if the property value is undefined or
343         *            empty.
344         *
345         * @return The property as a string.
346         *
347         * @throws PropertyParseException On an invalid property.
348         */
349        public String getOptString(final String key, final String def)
350                throws PropertyParseException {
351        
352                String value = props.getProperty(key);
353                
354                if (value == null || value.trim().isEmpty())
355                        return def;
356                
357                return value;
358        }
359        
360        
361        /**
362         * Retrieves an enumerated string value. String case is ignored during
363         * comparison.
364         *
365         * @param key   The property name.
366         * @param enums A string array defining the acceptable values.
367         *
368         * @return The property as a string.
369         *
370         * @throws PropertyParseException On a missing or invalid property.
371         */
372        public String getEnumString(final String key, final String[] enums)
373                throws PropertyParseException {
374        
375                String value = props.getProperty(key);
376                
377                if (value == null)
378                        throw new PropertyParseException("Missing property", key);
379                
380                for (String en: enums) {
381                        
382                        if (en.equalsIgnoreCase(value))
383                                return value;
384                }
385                        
386                throw new PropertyParseException("Invalid enum string property", key, value);
387        }
388        
389        
390        /**
391         * Retrieves an enumerated string value. String case is ignored during
392         * comparison.
393         *
394         * @param key   The property name.
395         * @param enums A string array defining the acceptable values.
396         * @param def   The default value if the property value is undefined or
397         *              empty.
398         *
399         * @return The property as a string.
400         *
401         * @throws PropertyParseException On an invalid property.
402         */
403        public String getOptEnumString(final String key, final String[] enums, final String def)
404                throws PropertyParseException {
405        
406                String value = props.getProperty(key);
407                
408                if (value == null || value.trim().isEmpty())
409                        return def;
410                
411                for (String en: enums) {
412                        
413                        if (en.equalsIgnoreCase(value))
414                                return value;
415                }
416                        
417                throw new PropertyParseException("Invalid enum string property", key, value);
418        }
419        
420        
421        /**
422         * Retrieves an enumerated constant. String case is ignored during
423         * comparison.
424         *
425         * @param key       The property name.
426         * @param enumClass The enumeration class specifying the acceptable
427         *                  values.
428         *
429         * @return The matching enumerated constant.
430         *
431         * @throws PropertyParseException On a missing or invalid property.
432         */
433        public <T extends Enum<T>> T getEnum(final String key, final Class<T> enumClass)
434                throws PropertyParseException {
435                
436                String value = props.getProperty(key);
437                
438                if (value == null)
439                        throw new PropertyParseException("Missing property", key);
440                        
441                for (T en: enumClass.getEnumConstants()) {
442                
443                        if (en.toString().equalsIgnoreCase(value))
444                                return en;
445                }
446                
447                // No match? -> raise exception
448                throw new PropertyParseException("Invalid enum property", key, value);
449        }
450        
451        
452        /**
453         * Retrieves an optional enumerated constant. String case is ignored
454         * during comparison.
455         *
456         * @param key       The property name.
457         * @param enumClass The enumeration class specifying the acceptable
458         *                  values.
459         * @param def       The default value if the property value is 
460         *                  undefined or empty.
461         *
462         * @return The matching enumerated constant.
463         *
464         * @throws PropertyParseException On a missing or invalid property.
465         */
466        public <T extends Enum<T>> T getOptEnum(final String key, final Class<T> enumClass, final T def)
467                throws PropertyParseException {
468                
469                String value = props.getProperty(key);
470                
471                if (value == null || value.trim().isEmpty())
472                        return def;
473                        
474                for (T en: enumClass.getEnumConstants()) {
475                
476                        if (en.toString().equalsIgnoreCase(value))
477                                return en;
478                }
479                
480                // No match? -> raise exception
481                throw new PropertyParseException("Invalid enum property", key, value);
482        }
483
484
485        /**
486         * Retrieves a URL value.
487         *
488         * @param key The property name.
489         *
490         * @return The property as a URL.
491         *
492         * @throws PropertyParseException On a missing or invalid property.
493         */
494        public URL getURL(final String key)
495                throws PropertyParseException {
496        
497                String value = props.getProperty(key);
498                
499                if (value == null)
500                        throw new PropertyParseException("Missing property", key);
501                
502                try {
503                        return new URL(value);
504
505                } catch (MalformedURLException e) {
506
507                        throw new PropertyParseException("Invalid URL property: " + e.getMessage(), key, value);
508                }
509        }
510        
511        
512        /**
513         * Retrieves an optional URL value.
514         *
515         * @param key The property name.
516         * @param def The default value if the property value is undefined or
517         *            empty.
518         *
519         * @return The property as a URL.
520         *
521         * @throws PropertyParseException On an invalid property.
522         */
523        public URL getOptURL(final String key, final URL def)
524                throws PropertyParseException {
525        
526                String value = props.getProperty(key);
527                
528                if (value == null || value.trim().isEmpty())
529                        return def;
530                
531                try {
532                        return new URL(value);
533
534                } catch (MalformedURLException e) {
535
536                        throw new PropertyParseException("Invalid URL property: " + e.getMessage(), key, value);
537                }
538        }
539}