cziegeler 2004/04/02 02:29:03
Modified: fortress/container-impl/src/java/org/apache/avalon/fortress/impl/handler
ComponentFactory.java
Log:
Add dynamic creation/instantiation of objects (currently turned off)
Revision Changes Path
1.29 +294 -21
avalon-excalibur/fortress/container-impl/src/java/org/apache/avalon/fortress/impl/handler/ComponentFactory.java
Index: ComponentFactory.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/fortress/container-impl/src/java/org/apache/avalon/fortress/impl/handler/ComponentFactory.java,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- ComponentFactory.java 28 Feb 2004 15:16:25 -0000 1.28
+++ ComponentFactory.java 2 Apr 2004 10:29:03 -0000 1.29
@@ -17,22 +17,31 @@
package org.apache.avalon.fortress.impl.handler;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
import org.apache.avalon.excalibur.logger.LoggerManager;
import org.apache.avalon.fortress.util.LifecycleExtensionManager;
import org.apache.avalon.framework.CascadingException;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.WrapperComponentManager;
+import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.context.DefaultContext;
+import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.logger.LogKit2AvalonLoggerAdapter;
import org.apache.avalon.framework.logger.Loggable;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.beanutils.MethodUtils;
import org.apache.excalibur.instrument.AbstractLogEnabledInstrumentable;
import org.apache.excalibur.instrument.CounterInstrument;
import org.apache.excalibur.mpool.ObjectFactory;
@@ -81,6 +90,14 @@
private final Logger m_componentLogger;
/**
+ * The class info for creating the component
+ */
+ private ClassInfo m_classinfo;
+
+ /** Use the dynamic configuration */
+ private boolean m_useDynamicCreation = false;
+
+ /**
* Construct a new component factory for the specified component.
*
* @param componentClass the class to instantiate (must have a default
constructor).
@@ -126,6 +143,7 @@
addInstrument( m_newInstance );
addInstrument( m_dispose );
+
}
/**
@@ -143,7 +161,7 @@
try
{
- component = m_componentClass.newInstance();
+ component = this.createComponent();
if ( getLogger().isDebugEnabled() )
{
@@ -153,27 +171,13 @@
getLogger().debug( message );
}
- ContainerUtil.enableLogging( component, m_componentLogger );
-
- if ( component instanceof Loggable )
- {
- final org.apache.log.Logger logkitLogger =
- LogKit2AvalonLoggerAdapter.createLogger( m_componentLogger );
- ( (Loggable) component ).setLogger( logkitLogger );
- }
+ this.enabledComponentLogging(component);
- ContainerUtil.contextualize( component, m_context );
- if ( component instanceof Composable )
- {
- ContainerUtil.compose( component, new WrapperComponentManager(
m_serviceManager ) );
- }
- ContainerUtil.service( component, m_serviceManager );
- ContainerUtil.configure( component, m_configuration );
+ this.contextualizeComponent(component);
- if ( component instanceof Parameterizable )
- {
- ContainerUtil.parameterize( component,
Parameters.fromConfiguration( m_configuration ) );
- }
+ this.serviceComponent(component);
+
+ this.configureComponent(component);
m_extManager.executeCreationExtensions( component, m_context );
@@ -260,6 +264,275 @@
final String message = "The object given to be disposed does " +
"not come from this ObjectFactory";
throw new IllegalArgumentException( message );
+ }
+ }
+
+ /**
+ * Create a new component
+ */
+ protected Object createComponent() throws Exception
+ {
+ if ( !m_useDynamicCreation )
+ {
+ return m_componentClass.newInstance();
+ }
+
+ if ( m_classinfo == null )
+ {
+ m_classinfo = new ClassInfo();
+ }
+
+ return
m_classinfo.m_constructor.newInstance(m_classinfo.m_constructorArguments);
+ }
+
+ /**
+ * Enable logging for the component
+ */
+ protected void enabledComponentLogging(Object component) throws Exception
+ {
+ ContainerUtil.enableLogging( component, m_componentLogger );
+
+ if ( component instanceof Loggable )
+ {
+ final org.apache.log.Logger logkitLogger =
+ LogKit2AvalonLoggerAdapter.createLogger( m_componentLogger );
+ ( (Loggable) component ).setLogger( logkitLogger );
+ }
+
+ if ( m_useDynamicCreation )
+ {
+
+ if ( m_classinfo.m_setLoggerMethod != null ) {
+ m_classinfo.m_setLoggerMethod.invoke( component, new Object[]
{m_componentLogger});
+ }
+ }
+ }
+
+ /**
+ * Contextualize the component
+ */
+ protected void contextualizeComponent(Object component) throws Exception
+ {
+ ContainerUtil.contextualize( component, m_context );
+ if ( !(component instanceof Contextualizable ) )
+ {
+ try
+ {
+ MethodUtils.invokeMethod(component, "setContext", m_context);
+ }
+ catch (Exception ignore) {}
+ }
+
+ if ( m_useDynamicCreation )
+ {
+ if ( m_classinfo.m_setContextMethod != null ) {
+ m_classinfo.m_setContextMethod.invoke( component, new Object[]
{m_context});
+ }
+ }
+ }
+
+ /**
+ * Service the component
+ */
+ protected void serviceComponent(Object component) throws Exception
+ {
+ if ( component instanceof Composable )
+ {
+ ContainerUtil.compose( component, new WrapperComponentManager(
m_serviceManager ) );
+ }
+ ContainerUtil.service( component, m_serviceManager );
+
+ if ( m_useDynamicCreation )
+ {
+ if ( m_classinfo.m_setServiceManagerMethod != null ) {
+ m_classinfo.m_setServiceManagerMethod.invoke( component, new
Object[] {m_serviceManager});
+ }
+ }
+ }
+
+ /**
+ * Configure the component
+ */
+ protected void configureComponent(Object component) throws Exception
+ {
+ ContainerUtil.configure( component, m_configuration );
+
+ if ( component instanceof Parameterizable )
+ {
+ ContainerUtil.parameterize( component, Parameters.fromConfiguration(
m_configuration ) );
+ }
+
+ if ( m_useDynamicCreation )
+ {
+ if ( m_classinfo.m_setParametersMethod!= null ) {
+ m_classinfo.m_setParametersMethod.invoke( component, new Object[]
{Parameters.fromConfiguration( m_configuration )});
+ }
+ if ( m_classinfo.m_setConfigurationMethod != null ) {
+ m_classinfo.m_setConfigurationMethod.invoke( component, new
Object[] {m_configuration});
+ }
+
+ // if the component has a configuration, but does not implement the
+ // interfaces, try to set the parameters using reflection
+ if ( m_classinfo.m_dynamicConfiguration )
+ {
+ if ( m_configuration != null &&
m_configuration.getChildren().length > 0)
+ {
+ final Parameters p = Parameters.fromConfiguration(
m_configuration );
+ String[] names = p.getNames();
+ for( int i = 0; i < names.length; i++ )
+ {
+ try
+ {
+ BeanUtils.setProperty( component, names[i],
p.getParameter(names[i]));
+ }
+ catch (Exception ignore)
+ {
+ if ( this.getLogger() != null &&
this.getLogger().isWarnEnabled() )
+ {
+ this.getLogger().warn("Error while trying to
configure " + component
+ + " with parameter: " + names[i],
ignore);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * This class collects all information about the components class:
+ * - the constructor to use
+ *
+ */
+ protected class ClassInfo {
+
+ public Constructor m_constructor;
+ public Object[] m_constructorArguments;
+ public Method m_setLoggerMethod;
+ public Method m_setConfigurationMethod;
+ public Method m_setParametersMethod;
+ public Method m_setContextMethod;
+ public boolean m_dynamicConfiguration = false;
+ public Method m_setServiceManagerMethod;
+
+ /** Constructor */
+ public ClassInfo()
+ throws Exception {
+ // let's see which constructors are available
+ Constructor[] constructors = m_componentClass.getConstructors();
+
+ if( constructors.length < 1 )
+ {
+ throw new Exception("Class " + m_componentClass + " does not have a
public constructor.");
+ }
+
+ if( constructors.length > 1 )
+ {
+ // if we have more than one constructor, we first search for
+ // an empty argument constructor
+ // if that is not available we simply take the first constructor
+ // we find
+ try
+ {
+ m_constructor = m_componentClass.getConstructor( new Class[0] );
+ }
+ catch( NoSuchMethodException e )
+ {
+ // we ignore the exception and take the first one
+ m_constructor = constructors[0];
+ }
+ }
+ else
+ {
+ m_constructor = constructors[0];
+ }
+
+ // now test the parameters for the constructor
+ final Class[] classes = m_constructor.getParameterTypes();
+ m_constructorArguments = new Object[ classes.length ];
+ for( int i=0; i<classes.length; i++ )
+ {
+ final Class current = classes[i];
+ if( Logger.class.isAssignableFrom( current ) )
+ {
+ if ( m_componentLogger == null )
+ {
+ throw new IllegalArgumentException("Logger is null.");
+ }
+ m_constructorArguments[i] = m_componentLogger;
+ }
+ else if( Context.class.isAssignableFrom( current ) )
+ {
+ if ( m_context == null )
+ {
+ throw new IllegalArgumentException("Context is null.");
+ }
+ m_constructorArguments[i] = m_context;
+ }
+ else if( Configuration.class.isAssignableFrom( current ) )
+ {
+ if ( m_configuration == null )
+ {
+ throw new IllegalArgumentException("Configuration is
null.");
+ }
+ m_constructorArguments[i] = m_configuration;
+ }
+ else if( Parameters.class.isAssignableFrom( current ) )
+ {
+ if ( m_configuration == null )
+ {
+ throw new IllegalArgumentException("Configuration is
null.");
+ }
+ m_constructorArguments[i] = Parameters.fromConfiguration(
m_configuration );
+ }
+ else if( ServiceManager.class.isAssignableFrom( current ) )
+ {
+ m_constructorArguments[i] = m_serviceManager;
+ }
+ else
+ {
+ throw new Exception("Unknown parameter type for constructor of
component: " + current);
+ }
+ }
+
+ // now test for some setter methods
+ if ( !Loggable.class.isAssignableFrom( m_componentClass)
+ && !LogEnabled.class.isAssignableFrom(m_componentClass))
+ {
+ m_setLoggerMethod = this.getMethod("setLogger", Logger.class);
+ }
+
+ if ( !Contextualizable.class.isAssignableFrom( m_componentClass))
+ {
+ m_setContextMethod = this.getMethod("setContext", Context.class);
+ }
+
+ if ( !Parameterizable.class.isAssignableFrom( m_componentClass)
+ && !Configurable.class.isAssignableFrom(m_componentClass))
+ {
+ m_setConfigurationMethod = this.getMethod("setConfiguration",
Configuration.class);
+ m_setParametersMethod = this.getMethod("setParameters",
Parameters.class);
+ if ( m_setConfigurationMethod == null && m_setParametersMethod ==
null )
+ {
+ m_dynamicConfiguration = true;
+ }
+ }
+
+ if ( !Composable.class.isAssignableFrom(m_componentClass)
+ && !Serviceable.class.isAssignableFrom(m_componentClass))
+ {
+ m_setServiceManagerMethod = this.getMethod("setServiceManager",
ServiceManager.class);
+ }
+ }
+
+ protected Method getMethod(String name, Class clazz) throws Exception
+ {
+ try
+ {
+ return m_componentClass.getMethod(name, new Class[] {clazz});
+ }
+ catch (NoSuchMethodException ignore) {}
+ return null;
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]