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