001 package org.apache.ojb.broker.util.configuration.impl;
002
003 /* Copyright 2002-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import org.apache.ojb.broker.metadata.MetadataException;
019 import org.apache.ojb.broker.util.configuration.Configuration;
020 import org.apache.ojb.broker.util.logging.Logger;
021 import org.apache.ojb.broker.util.logging.LoggerFactory;
022 import org.apache.ojb.broker.util.ClassHelper;
023
024 import java.io.File;
025 import java.io.FileNotFoundException;
026 import java.io.InputStream;
027 import java.net.URL;
028 import java.net.URLConnection;
029 import java.util.Properties;
030 import java.util.StringTokenizer;
031
032 /**
033 * Configuration Base Class that
034 * keeps a Properties based configuration persistent in a file.
035 * This class provides only basic infrastructure for loading etc.
036 *
037 * @author Thomas Mahler
038 * @version $Id: ConfigurationAbstractImpl.java,v 1.1 2007-08-24 22:17:42 ewestfal Exp $
039 */
040 public abstract class ConfigurationAbstractImpl implements Configuration
041 {
042 /**the logger used in this class.*/
043 private Logger logger = LoggerFactory.getBootLogger();
044
045 /**the name of the properties file*/
046 protected String filename;
047
048 /**the properties object holding the configuration data*/
049 protected Properties properties;
050
051 /**
052 * Contains all legal values for boolean configuration entries that represent
053 * <code>true</code>.
054 */
055 private String[] trueValues = {"true", "yes", "1"};
056 /**
057 * Contains all legal values for boolean configuration entries that represent
058 * <code>false</code>.
059 */
060 private String[] falseValues = {"false", "no", "0"};
061
062 /**
063 * The constructor loads the configuration from file
064 */
065 public ConfigurationAbstractImpl()
066 {
067 load();
068 }
069
070 /**
071 * Returns the string value for the specified key. If no value for this key
072 * is found in the configuration <code>defaultValue</code> is returned.
073 *
074 * @param key the key
075 * @param defaultValue the default value
076 * @return the value for the key, or <code>defaultValue</code>
077 */
078 public String getString(String key, String defaultValue)
079 {
080 String ret = properties.getProperty(key);
081 if (ret == null)
082 {
083 if(defaultValue == null)
084 {
085 logger.info("No value for key '" + key + "'");
086 }
087 else
088 {
089 logger.debug("No value for key \"" + key + "\", using default \""
090 + defaultValue + "\".");
091 properties.put(key, defaultValue);
092 }
093
094 ret = defaultValue;
095 }
096
097 return ret;
098 }
099
100 /**
101 * Gets an array of Strings from the value of the specified key, seperated
102 * by any key from <code>seperators</code>. If no value for this key
103 * is found the array contained in <code>defaultValue</code> is returned.
104 *
105 * @param key the key
106 * @param defaultValue the default Value
107 * @param seperators the seprators to be used
108 * @return the strings for the key, or the strings contained in <code>defaultValue</code>
109 *
110 * @see StringTokenizer
111 */
112 public String[] getStrings(String key, String defaultValue, String seperators)
113 {
114 StringTokenizer st = new StringTokenizer(getString(key, defaultValue), seperators);
115 String[] ret = new String[st.countTokens()];
116 for (int i = 0; i < ret.length; i++)
117 {
118 ret[i] = st.nextToken();
119 }
120 return ret;
121 }
122
123 /**
124 * Gets an array of Strings from the value of the specified key, seperated
125 * by ";". If no value for this key
126 * is found the array contained in <code>defaultValue</code> is returned.
127 *
128 * @param key the key
129 * @param defaultValue the default Value
130 * @return the strings for the key, or the strings contained in <code>defaultValue</code>
131 */
132 public String[] getStrings(String key, String defaultValue)
133 {
134 return getStrings(key, defaultValue, ";");
135 }
136
137 /**
138 * Returns the integer value for the specified key. If no value for this key
139 * is found in the configuration or the value is not an legal integer
140 * <code>defaultValue</code> is returned.
141 *
142 * @param key the key
143 * @param defaultValue the default Value
144 * @return the value for the key, or <code>defaultValue</code>
145 */
146 public int getInteger(String key, int defaultValue)
147 {
148 int ret;
149 try
150 {
151 String tmp = properties.getProperty(key);
152 if (tmp == null)
153 {
154 properties.put(key, String.valueOf(defaultValue));
155 logger.debug("No value for key \"" + key + "\", using default "
156 + defaultValue + ".");
157 return defaultValue;
158 }
159 ret = Integer.parseInt(tmp);
160 }
161 catch (NumberFormatException e)
162 {
163 Object wrongValue = properties.put(key, String.valueOf(defaultValue));
164 logger.warn(
165 "Value \""
166 + wrongValue
167 + "\" is illegal for key \""
168 + key
169 + "\" (should be an integer, using default value "
170 + defaultValue
171 + ")");
172 ret = defaultValue;
173 }
174 return ret;
175 }
176
177 public long getLong(String key, long defaultValue)
178 {
179 long ret;
180 try
181 {
182 String tmp = properties.getProperty(key);
183 if (tmp == null)
184 {
185 properties.put(key, String.valueOf(defaultValue));
186 logger.debug("No value for key \"" + key + "\", using default "
187 + defaultValue + ".");
188 return defaultValue;
189 }
190 ret = Long.parseLong(tmp);
191 }
192 catch (NumberFormatException e)
193 {
194 Object wrongValue = properties.put(key, String.valueOf(defaultValue));
195 logger.warn(
196 "Value \""
197 + wrongValue
198 + "\" is illegal for key \""
199 + key
200 + "\" (should be an integer, using default value "
201 + defaultValue
202 + ")");
203 ret = defaultValue;
204 }
205 return ret;
206 }
207
208 public byte getByte(String key, byte defaultValue)
209 {
210 byte ret;
211 try
212 {
213 String tmp = properties.getProperty(key);
214 if (tmp == null)
215 {
216 properties.put(key, String.valueOf(defaultValue));
217 logger.debug("No value for key \"" + key + "\", using default "
218 + defaultValue + ".");
219 return defaultValue;
220 }
221 ret = Byte.parseByte(tmp);
222 }
223 catch (NumberFormatException e)
224 {
225 Object wrongValue = properties.put(key, String.valueOf(defaultValue));
226 logger.warn(
227 "Value \""
228 + wrongValue
229 + "\" is illegal for key \""
230 + key
231 + "\" (should be an integer, using default value "
232 + defaultValue
233 + ")");
234 ret = defaultValue;
235 }
236 return ret;
237 }
238
239 /**
240 * Returns the boolean value for the specified key. If no value for this key
241 * is found in the configuration or the value is not an legal boolean
242 * <code>defaultValue</code> is returned.
243 *
244 * @see #trueValues
245 * @see #falseValues
246 *
247 * @param key the key
248 * @param defaultValue the default Value
249 * @return the value for the key, or <code>defaultValue</code>
250 */
251 public boolean getBoolean(String key, boolean defaultValue)
252 {
253 String tmp = properties.getProperty(key);
254
255 if (tmp == null)
256 {
257 logger.debug("No value for key \"" + key + "\", using default "
258 + defaultValue + ".");
259 properties.put(key, String.valueOf(defaultValue));
260 return defaultValue;
261 }
262
263 for (int i = 0; i < trueValues.length; i++)
264 {
265 if (tmp.equalsIgnoreCase(trueValues[i]))
266 {
267 return true;
268 }
269 }
270
271 for (int i = 0; i < falseValues.length; i++)
272 {
273 if (tmp.equalsIgnoreCase(falseValues[i]))
274 {
275 return false;
276 }
277 }
278
279 logger.warn(
280 "Value \""
281 + tmp
282 + "\" is illegal for key \""
283 + key
284 + "\" (should be a boolean, using default value "
285 + defaultValue
286 + ")");
287 return defaultValue;
288 }
289
290 /**
291 * Returns the class specified by the value for the specified key. If no
292 * value for this key is found in the configuration, no class of this name
293 * can be found or the specified class is not assignable to each
294 * class/interface in <code>assignables defaultValue</code> is returned.
295 *
296 * @param key the key
297 * @param defaultValue the default Value
298 * @param assignables classes and/or interfaces the specified class must
299 * extend/implement.
300 * @return the value for the key, or <code>defaultValue</code>
301 */
302 public Class getClass(String key, Class defaultValue, Class[] assignables)
303 {
304 String className = properties.getProperty(key);
305
306 if (className == null)
307 {
308 if (defaultValue == null)
309 {
310 logger.info("No value for key '" + key + "'");
311 return null;
312 }
313 else
314 {
315 className = defaultValue.getName();
316 properties.put(key, className);
317 logger.debug("No value for key \"" + key + "\", using default "
318 + className + ".");
319 return defaultValue;
320 }
321 }
322
323 Class clazz = null;
324 try
325 {
326 clazz = ClassHelper.getClass(className);
327 }
328 catch (ClassNotFoundException e)
329 {
330 clazz = defaultValue;
331 logger.warn(
332 "Value \""
333 + className
334 + "\" is illegal for key \""
335 + key
336 + "\" (should be a class, using default value "
337 + defaultValue
338 + ")", e);
339 }
340
341 for (int i = 0; i < assignables.length; i++)
342 {
343 Class assignable = assignables[i];
344 if (!assignable.isAssignableFrom(clazz))
345 {
346 String extendsOrImplements;
347 if (assignable.isInterface())
348 {
349 extendsOrImplements = "implement the interface ";
350 }
351 else
352 {
353 extendsOrImplements = "extend the class ";
354
355 }
356 logger.error(
357 "The specified class \""
358 + className
359 + "\" does not "
360 + extendsOrImplements
361 + assignables[i].getName()
362 + ", which is a requirement for the key \""
363 + key
364 + "\". Using default class "
365 + defaultValue);
366 clazz = defaultValue;
367 }
368
369 }
370
371 return clazz;
372 }
373
374 /**
375 * Returns the class specified by the value for the specified key. If no
376 * value for this key is found in the configuration, no class of this name
377 * can be found or the specified class is not assignable <code>assignable
378 * defaultValue</code> is returned.
379 *
380 * @param key the key
381 * @param defaultValue the default Value
382 * @param assignable a classe and/or interface the specified class must
383 * extend/implement.
384 * @return the value for the key, or <code>defaultValue</code>
385 */
386 public Class getClass(String key, Class defaultValue, Class assignable)
387 {
388 return getClass(key, defaultValue, new Class[]{assignable});
389 }
390
391 /**
392 * Returns the class specified by the value for the specified key. If no
393 * value for this key is found in the configuration or no class of this name
394 * can be found <code>defaultValue</code> is returned.
395 *
396 * @param key the key
397 * @param defaultValue the default Value
398 * @return the value for the key, or <code>defaultValue</code>
399 */
400 public Class getClass(String key, Class defaultValue)
401 {
402 return getClass(key, defaultValue, new Class[0]);
403 }
404
405 /**
406 * Loads the Configuration from the properties file.
407 *
408 * Loads the properties file, or uses defaults on failure.
409 *
410 * @see org.apache.ojb.broker.util.configuration.impl.ConfigurationAbstractImpl#setFilename(java.lang.String)
411 *
412 */
413 protected void load()
414 {
415 properties = new Properties();
416
417 String filename = getFilename();
418
419 try
420 {
421 URL url = ClassHelper.getResource(filename);
422
423 if (url == null)
424 {
425 url = (new File(filename)).toURL();
426 }
427
428 logger.info("Loading OJB's properties: " + url);
429
430 URLConnection conn = url.openConnection();
431 conn.setUseCaches(false);
432 conn.connect();
433 InputStream strIn = conn.getInputStream();
434 properties.load(strIn);
435 strIn.close();
436 }
437 catch (FileNotFoundException ex)
438 {
439 // [tomdz] If the filename is explicitly reset (null or empty string) then we'll
440 // output an info message because the user did this on purpose
441 // Otherwise, we'll output a warning
442 if ((filename == null) || (filename.length() == 0))
443 {
444 logger.info("Starting OJB without a properties file. OJB is using default settings instead.");
445 }
446 else
447 {
448 logger.warn("Could not load properties file '"+filename+"'. Using default settings!", ex);
449 }
450 // [tomdz] There seems to be no use of this setting ?
451 //properties.put("valid", "false");
452 }
453 catch (Exception ex)
454 {
455 throw new MetadataException("An error happend while loading the properties file '"+filename+"'", ex);
456 }
457 }
458
459 private String getFilename()
460 {
461 if (filename == null)
462 {
463 filename = this.getClass().getName() + ".properties";
464 }
465 return filename;
466 }
467
468 protected void setFilename(String name)
469 {
470 filename = name;
471 }
472
473 /**
474 * @see Configuration#setLogger(Logger)
475 */
476 public void setLogger(Logger loggerInstance)
477 {
478 logger = loggerInstance;
479 }
480
481 }