Package org.beangle.spring.bind

Source Code of org.beangle.spring.bind.AutoConfigProcessor

/* Copyright c 2005-2012.
* Licensed under GNU  LESSER General Public License, Version 3.
* http://www.gnu.org/licenses
*/
package org.beangle.spring.bind;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.time.StopWatch;
import org.beangle.commons.collection.CollectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;

public class AutoConfigProcessor implements BeanDefinitionRegistryPostProcessor {
  private static final Logger logger = LoggerFactory.getLogger(AutoConfigProcessor.class);

  protected Map<String, BeanDefinition> newBeanDefinitions = CollectUtils.newHashMap();

  protected BindRegistry bindRegistry;

  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    StopWatch watch = new StopWatch();
    watch.start();
    bindRegistry = new DefinitionBindRegistry(registry);
    register(registry);
    autowire();
    logger.debug("Auto register and wire bean [{}]", newBeanDefinitions.keySet());
    logger.info("Auto register and wire {} beans using {} mills", newBeanDefinitions.size(),
        watch.getTime());
    newBeanDefinitions.clear();
    bindRegistry = null;
  }

  public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
  }

  protected void register(BeanDefinitionRegistry registry) {
    List<String> modules = bindRegistry.getBeanNames(BindModule.class);
    for (String name : modules) {
      Class<?> beanClass = bindRegistry.getBeanType(name);
      BeanConfig config = null;
      try {
        config = ((BindModule) beanClass.newInstance()).getConfig();
      } catch (Exception e) {
        logger.error("class initialization error of  " + beanClass, e);
        continue;
      }
      List<BeanConfig.Definition> definitions = config.getDefinitions();
      for (BeanConfig.Definition definition : definitions) {
        String beanName = definition.beanName;
        if (bindRegistry.contains(beanName)) {
          logger.warn("Ingore exists bean definition {}", beanName);
        } else {
          BeanDefinition def = register(beanName, definition.clazz, definition.scope, registry);
          newBeanDefinitions.put(beanName, def);
        }
      }
    }
  }

  /**
   * @param beanName
   * @param clazz
   * @param registry
   * @param definition
   */
  protected BeanDefinition register(String beanName, Class<?> clazz, String scope,
      BeanDefinitionRegistry registry) {
    GenericBeanDefinition def = new GenericBeanDefinition();
    def.setBeanClass(clazz);
    def.setScope(scope);
    registry.registerBeanDefinition(beanName, def);
    bindRegistry.register(clazz, beanName);
    logger.debug("Register definition {} for {}", beanName, clazz);
    return def;
  }

  protected void autowire() {
    for (Map.Entry<String, BeanDefinition> entry : newBeanDefinitions.entrySet()) {
      String beanName = entry.getKey();
      BeanDefinition mbd = entry.getValue();
      autowire(beanName, mbd);
    }
  }

  protected void autowire(String beanName, BeanDefinition mbd) {
    Map<String, PropertyDescriptor> properties = unsatisfiedNonSimpleProperties(mbd);
    for (Map.Entry<String, PropertyDescriptor> entry : properties.entrySet()) {
      String propertyName = entry.getKey();
      PropertyDescriptor pd = entry.getValue();
      if (Object.class.equals(pd.getPropertyType())) continue;
      MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
      List<String> beanNames = bindRegistry.getBeanNames(methodParam.getParameterType());
      boolean binded = false;
      if (beanNames.size() == 1) {
        mbd.getPropertyValues().add(propertyName, new RuntimeBeanReference(beanNames.get(0)));
        binded = true;
      } else if (beanNames.size() > 1) {
        for (String name : beanNames) {
          if (name.equals(propertyName)) {
            mbd.getPropertyValues().add(propertyName, new RuntimeBeanReference(propertyName));
            binded = true;
            break;
          }
        }
      }
      if (!binded) {
        if (beanNames.isEmpty()) {
          logger.debug(beanName + "'s " + propertyName + "  cannot  found candidate bean");
        } else {
          logger.warn(beanName + "'s " + propertyName + " expected single bean but found {} : {}",
              beanNames.size(), beanNames);
        }
      }
    }
  }

  public static boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
    Method wm = pd.getWriteMethod();
    if (wm == null) { return false; }
    if (!wm.getDeclaringClass().getName().contains("$$")) {
      // Not a CGLIB method so it's OK.
      return false;
    }
    // It was declared by CGLIB, but we might still want to autowire it
    // if it was actually declared by the superclass.
    Class<?> superclass = wm.getDeclaringClass().getSuperclass();
    return !ClassUtils.hasMethod(superclass, wm.getName(), wm.getParameterTypes());
  }

  protected Map<String, PropertyDescriptor> unsatisfiedNonSimpleProperties(BeanDefinition mbd) {
    Map<String, PropertyDescriptor> properties = CollectUtils.newHashMap();
    PropertyValues pvs = mbd.getPropertyValues();
    Class<?> clazz = null;
    try {
      clazz = Class.forName(mbd.getBeanClassName());
    } catch (ClassNotFoundException e) {
      logger.error("Class " + mbd.getBeanClassName() + "not found", e);
      return properties;
    }
    PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(clazz);
    for (PropertyDescriptor pd : pds) {
      if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd)
          && !pvs.contains(pd.getName()) && !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
        properties.put(pd.getName(), pd);
      }
    }
    return properties;
  }

}
TOP

Related Classes of org.beangle.spring.bind.AutoConfigProcessor

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.