org.constretto.spring.EnvironmentAnnotationConfigurer Maven / Gradle / Ivy
/*
* 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