001    package org.apache.ojb.broker.util.factory;
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.commons.lang.SystemUtils;
019    import org.apache.ojb.broker.PersistenceBrokerException;
020    import org.apache.ojb.broker.util.ClassHelper;
021    import org.apache.ojb.broker.util.configuration.Configurable;
022    import org.apache.ojb.broker.util.configuration.Configuration;
023    import org.apache.ojb.broker.util.configuration.ConfigurationException;
024    import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
025    import org.apache.ojb.broker.util.interceptor.InterceptorFactory;
026    import org.apache.ojb.broker.util.logging.Logger;
027    import org.apache.ojb.broker.util.logging.LoggerFactory;
028    
029    /**
030     * ConfigurableFactory is an abstract baseclass for OJB factory classes.
031     * It provides all infrastructure for configuration through OJB.properties.
032     * A derived class must implement the getConfigurationKey() method.
033     * The returned configuration key is used to lookup the class to be instantiated
034     * by the derived factory.
035     * The lookup is performed in the configure() method and uses the OJB.properties
036     * information.
037     *
038     * @author Thomas Mahler
039     */
040    public abstract class ConfigurableFactory implements Configurable
041    {
042        private Logger log = LoggerFactory.getLogger(this.getClass());
043    
044        /**
045         * the class to be served
046         */
047        private Class classToServe = null;
048    
049    
050        /**
051         * the public constructor calls configure() to perform configuration
052         * of the factory instance.
053         */
054        public ConfigurableFactory()
055        {
056            OjbConfigurator.getInstance().configure(this);
057        }
058    
059        /**
060         * must be implemented in the concrete factory classes.
061         * the configuration key is used to lookup the Class to serve
062         * from the OjbConfiguration in configure().
063         */
064        protected abstract String getConfigurationKey();
065    
066        /**
067         * @see org.apache.ojb.broker.util.configuration.Configurable#configure(Configuration)
068         * looks up the the key getConfigurationKey() in the OjbConfiguration
069         * to determine the Class to be served.
070         */
071        public void configure(Configuration pConfig) throws ConfigurationException
072        {
073            if (getConfigurationKey() == null)
074            {
075                getLogger().error("ConfigurableFactory configuration key is 'null'");
076                throw new PersistenceBrokerException("ConfigurableFactory configuration key is 'null'");
077            }
078            Class clazz = pConfig.getClass(getConfigurationKey(), null);
079            if (clazz == null)
080            {
081                getLogger().error("ConfigurableFactory configuration key class for key'" + getConfigurationKey() + "' does not exist.");
082                throw new PersistenceBrokerException(
083                        "ConfigurableFactory configuration key class for key'" + getConfigurationKey() + "' does not exist.");
084            }
085            this.setClassToServe(clazz);
086        }
087    
088        /**
089         * factory method for creating new instances
090         * the Class to be instantiated is defined by getClassToServe().
091         * @return Object the created instance
092         */
093        public Object createNewInstance(Class[] types, Object[] args)
094        {
095            try
096            {
097                Object result;
098                // create an instance of the target class
099                if (types != null)
100                {
101                    result = ClassHelper.newInstance(getClassToServe(), types, args, true);
102                }
103                else
104                {
105                    result = ClassHelper.newInstance(getClassToServe(), true);
106                }
107                // if defined in OJB.properties all instances are wrapped by an interceptor
108                result = InterceptorFactory.getInstance().createInterceptorFor(result);
109                return result;
110    
111            }
112            catch (InstantiationException e)
113            {
114                getLogger().error("ConfigurableFactory can't instantiate class " +
115                        getClassToServe() + buildArgumentString(types, args), e);
116                throw new PersistenceBrokerException(e);
117            }
118            catch (IllegalAccessException e)
119            {
120                getLogger().error("ConfigurableFactory can't access constructor for class " +
121                        getClassToServe() + buildArgumentString(types, args), e);
122                throw new PersistenceBrokerException(e);
123            }
124            catch (Exception e)
125            {
126                getLogger().error("ConfigurableFactory instantiation failed for class " +
127                        getClassToServe() + buildArgumentString(types, args), e);
128                throw new PersistenceBrokerException(e);
129            }
130        }
131    
132        protected String buildArgumentString(Class[] types, Object[] args)
133        {
134            StringBuffer buf = new StringBuffer();
135            String eol = SystemUtils.LINE_SEPARATOR;
136            buf.append(eol + "* Factory types: ");
137            if (types != null)
138            {
139                for (int i = 0; i < types.length; i++)
140                {
141                    Class type = types[i];
142                    buf.append(eol + (i + 1) + " - Type: " + (type != null ? type.getName() : null));
143                }
144            }
145            else
146                buf.append(eol + "none");
147    
148            buf.append(eol + "* Factory arguments: ");
149            if (args != null)
150            {
151                for (int i = 0; i < args.length; i++)
152                {
153                    Object obj = args[i];
154                    buf.append(eol + (i + 1) + " - Argument: " + obj);
155                }
156            }
157            else
158                buf.append(eol + "none");
159            return buf.toString();
160        }
161    
162        /**
163         * factory method for creating new instances
164         * the Class to be instantiated is defined by getClassToServe().
165         * @return Object the created instance
166         */
167        public Object createNewInstance()
168        {
169            return createNewInstance((Class) null, (Object) null);
170        }
171    
172    
173        /**
174         * factory method for creating new instances
175         * the Class to be instantiated is defined by getClassToServe().
176         * @return Object the created instance
177         */
178        public Object createNewInstance(Class type, Object arg)
179        {
180            if (type != null)
181                return createNewInstance(new Class[]{type}, new Object[]{arg});
182            else
183                return createNewInstance((Class[]) null, (Object[]) null);
184        }
185    
186        /**
187         * Returns the classToServe.
188         * @return Class
189         */
190        public Class getClassToServe()
191        {
192            return classToServe;
193        }
194    
195        /**
196         * Sets the classToServe.
197         * <br/>
198         * Normally this is done by the factory using
199         * {@link #getConfigurationKey}.
200         * <br/>
201         * <b>Note:</b> For internal use only!
202         * @param classToServe The classToServe to set
203         */
204        public void setClassToServe(Class classToServe)
205        {
206            this.classToServe = classToServe;
207        }
208    
209        /**
210         * the logger for the ConfigurableFactory
211         */
212        protected Logger getLogger()
213        {
214            return log;
215        }
216    }