Save This Page
Home » xwork-2.1.1-src » com.opensymphony.xwork2.spring » [javadoc | source]
    1   /*
    2    * Copyright (c) 2002-2006 by OpenSymphony
    3    * All rights reserved.
    4    */
    5   package com.opensymphony.xwork2.spring;
    6   
    7   import java.util.HashMap;
    8   import java.util.Map;
    9   
   10   import org.springframework.beans.BeansException;
   11   import org.springframework.beans.factory.NoSuchBeanDefinitionException;
   12   import org.springframework.beans.factory.UnsatisfiedDependencyException;
   13   import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
   14   import org.springframework.context.ApplicationContext;
   15   import org.springframework.context.ApplicationContextAware;
   16   import org.springframework.context.ConfigurableApplicationContext;
   17   import org.springframework.context.support.ClassPathXmlApplicationContext;
   18   
   19   import com.opensymphony.xwork2.ObjectFactory;
   20   import com.opensymphony.xwork2.inject.Inject;
   21   import com.opensymphony.xwork2.util.logging.Logger;
   22   import com.opensymphony.xwork2.util.logging.LoggerFactory;
   23   
   24   /**
   25    * Simple implementation of the ObjectFactory that makes use of Spring's application context if one has been configured,
   26    * before falling back on the default mechanism of instantiating a new class using the class name. <p/> In order to use
   27    * this class in your application, you will need to instantiate a copy of this class and set it as XWork's ObjectFactory
   28    * before the xwork.xml file is parsed. In a servlet environment, this could be done using a ServletContextListener.
   29    *
   30    * @author Simon Stewart (sms@lateral.net)
   31    */
   32   public class SpringObjectFactory extends ObjectFactory implements ApplicationContextAware {
   33       private static final Logger LOG = LoggerFactory.getLogger(SpringObjectFactory.class);
   34   
   35       protected ApplicationContext appContext;
   36       protected AutowireCapableBeanFactory autoWiringFactory;
   37       protected int autowireStrategy = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
   38       private Map classes = new HashMap();
   39       private boolean useClassCache = true;
   40   
   41       @Inject(value="applicationContextPath",required=false)
   42       public void setApplicationContextPath(String ctx) {
   43           if (ctx != null) {
   44               setApplicationContext(new ClassPathXmlApplicationContext(ctx));
   45           }
   46       }
   47       
   48       /**
   49        * Set the Spring ApplicationContext that should be used to look beans up with.
   50        *
   51        * @param appContext The Spring ApplicationContext that should be used to look beans up with.
   52        */
   53       public void setApplicationContext(ApplicationContext appContext)
   54               throws BeansException {
   55           this.appContext = appContext;
   56           autoWiringFactory = findAutoWiringBeanFactory(this.appContext);
   57       }
   58   
   59       /**
   60        * Sets the autowiring strategy
   61        *
   62        * @param autowireStrategy
   63        */
   64       public void setAutowireStrategy(int autowireStrategy) {
   65           switch (autowireStrategy) {
   66               case AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT:
   67                   LOG.info("Setting autowire strategy to autodetect");
   68                   this.autowireStrategy = autowireStrategy;
   69                   break;
   70               case AutowireCapableBeanFactory.AUTOWIRE_BY_NAME:
   71                   LOG.info("Setting autowire strategy to name");
   72                   this.autowireStrategy = autowireStrategy;
   73                   break;
   74               case AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE:
   75                   LOG.info("Setting autowire strategy to type");
   76                   this.autowireStrategy = autowireStrategy;
   77                   break;
   78               case AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR:
   79                   LOG.info("Setting autowire strategy to constructor");
   80                   this.autowireStrategy = autowireStrategy;
   81                   break;
   82               default:
   83                   throw new IllegalStateException("Invalid autowire type set");
   84           }
   85       }
   86   
   87       public int getAutowireStrategy() {
   88           return autowireStrategy;
   89       }
   90   
   91   
   92       /**
   93        * If the given context is assignable to AutowireCapbleBeanFactory or contains a parent or a factory that is, then
   94        * set the autoWiringFactory appropriately.
   95        *
   96        * @param context
   97        */
   98       protected AutowireCapableBeanFactory findAutoWiringBeanFactory(ApplicationContext context) {
   99           if (context instanceof AutowireCapableBeanFactory) {
  100               // Check the context
  101               return (AutowireCapableBeanFactory) context;
  102           } else if (context instanceof ConfigurableApplicationContext) {
  103               // Try and grab the beanFactory
  104               return ((ConfigurableApplicationContext) context).getBeanFactory();
  105           } else if (context.getParent() != null) {
  106               // And if all else fails, try again with the parent context
  107               return findAutoWiringBeanFactory(context.getParent());
  108           }
  109           return null;
  110       }
  111   
  112       /**
  113        * Looks up beans using Spring's application context before falling back to the method defined in the {@link
  114        * ObjectFactory}.
  115        *
  116        * @param beanName     The name of the bean to look up in the application context
  117        * @param extraContext
  118        * @return A bean from Spring or the result of calling the overridden
  119        *         method.
  120        * @throws Exception
  121        */
  122       public Object buildBean(String beanName, Map extraContext, boolean injectInternal) throws Exception {
  123           Object o = null;
  124           try {
  125               o = appContext.getBean(beanName);
  126           } catch (NoSuchBeanDefinitionException e) {
  127               Class beanClazz = getClassInstance(beanName);
  128               o = buildBean(beanClazz, extraContext);
  129           }
  130           if (injectInternal) {
  131               injectInternalBeans(o);
  132           }
  133           return o;
  134       }
  135   
  136       /**
  137        * @param clazz
  138        * @param extraContext
  139        * @throws Exception
  140        */
  141       public Object buildBean(Class clazz, Map extraContext) throws Exception {
  142           Object bean;
  143   
  144           try {
  145               bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
  146           } catch (UnsatisfiedDependencyException e) {
  147               // Fall back
  148               bean = super.buildBean(clazz, extraContext);
  149           }
  150   
  151           bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());
  152           // We don't need to call the init-method since one won't be registered.
  153           bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());
  154           return autoWireBean(bean, autoWiringFactory);
  155       }
  156   
  157       public Object autoWireBean(Object bean) {
  158           return autoWireBean(bean, autoWiringFactory);
  159       }
  160   
  161       /**
  162        * @param bean
  163        * @param autoWiringFactory
  164        */
  165       public Object autoWireBean(Object bean, AutowireCapableBeanFactory autoWiringFactory) {
  166           if (autoWiringFactory != null) {
  167               autoWiringFactory.autowireBeanProperties(bean,
  168                       autowireStrategy, false);
  169           }
  170           if (bean instanceof ApplicationContextAware) {
  171               ((ApplicationContextAware) bean).setApplicationContext(appContext);
  172           }
  173           
  174           injectInternalBeans(bean);
  175   
  176           return bean;
  177       }
  178   
  179       public Class getClassInstance(String className) throws ClassNotFoundException {
  180           Class clazz = null;
  181           if (useClassCache) {
  182               synchronized(classes) {
  183                   // this cache of classes is needed because Spring sucks at dealing with situations where the
  184                   // class instance changes 
  185                   clazz = (Class) classes.get(className);
  186               }
  187           }
  188   
  189           if (clazz == null) {
  190               if (appContext.containsBean(className)) {
  191                   clazz = appContext.getBean(className).getClass();
  192               } else {
  193                   clazz = super.getClassInstance(className);
  194               }
  195   
  196               if (useClassCache) {
  197                   synchronized(classes) {
  198                       classes.put(className, clazz);
  199                   }
  200               }
  201           }
  202   
  203           return clazz;
  204       }
  205   
  206       /**
  207        * This method sets the ObjectFactory used by XWork to this object. It's best used as the "init-method" of a Spring
  208        * bean definition in order to hook Spring and XWork together properly (as an alternative to the
  209        * org.apache.struts2.spring.lifecycle.SpringObjectFactoryListener)
  210        * @deprecated Since 2.1 as it isn't necessary
  211        */
  212       public void initObjectFactory() {
  213           // not necessary anymore
  214       }
  215   
  216       /**
  217        * Allows for ObjectFactory implementations that support
  218        * Actions without no-arg constructors.
  219        *
  220        * @return false
  221        */
  222       public boolean isNoArgConstructorRequired() {
  223           return false;
  224       }
  225   
  226       /**
  227        *  Enable / disable caching of classes loaded by Spring.
  228        *  
  229        * @param useClassCache
  230        */
  231       public void setUseClassCache(boolean useClassCache) {
  232           this.useClassCache = useClassCache;
  233       }
  234   }

Save This Page
Home » xwork-2.1.1-src » com.opensymphony.xwork2.spring » [javadoc | source]