Package jfun.yan.spring

Source Code of jfun.yan.spring.SpringAdapter

package jfun.yan.spring;

import java.util.Properties;

import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.TransactionProxyFactoryBean;

import jfun.yan.Component;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.Map;
import jfun.yan.Map3;
import jfun.yan.Monad;
import jfun.yan.Mutation;
import jfun.yan.factory.ThreadLocalScope;
import jfun.yan.xml.NutsUtils;
import jfun.yan.xml.SingletonMode;



/**
* The main adapter class to between Yan and Spring.
* <p>
* @author Ben Yu
* Nov 17, 2005 12:01:20 AM
*/
public class SpringAdapter {

  private static Object injectFactoryBeanResult(final SpringContext ctxt, Object obj)
  throws ClassNotFoundException, Exception {
    //injectBasicBean(obj, ctxt);
    if(obj instanceof FactoryBean){
      obj = ((FactoryBean)obj).getObject();
      //Spring 1.2.6 source code doesn't handle FactoryBean results. so we skip.
      //injectBasicBean(obj, ctxt);
    }
    return obj;
  }
  private static Map3 getFactoryBeanMap3(final SpringContext ctxt,
      final String[] itfs){
    return new Map3(){
      public Object map(Object tx, Object attrs, Object obj)
      throws Exception{
        final PlatformTransactionManager man =(PlatformTransactionManager)tx;
        final Properties tattrs = (Properties)attrs;
        final Object r = injectFactoryBeanResult(ctxt, obj);
        return proxyTransaction(r, ctxt, man, tattrs, itfs);
      }
    };
  }

