xwork com.opensymphony.xwork2.config.ConfigurationManager needs better error
handling for missing plugin config,class
---------------------------------------------------------------------------------------------------------------------
Key: WW-3153
URL: https://issues.apache.org/struts/browse/WW-3153
Project: Struts 2
Issue Type: Bug
Environment: Struts 2.1.6
xwork 2.0-SNAPSHOT
J2SE 1.6.0.10
TC 1.6
Reporter: Martin Gainty
xwork com.opensymphony.xwork2.config.ConfigurationManager code
/*** Get the current XWork configuration object. By default an instance of
DefaultConfiguration will be returned
* @see com.opensymphony.xwork2.config.impl.DefaultConfiguration
*/
public synchronized Configuration getConfiguration() {
if (configuration == null) {
setConfiguration(new
DefaultConfiguration(defaultFrameworkBeanName));
try {
configuration.reload(getConfigurationProviders());
} catch (ConfigurationException e) {
setConfiguration(null);
/****** xwork getConfigurationProviders code inlined so we can see whats
going on ***
* Get the current list of ConfigurationProviders. If no custom
ConfigurationProviders have been added, this method
* will return a list containing only the default ConfigurationProvider,
XMLConfigurationProvider. if a custom
* ConfigurationProvider has been added, then the XmlConfigurationProvider
must be added by hand.
* </p>
* <p/>
* TODO: the lazy instantiation of XmlConfigurationProvider should be
refactored to be elsewhere. the behavior described above seems unintuitive.
*
* @return the list of registered ConfigurationProvider objects
* @see ConfigurationProvider
*/
public List<ConfigurationProvider> getConfigurationProviders() {
providerLock.lock();
try {
if (configurationProviders.size() == 0) {
configurationProviders.add(new
XmlConfigurationProvider("xwork.xml", true));
}
return configurationProviders;
} finally {
providerLock.unlock();
}
}
***********/
throw e;
}
} else {
conditionalReload();
}
return configuration;
}
//end configurationManager
//Here is com.opensymphony.xwork2.config.impl.DefaultConfigurationProvider
public synchronized List<PackageProvider>
reloadContainer(List<ContainerProvider> providers) throws
ConfigurationException {
ContainerProperties props = new ContainerProperties();
ContainerBuilder builder = new ContainerBuilder();
for (final ContainerProvider containerProvider : providers)
{
containerProvider.init(this);
containerProvider.register(builder, props);
}
props.setConstants(builder);
//a quick recap of setConstants
/*public void setConstants(ContainerBuilder builder) {
//keySet appears to be empty so the iterator to key wont work here
for (Object keyobj : keySet()) {
String key = (String)keyobj;
builder.factory(String.class, key,
new LocatableConstantFactory<String>(getProperty(key),
getPropertyLocation(key)));
}
}
*/
container = builder.create(false);
/*start code com.opensymphony.xwork2.inject.ConfigurationBuilder.create()
public Container create(boolean loadSingletons) {
ensureNotCreated();
created = true;
final ContainerImpl container = new ContainerImpl(
new HashMap<Key<?>, InternalFactory<?>>(factories));
if (loadSingletons) { //wont happen as this is always false
container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
public Void call(InternalContext context) {
for (InternalFactory<?> factory : singletonFactories) {
factory.create(context);
}
return null;
}
});
}
//final List<Class<?>> staticInjections = new ArrayList<Class<?>>();
//no effect as staticInjections are null at this point
container.injectStatics(staticInjections);
return container;
}
//end com.opensymphony.xwork2.inject.ConfigurationBuilder.create()
*/
setContext(container);
/******* setContext code inlined so we can see whats going on
protected ActionContext setContext(Container cont) {
ValueStack vs =
cont.getInstance(ValueStackFactory.class).createValueStack();
ActionContext context = new ActionContext(vs.getContext());
ActionContext.setContext(context);
return context; //returns the context of the VS from the supplied
container
}
********/
// Set<String> getInstanceNames(Class<?> type);
objectFactory = container.getInstance(ObjectFactory.class);
//a not null objectFactory with no contained objects
// Process the configuration providers first (WARNING providers
could be null!)
for (final ContainerProvider containerProvider : providers)
{
if (containerProvider instanceof PackageProvider) {
container.inject(containerProvider);
((PackageProvider)containerProvider).loadPackages();
packageProviders.add((PackageProvider)containerProvider);
}
}
// Then process any package providers from the plugins
//Container.getInstanceNames Set<String> getInstanceNames(Class<?> type);
/*com.opensymphony.xwork2.inject.ContainerImpl has getInstanceNames we can use
public Set<String> getInstanceNames(final Class<?> type) {
return factoryNamesByType.get(type);
//FYI this.factoryNamesByType = Collections.unmodifiableMap(map);
//now a simple get on the key should return the Factory for PackageProvider
}
*/
Set<String> packageProviderNames =
container.getInstanceNames(PackageProvider.class);
if (packageProviderNames != null) {
for (String name : packageProviderNames) {
PackageProvider provider =
container.getInstance(PackageProvider.class, name);
provider.init(this);
provider.loadPackages();
packageProviders.add(provider);
}
}
rebuildRuntimeConfiguration();
} finally {
ActionContext.setContext(null);
}
return packageProviders;
//how does a factory for PackageProvider get created?
/* CAUTION members needs to contain the classnames for factory to create
<M extends Member & AnnotatedElement> void addInjectorsForMembers(
List<M> members, boolean statics, List<Injector> injectors,
InjectorFactory<M> injectorFactory) {
for (M member : members) {
if (isStatic(member) == statics) {
Inject inject = member.getAnnotation(Inject.class);
if (inject != null) {
try {
injectors.add(injectorFactory.create(this, member, inject.value()));
} catch (MissingDependencyException e) {
if (inject.required()) {
throw new DependencyException(e);
}
}
}
}
}
}
*/
//where is addInjectorsForMembers called?
/*addInjectorsForMembers is called as Injector parameter to method
void addInjectorsForMethods(Method[] methods, boolean statics,
List<Injector> injectors) {
addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
new InjectorFactory<Method>() {
public Injector create(ContainerImpl container, Method method,
String name) throws MissingDependencyException {
return new MethodInjector(container, method, name);
}
});
}
*/
OR addInjectorsForMember is called as parameter to Field
void addInjectorsForFields(Field[] fields, boolean statics,
List<Injector> injectors) {
addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
new InjectorFactory<Field>() {
public Injector create(ContainerImpl container, Field field,
String name) throws MissingDependencyException {
return new FieldInjector(container, field, name);
}
});
}
//where do the injectors come from
//they are called as a parameter to injectStatics here is the code:
void injectStatics(List<Class<?>> staticInjections) {
final List<Injector> injectors = new ArrayList<Injector>();
for (Class<?> clazz : staticInjections) {
addInjectorsForFields(clazz.getDeclaredFields(), true, injectors);
addInjectorsForMethods(clazz.getDeclaredMethods(), true, injectors);
}
callInContext(new ContextualCallable<Void>() {
public Void call(InternalContext context) {
for (Injector injector : injectors) {
injector.inject(context, null);
}
return null;
}
});
}
//the solution comes provided with test samples for xwork2
//com.opensymphony.xwork2.conf.XmlConfigurationProvider.java
String
impl=java.util.Properties.getProperty("struts.convention.actionConfigBuilder");
Class clazz = new Class(impl);
//quick sanity check
if (clazz==null)
{ log.debug(impl+"class is not on classpath please put actionConfigBuilder
class on classpath"); }
//if the instantiated class is null because of wrong name or not on classpath
we should log the error!
Class cimpl = ClassLoaderUtil.loadClass(impl,
clazz);
if (cimpl==null)
{ log.debug(impl+"class is not on classpath please put actionConfigBuilder
class on classpath"); }
//if the instantiated class is null because of wrong name or not on classpath
or CL couldnt find we should log the error!
/*the resourceName HAS TO BE PRECONFIGURED in context otherwise call to
getResource on impl will fail
public static URL getResource(String resourceName, Class callingClass) {
URL url =
Thread.currentThread().getContextClassLoader().getResource(resourceName);
if (url == null) {
url =
ClassLoaderUtil.class.getClassLoader().getResource(resourceName);
}
if (url == null) {
ClassLoader cl = callingClass.getClassLoader();
if (cl != null) {
url = cl.getResource(resourceName);
}
}
*/
// Force loading of class to detect no class def
found exceptions
try
{
cimpl.getDeclaredClasses();
}
catch(ClassNotFoundException cnfe)
{
log.debug("current CL cant locate class
"+cimpl+"place class on CLASSPATH or configuration for plugin class is missing
please try again");
}
//now that you have the actionConfigBuilder Class built and the
configuration is verified go ahead and inject
containerBuilder.injectStatics(cimpl);
HTH
Martin Gainty
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.