/*
* Copyright 2002-2016 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.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.core.OrderComparator;
import org.springframework.integration.channel.ChannelInterceptorAware;
import org.springframework.integration.channel.interceptor.GlobalChannelInterceptorWrapper;
import org.springframework.integration.channel.interceptor.VetoCapableInterceptor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;
/**
* Will apply global interceptors to channels (<channel-interceptor>).
*
* @author Oleg Zhurakousky
* @author Mark Fisher
* @author Artem Bilan
* @author Gary Russell
* @since 2.0
*/
final class GlobalChannelInterceptorProcessor implements BeanFactoryAware, SmartInitializingSingleton {
private static final Log logger = LogFactory.getLog(GlobalChannelInterceptorProcessor.class);
private final OrderComparator comparator = new OrderComparator();
private final Set<GlobalChannelInterceptorWrapper> positiveOrderInterceptors =
new LinkedHashSet<GlobalChannelInterceptorWrapper>();
private final Set<GlobalChannelInterceptorWrapper> negativeOrderInterceptors =
new LinkedHashSet<GlobalChannelInterceptorWrapper>();
private ListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ListableBeanFactory.class, beanFactory);
this.beanFactory = (ListableBeanFactory) beanFactory; //NOSONAR (inconsistent sync)
}
@Override
public void afterSingletonsInstantiated() {
Collection<GlobalChannelInterceptorWrapper> interceptors =
this.beanFactory.getBeansOfType(GlobalChannelInterceptorWrapper.class).values();
if (CollectionUtils.isEmpty(interceptors)) {
logger.debug("No global channel interceptors.");
}
else {
for (GlobalChannelInterceptorWrapper channelInterceptor : interceptors) {
if (channelInterceptor.getOrder() >= 0) {
this.positiveOrderInterceptors.add(channelInterceptor);
}
else {
this.negativeOrderInterceptors.add(channelInterceptor);
}
}
Map<String, ChannelInterceptorAware> channels =
this.beanFactory.getBeansOfType(ChannelInterceptorAware.class);
for (Entry<String, ChannelInterceptorAware> entry : channels.entrySet()) {
addMatchingInterceptors(entry.getValue(), entry.getKey());
}
}
}
/**
* Adds any interceptor whose pattern matches against the channel's name.
*/
private void addMatchingInterceptors(ChannelInterceptorAware channel, String beanName) {
if (logger.isDebugEnabled()) {
logger.debug("Applying global interceptors on channel '" + beanName + "'");
}
List<GlobalChannelInterceptorWrapper> tempInterceptors = new ArrayList<GlobalChannelInterceptorWrapper>();
for (GlobalChannelInterceptorWrapper globalChannelInterceptorWrapper : this.positiveOrderInterceptors) {
String[] patterns = globalChannelInterceptorWrapper.getPatterns();
patterns = StringUtils.trimArrayElements(patterns);
if (PatternMatchUtils.simpleMatch(patterns, beanName)) {
tempInterceptors.add(globalChannelInterceptorWrapper);
}
}
Collections.sort(tempInterceptors, this.comparator);
for (GlobalChannelInterceptorWrapper next : tempInterceptors) {
ChannelInterceptor channelInterceptor = next.getChannelInterceptor();
if (!(channelInterceptor instanceof VetoCapableInterceptor)
|| ((VetoCapableInterceptor) channelInterceptor).shouldIntercept(beanName, channel)) {
channel.addInterceptor(channelInterceptor);
}
}
tempInterceptors.clear();
for (GlobalChannelInterceptorWrapper globalChannelInterceptorWrapper : this.negativeOrderInterceptors) {
String[] patterns = globalChannelInterceptorWrapper.getPatterns();
patterns = StringUtils.trimArrayElements(patterns);
if (PatternMatchUtils.simpleMatch(patterns, beanName)) {
tempInterceptors.add(globalChannelInterceptorWrapper);
}
}
Collections.sort(tempInterceptors, this.comparator);
if (!tempInterceptors.isEmpty()) {
for (int i = tempInterceptors.size() - 1; i >= 0; i--) {
ChannelInterceptor channelInterceptor = tempInterceptors.get(i).getChannelInterceptor();
if (!(channelInterceptor instanceof VetoCapableInterceptor)
|| ((VetoCapableInterceptor) channelInterceptor).shouldIntercept(beanName, channel)) {
channel.addInterceptor(0, channelInterceptor);
}
}
}
}
}