  private static Map getFactoryBeanMap(final SpringContext ctxt){
    return new Map(){
      public Object map(Object obj)
      throws Exception{
        return injectFactoryBeanResult(ctxt, obj);
      }
    };
  }
  private static Mutation getBeanMutation(final SpringContext ctxt){
    return new Mutation(){
      public void mutate(Object obj)
      throws Exception{
        injectBasicBean(obj, ctxt);
      }
    };
  }
  /**
   * Inject spring dependencies into an object when it is of any
   * Spring marker interface. Run FactoryBean if any.
   * Add transaction proxy if any.
   * @param obj the object to inject dependencies.
   * @param ctxt the SpringContext object hosting all pertinent
   * runtime information.
   * @param transaction_manager the Component that instantiates the transaction manager.
   * Can be null if transaction_attributes is null.
   * @param transaction_attributes the Component that instantiates a Properties object
   * that contains transaction attributes.
   * This is the indicator parameter. When it is null, no transaction proxying is done.
   * And when it is not null, the transaction_manager cannot be null.
   * @param interfaces the interface names to proxy on.
   * Can be null.
   * @return the final result object.
   */
  public static Object injectBean(Object obj, SpringContext ctxt,
      PlatformTransactionManager transaction_manager,
      Properties transaction_attributes, String[] interfaces)
  throws Exception{
    injectBasicBean(obj, ctxt);
    return proxyTransaction(obj, ctxt,
        transaction_manager, transaction_attributes, interfaces);
  }
  private static void injectApplicationContext(Object obj, ApplicationContext actxt){
    if(obj instanceof ApplicationContextAware){
      ((ApplicationContextAware)obj).setApplicationContext(actxt);
    }
    else{
      if(obj instanceof BeanFactoryAware){
        ((BeanFactoryAware)obj).setBeanFactory(actxt);
      }

      if(obj instanceof ResourceLoaderAware){
        ((ResourceLoaderAware)obj).setResourceLoader(actxt);
      }
      if(obj instanceof ApplicationEventPublisherAware){
        ((ApplicationEventPublisherAware)obj).setApplicationEventPublisher(actxt);
      }
      if(obj instanceof MessageSourceAware){
        ((MessageSourceAware)obj).setMessageSource(actxt);
      }
    }
  }
  /**
   * Inject spring dependencies into an object when it is of any
   * Spring marker interface.
   * @param obj the object to inject dependencies.
   * @param ctxt the SpringContext object hosting all pertinent
   * runtime information.
   * @param transaction_manager the Component that instantiates the transaction manager.
   * @param transaction_attributes the Component that instantiates a Properties object
   * that contains transaction attributes.
   * @param interfaces the interface names to proxy on.
   * @return the final result object.
   */
  private static void injectBasicBean(Object obj, SpringContext ctxt)
  throws Exception{
    if(ctxt.isGloballyDefined()){
      //only ids of global components make sense.
      final String id = ctxt.getId();
      if(id!=null && obj instanceof BeanNameAware){
        ((BeanNameAware)obj).setBeanName(id);
      }
    }
    injectApplicationContext(obj, ctxt.getApplicationContext());

    initBean(obj, ctxt);
  }
  private static void initBean(Object obj, SpringContext ctxt)
  throws Exception{
    final Object original = obj;
    //  applyBeanPostProcessorsBeforeInitialization(bean, beanName, mergedBeanDefinition)
    if(obj instanceof InitializingBean){
      ((InitializingBean)obj).afterPropertiesSet();
    }
    //runInitializer(obj, ctxt.getInitializer());
    //applyBeanPostProcessorsAfterInitialization(bean, beanName, mergedBeanDefinition);
    if(original instanceof DisposableBean){
      final DisposableBean db = (DisposableBean)original;
      ctxt.manageDisposableBean(db);
    }
  }
  private static final Component autowire_txman =
    Components.useType(PlatformTransactionManager.class);
  /**
   * Decorate a Component with spring context so that
   * dependencies can be injected automatically, and
   * FactoryBean can be automatically instantiated.
   * @param c the Component object.
   * @param ctxt the SpringContext object.
   * @param transaction_manager the Component that instantiates the transaction manager.
   * Can be null if transaction_attributes is null.
   * @param transaction_attributes the Component that instantiates a Properties object
   * that contains transaction attributes.
   * This is the indicator parameter. When it is null, no transaction proxying is done.
   * And when it is not null, the transaction_manager cannot be null.
   * @param interfaces the interface names to proxy on.
   * Can be null.
   * @return the new Component that does all the spring-related work.
   */
  public static Component adapt(Component c,
      SpringContext ctxt, Component transaction_manager,
      Component transaction_attributes, String[] interfaces){
    if(transaction_attributes!=null && transaction_manager==null){
      transaction_manager =
        ctxt.cast(PlatformTransactionManager.class,
            autowire_txman
        ).label("transaction manager auto detection");
    }
    final Class type = c.getType();

    final Component r = createSpringBeanComponent(c, ctxt, transaction_manager, transaction_attributes, interfaces);
    if(type!=null && BeanPostProcessor.class.isAssignableFrom(type)){
      //does bpp suffer from proxies?
      ctxt.addBeanPostProcessor(ctxt.getTagName(), c);
    }
    if(type!=null && FactoryBean.class.isAssignableFrom(type)){
      //for factory bean, we do not know its type in advance.
      return r;
    }
    if(transaction_attributes!=null){
      //for beans to be proxied, we do not know the type.
      return r;
    }
    if(r.getType()==null && type!=null)
      return ctxt.cast(type, r);
    else return r;
  }
  private static Component createSpringBeanComponent(Component c, SpringContext ctxt,
      Component transaction_manager, Component transaction_attributes,
      String[] interfaces) {
    final Class type = c.getType();
    c = c.mutate(getBeanMutation(ctxt));
    if(type!=null && SpringUtils.isSpringInfrastructureClass(type)){
      //no proxy for spring special cases.
      return c;//.map(getBeanMap(ctxt));
    }
    final boolean isfactorybean = type!=null && FactoryBean.class.isAssignableFrom(type);
    if(isfactorybean){
      if(ctxt.isSingletonAttributeSet()){
        final SingletonMode mode = ctxt.getSingleton();
        if(mode!=null)
          c = mode.decorate(c);
      }
      else{
        //factroy bean is by default singleton.
        c = c.singleton(new ThreadLocalScope());
      }
    }
    if(transaction_attributes==null){
      //no transaction to do
      if(type==null || isfactorybean){
        return singletonedFactoryBean(isfactorybean,c,
            c.map(getFactoryBeanMap(ctxt)));
      }
      else{
        return c;
      }
    }
    else{
      return singletonedFactoryBean(isfactorybean, c,
          Monad.map(transaction_manager, transaction_attributes, c, getFactoryBeanMap3(ctxt, interfaces)));
    }
  }
  private static Component singletonedFactoryBean(boolean factorybean,
      Component original_cc, Component c){
    if(factorybean){
      return decorateFactoryBean(new NonSingletonComponent(c), original_cc);
    }
    else{
      return c;
    }
  }
  private static Object proxyTransaction(Object target, SpringContext ctxt,
      PlatformTransactionManager tx, Properties attrs, String[] itfs)
  throws Exception{
    if(tx==null){
      if(attrs==null)
        return target;
      else
        throw new IllegalArgumentException("transaction manager is missing to perform declarative transaction");
    }
    final TransactionProxyFactoryBean tpfb = new TransactionProxyFactoryBean();
    //tpfb.setBeanFactory(ctxt.getApplicationContext());
    tpfb.setTarget(target);
    tpfb.setTransactionManager(tx);
    if(itfs!=null)
      tpfb.setProxyInterfaces(itfs);
    tpfb.setTransactionAttributes(attrs);
    //injectBasicBean(tpfb, ctxt);
    tpfb.setTarget(target);
    tpfb.setTransactionManager(tx);
    tpfb.setTransactionAttributes(attrs);
   
    if(itfs!=null){
      tpfb.setProxyInterfaces(itfs);
    }
    injectBasicBean(tpfb, ctxt);
    return tpfb.getObject();
  }
  static final SpringKey factory_bean_key = new SpringKey("org.springframework.FactoryBean");
  static Component decorateFactoryBean(Component c, Component factorybean_cc){
    return NutsUtils.setState(c, factory_bean_key, factorybean_cc);
  }
  static boolean isFactoryBeanComponent(Component c){
    return getFactoryBeanComponent(c) != null;
  }
  static Component getFactoryBeanComponent(Component c){
    final Class type = c.getType();
    if(type!=null && FactoryBean.class.isAssignableFrom(type)){
      return c;
    }
    else{
      final Component fbc = (Component)NutsUtils.getState(c, factory_bean_key);
      return fbc;
    }
  }
  /**
   * Get FactoryBean instance from a Spring integrated Container object.
   * @param yan the Container object.
   * @param key the key of the FactoryBean component. The key doesn't need to be
   * prefixed with a '&' as one has to do in Spring.
   * @return the FactoryBean instance.
   */
  public static FactoryBean getFactoryBean(Container yan, Object key){
    final Component c = yan.getComponent(key);
    if(c==null){
      return null;
    }
    final Component fbc = getFactoryBeanComponent(c);
    if(fbc==null){
      return null;
    }
    return (FactoryBean)yan.instantiateComponent(fbc);
  }
}
TOP

Related Classes of jfun.yan.spring.SpringAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.