1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 or later
5    * as published by the Free Software Foundation. This program is distributed
6    * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7    * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *      http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * © CrossWire Bible Society, 2008 - 2016
18   *
19   */
20  package org.crosswire.common.util;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.util.Enumeration;
26  import java.util.LinkedHashMap;
27  import java.util.Properties;
28  
29  
30  /**
31   * A PropertyMap is a Map<String,String> sitting over top a Property file.
32   * As such it must be defined in the same way as a java.util.Properties expects.
33   *
34   * @see java.util.Properties
35   * @see gnu.lgpl.License The GNU Lesser General Public License for details.
36   * @author DM Smith
37   */
38  public class PropertyMap extends LinkedHashMap<String, String> {
39      /**
40       * Creates an empty property list with no default values.
41       */
42      public PropertyMap() {
43          this(null);
44      }
45  
46      /**
47       * Creates an empty property map with the specified defaults.
48       *
49       * @param   defaults   the defaults.
50       */
51      public PropertyMap(PropertyMap defaults) {
52          this.defaults = defaults;
53      }
54  
55      /**
56       * Searches for the property with the specified key in this property list.
57       * If the key is not found in this property list, the default property list,
58       * and its defaults, recursively, are then checked. The method returns
59       * <code>null</code> if the property is not found.
60       *
61       * @param   key   the lookup key.
62       * @return  the value in this property list with the specified key value.
63       * @see     java.util.Properties#setProperty
64       */
65      public String get(String key) {
66          String value = super.get(key);
67          return ((value == null) && (defaults != null)) ? defaults.get(key) : value;
68      }
69  
70      /**
71       * Searches for the property with the specified key in this property list.
72       * If the key is not found in this property list, the default property list,
73       * and its defaults, recursively, are then checked. The method returns the
74       * default value argument if the property is not found.
75       *
76       * @param   key            the lookup key.
77       * @param   defaultValue   a default value.
78       *
79       * @return  the value in this property list with the specified key value.
80       * @see     java.util.Properties#setProperty
81       */
82      public String get(String key, String defaultValue) {
83          String value = get(key);
84          return value == null ? defaultValue : value;
85      }
86  
87      /**
88       * Reads a property list (key and element pairs) from the input
89       * byte stream. The input stream is in a simple line-oriented
90       * format as specified in
91       * {@link java.util.Properties#load(java.io.InputStream) load(InputStream)} and is assumed to use
92       * the ISO 8859-1 character encoding; that is each byte is one Latin1
93       * character. Characters not in Latin1, and certain special characters,
94       * are represented in keys and elements using
95       * <a href="http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.3">Unicode escapes</a>.
96       * <p>
97       * The specified stream remains open after this method returns.
98       *
99       * @param      inStream   the input stream.
100      * @exception  IOException  if an error occurred when reading from the
101      *             input stream.
102      * @throws     IllegalArgumentException if the input stream contains a
103      *         malformed Unicode escape sequence.
104      * @since 1.2
105      */
106     public void load(InputStream inStream) throws IOException {
107         Properties prop = new Properties();
108         prop.load(inStream);
109         for (Enumeration<Object> e = prop.keys(); e.hasMoreElements(); ) {
110             Object k = e.nextElement();
111             Object v = prop.get(k);
112             if (k instanceof String && v instanceof String) {
113                 put((String) k, (String) v);
114             }
115         }
116     }
117 
118     /**
119      * Writes this property list (key and element pairs) in this
120      * <code>PropertyMap</code> table to the output stream in a format suitable
121      * for loading into a <code>PropertyMap</code> table using the
122      * {@link #load(InputStream) load(InputStream)} method.
123      * <p>
124      * Properties from the defaults table of this <code>PropertyMap</code>
125      * table (if any) are <i>not</i> written out by this method.
126      * <p>
127      * This method outputs the comments, properties keys and values in 
128      * the same format as specified in
129      * {@link java.util.Properties#store(java.io.OutputStream, java.lang.String) store(Writer)},
130      * <p>
131      * After the entries have been written, the output stream is flushed.  
132      * The output stream remains open after this method returns.
133      * <p>
134      * @param   out      an output stream.
135      * @param   comments   a description of the property list.
136      * @exception  IOException if writing this property list to the specified
137      *             output stream throws an <tt>IOException</tt>.
138      * @exception  NullPointerException  if <code>out</code> is null.
139      * @since 1.2
140      */
141     public void store(OutputStream out, String comments) throws IOException {
142         Properties temp = new Properties();
143         temp.putAll(this);
144         temp.store(out, comments);
145     }
146 
147     /**
148      * Default values for any keys not found in this property map.
149      */
150     private PropertyMap defaults;
151 
152     /**
153      * Serialization ID
154      */
155     private static final long serialVersionUID = 2821277155924802795L;
156 }
157