001 // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org)
002 // The Molly framework is freely distributable under the terms of an
003 // MIT-style license. For details, see the molly pages web site at:
004 // http://www.mollypages.org/. Use, modify, have fun !
005
006 package fc.util;
007
008 import java.io.*;
009 import fc.io.*;
010
011 /**
012 Implementations help load and manage properties from various
013 sources including java property files, databases, custom
014 file formats etc. Regardless of where the properties are
015 loaded from, each property consists of a pair of <b>name</b>
016 and <b>value</b> strings.
017
018 @author hursh jain
019 @version 1.0 12/30/2001
020 */
021 public abstract class PropertyMgr
022 {
023 protected String usage;
024 protected Log log;
025
026 /**
027 Constructs a new PropertyMgr.
028 **/
029 public PropertyMgr() {
030 this.log = Log.getDefault();
031 }
032
033 /**
034 Returns the property associated with the specified key or <tt>null</tt>
035 if the property was not found.
036 @param name the property key
037 **/
038 public abstract String get(String name);
039
040
041 /**
042 Returns the property associated with the specified key.
043 @param name the property key
044 @param backup value to return if the property for the specified key is not found
045
046 @return value of specified key or backup string
047 **/
048 public String get(String name, String backup)
049 {
050 String val = get(name);
051 if (val == null)
052 {
053 return backup;
054 }
055 else return val;
056 }
057
058 /**
059 Returns the property associated with the specified key as a
060 boolean value. If the property <b>is</b> present, then the
061 corresponding boolean value is <tt>true</tt> if the property
062 value is any of the following (case-insensitive):
063 <blockquote>
064 <code>
065 yes, 1, true
066 </code>
067 <blockquote>
068 else <tt>false</tt> is returned.
069
070 @param name the property key
071 @param backup value to return if the property for the
072 specified property is <b>not</b> present
073
074 @return value of specified key or backup string
075 */
076 public boolean getBoolean(String name, boolean backup)
077 {
078 String val = get(name);
079 if (val == null)
080 return backup;
081 else
082 return toBoolean(val);
083 }
084
085 /**
086 Returns the property associated with the specified key as a
087 integer value. If the property is present but cannot be
088 converted into an integer (via a {@link
089 Integer.parseInt(String)} call), the backup value will be
090 returned.
091
092 @param name the property key
093 @param backup value to return if the property for the
094 specified property is <b>not</b> present
095
096 @return value of specified key or backup string
097 */
098 public int getInt(String name, int backup)
099 {
100 String val = get(name);
101 if (val != null)
102 {
103 try {
104 return Integer.parseInt(val);
105 }
106 catch (NumberFormatException e) {
107 log.warn("Cannot convert property '" + name + "', into a number, returning backup value " + backup);
108 }
109 }
110 return backup;
111 }
112
113 /**
114 Returns the value corresponding to the specified key. If the
115 property <b>value</b> is not found, the {@link #handleError} method
116 is called, which by default prints a stack trace and exits
117 the application.
118 <p>
119 If the handleError method is overriden to <b>not</b> exit
120 the application, then this method will return <tt>null</tt>
121 if the specified key is not found.
122
123 @param name the property key
124 **/
125 public String getRequired(String name)
126 {
127 String val = get(name);
128 if (val == null || val.trim().length() == 0) {
129 try {
130 handleError(name);
131 }
132 catch (Exception e) {
133 /*
134 If the handler throws us an Exception, we pass
135 it along as a Runtime Exception (since this
136 method does not throw a checked exception). Of
137 course, handlers are free to deal with
138 Exceptions in any other way they see fit.
139 */
140 throw new RuntimeException(e);
141 }
142 }
143 return val;
144 }
145
146 /*
147 Returns the value obtained via {@link getRequired(String)}
148 as as a boolean. The boolean value returned is
149 <code>true</code> if the property value is any of the
150 following (case-insensitive):
151 <blockquote>
152 <code>
153 yes, 1, true
154 </code>
155 <blockquote>
156 else <tt>false</tt> is returned.
157 */
158 public boolean getRequiredBoolean(String name)
159 {
160 String val = getRequired(name);
161 return toBoolean(val);
162 }
163
164 /*
165 Returns the value obtained via {@link getRequired(String)} as
166 as an integer. If the property cannot be converted into an integer (via a {@link
167 Integer.parseInt(String)} call), the resulting action would
168 be the same as if the required key was not present.
169 */
170 public int getRequiredInt(String name)
171 {
172 String val = getRequired(name);
173
174 int result = 0;
175
176 try {
177 result = Integer.parseInt(val);
178 }
179 catch (NumberFormatException ne) {
180 log.warn("Cannot convert property '" + name + "', into a number");
181 try {
182 handleError(name);
183 }
184 catch (Exception e) {
185 /*
186 If the handler throws us an Exception, we pass
187 it along as a Runtime Exception (since this
188 method does not throw a checked exception). Of
189 course, handlers are free to deal with
190 Exceptions in any other way they see fit.
191 */
192 throw new RuntimeException(e);
193 }
194 }
195
196 return result;
197 }
198
199 /**
200 Sets the property associated with the specified key.
201 @param name the property key
202 @param backup the property value
203 @return the previous value of the specified key or null if it did not
204 have one.
205 **/
206 public abstract String set(String name, String backup);
207
208 /**
209 Saves any properties that were set previously. This method does not
210 need to be called if properties were only read, however if any
211 property was modified or added, it is essential to call this method
212 to save any such changes.
213 **/
214 public abstract void save() throws IOException;
215
216 /**
217 Specify program usage information to be output when an error occurs. This
218 information should contain a short description of required keys and any
219 other information that the application expects.
220 @param str Usage information
221 **/
222 public void setUsage(String str)
223 {
224 this.usage = str;
225 }
226
227 /**
228 Default implementation:<br>
229 Handles all error situation - such as when a required property is
230 not found. By default, prints an error message to <tt>System.err</tt> and
231 exits the JVM by calling <tt>System.exit(1)</tt>.
232 This method can be overriden in subclasses to handle errors differently.
233 @param str the error message
234 @throws Exception sub classes can throw an Exception, if necessary
235 **/
236 protected void handleError(String str) throws PropertyNotFoundException
237 {
238 log.error("Application is missing required Property: " + str);
239 new Exception().printStackTrace(System.err);
240 if (usage != null) {
241 log.error(usage);
242 }
243 System.exit(1);
244 }
245
246 final boolean toBoolean(String val)
247 {
248 val = val.trim().toLowerCase().intern();
249 if ( val == "true" || val == "yes" || val == "1" )
250 return true;
251 return false;
252 }
253
254 } //~class PropertyMgr