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

org.constretto.spring.EnvironmentAnnotationConfigurer Maven / Gradle / Ivy

There is a newer version: 3.0.0-BETA1
Show newest version
/*
 * Copyright 2008 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.constretto.spring;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.constretto.exception.ConstrettoException;
import org.constretto.spring.annotation.Environment;
import org.constretto.spring.internal.ConstrettoAutowireCandidateResolver;
import org.constretto.spring.resolver.AssemblyContextResolver;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import static java.util.Arrays.asList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * A BeanFactoryBeanFactoryPostProcessor implementation that will if registered as a bean in a spring context, enable
 * the constretto autowiring capabilities in the container.
 * 

*

* May be used on any existing configurations and in combination with all the standard context implementations from the * Spring framework. * * @author Kaare Nilsen */ public class EnvironmentAnnotationConfigurer implements BeanFactoryPostProcessor { private final Log logger = LogFactory.getLog(getClass()); private final AssemblyContextResolver assemblyContextResolver; public static final String INCLUDE_IN_COLLECTIONS = "includeInCollections"; public EnvironmentAnnotationConfigurer(AssemblyContextResolver assemblyContextResolver) { this.assemblyContextResolver = assemblyContextResolver; } @SuppressWarnings("unchecked") public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { if (!(configurableListableBeanFactory instanceof DefaultListableBeanFactory)) { throw new IllegalStateException( "EnvironmentAnnotationConfigurer needs to operate on a DefaultListableBeanFactory"); } DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory; defaultListableBeanFactory.setAutowireCandidateResolver(new ConstrettoAutowireCandidateResolver()); String[] beanNames = configurableListableBeanFactory.getBeanDefinitionNames(); int lowestDiscoveredPriority = Integer.MAX_VALUE; for (String beanName : beanNames) { BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition(beanName); if (beanDefinition.getBeanClassName() != null) { try { Class beanClass = Class.forName(beanDefinition.getBeanClassName()); Environment environmentAnnotation = findEnvironmentAnnotation(beanClass); if (environmentAnnotation != null) { if (!assemblyContextResolver.getAssemblyContext().isEmpty()) { boolean autowireCandidate = decideIfAutowireCandiate(beanName, environmentAnnotation); beanDefinition.setAutowireCandidate(autowireCandidate); if (autowireCandidate) { removeNonAnnotatedBeansFromAutowireForType(beanClass, configurableListableBeanFactory); } } else { beanDefinition.setAutowireCandidate(false); } } } catch (ClassNotFoundException e) { beanDefinition.setAutowireCandidate(false); } } } } @SuppressWarnings("unchecked") public static Environment findEnvironmentAnnotation(Class beanClass) { if (beanClass.isAnnotationPresent(Environment.class)) { return (Environment) beanClass.getAnnotation(Environment.class); } else { return findEnvironmentMetaAnnotation(new HashSet(), beanClass.getAnnotations()); } } public static Environment findEnvironmentMetaAnnotation(Set visited, Annotation[] annotations) { for (Annotation annotation : annotations) { if (annotation instanceof Environment) { return (Environment) annotation; } else { if (!visited.contains(annotation)) { visited.add(annotation); Environment environment = findEnvironmentMetaAnnotation(visited, annotation.annotationType().getAnnotations()); if (environment != null) { return environment; } } } } return null; } @SuppressWarnings("unchecked") private void removeNonAnnotatedBeansFromAutowireForType(Class lookupClass, ConfigurableListableBeanFactory configurableListableBeanFactory) throws ClassNotFoundException { List beanNames = new ArrayList(); Class[] interfaces = lookupClass.getInterfaces(); for (Class anInterface : interfaces) { beanNames.addAll(asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(configurableListableBeanFactory, anInterface))); } List potentialMatches = new ArrayList(); for (String beanName : beanNames) { BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition(beanName); Class beanClass = Class.forName(beanDefinition.getBeanClassName()); beanDefinition.setAttribute(INCLUDE_IN_COLLECTIONS, beanClass.getInterfaces()); Environment environmentAnnotation = findEnvironmentAnnotation(beanClass); if (environmentAnnotation == null) { beanDefinition.setAutowireCandidate(false); } else { potentialMatches.add(beanDefinition); } } if (potentialMatches.size() == 1) { potentialMatches.get(0).setAutowireCandidate(true); } else { List highestPriorityBeans = new ArrayList(); for (BeanDefinition potentialMatch : potentialMatches) { if (potentialMatch.isAutowireCandidate()) { potentialMatch.setAutowireCandidate(false); highestPriorityBeans = prioritizeBeans(potentialMatch, highestPriorityBeans); } } if (highestPriorityBeans.size() == 1) { highestPriorityBeans.get(0).setAutowireCandidate(true); } else { List equalPriorityBeans = new ArrayList(); for (BeanDefinition highestPriorityBean : highestPriorityBeans) { equalPriorityBeans.add(highestPriorityBean.getBeanClassName()); } throw new ConstrettoException( "More than one bean with the class or interface + [" + lookupClass.getSimpleName() +"] registered with same tag. Could not resolve priority. To fix this, remove one of the following beans " + equalPriorityBeans.toString()); } } } private List prioritizeBeans(BeanDefinition potentialMatch, List highestPriorityBeans) throws ClassNotFoundException { List result = new ArrayList(); int matchPriority = getAutowirePriority(Class.forName(potentialMatch.getBeanClassName())); if (highestPriorityBeans.isEmpty()) { result.add(potentialMatch); } else { for (BeanDefinition highestPriorityBean : highestPriorityBeans) { int mostSpesificPriority = getAutowirePriority(Class.forName(highestPriorityBean.getBeanClassName())); if ((matchPriority - mostSpesificPriority) < 0) { result.clear(); result.add(potentialMatch); } else if (((matchPriority - mostSpesificPriority) == 0)) { result.add(potentialMatch); result.add(highestPriorityBean); } else { result.add(highestPriorityBean); } } } return result; } @SuppressWarnings("unchecked") private int getAutowirePriority(Class beanClass) { Environment environmentAnnotation = findEnvironmentAnnotation(beanClass); if (environmentAnnotation != null) { List environments = asList(environmentAnnotation.value()); List assemblyContext = assemblyContextResolver.getAssemblyContext(); for (int i = 0; i < assemblyContext.size(); i++) { if (environments.contains(assemblyContext.get(i))) { return i; } } } return Integer.MAX_VALUE; } private boolean decideIfAutowireCandiate(String beanName, final Environment environmentAnnotation) { List targetEnvironments = new ArrayList() {{ addAll(asList(environmentAnnotation.value())); }}; validateAnnotationValues(beanName, targetEnvironments); List assemblyContext = assemblyContextResolver.getAssemblyContext(); targetEnvironments.retainAll(assemblyContext); boolean autowireCandidate = !targetEnvironments.isEmpty(); if (autowireCandidate) { logger.info(beanName + " is annotated with environment '" + environmentAnnotation.value() + "', and is selected for autowiring in the current environment '" + assemblyContextResolver.getAssemblyContext() + "'"); } else { logger.info(beanName + " is annotated with environment '" + environmentAnnotation.value() + "', and is discarded for autowiring in the current environment '" + assemblyContextResolver.getAssemblyContext() + "'"); } return autowireCandidate; } private void validateAnnotationValues(String beanName, List beanEnvironments) { if (beanEnvironments.isEmpty()) { throw new ConstrettoException( "You must specify environment tags in @Environment. offending bean: " + beanName); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy