Eric Pugh wrote:
Hi Ricardo..  Sounds like you are working on something I've been wanting for
a long time!

Of course, I was going to release it anyway so please find the source-code attached. Not sure it belongs in commons-configration API; probably better contributed to the hibernate project. If you can think of any improvements please mail the patches back to me for my own project :)


In otherwords, say I am using a Configuration object in my code, and I do
configuration.getDouble("key");.  If getDouble throws an exception then I am
going to have these try/catch cluases all over the place, cluttering the
code.  and, I really except getDouble() to allows work.  If it doesn't, my
application will just pass it on,not have some sort of fancy if getDouble
fails, then try getString or something weird.

Good point, although I'm still dubious about throwing RuntimeExceptions - those things shoot straight through everything like a silver bullet and can even crash some servlet engines.


From my perspective, I'm not bothered if the Configuration object throws exceptions: I wouldn't catch such exceptions in my web application, instead letting them fly all the way to the exception screen. This way, I can see them occuring as I test my application through the browser.

Obviously, sometimes when configuring your application you just want your configuration to work or keep on working untill if it encounters an errors. However, simply allowing your application to ignore exceptions until they create new exception elsewhere seems like a good way to create hard-to-fix bugs. Surely, it would be better to relay the errors and let the application decide what to do with them?

I think what you can do is just wrap your HibernateException in a
ConfiguratoinRuntimeException and toss that.  JDBCConfiguration should
probably be doning the same thing.

Another alternative would be to have a getExceptions() method for all Configurations which stores exceptions occuring and stores them for later reporting. A good comprimise would be to allow all Configuration objects to have two modes: one where exceptions are thrown as soon as they occur and another one which stores exceptions as I suggested.


Kind regards,
-- Ricardo Gladwell

-----Original Message-----
From: Ricardo Gladwell [mailto:[EMAIL PROTECTED]
Sent: Wednesday, October 06, 2004 12:56 PM
To: Jakarta Commons Developers List
Subject: [configuration] handling exceptions in AbstractConfiguration
implementations


Hi All,

I'm currently developing a sub-class of the AbstractConfiguration
classthat uses Hibernate to access configuration properties
(unimaginatively called Hibernate Configuration). I'm slightly concerned
about the way sub-classes are suposed to handle exceptions:

All the abstract method are defined as not throwing exceptions. All
calls to hibernate, however, throw HibernateExceptions. So, for example,
my implementation of getPropertyDirect calls the hibernate Session.get()
method which can throw an exception.

Looking at your implementation of the DatabaseConfiguration I can see
that it simply consumes SQLExceptions thrown from the JDBC API, logging
the stack trace. However, what if you want to be warned of exceptions
being thrown by the underlying implementation of Configuration?

I notice you already have a nestable ConfigurationException implemented.
Surely, all Configuration methods should indicate they will throw this
exception if they are expected to read/write data?

Also, the AbstractConfiguration class does not describe this contract
(logging all errors throw by underlying framework) or what should be
returned in the event of an error? I assume you should return null
values but this is not described anywhere.

Kind regards,
-- Ricardo Gladwell
package net.sf.jexus.server.components;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.Iterator;
import java.util.List;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;
import net.sf.jexus.server.data.object.ConfigurationProperty;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.configuration.AbstractConfiguration;

/**
 * <p>Hibernate configuation class. Reads configuration infomation from a
 * database through the <a href="http://www.hibernate.org/";>Hibernate</a>
 * O/R mapping API. Data is stored as name-value pairs, along with the class
 * information of data stored, using the mapping* defined by the
 * [EMAIL PROTECTED] ConfigurationProperty} POJO hibernate xdoclet directives. Values 
are
 * converted to and from strings using 
 * [EMAIL PROTECTED] org.apache.commons.beanutils.ConvertUtils}.</p>
 * 
 * @author <a href="mailto:[EMAIL PROTECTED]">Ricardo Gladwell</a>
 */
public class HibernateConfiguration extends AbstractConfiguration {

    /**
     * Logger for this class
     */
    private static final Log log = LogFactory.getLog(HibernateConfiguration.class);

    /**
     * Reference to the session factory.
     */
    Session session;

    /**
     * 
     */
    class KeyIterator implements Iterator {

        Iterator iterator;
        String last;

        public KeyIterator(Iterator iterator) throws HibernateException {
            this.iterator = iterator;
        }

        /**
         * @see java.util.Iterator#hasNext()
         */
        public boolean hasNext() {
            return iterator.hasNext();
        }

        /**
         * @see java.util.Iterator#next()
         */
        public Object next() {
            ConfigurationProperty config = (ConfigurationProperty)iterator.next();
            String key = config.getName();
            last = key;
            return key;
        }

        /**
         * @see java.util.Iterator#remove()
         */
        public void remove() {
            clearProperty(last);
        }

    }

    /**
     * 
     */
    public HibernateConfiguration(Session session) {
        super();
        if(log.isTraceEnabled()) log.trace("HibernateConfiguration()");
        this.session = session;
    }

    /**
     * @see 
org.apache.commons.configuration.AbstractConfiguration#getPropertyDirect(java.lang.String)
     */
    protected Object getPropertyDirect(String key) {
        if(log.isTraceEnabled()) log.trace("getPropertyDirect("+key+")");
        ConfigurationProperty config = null;
        try {
            config = (ConfigurationProperty) 
session.get(ConfigurationProperty.class,key);
        } catch(HibernateException e) {
            log.error("Error reading congfiguration property=["+key+"]",e);
            return null;
        }
        try {
            Class clazz = getClass().getClassLoader().loadClass(config.getType());
            return ConvertUtils.convert(config.getValue(), clazz);
        } catch(ClassNotFoundException e) {
            log.warn("Cannot find class=["+config.getType()+"] for 
property=["+key+"]",e);
        }
        return config.getValue();
    }

    /**
     * @see 
org.apache.commons.configuration.AbstractConfiguration#addPropertyDirect(java.lang.String,
 java.lang.Object)
     */
    protected void addPropertyDirect(String key, Object value) {
        if(log.isTraceEnabled()) log.trace("addPropertyDirect("+key+","+value+")");
        ConfigurationProperty config = new ConfigurationProperty();
        config.setName(key);
        config.setValue(ConvertUtils.convert(value));
        config.setType(value.getClass().getName());
        try {
            Transaction transaction = session.beginTransaction();
            session.save(config);
            transaction.commit();
        } catch(HibernateException e) {
            log.error("Error adding congfiguration property=["+key+"]",e);
        }
    }

    /**
     * @see org.apache.commons.configuration.Configuration#isEmpty()
     */
    public boolean isEmpty() {
        if(log.isTraceEnabled()) log.trace("isEmpty()");
        try {
            List list = session.find("from Configuration");
            return list.isEmpty();
        } catch(HibernateException e) {
            log.error("Error reading keys.",e);
            return true;
        }
    }

    /***
     * @see 
org.apache.commons.configuration.Configuration#containsKey(java.lang.String)
     */
    public boolean containsKey(String key) {
        if(log.isTraceEnabled()) log.trace("containsKey("+key+")");
        return (getPropertyDirect(key) != null);
    }

    /**
     * @see 
org.apache.commons.configuration.Configuration#clearProperty(java.lang.String)
     */
    public void clearProperty(String key) {
        if(log.isTraceEnabled()) log.trace("clearProperty("+key+")");
        ConfigurationProperty config = new ConfigurationProperty();
        config.setName(key);
        try {
            Transaction transaction = session.beginTransaction();
            session.delete(config);
            transaction.commit();
        } catch(HibernateException e) {
            log.error("Error clearing congfiguration property=["+key+"]",e);
        }
    }

    /**
     * @see org.apache.commons.configuration.Configuration#getKeys()
     */
    public Iterator getKeys() {
        if(log.isTraceEnabled()) log.trace("getKeys()");
        try {
            List list = session.find("from Configuration");
            return new KeyIterator(list.iterator());
        } catch(HibernateException e) {
            log.error("Error reading keys.",e);
            return null;
        }
    }

}
/*
 * Copyright 2004 Ricardo Gladwell
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.sf.jexus.server.data.object;

/**
 * Hibernate persistance JavaBean encapsulating information about
 * a configuration property.
 * 
 * @hibernate.class
 *      table="configuration"
 * 
 * @todo Create JUnit test cases.
 * @author <a href="mailto:[EMAIL PROTECTED]">Ricardo Gladwell</a>
 * @version $Revision: 1.1 $, $Date: 2004/10/05 14:03:55 $
 */
public class ConfigurationProperty {

    /**
     * Name of this configuration property.
     */
    String name;

    /**
     * String representation of the valye of this configuration property.
     */
    String value;

    /**
     * Fully qualified class for this configuration property's type.
     */
    String type;

    /**
     * Returns the key name for this configuration property.
     * 
     * @hibernate.id
     *      generator-class="assigned"
     * 
     * @return Returns the name.
     */
    public String getName() {
        return name;
    }

    /**
     * Sets the key name for this configuration property.
     * @param name The name to set.
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Returns the value of this property.
     * 
     * @hibernate.property
     * 
     * @return Returns the value.
     */
    public String getValue() {
        return value;
    }

    /**
     * Sets the value of this property.
     * @param value The value to set.
     */
    public void setValue(String value) {
        this.value = value;
    }

    /**
     * Returns the fully qualified class name for the type
     * of the value for this configuration property.
     * 
     * @hibernate.property
     * 
     * @return Returns the type.
     */
    public String getType() {
        return type;
    }

    /**
     * Sets the fully qualified class name for the type
     * of the value for this configuration property.
     * @param type The type to set.
     */
    public void setType(String type) {
        this.type = type;
    }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to