/*
* Copyright 2014-2015 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.integration.config;
import java.util.List;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.integration.annotation.IdempotentReceiver;
import org.springframework.integration.handler.advice.IdempotentReceiverInterceptor;
import org.springframework.messaging.MessageHandler;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* The {@link IntegrationConfigurationInitializer} that populates
* the {@link ConfigurableListableBeanFactory}
* with an {@link IdempotentReceiverAutoProxyCreator}
* when {@code IdempotentReceiverInterceptor} {@link BeanDefinition}s and their {@code mapping}
* to Consumer Endpoints are present.
*
* @author Artem Bilan
* @since 4.1
*/
public class IdempotentReceiverAutoProxyCreatorInitializer implements IntegrationConfigurationInitializer {
public static final String IDEMPOTENT_ENDPOINTS_MAPPING = "IDEMPOTENT_ENDPOINTS_MAPPING";
private static final String IDEMPOTENT_RECEIVER_AUTO_PROXY_CREATOR_BEAN_NAME =
IdempotentReceiverAutoProxyCreator.class.getName();
@Override
public void initialize(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<Map<String, String>> idempotentEndpointsMapping = new ManagedList<Map<String, String>>();
for (String beanName : registry.getBeanDefinitionNames()) {
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
if (IdempotentReceiverInterceptor.class.getName().equals(beanDefinition.getBeanClassName())) {
Object value = beanDefinition.removeAttribute(IDEMPOTENT_ENDPOINTS_MAPPING);
Assert.isInstanceOf(String.class, value,
"The 'mapping' of BeanDefinition 'IDEMPOTENT_ENDPOINTS_MAPPING' must be String.");
String mapping = (String) value;
String[] endpoints = StringUtils.tokenizeToStringArray(mapping, ",");
for (String endpoint : endpoints) {
Map<String, String> idempotentEndpoint = new ManagedMap<String, String>();
idempotentEndpoint.put(beanName,
beanFactory.resolveEmbeddedValue(endpoint) + IntegrationConfigUtils.HANDLER_ALIAS_SUFFIX);
idempotentEndpointsMapping.add(idempotentEndpoint);
}
}
else if (beanDefinition instanceof AnnotatedBeanDefinition) {
if (beanDefinition.getSource() instanceof MethodMetadata) {
MethodMetadata beanMethod = (MethodMetadata) beanDefinition.getSource();
String annotationType = IdempotentReceiver.class.getName();
if (beanMethod.isAnnotated(annotationType)) {
Object value = beanMethod.getAnnotationAttributes(annotationType).get("value");
if (value != null) {
Class<?> returnType;
if (beanMethod instanceof StandardMethodMetadata) {
returnType = ((StandardMethodMetadata) beanMethod).getIntrospectedMethod()
.getReturnType();
}
else {
try {
returnType = ClassUtils.forName(beanMethod.getReturnTypeName(),
beanFactory.getBeanClassLoader());
}
catch (ClassNotFoundException e) {
throw new CannotLoadBeanClassException(beanDefinition.getDescription(),
beanName, beanMethod.getReturnTypeName(), e);
}
}
String endpoint = beanName;
if (!MessageHandler.class.isAssignableFrom(returnType)) {
/*
MessageHandler beans, populated from @Bean methods, have a complex id,
including @Configuration bean name, method name and the Messaging annotation name.
The following pattern matches the bean name, regardless of the annotation name.
*/
endpoint = beanDefinition.getFactoryBeanName() + "." + beanName +
".*" + IntegrationConfigUtils.HANDLER_ALIAS_SUFFIX;
}
String[] interceptors = (String[]) value;
for (String interceptor : interceptors) {
Map<String, String> idempotentEndpoint = new ManagedMap<String, String>();
idempotentEndpoint.put(interceptor, endpoint);
idempotentEndpointsMapping.add(idempotentEndpoint);
}
}
}
}
}
}
if (!idempotentEndpointsMapping.isEmpty()) {
BeanDefinition bd = BeanDefinitionBuilder.rootBeanDefinition(IdempotentReceiverAutoProxyCreator.class)
.addPropertyValue("idempotentEndpointsMapping", idempotentEndpointsMapping)
.getBeanDefinition();
registry.registerBeanDefinition(IDEMPOTENT_RECEIVER_AUTO_PROXY_CREATOR_BEAN_NAME, bd);
}
}
}