Uploaded image for project: 'Struts 2'
  1. Struts 2
  2. WW-3153

xwork com.opensymphony.xwork2.config.ConfigurationManager needs better error handling for missing plugin config,class

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Not A Problem
    • None
    • None
    • None
    • None
    • Struts 2.1.6
      xwork 2.0-SNAPSHOT
      J2SE 1.6.0.10
      TC 1.6

    Description

      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
        Unknown macro: { 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

      Attachments

        Activity

          People

            Unassigned Unassigned
            mgainty Martin Gainty
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: