[Actionframework-users] new version of DefaultInstantiator.java
Status: Inactive
Brought to you by:
ptoman
|
From: Mark D. A. <md...@di...> - 2002-09-19 21:54:37
|
below is a new version of DefaultInstantiator.java
I cleaned up the code, and added the ability to find and use a 3-arg constructor,
which takes arguments (ActionServlet, String, Context).
I included updated javadoc at the top of the file, but updating documentation
and specification elsewhere is left to the maintainer :).
This change is useful for "request" level components, which often (to me) seem
to need access to context.
-mda
----------- DefaultInstantiator.java ------------
package org.actionframework.instantiators;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Hashtable;
import org.actionframework.ActionServlet;
import org.actionframework.Context;
/**
* Instantiates "normal" ActionServlet components. Used if '<TT>instantiator</TT>' attribute
* is not specified for the component in ActionConfig.
*
* Each component class must have a public constructor with the parameter types that are assignable (that is class or subclass)
from one of these:
* <ul>
* <li>({@link org.actionframework.ActionServlet}, <TT>java.lang.String</TT>, {@link org.actionframework.Context})
* <li>({@link org.actionframework.ActionServlet}, <TT>java.lang.String</TT>)
* <li>({@link org.actionframework.ActionServlet})
* <li>()
* </ul>
* That is, it attempts to find the longest match.
*
* @since version 0.92
*/
public class DefaultInstantiator implements Instantiator {
private class ComponentEntry {
Constructor constructor;
int n;
ComponentEntry(Constructor constructor) {
this.constructor = constructor;
this.n = constructor.getParameterTypes().length;
}
}
/**
* Key: component class name, value = ComponentEntry
*/
private final Hashtable componentClasses = new Hashtable();
protected ActionServlet servlet;
/**
* Creates instantiator.
*/
public DefaultInstantiator(ActionServlet servlet) {
this.servlet = servlet;
}
/**
* generic utility for finding a constructor which matches subclasses,
* not just formal parameters (unlike Class.getConstructor()).
* <p>
* If n_avail >= 0, it pretends that is the length of avail_param_types.
* If n_avail == -1, it uses n_avail = avail_param_types.length.
* <p>
* Returns null if none is found.
*/
public static Constructor getAssignableConstructor(Class obj_class, Class[] avail_param_types, int n_avail) {
Constructor[] constructors = obj_class.getConstructors();
if (n_avail == -1) n_avail = avail_param_types.length;
for (int i = 0; i < constructors.length; i++) {
Class[] paramTypes = constructors[i].getParameterTypes();
if (paramTypes.length != n_avail) continue;
int j;
for (j = 0; j < n_avail; ++j) {
if (!avail_param_types[j].isAssignableFrom(paramTypes[j])) break;
}
if (j == n_avail) return constructors[i];
}
return null;
}
/**
* Finds the constructor matching the longest number of args.
* Iterates using getAssignableConstructor decreasing n.
*/
public static Constructor getLongestAssignableConstructor(Class obj_class, Class[] avail_param_types) {
for(int n=avail_param_types.length; n>=0; --n) {
Constructor found = getAssignableConstructor(obj_class, avail_param_types, n);
if (found != null) return found;
}
return null;
}
protected static Class[] CON_CLASSES = new Class[] {ActionServlet.class, String.class, Context.class};
/**
* Returns a new instance of ActionServlet component.
*/
public Object createComponent(Context context, Class componentClass, String componentName)
throws InstantiatorException {
String componentClassName = componentClass.getName();
// check cache
ComponentEntry componentEntry = (ComponentEntry) componentClasses.get(componentClassName);
if (componentEntry == null) {
Constructor constructor = getLongestAssignableConstructor(componentClass, CON_CLASSES);
if (constructor == null)
throw new InstantiatorException("Component class '" + componentClassName +
"' does not have a public constructor with parameters: () or (ActionServlet) or (ActionServlet, String) or
(ActionServlet, String, Context)");
// put in cache
componentEntry = new ComponentEntry(constructor);
componentClasses.put(componentClassName, componentEntry);
}
try {
switch (componentEntry.n) {
case 0: return componentEntry.constructor.newInstance(new Object[] {});
case 1: return componentEntry.constructor.newInstance(new Object[] {servlet});
case 2: return componentEntry.constructor.newInstance(new Object[] {servlet, componentName});
case 3: return componentEntry.constructor.newInstance(new Object[] {servlet, componentName, context});
default: return null; // cannot happen
}
} catch(InvocationTargetException e) {
throw new InstantiatorException("Error while invoking constructor of component '" + componentName + "'",
e.getTargetException());
} catch(java.lang.InstantiationException e) {
throw new InstantiatorException("Cannot instantiate component '" + componentName + "'", e);
} catch(IllegalAccessException e) {
throw new InstantiatorException("Cannot access component '" + componentName + "'", e);
}
}
}
|