Package org.springframework.yarn.config.annotation

Source Code of org.springframework.yarn.config.annotation.SpringYarnAnnotationPostProcessor

/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.yarn.config.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.Lifecycle;
import org.springframework.context.SmartLifecycle;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.yarn.annotation.OnContainerStart;
import org.springframework.yarn.container.ContainerHandler;

/**
* A {@link BeanPostProcessor} implementation that processes method-level
* annotations such as @{@link OnContainerStart}.
*
* @author Mark Fisher
* @author Marius Bogoevici
* @author Janne Valkealahti
*
*/
public class SpringYarnAnnotationPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean,
    Lifecycle, ApplicationListener<ApplicationEvent> {

  private final static Log log = LogFactory.getLog(SpringYarnAnnotationPostProcessor.class);

  /** Factory from BeanFactoryAware */
  private volatile ConfigurableListableBeanFactory beanFactory;

  /** Post processors map - annotation -> method post processor */
  private final Map<Class<? extends Annotation>, MethodAnnotationPostProcessor<?>> postProcessors =
      new HashMap<Class<? extends Annotation>, MethodAnnotationPostProcessor<?>>();

  /**
   * Application events for post processed beans (if bean instance of ApplicationListener) will
   * be dispatched from here via callback in this class.
   */
  private final Set<ApplicationListener<ApplicationEvent>> listeners = new HashSet<ApplicationListener<ApplicationEvent>>();

  /**
   * Lifecycle callbacks for post processed bean (if bean instance of Lifecycle) will
   * be dispatched from here via callback in this class.
   */
  private final Set<Lifecycle> lifecycles = new HashSet<Lifecycle>();

  /** Flag for Lifecycle in this class */
  private volatile boolean running = true;

  @Override
  public void setBeanFactory(BeanFactory beanFactory) {
    Assert.isAssignable(ConfigurableListableBeanFactory.class, beanFactory.getClass(),
        "a ConfigurableListableBeanFactory is required");
    this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
  }

  @Override
  public void afterPropertiesSet() {
    Assert.notNull(beanFactory, "BeanFactory must not be null");
    postProcessors.put(OnContainerStart.class, new ContainerActivatorAnnotationPostProcessor(beanFactory));
  }

  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }

  @Override
  public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
    Assert.notNull(beanFactory, "BeanFactory must not be null");
    final Class<?> beanClass = getBeanClass(bean);

    if (!isStereotype(beanClass)) {
      // we only post-process stereotype components
      return bean;
    }

    ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {

      @SuppressWarnings({ "unchecked", "rawtypes" })
      public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
        Annotation[] annotations = AnnotationUtils.getAnnotations(method);

        for (Annotation annotation : annotations) {
          MethodAnnotationPostProcessor postProcessor = postProcessors.get(annotation.annotationType());

          if (postProcessor != null && shouldCreateHandler(annotation)) {
            Object result = postProcessor.postProcess(bean, beanName, method, annotation);

            if (result != null && result instanceof ContainerHandler) {
              String endpointBeanName = generateBeanName(beanName, method, annotation.annotationType());

              if (result instanceof BeanNameAware) {
                ((BeanNameAware) result).setBeanName(endpointBeanName);
              }
              beanFactory.registerSingleton(endpointBeanName, result);
              if (result instanceof BeanFactoryAware) {
                ((BeanFactoryAware) result).setBeanFactory(beanFactory);
              }
              if (result instanceof InitializingBean) {
                try {
                  ((InitializingBean) result).afterPropertiesSet();
                } catch (Exception e) {
                  throw new BeanInitializationException("failed to initialize annotated component", e);
                }
              }
              if (result instanceof Lifecycle) {
                lifecycles.add((Lifecycle) result);
                if (result instanceof SmartLifecycle && ((SmartLifecycle) result).isAutoStartup()) {
                  ((SmartLifecycle) result).start();
                }
              }
              if (result instanceof ApplicationListener) {
                listeners.add((ApplicationListener) result);
              }
            }
          }
        }
      }
    });
    return bean;
  }

  @Override
  public void onApplicationEvent(ApplicationEvent event) {
    for (ApplicationListener<ApplicationEvent> listener : listeners) {
      try {
        listener.onApplicationEvent(event);
      } catch (ClassCastException e) {
        if (log.isWarnEnabled() && event != null) {
          log.warn("ApplicationEvent of type [" + event.getClass()
              + "] not accepted by ApplicationListener [" + listener + "]");
        }
      }
    }
  }

  @Override
  public boolean isRunning() {
    return this.running;
  }

  @Override
  public void start() {
    for (Lifecycle lifecycle : this.lifecycles) {
      if (!lifecycle.isRunning()) {
        lifecycle.start();
      }
    }
    this.running = true;
  }

  @Override
  public void stop() {
    for (Lifecycle lifecycle : this.lifecycles) {
      if (lifecycle.isRunning()) {
        lifecycle.stop();
      }
    }
    this.running = false;
  }

  private boolean shouldCreateHandler(Annotation annotation) {
    return true;
  }

  /**
   * Gets the bean class. Will check if bean is a proxy and
   * find a class from there as target class, otherwise
   * we just get bean class.
   *
   * @param bean the bean
   * @return the bean class
   */
  private Class<?> getBeanClass(Object bean) {
    Class<?> targetClass = AopUtils.getTargetClass(bean);
    return (targetClass != null) ? targetClass : bean.getClass();
  }

  /**
   * Checks if class is a stereotype meaning if there is
   * a Component annotation present.
   *
   * @param beanClass the bean class
   * @return true, if is stereotype
   */
  private boolean isStereotype(Class<?> beanClass) {
    List<Annotation> annotations = new ArrayList<Annotation>(Arrays.asList(beanClass.getAnnotations()));
    Class<?>[] interfaces = beanClass.getInterfaces();
    for (Class<?> iface : interfaces) {
      annotations.addAll(Arrays.asList(iface.getAnnotations()));
    }
    for (Annotation annotation : annotations) {
      Class<? extends Annotation> annotationType = annotation.annotationType();
      if (annotationType.equals(Component.class) || annotationType.isAnnotationPresent(Component.class)) {
        return true;
      }
    }
    return false;
  }

  private String generateBeanName(String originalBeanName, Method method, Class<? extends Annotation> annotationType) {
    String baseName = originalBeanName + "." + method.getName() + "." + ClassUtils.getShortNameAsProperty(annotationType);
    String name = baseName;
    int count = 1;
    while (beanFactory.containsBean(name)) {
      name = baseName + "#" + (++count);
    }
    return name;
  }

}
TOP

Related Classes of org.springframework.yarn.config.annotation.SpringYarnAnnotationPostProcessor

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.