Package jfun.yan.spring

Source Code of jfun.yan.spring.Container2ApplicationContext$BeanListener

package jfun.yan.spring;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import jfun.yan.Component;
import jfun.yan.Container;
import jfun.yan.util.ReflectionUtil;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.HierarchicalMessageSource;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;

/**
* This class adapts a yan Container object
* to Spring's ApplicationContext (primarily ListableBeanFactory) interface.
* <p>
* Many Thanks to spring for making ApplicationContext an interface!
* It helped.
* </p>
* <p>
* @author Ben Yu
* Nov 16, 2005 11:40:13 PM
*/
public class Container2ApplicationContext implements ListableBeanFactory,
ApplicationContext{
 
  private final String name;
  private final long startup_timestamp;
  private final Container yan;
  private final MessageSource parent_message_source;
  private final ResourcePatternResolver resource_loader;
  private final ApplicationEventPublisher parent_publisher;
  private static final String prefix = BeanFactory.FACTORY_BEAN_PREFIX;;
  private MessageSource message_source = null;
  private ApplicationEventMulticaster multicaster = null;
  private synchronized MessageSource getMessageSource(){
    if(message_source!=null) return message_source;
    final String key = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME;
    final Class type = yan.getComponentType(key);
    if(type!=null && MessageSource.class.isAssignableFrom(type)){
      message_source = (MessageSource)yan.getInstance(key);
      if (parent_message_source != null && message_source instanceof HierarchicalMessageSource) {
        HierarchicalMessageSource hms = (HierarchicalMessageSource) message_source;
        if (hms.getParentMessageSource() == null) {
          // Only set parent context as parent MessageSource if no parent MessageSource
          // registered already.
          hms.setParentMessageSource(parent_message_source);
        }
      }
    }
    else{
      return parent_message_source;
    }
    return message_source;
  }
  private synchronized ApplicationEventMulticaster getApplicationEventMulticaster(){
    if(multicaster!=null) return multicaster;
    final String key = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME;
    final Class type = yan.getComponentType(key);
    if(type!=null && ApplicationEventMulticaster.class.isAssignableFrom(type)){
      multicaster = (ApplicationEventMulticaster)yan.getInstance(key);
    }
    else{
      multicaster = new SimpleApplicationEventMulticaster();
    }
    return multicaster;
  }
  /**
   * Create a Container2BeanFactory object.
   * @param message_source the MessageSource object.
   * @param resource_loader the ResourcePatternResolver object.
   * @param publisher the ApplicationEventPublisher object.
   * @param name the name of the ApplicationContext.
   * @param startup_timestamp the startup timestamp.
   * @param yan the yan Container object.
   */
  public Container2ApplicationContext(
      MessageSource message_source, ResourcePatternResolver resource_loader,
      ApplicationEventPublisher publisher,
      String name, long startup_timestamp,
      Container yan
  )
  {
    this.parent_message_source = message_source;
    this.name = name;
    this.resource_loader = resource_loader;
    this.startup_timestamp = startup_timestamp;
    this.yan = yan;
    this.parent_publisher = publisher;
  }

  /**
   * Get the container in this object.
   */
  public Container getContainer() {
    return yan;
  }


  /**
   * Get the number of components registered under a string key.
   */
  public int getBeanDefinitionCount() {
    final Set keys = yan.keys();
    int ret = 0;
    for(Iterator it=keys.iterator(); it.hasNext();){
      final Object key = it.next();
      if(key instanceof String){
        ret++;
      }
    }
    return ret;
  }

  /**
   * Get all the component keys that are of String type.
   */
  public String[] getBeanDefinitionNames() {
    final Set keys = yan.keys();
    final ArrayList names = new ArrayList();
    for(Iterator it=keys.iterator(); it.hasNext();){
      final Object key = it.next();
      if(key instanceof String){
        names.add((String)key);
      }
    }
    final String[] ret = new String[names.size()];
    names.toArray(ret);
    return ret;
  }

  /**
   * retrieves the string keys of all components
   * whose's static instance type is a subtype of the required type.
   * <p>
   * FactoryBean's are not instantiated.
   * </p>
   * @param type the type to match. Null indicates all.
   * @return the keys.
   */
  public String[] getBeanDefinitionNames(Class type) {
    return getBeanNamesForType(type, true, false);
  }
  /**
   * retrieves the string keys of all components
   * whose's static instance type is a subtype of the required type.
   * <p>
   * FactoryBean's are instantiated if necessary to find out the product type.
   * </p>
   * @param type the type to match. Null indicates all.
   * @return the keys.
   */
  public String[] getBeanNamesForType(Class type){
    return getBeanNamesForType(type, true, true);
  }
  private interface BeanListener{
    /**
     * When a regular bean is found.
     */
    void onBean(String key, Component c);
    /**
     * When a FactoryBean is instantiated and the product type and singleton mode satisifies the condition.
     */
    void onFactoryBean(String key, FactoryBean fb);
    /**
     * When a FactoryBean component itself is matched.
     */
    void onFactoryBean(String key, Component fbc);
  }
  /**
   * Iterate through the beans for a certain type.
   * @param type the required type.
   * @param includePrototypes whether prototype beans are included.
   * (thread scope singleotn is considered prototype as well because it doesn't guarantee one instance globally).
   * @param includeFactoryBeans whether we want to instantiate FactoryBean to find out the product type
   * and the singleton mode.
   * @param listener the BeanListener object.
   */
  private void foreachBean(Class type,
      boolean includePrototypes, boolean includeFactoryBeans,
      BeanListener listener){
    final boolean for_factorybean = isFactoryBeanType(type);
    for(Iterator it=yan.keys().iterator();it.hasNext();){
      final Object key = it.next();
      if(!(key instanceof String)) continue;
      final jfun.yan.Component c = yan.getComponent(key);
      final Component fbc = SpringAdapter.getFactoryBeanComponent(c);
      if(fbc!=null){
        //I am Factory Bean
        if(includeFactoryBeans){
          //attempt to match the FactoryBean result.
          final FactoryBean fb = (FactoryBean)instantiate(fbc);
          if(!includePrototypes && !fb.isSingleton()){
            continue;
          }
          final Class fbt = fb.getObjectType();
          if(type==null || ReflectionUtil.isAssignableFrom(type, fbt)){
            final String beanname = (String)key;
            listener.onFactoryBean(beanname, fb);
            continue;
          }
        }
        if(!includePrototypes && !c.isSingleton()){
          continue;
        }
        if(type==null || for_factorybean){
          //if searching FactoryBean.class or null, we return the FactoryBean itself.
          listener.onFactoryBean((String)key, fbc);
          continue;
        }
      }
      else{
        if(!includePrototypes && !c.isSingleton()){
          continue;
        }
        if(type==null){
          listener.onBean((String)key, c);
          continue;
        }
        final Class ctype = c.getType();
        if(ctype!=null&&ReflectionUtil.isAssignableFrom(type, ctype)){
          listener.onBean((String)key, c);
          continue;
        }
      }
    }
  }

  public String[] getBeanNamesForType(Class type, boolean includePrototypes,
      boolean includeFactoryBeans){
    /*
    final boolean for_factorybean = type!=null&&FactoryBean.class.equals(type);
    final ArrayList buf = new ArrayList();
    for(Iterator it=yan.keys().iterator();it.hasNext();){
      final Object key = it.next();
      if(!(key instanceof String)) continue;
      final jfun.yan.Component c = yan.getComponent(key);
      final Component fbc = SpringAdapter.getFactoryBeanComponent(c);
     
      if(fbc!=null){
        //I am Factory Bean
        if(includeFactoryBeans){
          //attempt to match the FactoryBean result.
          final FactoryBean fb = (FactoryBean)instantiate(fbc);
          if(!includePrototypes && !fb.isSingleton()){
            continue;
          }
          final Class fbt = fb.getObjectType();
          if(type==null || ReflectionUtil.isAssignableFrom(type, fbt)){
            final String beanname = (String)key;
            buf.add(beanname);
            continue;
          }
        }
        if(!includePrototypes && !c.isSingleton()){
          continue;
        }
        if(type==null || for_factorybean){
          //if searching FactoryBean.class or null, we return the FactoryBean itself.
          buf.add(BeanFactory.FACTORY_BEAN_PREFIX+key);
          continue;
        }
      }
      else{
        if(!includePrototypes && !c.isSingleton()){
          continue;
        }
        if(type==null){
          buf.add(key);
          continue;
        }
        final Class ctype = c.getType();
        if(ctype!=null&&ReflectionUtil.isAssignableFrom(type, ctype)){
          buf.add(key);
          continue;
        }
      }
    }*/
    final ArrayList buf = new ArrayList();
    final BeanListener listener = new BeanListener(){
      public void onBean(String key, Component c) {
        buf.add(key);
      }
      public void onFactoryBean(String key, Component fbc) {
        buf.add(prefix+key);
      }
      public void onFactoryBean(String key, FactoryBean fb) {
        buf.add(key);
      }
    };
    foreachBean(type, includePrototypes, includeFactoryBeans, listener);
    final String[] ret = new String[buf.size()];
    buf.toArray(ret);
    return ret;
  }
  /*
   * Does this container contains a component with the given name?
   * @param beanName the name of the component. If it starts with
   * a "&", as specified by Spring, this "&" is chopped off
   * before searching.
   */
  public boolean containsBeanDefinition(String beanName) {
    return yan.containsKey(getRealBeanName(beanName));
  }
  private static String getRealBeanName(String name){
    return BeanFactoryUtils.transformedBeanName(name);
  }
 
  private static boolean isFactoryBeanType(Class type){
    return type!=null && FactoryBean.class.equals(type);
  }
  /*
  private FactoryBean getFactoryBean(Component c){
    return new Component2FactoryBean(c, yan);
  }*/
  private Object instantiate(Component c){
    return yan.instantiateComponent(c);
  }
  /**
   * Get the (String,Object) map of all components with the given type.
   * @param type the expected type. If this type is FactoryBean,
   * the component is adapted to FactoryBean without actually instantiating
   * instance.
   * @return the Map object containing component instances (if the type
   * is not BeanFactory), otherwise BeanFactory objects.
   */
  public Map getBeansOfType(Class type) throws BeansException {
    return getBeansOfType(type, true, true);
  }
  /**
   * Get the (String,Object) map of all components with the given type.
   * @param type the expected type.
   * @param includePrototypes Are the components who may not be singletons included?
   * @param includeFactoryBeans Are FactoryBean objects included?
   * @return the Map object containing component instances.
   */
  public Map getBeansOfType(Class type, boolean includePrototypes,
      boolean includeFactoryBeans) throws BeansException {
    /*
    final String prefix = BeanFactory.FACTORY_BEAN_PREFIX;
    final Map result = new LinkedHashMap();
    if(isFactoryBeanType(type)){
      for(Iterator it=yan.keys().iterator();it.hasNext();){
        final Object key = it.next();
        if(!(key instanceof String))
          continue;
        final String beanname = (String)key;
        final Component c = yan.getComponent(key);
        if(!includePrototypes && !c.isSingleton())
          continue;
        final Component fbc = SpringAdapter.getFactoryBeanComponent(c);
        if(fbc!=null){
          result.put(beanname, yan.instantiateComponent(fbc));
        }
      }
    }
    else{
      for(Iterator it=yan.keys().iterator();it.hasNext();){
        final Object key = it.next();
        if(!(key instanceof String))
          continue;
        final Component c = yan.getComponent(key);
        if(!includePrototypes && !c.isSingleton())
          continue;
        final Class ctype = c.getType();
        if(ctype!=null && ReflectionUtil.isAssignableFrom(type, ctype)){
          result.put(key, instantiate(c));
        }
        else if(includeFactoryBeans){
          final Component fbc = SpringAdapter.getFactoryBeanComponent(c);
          if(fbc!=null){
            final FactoryBean fb = (FactoryBean)yan.instantiateComponent(fbc);
            if(ReflectionUtil.isAssignableFrom(type, fb.getObjectType())){
              final String beanname = (String)key;
              try{
                result.put(beanname, fb.getObject());
              }
              catch(RuntimeException e){
                throw e;
              }
              catch(Error e){
                throw e;
              }
              catch(Exception e){
                throw new BeanCreationException((String)key, "FactoryBean failed", e);
              }
            }
          }
        }
      }
    }
    return result;*/
    final Map result = new LinkedHashMap();
    final BeanListener listener = new BeanListener(){
      public void onBean(String key, Component c) {
        result.put(key, instantiate(c));
      }
      public void onFactoryBean(String key, Component fbc) {
        result.put(prefix+key, instantiate(fbc));
      }
      public void onFactoryBean(String key, FactoryBean fb) {
        result.put(key, instantiate(key, fb));
      }
    };
    return result;
  }
  private Component findComponent(String name){
    final Component c = yan.getComponent(name);
    if(c==null){
      throw new NoSuchBeanDefinitionException(name, "bean "+name+" not found.");
    }
    return c;
  }
  private Component getComponent(String name){
    return findComponent(BeanFactoryUtils.transformedBeanName(name));
  }
  /**
   * Get a bean object.
   * @param name the name of the component.
   * If the name starts with a "&", as specified by Spring,
   * a FactoryBean object is returned corresponding to the component,
   * otherwise the component itself is instantiated.
   */
  public Object getBean(final String name) throws BeansException {
    /*
    if(BeanFactoryUtils.isFactoryDereference(name)){
     final String factoryname = BeanFactoryUtils.transformedBeanName(name);
     return getFactoryBean(findComponent(factoryname));
    }
    else{
     return instantiate(findComponent(name));
    }*/
    return getBean(name, null);
  }

  /**
   * Get a bean object.
   * @param beanname the name of the component.
   * If the name starts with a "&", as specified by Spring,
   * a FactoryBean object is returned corresponding to the component,
   * otherwise the component itself is instantiated.
   * @param requiredType the expecting type. If the name starts with
   * a "&", as specified by Spring convention, the type has to be
   * either null or FactoryBean or a super type of FactoryBean.
   * And in that case, a FactoryBean object is returned.
   * If the name is a regular bean name, the corresponding component
   * is instantiated.
   */
  public Object getBean(final String beanname, Class requiredType) throws BeansException {
    if(BeanFactoryUtils.isFactoryDereference(beanname)){
      //return FactoryBean
      final String factoryname = BeanFactoryUtils.transformedBeanName(beanname);
      final Component c = findComponent(factoryname);
      final Component fbc = SpringAdapter.getFactoryBeanComponent(c);
      if(fbc!=null){
        throw new NoSuchBeanDefinitionException(beanname,
            "FactoryBean "+factoryname+" not found.");
      }
      final Object result = instantiate(fbc);
      checkBeanInstanceType(beanname, requiredType, result);
      return result;
    }
    else{
      final Component c = findComponent(beanname);
      final Component fbc = SpringAdapter.getFactoryBeanComponent(c);
      if(requiredType==null){
        return instantiate(c);
      }
      if(fbc!=null){
        final FactoryBean fb = (FactoryBean)instantiate(fbc);
        final Class ctype = fb.getObjectType();
        checkBeanType(beanname, requiredType, ctype);
        return instantiate(beanname, fb);
      }
      else{
        final Class ctype = c.getType();
        if(c.isConcrete()){
          checkBeanType(beanname, requiredType, ctype);
        }
        final Object result = instantiate(c);
        checkBeanInstanceType(beanname, requiredType, result);
        return result;
      }
    }
  }

  /**
   * Same as {@link #containsBeanDefinition(String)} since
   * this class does not care about hierarchy.
   * In fact, Yan does not create Spring hierarchies.
   */
  public boolean containsBean(String name) {
    return this.containsBeanDefinition(name);
    //yan.containsKey(BeanFactoryUtils.transformedBeanName(name));
  }

  /**
   * Is the component identified by the name a singleton?
   * FactoryBean is instantiated if the name doesn't start with '&'
   * and the bean is a FactoryBean.
   */
  public boolean isSingleton(final String name)
  throws NoSuchBeanDefinitionException {
    final Component c = getComponent(name);
    if(!BeanFactoryUtils.isFactoryDereference(name)){
      final Component fbc = SpringAdapter.getFactoryBeanComponent(c);
      if(fbc!=null){
        final FactoryBean fb = (FactoryBean)instantiate(fbc);
        return fb.isSingleton();
      }
    }
    return c.isSingleton();
  }

  /**
   * Get the static type of a component identified by the name.
   * @param name the bean name. FactoryBean is instantiated if
   * the name doesn't start with '&' and the bean is a FactoryBean.
   */
  public Class getType(final String name)
  throws NoSuchBeanDefinitionException {
    final Component c = getComponent(name);
    if(!BeanFactoryUtils.isFactoryDereference(name)){
      final Component fbc = SpringAdapter.getFactoryBeanComponent(c);
      if(fbc!=null){
        final FactoryBean fb = (FactoryBean)instantiate(fbc);
        return fb.getObjectType();
      }
    }
    return c.getType();
  }
  private static final String[] no_aliases = {};
  /**
   * Always returns empty.
   */
  public String[] getAliases(String name)
  throws NoSuchBeanDefinitionException {
    getComponent(name);
    return no_aliases;
  }

  public String getDisplayName() {
    return name;
  }

  public ApplicationContext getParent() {
    return null;
  }

  public long getStartupDate() {
    return startup_timestamp;
  }

  public void publishEvent(ApplicationEvent event) {
    final ApplicationEventMulticaster multicaster = getApplicationEventMulticaster();
    multicaster.multicastEvent(event);
    if(parent_publisher!=null)
      parent_publisher.publishEvent(event);
  }



  public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
    return getMessageSource().getMessage(code, args, locale);
  }

  public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
    return getMessageSource().getMessage(resolvable, locale);
  }

  public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
    return getMessageSource().getMessage(code, args, defaultMessage, locale);
  }

  public Resource[] getResources(String locationPattern) throws IOException {
    return resource_loader.getResources(locationPattern);
  }

  public Resource getResource(String location) {
    return resource_loader.getResource(location);
  }

  public BeanFactory getParentBeanFactory() {
    return null;
  }
  private void checkBeanType(String beanname, Class required, Class actual){
    if(actual!=null && required!=null &&
        !ReflectionUtil.isAssignableFrom(required, actual)){
      throw new BeanNotOfRequiredTypeException(beanname, required, actual);
    }
  }
  private void checkBeanInstanceType(String beanname, Class required, Object instance){
    if(required!=null &&
        !ReflectionUtil.isInstance(required, instance)){
      throw new BeanNotOfRequiredTypeException(beanname, required,
          instance==null?null:instance.getClass());
    }
  }
  private static Object instantiate(String beanname, FactoryBean fb){
    try{
      return fb.getObject();
    }
    catch(RuntimeException e){
      throw e;
    }
    catch(Error e){
      throw e;
    }
    catch(Exception e){
      throw new BeanCreationException(beanname, "FactoryBean failed", e);
    }
  }
}
TOP

Related Classes of jfun.yan.spring.Container2ApplicationContext$BeanListener

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.