[jboss-cvs] jboss-seam/src/ioc/org/jboss/seam/ioc/spring ...

Norman Richards norman.richards at jboss.com
Fri Feb 16 22:26:43 EST 2007


  User: nrichards
  Date: 07/02/16 22:26:43

  Added:       src/ioc/org/jboss/seam/ioc/spring         
                        SeamComponentPostProcessor.java
                        SeamFactoryBean.java SeamNamespaceHandler.java
                        SeamScope.java SeamScopePostProcessor.java
                        SeamTargetSource.java SpringComponent.java
                        TestAnnotation.java TestInterceptor.java
  Log:
  create main module
  
  Revision  Changes    Path
  1.1      date: 2007/02/17 03:26:43;  author: nrichards;  state: Exp;jboss-seam/src/ioc/org/jboss/seam/ioc/spring/SeamComponentPostProcessor.java
  
  Index: SeamComponentPostProcessor.java
  ===================================================================
  package org.jboss.seam.ioc.spring;
  
  import org.jboss.seam.Component;
  import org.springframework.beans.BeansException;
  import org.springframework.beans.factory.FactoryBean;
  import org.springframework.beans.factory.ObjectFactory;
  import org.springframework.beans.factory.config.BeanPostProcessor;
  import org.springframework.core.Ordered;
  
  /**
   * Intercepts when spring attempts to obtain an instance of a bean. If the bean is a seam component then we retrieve the
   * bean from seam to ensure it gets wrapped and managed by seam as well. This post processor must have a lower
   * precedence than any spring autoproxy creators.
   *
   * @author youngm
   */
  public class SeamComponentPostProcessor implements BeanPostProcessor, Ordered {
  
  	private int order = Ordered.LOWEST_PRECEDENCE;
  
  	/**
  	 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object,
  	 *      java.lang.String)
  	 */
  	public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
  		// Check to see if this bean is a component.
  		Component component = SpringComponent.forSpringBeanName(beanName);
  		// Not a spring component skip.
  		if (component == null || !(component instanceof SpringComponent)) {
  			return bean;
  		}
  		// If this bean is a FactoryBean only request the bean from Seam if the component is a FactoryBean as well
  		// The object created by the factory should come along later
  		if (bean instanceof FactoryBean && !FactoryBean.class.isAssignableFrom(component.getBeanClass())) {
  			return bean;
  		}
  		// Wrap our bean instance in an object factory for the SpringComponent to use
  		SpringComponent.setObjectFactory(new ObjectFactory() {
  			public Object getObject() throws BeansException {
  				return bean;
  			}
  		});
  		// Return the seam instance
  		return Component.getInstance(beanName, component.getScope());
  	}
  
  	/**
  	 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object,
  	 *      java.lang.String)
  	 */
  	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  		return bean;
  	}
  
  	/**
  	 * This post processor must run after any spring AutoProxyCreator
  	 *
  	 * @see org.springframework.core.Ordered#getOrder()
  	 */
  	public int getOrder() {
  		return order;
  	}
  
  	/**
  	 * @param order the order to set
  	 */
  	public void setOrder(int order) {
  		this.order = order;
  	}
  }
  
  
  
  1.1      date: 2007/02/17 03:26:43;  author: nrichards;  state: Exp;jboss-seam/src/ioc/org/jboss/seam/ioc/spring/SeamFactoryBean.java
  
  Index: SeamFactoryBean.java
  ===================================================================
  package org.jboss.seam.ioc.spring;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import javax.servlet.http.HttpSessionActivationListener;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.InterceptionType;
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.core.Mutable;
  import org.jboss.seam.intercept.Proxy;
  import org.springframework.aop.framework.DefaultAopProxyFactory;
  import org.springframework.aop.framework.ProxyFactory;
  import org.springframework.beans.factory.InitializingBean;
  import org.springframework.beans.factory.config.AbstractFactoryBean;
  
  /**
   * Obtains an instance of a Seam Component in the current context
   * given the name and other optional parameters. If proxy is set to
   * true then return a scoped proxy of the seam component instance. Use
   * <seam:instance/> to simplify use of this factory.
   *
   * @author youngm
   */
  public class SeamFactoryBean 
      extends AbstractFactoryBean 
      implements InitializingBean
  {
      private ScopeType scope;
      private String name;
      private Boolean create;
      private SeamTargetSource targetSource;
      private Object proxyInstance;
      private boolean proxy = false;
      
      /**
       * Initializes the factory. If proxy=true then initialize the proxy.
       *
       * @see org.springframework.beans.factory.config.AbstractFactoryBean#afterPropertiesSet()
       */
      @Override
      public void afterPropertiesSet() throws Exception {
          if (name == null) {
              throw new IllegalArgumentException("name must not be null");
          }
          // If we're creating a proxy then we want this to be a singleton
          setSingleton(proxy);
          
          this.targetSource = new SeamTargetSource(name, scope, create);
          
          if (proxy) {
              // Not sure if I should allow people to change these proxy
              // parameters or not. We'll see what issues we get hard coding them.
              ProxyFactory pf = new ProxyFactory();
              pf.setProxyTargetClass(true);
              pf.setOptimize(true);
              pf.setExposeProxy(false);
              pf.setFrozen(true);
              pf.setAopProxyFactory(new DefaultAopProxyFactory());
              pf.setTargetSource(this.targetSource);
              
              // Attempt to piece together all of the possible interfaces to apply
              // to our proxy.
              List<Class> interfaces = new ArrayList<Class>();
              Component component = targetSource.getComponent();
              if (component.getInterceptionType() != InterceptionType.NEVER) {
                  if (component.getType().isSessionBean()) {
                      interfaces.addAll(component.getBusinessInterfaces());
                  } else {
                      interfaces.add(HttpSessionActivationListener.class);
                      interfaces.add(Mutable.class);
                  }
                  interfaces.add(Proxy.class);
              }
              pf.setInterfaces(interfaces.toArray(new Class[interfaces.size()]));
              
              this.proxyInstance = pf.getProxy();
          }
          super.afterPropertiesSet();
      }
      
      /**
       * Return the current instance of a Seam component or the proxy if proxy was set to true.
       *
       * @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
       */
      @Override
      protected Object createInstance() throws Exception {
          if (proxy) {
              return proxyInstance;
          } else {
              return targetSource.getTarget();
          }
      }
      /**
       * Return the type of the component if available.
       *
       * @throws IllegalStateException if the component cannot be found or if seam has not yet been initialized.
       *
       * @see org.springframework.beans.factory.config.AbstractFactoryBean#getObjectType()
       */
      @Override
      public Class getObjectType() {
          return targetSource.getTargetClass();
      }
      
      /**
       * The name of the seam component to get an instance of. (required)
       *
       * @param name the name of the component
       */
      public void setName(String name) {
          this.name = name;
      }
  
      /**
       * The scope of the seam component (optional)
       *
       * @param scope the scope of the component
       */
      public void setScope(ScopeType scope) {
          this.scope = scope;
      }
      
      /**
       * Should the factory create an instance of the component if one
       * doesn't already exist in this context. If null
       *
       * Must always be true for STATELESS components.
       *
       * @param create do we create an instance if needed
       */
      public void setCreate(Boolean create) {
          this.create = create;
      }
      
      /**
       * Should the factory wrap the component instance in a proxy so
       * the seam component can be safely injected into a singleton.
       *
       * @param proxy true to proxy the component
       */
      public void setProxy(boolean proxy) {
          this.proxy = proxy;
      }
  }
  
  
  
  1.1      date: 2007/02/17 03:26:43;  author: nrichards;  state: Exp;jboss-seam/src/ioc/org/jboss/seam/ioc/spring/SeamNamespaceHandler.java
  
  Index: SeamNamespaceHandler.java
  ===================================================================
  package org.jboss.seam.ioc.spring;
  
  import org.jboss.seam.InterceptionType;
  import org.jboss.seam.ScopeType;
  import org.springframework.beans.factory.BeanDefinitionStoreException;
  import org.springframework.beans.factory.BeanFactory;
  import org.springframework.beans.factory.config.BeanDefinition;
  import org.springframework.beans.factory.config.BeanDefinitionHolder;
  import org.springframework.beans.factory.support.AbstractBeanDefinition;
  import org.springframework.beans.factory.support.RootBeanDefinition;
  import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
  import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
  import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
  import org.springframework.beans.factory.xml.ParserContext;
  import org.springframework.core.Ordered;
  import org.springframework.util.ClassUtils;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  
  /**
   * NamespaceHandler for a number of seam features in spring.
   *
   * @author youngm
   */
  public class SeamNamespaceHandler 
      extends NamespaceHandlerSupport 
  {
      public static final String SEAM_SCOPE_POST_PROCESSOR = "org.jboss.seam.ioc.spring.SeamScopePostProcessor";
      
      public static final String SEAM_COMPONENT_POST_PROCESSOR = "org.jboss.seam.ioc.spring.SeamComponentPostProcessor";
      
      public static final String SEAM_COMPONENT_POST_PROCESSOR_BEAN_NAME = "org.jboss.seam.ioc.spring.seamComponentPostProcessor";
      
      /**
       * @see org.springframework.beans.factory.xml.NamespaceHandler#init()
       */
      public void init() {
          registerBeanDefinitionParser("configure-scopes", new SeamConfigureScopeParser());
          registerBeanDefinitionParser("instance", new SeamInstanceBeanDefinitionParser());
          registerBeanDefinitionDecorator("component", new SeamComponentBeanDefinitionDecorator());
      }
      
      /**
       * Registers the SeamScopePostProcessor in this bean factory under
       * the name defined in SEAM_SCOPE_POST_PROCESSOR.
       * &lt;seam:configure-scope/&gt;
       *
       * @see SeamScopePostProcessor
       * @author youngm
       */
      private static class SeamConfigureScopeParser 
          extends AbstractSimpleBeanDefinitionParser 
      {
          /**
           * @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
           */
          @Override
          protected Class getBeanClass(Element element) {
              return SeamScopePostProcessor.class;
          }
          
          /**
           * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element,
           *      org.springframework.beans.factory.support.AbstractBeanDefinition,
           *      org.springframework.beans.factory.xml.ParserContext)
           */
          @Override
          protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
              throws BeanDefinitionStoreException 
          {
              return SEAM_SCOPE_POST_PROCESSOR;
          }
      }
      
      /**
       * Makes a SeamFactoryBean available for use in a spring ApplicationContext. &lt;seam:instance
       * name="someSeamComponent"/&gt;
       *
       * @see SeamFactoryBean
       * @author youngm
       */
      private static class SeamInstanceBeanDefinitionParser 
          extends AbstractSimpleBeanDefinitionParser 
      {        
          protected Class getBeanClass(Element element) {
              return SeamFactoryBean.class;
          }
      }
      
      /**
       * Makes an existing spring bean definition a seam component or
       * provides hints in the creation of a seam component.  Will use
       * the bean definitions name and class by default and the classes
       * annotatated InterceptionType.
       *
       * If proxy=true will wrap the spring bean in a cglib proxy for
       * safe injection into singletons.
       *
       * &lt;seam:component/&gt;
       *
       * @author youngm
       */
      private static class SeamComponentBeanDefinitionDecorator implements BeanDefinitionDecorator {
          private static final String INTERCEPT_ATTR = "intercept";
          private static final String SPRING_NAME_ATTR = "springName";
          private static final String SEAM_NAME_ATTR = "seamName";
          private static final String BEAN_CLASS_ATTR = "beanClass";
          public  static final String AUTO_INTERCEPTION_TYPE = "AUTO";
  
          /**
           * @see org.springframework.beans.factory.xml.BeanDefinitionDecorator#decorate(org.w3c.dom.Node,
           *      org.springframework.beans.factory.config.BeanDefinitionHolder,
           *      org.springframework.beans.factory.xml.ParserContext)
           */
          public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
              // Add the Seam Component Post Processor to the bean factory if it doesn't already exist
              if (!parserContext.getRegistry().containsBeanDefinition(SEAM_COMPONENT_POST_PROCESSOR_BEAN_NAME)) {
                  Class cls = null;
                  try {
                      cls = ClassUtils.forName(SEAM_COMPONENT_POST_PROCESSOR);
                  } catch (ClassNotFoundException e) {
                      throw new IllegalStateException("Unable to load class '" + SEAM_COMPONENT_POST_PROCESSOR
                                                      + "' make sure you have the jboss-seam-spring.jar in your classpath.");
                  }
                  RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
                  beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                  beanDefinition.getPropertyValues().addPropertyValue("order", new Integer(Ordered.LOWEST_PRECEDENCE));
                  parserContext.getRegistry().registerBeanDefinition(SEAM_COMPONENT_POST_PROCESSOR_BEAN_NAME,
  						beanDefinition);
              }
              // get the optional beanClass
              String beanClassName = definition.getBeanDefinition().getBeanClassName();
              if (node.getAttributes().getNamedItem(BEAN_CLASS_ATTR) != null) {
                  beanClassName = node.getAttributes().getNamedItem(BEAN_CLASS_ATTR).getNodeValue();
              }
              String beanName = definition.getBeanName();
              // get the name of the seam component to create
              String seamName = beanName;
              if (node.getAttributes().getNamedItem(SEAM_NAME_ATTR) != null) {
                  seamName = node.getAttributes().getNamedItem(SEAM_NAME_ATTR).getNodeValue();
              }
              // get the name of the spring bean to use
              String springName = beanName;
              if (node.getAttributes().getNamedItem(SPRING_NAME_ATTR) != null) {
                  springName = node.getAttributes().getNamedItem(SPRING_NAME_ATTR).getNodeValue();
              }
              // get the interception type to use
              InterceptionType interceptionType = null;
              if (AUTO_INTERCEPTION_TYPE.equals(node.getAttributes().getNamedItem(INTERCEPT_ATTR).getNodeValue())) {
                  if (definition.getBeanDefinition().isSingleton()) {
                      interceptionType = InterceptionType.NEVER;
                  }
              } else {
                  interceptionType = InterceptionType.valueOf(node.getAttributes().getNamedItem(INTERCEPT_ATTR)
                                                              .getNodeValue());
              }
              
              // get the requested scope
              ScopeType scope = ScopeType.valueOf(node.getAttributes().getNamedItem("scope").getNodeValue());
              if (scope != ScopeType.STATELESS
                  && !BeanDefinition.SCOPE_PROTOTYPE.equals(definition.getBeanDefinition().getScope())) {
                  throw new IllegalStateException(
  						"The spring bean scope must be prototype to use a seam scope other than STATELESS.");
              }
              // determine if we want to override any existing seam component definitions
              boolean override = Boolean.parseBoolean(node.getAttributes().getNamedItem("override").getNodeValue());
              
              if (!(parserContext.getRegistry() instanceof BeanFactory)) {
                  throw new RuntimeException("For some reason your registry is not a BeanFactory");
              }
              SpringComponent.addSpringComponent(seamName, springName, beanClassName, scope, (BeanFactory) parserContext
                                                 .getRegistry(), interceptionType, override);
              return definition;
          }
      }
  }
  
  
  
  1.1      date: 2007/02/17 03:26:43;  author: nrichards;  state: Exp;jboss-seam/src/ioc/org/jboss/seam/ioc/spring/SeamScope.java
  
  Index: SeamScope.java
  ===================================================================
  package org.jboss.seam.ioc.spring;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.core.Events;
  import org.jboss.seam.log.LogProvider;
  import org.jboss.seam.log.Logging;
  import org.springframework.beans.factory.ObjectFactory;
  import org.springframework.beans.factory.config.Scope;
  
  /**
   * Allows for the creation of seam scoped component in spring. Seam
   * scopes are automatically made available if the
   * SeamScopePostProcessor is declared in the current
   * BeanFactory. &lt;seam:configure-scopes/&gt;
   *
   * @author youngm
   * @see SeamScopePostProcessor
   */
  public class SeamScope 
      implements Scope 
  {
      private static final LogProvider log = Logging.getLogProvider(SeamScope.class);
      
      private ScopeType scope;
      
      public SeamScope(ScopeType scope) {
          this.scope = scope;
      }
      
      /**
       * Gets an instance of a Seam component providing the current ObjectFactory if needed.
       *
       * @see org.springframework.beans.factory.config.Scope#get(java.lang.String,
       *      org.springframework.beans.factory.ObjectFactory)
       */
      public Object get(String name, ObjectFactory objectFactory) {
          try {
              SpringComponent.setObjectFactory(objectFactory);
              Component component = SpringComponent.forSpringBeanName(name);
              return Component.getInstance(component.getName(), scope, true);
          } finally {
              SpringComponent.setObjectFactory(null);
          }
      }
      
      /**
       * Not used yet.
       *
       * @see org.springframework.beans.factory.config.Scope#getConversationId()
       */
      public String getConversationId() {
          return null;
      }
      
      /**
       * @see org.springframework.beans.factory.config.Scope#registerDestructionCallback(java.lang.String,
       *      java.lang.Runnable)
       */
      public void registerDestructionCallback(String name, Runnable callback) {
          ((SpringComponent) SpringComponent.forSpringBeanName(name)).registerDestroyCallback(name, callback);
      }
      
      /**
       * On remove destroys the seam component.
       *
       * @see org.springframework.beans.factory.config.Scope#remove(java.lang.String)
       */
      public Object remove(String name) {
          // copied from Component.callDestory should be able to reuse. Needed because if remove is called then for some
          // reason spring doesn't use the destroy callback.
          log.debug("destroying: " + name);
          Component component = SpringComponent.forSpringBeanName(name);
          Object bean = scope.getContext().get(component.getName());
          if (component != null) {
              if (bean != null) { // in a portal environment, this is possible
                  if (Events.exists())
                      Events.instance().raiseEvent("org.jboss.seam.preDestroy." + name);
                  try {
                      if (component.hasDestroyMethod()) {
                          component.callComponentMethod(bean, component.getDestroyMethod());
                      }
                  } catch (Exception e) {
                      log.warn("Could not destroy component: " + component.getName(), e);
                  }
              }
          }
          scope.getContext().remove(component.getName());
          return bean;
      }
  }
  
  
  
  1.1      date: 2007/02/17 03:26:43;  author: nrichards;  state: Exp;jboss-seam/src/ioc/org/jboss/seam/ioc/spring/SeamScopePostProcessor.java
  
  Index: SeamScopePostProcessor.java
  ===================================================================
  package org.jboss.seam.ioc.spring;
  
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.contexts.Contexts;
  import org.jboss.seam.contexts.Lifecycle;
  import org.jboss.seam.log.LogProvider;
  import org.jboss.seam.log.Logging;
  import org.springframework.beans.BeansException;
  import org.springframework.beans.factory.InitializingBean;
  import org.springframework.beans.factory.config.BeanDefinition;
  import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
  import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  
  /**
   * Post processor that makes all of the seam scopes available in
   * spring and takes all of the beans with those scopes and creates
   * Seam Components out of them. <p/> To use simply define the
   * namespace hanlder in in your ApplicationContext.
   * &lt;seam:configure-scopes/&gt;
   *
   * @author youngm
   */
  public class SeamScopePostProcessor 
      implements BeanFactoryPostProcessor, 
                 InitializingBean 
  {
      private static final LogProvider log = Logging.getLogProvider(SeamScopePostProcessor.class);
      
      /**
       * Default seam scope prefix.
       */
      public static final String DEFAULT_SCOPE_PREFIX = "seam.";
      
      private String prefix;
      
      private boolean override = false;
      
      /**
       * Null is not a valid prefix so make it the default is used if null or empty.
       *
       * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
       */
      public void afterPropertiesSet() throws Exception {
          if (prefix == null || "".equals(prefix)) {
              prefix = DEFAULT_SCOPE_PREFIX;
          }
      }
      
      /**
       * Add all of the seam scopes to this beanFactory.
       *
       * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
       */
      public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
          throws BeansException 
      {
          for (ScopeType scope : ScopeType.values()) {
              // Don't create a scope for Unspecified
              if (scope != ScopeType.UNSPECIFIED) {
                  beanFactory.registerScope(prefix + scope.name(), new SeamScope(scope));
              }
          }
          // Create a mock application context if not available.
          // TODO Reuse
          boolean unmockApplication = false;
          if (!Contexts.isApplicationContextActive()) {
              Lifecycle.mockApplication();
              unmockApplication = true;
          }
          try {
              // Iterate through all the beans in the factory
              for (String beanName : beanFactory.getBeanDefinitionNames()) {
                  BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
                  ScopeType scope;
                  if (definition.getScope().startsWith(prefix)) {
                      // Will throw an error if the scope is not found.
                      scope = ScopeType.valueOf(definition.getScope().replaceFirst(prefix, "").toUpperCase());
                  } else {
                      if (log.isDebugEnabled()) {
                          log.debug("No scope could be derived for bean with name: " + beanName);
                      }
                      continue;
                  }
                  if (scope == ScopeType.UNSPECIFIED) {
                      if (log.isDebugEnabled()) {
                          log.debug("Discarding bean with scope UNSPECIFIED.  Spring will throw an error later: "
                                    + beanName);
                                          }
                      continue;
                  }
                  // Cannot be a seam component without a specified class seam:component will need to be used for this
                  // bean.
                  if (definition.getBeanClassName() == null) {
                      if (log.isDebugEnabled()) {
                          log.debug("Unable to create component for bean: " + beanName
                                    + ".  No class defined try seam:component instead.");
                      }
                      continue;
                  }
                  SpringComponent.addSpringComponent(beanName, beanName, definition.getBeanClassName(), scope, beanFactory, null,
                                                     override);
              }
          } finally {
              if (unmockApplication) {
                  Lifecycle.unmockApplication();
              }
          }
      }
      
      /**
       * @param casesensitive prefix the prefix to use to identify seam scopes for spring beans. Default is "seam."
       */
      public void setPrefix(String prefix) {
          this.prefix = prefix;
      }
      
      /**
       * @param duplicate set to tell the postprocessor to duplicate any preexisting seam components that may have the same
       *        name as the candidate spring bean. Default: false
       */
      public void setOverride(boolean override) {
          this.override = override;
      }
  }
  
  
  
  1.1      date: 2007/02/17 03:26:43;  author: nrichards;  state: Exp;jboss-seam/src/ioc/org/jboss/seam/ioc/spring/SeamTargetSource.java
  
  Index: SeamTargetSource.java
  ===================================================================
  package org.jboss.seam.ioc.spring;
  
  import java.io.Serializable;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.contexts.Contexts;
  import org.jboss.seam.contexts.Lifecycle;
  import org.jboss.seam.log.LogProvider;
  import org.jboss.seam.log.Logging;
  import org.springframework.aop.TargetSource;
  
  /**
   * A TargetSource for a seam component instance. Will obtain an instance given a name and optionally a scope and create.
   * Used by the SeamFactoryBean to create a proxy for a requested seam component instance.
   *
   * @author youngm
   */
  @SuppressWarnings("serial")
  public class SeamTargetSource implements TargetSource, Serializable {
  	private static final LogProvider log = Logging.getLogProvider(SeamTargetSource.class);
  
  	private ScopeType scope;
  
  	private String name;
  
  	private Boolean create;
  
  	/**
  	 * @param name Name of the component: required
  	 * @param scope Name of the scope the component is in: optional
  	 * @param create Whether to create a new instance if one doesn't already exist: optional
  	 */
  	public SeamTargetSource(String name, ScopeType scope, Boolean create) {
  		if (name == null || "".equals(name)) {
  			throw new IllegalArgumentException("Name is required.");
  		}
  		this.name = name;
  		this.scope = scope;
  		this.create = create;
  	}
  
  	/**
  	 * Returns a component instance for this TargetSource.
  	 *
  	 * @see org.springframework.aop.TargetSource#getTarget()
  	 */
  	public Object getTarget() throws Exception {
  		if (scope == null && create == null) {
  			return Component.getInstance(name);
  		} else if (scope == null) {
  			return Component.getInstance(name, create);
  		} else if (create == null) {
  			return Component.getInstance(name, scope);
  		} else {
  			return Component.getInstance(name, scope, create);
  		}
  	}
  
  	/**
  	 * Obtains the seam component beanClass for this TargetSource.
  	 *
  	 * @see org.springframework.aop.TargetSource#getTargetClass()
  	 */
  	public Class getTargetClass() {
  		return getComponent().getBeanClass();
  	}
  
  	/**
  	 * Get the component for this TargetSource
  	 *
  	 * @return
  	 */
  	public Component getComponent() {
  		// TODO reuse
  		boolean unmockApplication = false;
  		if (!Contexts.isApplicationContextActive()) {
  			Lifecycle.mockApplication();
  			unmockApplication = true;
  		}
  		try {
  			Component component = Component.forName(name);
  			if (component == null) {
  				throw new IllegalStateException("Cannot find targetClass for seam component: " + name
  						+ ".  Make sure Seam is being configured before Spring.");
  			}
  			return component;
  		} finally {
  			if (unmockApplication) {
  				Lifecycle.unmockApplication();
  			}
  		}
  	}
  
  	/**
  	 * @see org.springframework.aop.TargetSource#isStatic()
  	 */
  	public boolean isStatic() {
  		return false;
  	}
  
  	/**
  	 * Don't think we need to do anything here.
  	 *
  	 * @see org.springframework.aop.TargetSource#releaseTarget(java.lang.Object)
  	 */
  	public void releaseTarget(Object target) throws Exception {
  		// Do Nothing
  	}
  }
  
  
  
  1.1      date: 2007/02/17 03:26:43;  author: nrichards;  state: Exp;jboss-seam/src/ioc/org/jboss/seam/ioc/spring/SpringComponent.java
  
  Index: SpringComponent.java
  ===================================================================
  package org.jboss.seam.ioc.spring;
  
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.Set;
  
  import javax.servlet.http.HttpSessionActivationListener;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.InterceptionType;
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.contexts.Contexts;
  import org.jboss.seam.contexts.Lifecycle;
  import org.jboss.seam.core.Mutable;
  import org.jboss.seam.init.Initialization;
  import org.jboss.seam.intercept.Proxy;
  import org.jboss.seam.ioc.IoCComponent;
  import org.jboss.seam.ioc.ProxyUtils;
  import org.springframework.aop.framework.Advised;
  import org.springframework.beans.FatalBeanException;
  import org.springframework.beans.factory.BeanFactory;
  import org.springframework.beans.factory.ObjectFactory;
  import org.springframework.util.ClassUtils;
  
  /**
   * An extension of Component that allows spring to provide the base instance for a seam component.
   *
   * @author youngm
   */
  public class SpringComponent extends IoCComponent {
  	private static final String SPRING_COMPONENT_NAME_MAP = "org.jboss.seam.SpringComponentNameMap";
  
  	public static final String DESTRUCTION_CALLBACK_NAME_PREFIX = IoCComponent.class.getName()
  			+ ".DESTRUCTION_CALLBACK.";
  
  	private BeanFactory beanfactory;
  
  	private InterceptionType interceptionType;
  
  	private String springBeanName;
  
  	private static final ThreadLocal<ObjectFactory> objectFactory = new ThreadLocal<ObjectFactory>();
  
  	public static ObjectFactory getObjectFactory() {
  		return objectFactory.get();
  	}
  
  	public static void setObjectFactory(ObjectFactory bean) {
  		objectFactory.set(bean);
  	}
  
  	/**
  	 * Utility to add a SpringComponent to the seam component ApplicationContext.
  	 *
  	 * @param componentName the seam component name to use
  	 * @param springBeanName the spring bean name to map to this seam component
  	 * @param beanClassName the seam beanClass to use
  	 * @param scopeType the scope of this component
  	 * @param beanFactory the beanfactory this spring bean exists in
  	 * @param interceptorType the InterceptorTyp to force the bean to use. Will override any annotations on the bean.
  	 * @param override If a seam component already exists should we override it?
  	 */
  	public static void addSpringComponent(String componentName, String springBeanName, String beanClassName,
  			ScopeType scopeType, BeanFactory beanFactory, InterceptionType interceptorType, boolean override) {
  		// mock the application context
  		// TODO reuse
  		boolean unmockApplication = false;
  		if (!Contexts.isApplicationContextActive()) {
  			Lifecycle.mockApplication();
  			unmockApplication = true;
  		}
  		try {
  			if (!override && Component.forName(componentName) != null) {
  				throw new IllegalStateException("Cannot add spring component to seam with name: " + componentName
  						+ ".  There is already a seam component with that name.");
  			}
  			Map<String, String> springComponentNameMap = getSpringComponentNameMap();
  			// Add an entry to the spring+seam name association map
  			springComponentNameMap.put(springBeanName, componentName);
  			Class beanClass = ClassUtils.forName(beanClassName);
  			// Add the component to seam
  			Contexts.getApplicationContext().set(
  					componentName + Initialization.COMPONENT_SUFFIX,
  					new SpringComponent(beanClass, componentName, springBeanName, scopeType, beanFactory,
  							interceptorType));
  		} catch (ClassNotFoundException e) {
  			throw new FatalBeanException("Error", e);
  		} finally {
  			if (unmockApplication) {
  				Lifecycle.unmockApplication();
  			}
  		}
  	}
  
  	@SuppressWarnings("unchecked")
  	private static Map<String, String> getSpringComponentNameMap() {
  		if (Contexts.getApplicationContext().get(SPRING_COMPONENT_NAME_MAP) == null) {
  			Contexts.getApplicationContext().set(SPRING_COMPONENT_NAME_MAP, new HashMap<String, String>());
  		}
  		return (Map<String, String>) Contexts.getApplicationContext().get(SPRING_COMPONENT_NAME_MAP);
  	}
  
  	/**
  	 * Just like Component.forName() but mocks the applicationContext and you provide it with the spring bean name
  	 * instead of the seam component name.
  	 *
  	 * @param name the spring bean name.
  	 * @return the SpringComponent mapped to that spring bean name.
  	 */
  	public static SpringComponent forSpringBeanName(String springBeanName) {
  		// TODO reuse
  		boolean unmockApplication = false;
  		if (!Contexts.isApplicationContextActive()) {
  			Lifecycle.mockApplication();
  			unmockApplication = true;
  		}
  		try {
  			return (SpringComponent) Component.forName(getSpringComponentNameMap().get(springBeanName));
  		} finally {
  			if (unmockApplication) {
  				Lifecycle.unmockApplication();
  			}
  		}
  	}
  
  	/**
  	 * Creates a Spring Seam Component given a beanFactory.
  	 *
  	 * @param clazz the seam beanClass to use
  	 * @param componentName component name
  	 * @param springBeanName the spring bean name
  	 * @param scope component scope
  	 * @param factory the beanfactory this spring component should use
  	 */
  	public SpringComponent(Class clazz, String componenentName, String springBeanName, ScopeType scope,
  			BeanFactory factory, InterceptionType interception) {
  		super(clazz, componenentName, scope);
  		this.springBeanName = springBeanName;
  		this.beanfactory = factory;
  		this.interceptionType = interception;
  	}
  
  	protected String getIoCName() {
  		return "Spring";
  	}
  
  	protected Object instantiateIoCBean() throws Exception {
  		ObjectFactory objectFactory = getObjectFactory();
  		if (objectFactory == null) {
  			return beanfactory.getBean(springBeanName);
  		}
  		setObjectFactory(null);
  		Object bean = objectFactory.getObject();
  		// initialize the bean following Component.instantiateJavaBean()'s
  		// pattern.
  		if (getInterceptionType() == InterceptionType.NEVER) {
  			// Only call postConstruct if the bean is not stateless otherwise in the case of a singleton it wowuld be
  			// called every time seam request the bean not just when it is created.
  			if (getScope() != ScopeType.STATELESS) {
  				callPostConstructMethod(bean);
  			}
  		} else if (!(bean instanceof Proxy)) {
  			// Add all of the interfaces of the bean instance into the Seam
  			// proxy bean because spring's proxies add a bunch of interfaces too
  			// that should be accessible.
  			Set<Class> interfaces = new HashSet<Class>(Arrays.asList(bean.getClass().getInterfaces()));
  			interfaces.add(HttpSessionActivationListener.class);
  			interfaces.add(Mutable.class);
  			interfaces.add(Proxy.class);
  			// enhance bean
  			bean = ProxyUtils.enhance(bean, interfaces, this);
  		}
  		return bean;
  	}
  
  	/**
  	 * Instantiates a IoC bean and provides it as a java bean to be wrapped by seam.
  	 *
  	 * @see org.jboss.seam.Component#instantiateJavaBean()
  	 */
  	protected Object instantiateJavaBean() throws Exception {
  		return instantiateIoCBean();
  	}
  
  	/**
  	 * Calls the spring destroy callback when seam destroys the component
  	 *
  	 * @see org.jboss.seam.Component#callDestroyMethod(Object)
  	 */
  	@Override
  	public void callDestroyMethod(Object instance) {
  		super.callDestroyMethod(instance);
  		// Cannot call the callback on a STATELESS bean because we have no way of storing it.
  		if (getScope() != ScopeType.STATELESS) {
  			Runnable callback = (Runnable) getScope().getContext().get(DESTRUCTION_CALLBACK_NAME_PREFIX + getName());
  			if (callback != null) {
  				callback.run();
  			}
  		}
  	}
  
  	/**
  	 * Registers a destruction callback with this bean.
  	 *
  	 * @param name bean name
  	 * @param destroy the destroy to set
  	 */
  	public void registerDestroyCallback(String name, Runnable destroy) {
  		// Not sure yet how to register a stateless bean's Destruction callback.
  		if (getScope() != ScopeType.STATELESS) {
  			getScope().getContext().set(DESTRUCTION_CALLBACK_NAME_PREFIX + name, destroy);
  		}
  	}
  
  	/**
  	 * Overrides Components inject to unwrap all of the spring AOP layers so that fields can be injected into this bean.
  	 *
  	 * @see org.jboss.seam.Component#inject(java.lang.Object, boolean)
  	 */
  	@Override
  	public void inject(Object bean, boolean enforceRequired) {
  		if (bean instanceof Advised) {
  			try {
  				inject(((Advised) bean).getTargetSource().getTarget(), enforceRequired);
  			} catch (RuntimeException e) {
  				throw e;
  			} catch (Exception e) {
  				throw new RuntimeException(e);
  			}
  		}
  		super.inject(bean, enforceRequired);
  	}
  
  	/**
  	 * Use the InterceptionType override if available otherwise use the annotation or seam default.
  	 *
  	 * @see org.jboss.seam.Component#getInterceptionType()
  	 */
  	@Override
  	public InterceptionType getInterceptionType() {
  		if (interceptionType == null) {
  			return super.getInterceptionType();
  		}
  		return interceptionType;
  	}
  }
  
  
  
  1.1      date: 2007/02/17 03:26:43;  author: nrichards;  state: Exp;jboss-seam/src/ioc/org/jboss/seam/ioc/spring/TestAnnotation.java
  
  Index: TestAnnotation.java
  ===================================================================
  /**
   *
   */
  package org.jboss.seam.example.spring;
  
  import static java.lang.annotation.ElementType.TYPE;
  import static java.lang.annotation.RetentionPolicy.RUNTIME;
  
  import java.lang.annotation.Retention;
  import java.lang.annotation.Target;
  
  /**
   * @author youngm
   *
   */
  @Target({TYPE})
  @Retention(RUNTIME)
  public @interface TestAnnotation {
  
  }
  
  
  
  1.1      date: 2007/02/17 03:26:43;  author: nrichards;  state: Exp;jboss-seam/src/ioc/org/jboss/seam/ioc/spring/TestInterceptor.java
  
  Index: TestInterceptor.java
  ===================================================================
  /**
   *
   */
  package org.jboss.seam.example.spring;
  
  import java.io.Serializable;
  
  import org.aopalliance.intercept.MethodInterceptor;
  import org.aopalliance.intercept.MethodInvocation;
  
  /**
   * @author youngm
   *
   */
  public class TestInterceptor implements MethodInterceptor, Serializable {
  
  	/**
  	 * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
  	 */
  	public Object invoke(MethodInvocation arg0) throws Throwable {
  		System.out.println("Hit interceptor");
  		return arg0.proceed();
  	}
  
  }
  
  
  



More information about the jboss-cvs-commits mailing list