All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dmulcahey.componentconfiguration.spring.ClasspathResourceInjectionAnnotationBeanPostProcessor Maven / Gradle / Ivy

The newest version!
package com.github.dmulcahey.componentconfiguration.spring;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import com.github.dmulcahey.componentconfiguration.manager.ComponentConfigurationResolver;
import com.github.dmulcahey.configurationresolver.resources.classpath.ClasspathResource;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

@Component
public class ClasspathResourceInjectionAnnotationBeanPostProcessor  implements MergedBeanDefinitionPostProcessor, PriorityOrdered {

	protected transient Log logger = LogFactory.getLog(getClass());

	private Class configurationResourceAnnotationType;

	private int order = Ordered.LOWEST_PRECEDENCE;

	private transient final Map, Collection> metadataCache = Maps.newHashMap();
	
	public ClasspathResourceInjectionAnnotationBeanPostProcessor() {
		this.configurationResourceAnnotationType = com.github.dmulcahey.componentconfiguration.spring.ClasspathResource.class;
	}

	@Override
	public int getOrder() {
		return this.order;
	}

	public void setOrder(int order) {
		this.order = order;
	}

	public Class getConfigurationResourceAnnotationType() {
		return configurationResourceAnnotationType;
	}

	public void setConfigurationResourceAnnotationType(Class configurationResourceAnnotationType) {
		this.configurationResourceAnnotationType = configurationResourceAnnotationType;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		Collection metadata = findMetadata(bean.getClass());
		try {
			for (ConfigurationElement element : metadata) {
				element.set(bean, getConfigurationResource(element));
			}
		} catch (InvocationTargetException ex) {
			throw new BeanCreationException(beanName, "Injection of component configuration failed", ex.getTargetException());
		} catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Couldn't inject component configuration", ex);
		}
		return bean;
	}

	private ClasspathResource getConfigurationResource(ConfigurationElement element) {
		com.github.dmulcahey.componentconfiguration.spring.ClasspathResource annotation = (com.github.dmulcahey.componentconfiguration.spring.ClasspathResource) element.getField().getAnnotation(this.configurationResourceAnnotationType);
		String componentName = "";
		String configurationResourceName = "";
		if(!Strings.isNullOrEmpty(annotation.value())){
			if(!annotation.value().contains(">")){
				throw new RuntimeException("The value should be set to componentName>configurationName or the componentName and configurationName elements should be used instead!");
			}
			componentName = annotation.value().substring(0, annotation.value().indexOf('>'));
			configurationResourceName = annotation.value().substring(annotation.value().indexOf('>') + 1);
		}else{
			componentName = annotation.componentName();
			configurationResourceName = annotation.name();
		}
		String environmentName = annotation.environment();
		if(Strings.isNullOrEmpty(environmentName)){
			environmentName = ComponentConfigurationResolver.DEFAULT_ENVIRONMENT;
		}
		return (ClasspathResource) Enhancer.create(ClasspathResource.class, new ClasspathResourceMethodInterceptor(componentName, configurationResourceName, environmentName));
	}

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

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
		if (beanType != null) {
			findMetadata(beanType);
		}
	}

	private Collection findMetadata(Class clazz) {
		if (this.metadataCache == null) {
			// Happens after deserialization, during destruction...
			return buildMetadata(clazz);
		}
		Collection metadata = this.metadataCache.get(clazz);
		if (metadata == null) {
			synchronized (this.metadataCache) {
				metadata = this.metadataCache.get(clazz);
				if (metadata == null) {
					metadata = buildMetadata(clazz);
					this.metadataCache.put(clazz, metadata);
				}
				return metadata;
			}
		}
		return metadata;
	}

	private Collection buildMetadata(Class clazz) {
		final boolean debug = logger.isDebugEnabled();
		LinkedList autowiredConfigurationResources = Lists.newLinkedList();
		Class targetClass = clazz;

		do {
			LinkedList currentAutowiredConfigurationResources = Lists.newLinkedList();

			for (Field field : targetClass.getDeclaredFields()) {
				if (this.configurationResourceAnnotationType != null) {
					if (field.getAnnotation(this.configurationResourceAnnotationType) != null) {
						ConfigurationElement element = new ConfigurationElement(field);
						currentAutowiredConfigurationResources.add(element);
						if (debug) {
							logger.debug("Found injectible configuration field on class [" + clazz.getName() + "]: " + field);
						}
					}
				}
			}
			autowiredConfigurationResources.addAll(0, currentAutowiredConfigurationResources);
			targetClass = targetClass.getSuperclass();
		} while (targetClass != null && targetClass != Object.class);

		return autowiredConfigurationResources;
	}

	private static class ConfigurationElement {

		private final Field field;

		public ConfigurationElement(Field field) {
			this.field = field;
		}

		public Field getField() {
			return field;
		}

		public void set(Object target, Object value) throws Throwable {
			ReflectionUtils.makeAccessible(this.field);
			this.field.set(target, value);
		}

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy