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.

Reply via email to