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    }