/* * Copyright 2014-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.transformer.support; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.integration.routingslip.ExpressionEvaluatingRoutingSlipRouteStrategy; import org.springframework.integration.routingslip.RoutingSlipRouteStrategy; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.util.Assert; /** * The {@code RoutingSlip} {@link HeaderValueMessageProcessor} specific implementation. * Accepts the {@code routingSlipPath} array, checks each of them against * {@link BeanFactory} on the first {@link #processMessage} invocation. * Converts those items, which aren't beans in the application context, to the * {@link ExpressionEvaluatingRoutingSlipRouteStrategy} and return a {@code singletonMap} * with the {@code path} as {@code key} and {@code 0} as initial {@code routingSlipIndex}. * * @author Artem Bilan * @author Gary Russell * @since 4.1 */ public class RoutingSlipHeaderValueMessageProcessor extends AbstractHeaderValueMessageProcessor<Map<List<Object>, Integer>> implements BeanFactoryAware { private final List<Object> routingSlipPath; private volatile Map<List<Object>, Integer> routingSlip; private BeanFactory beanFactory; public RoutingSlipHeaderValueMessageProcessor(Object... routingSlipPath) { Assert.notNull(routingSlipPath, "'routingSlipPath' must not be null"); Assert.noNullElements(routingSlipPath, "'routingSlipPath' must not contain null elements"); for (Object entry : routingSlipPath) { if (!(entry instanceof String || entry instanceof MessageChannel || entry instanceof RoutingSlipRouteStrategy)) { throw new IllegalArgumentException("The RoutingSlip can contain " + "only bean names of MessageChannel or RoutingSlipRouteStrategy, " + "or MessageChannel and RoutingSlipRouteStrategy instances: " + entry); } } this.routingSlipPath = Arrays.asList(routingSlipPath); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { Assert.notNull(beanFactory, "beanFactory must not be null"); this.beanFactory = beanFactory; //NOSONAR (inconsistent sync) } @Override public Map<List<Object>, Integer> processMessage(Message<?> message) { // use a local variable to avoid the second access to volatile field on the happy path Map<List<Object>, Integer> routingSlip = this.routingSlip; if (routingSlip == null) { synchronized (this) { routingSlip = this.routingSlip; if (routingSlip == null) { List<Object> routingSlipPath = this.routingSlipPath; List<Object> routingSlipValues = new ArrayList<Object>(routingSlipPath.size()); for (Object path : routingSlipPath) { if (path instanceof String) { String entry = (String) path; if (this.beanFactory.containsBean(entry)) { Object bean = this.beanFactory.getBean(entry); if (!(bean instanceof MessageChannel || bean instanceof RoutingSlipRouteStrategy)) { throw new IllegalArgumentException("The RoutingSlip can contain " + "only bean names of MessageChannel or RoutingSlipRouteStrategy: " + bean); } routingSlipValues.add(entry); } else { ExpressionEvaluatingRoutingSlipRouteStrategy strategy = new ExpressionEvaluatingRoutingSlipRouteStrategy(entry); strategy.setBeanFactory(this.beanFactory); try { strategy.afterPropertiesSet(); } catch (Exception e) { throw new IllegalStateException(e); } routingSlipValues.add(strategy); } } else { routingSlipValues.add(path); } } routingSlip = Collections.singletonMap(Collections.unmodifiableList(routingSlipValues), 0); this.routingSlip = routingSlip; } } } return routingSlip; } }