org.springframework.yarn.config.annotation.SpringYarnAnnotationPostProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.yarn.config.annotation.SpringYarnAnnotationPostProcessor.java

Source

/*
 * 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;
    }

}