/* * Copyright 2016-2017 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.dsl; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import org.aopalliance.aop.Advice; import org.springframework.integration.config.ConsumerEndpointFactoryBean; import org.springframework.integration.handler.AbstractMessageHandler; import org.springframework.integration.handler.AbstractMessageProducingHandler; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; import org.springframework.integration.router.AbstractMessageRouter; import org.springframework.integration.scheduling.PollerMetadata; import org.springframework.integration.transaction.TransactionInterceptorBuilder; import org.springframework.messaging.MessageHandler; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.interceptor.DefaultTransactionAttribute; import org.springframework.transaction.interceptor.TransactionInterceptor; import reactor.util.function.Tuple2; /** * A {@link EndpointSpec} for consumer endpoints. * * @param <S> the target {@link ConsumerEndpointSpec} implementation type. * @param <H> the target {@link MessageHandler} implementation type. * * @author Artem Bilan * @author Gary Russell * * @since 5.0 */ public abstract class ConsumerEndpointSpec<S extends ConsumerEndpointSpec<S, H>, H extends MessageHandler> extends EndpointSpec<S, ConsumerEndpointFactoryBean, H> { protected final List<Advice> adviceChain = new LinkedList<>(); protected ConsumerEndpointSpec(H messageHandler) { super(messageHandler); this.endpointFactoryBean.setAdviceChain(this.adviceChain); if (messageHandler instanceof AbstractReplyProducingMessageHandler) { ((AbstractReplyProducingMessageHandler) messageHandler).setAdviceChain(this.adviceChain); } } @Override public S phase(int phase) { this.endpointFactoryBean.setPhase(phase); return _this(); } @Override public S autoStartup(boolean autoStartup) { this.endpointFactoryBean.setAutoStartup(autoStartup); return _this(); } @Override public S poller(PollerMetadata pollerMetadata) { this.endpointFactoryBean.setPollerMetadata(pollerMetadata); return _this(); } /** * Configure a list of {@link Advice} objects to be applied, in nested order, to the * endpoint's handler. The advice objects are applied only to the handler. * @param advice the advice chain. * @return the endpoint spec. */ public S advice(Advice... advice) { this.adviceChain.addAll(Arrays.asList(advice)); return _this(); } /** * Specify a {@link TransactionInterceptor} {@link Advice} with the provided * {@code PlatformTransactionManager} and default {@link DefaultTransactionAttribute} * for the {@link MessageHandler}. * @param transactionManager the {@link PlatformTransactionManager} to use. * @return the spec. */ public S transactional(PlatformTransactionManager transactionManager) { return transactional(transactionManager, false); } /** * Specify a {@link TransactionInterceptor} {@link Advice} with the provided * {@code PlatformTransactionManager} and default {@link DefaultTransactionAttribute} * for the {@link MessageHandler}. * @param transactionManager the {@link PlatformTransactionManager} to use. * @param handleMessageAdvice the flag to indicate the target {@link Advice} type: * {@code false} - regular {@link TransactionInterceptor}; {@code true} - * {@link org.springframework.integration.transaction.TransactionHandleMessageAdvice} * extension. * @return the spec. */ public S transactional(PlatformTransactionManager transactionManager, boolean handleMessageAdvice) { return transactional(new TransactionInterceptorBuilder(handleMessageAdvice) .transactionManager(transactionManager) .build()); } /** * Specify a {@link TransactionInterceptor} {@link Advice} for the {@link MessageHandler}. * @param transactionInterceptor the {@link TransactionInterceptor} to use. * @return the spec. * @see TransactionInterceptorBuilder */ public S transactional(TransactionInterceptor transactionInterceptor) { return advice(transactionInterceptor); } /** * Specify a {@link TransactionInterceptor} {@link Advice} with default * {@code PlatformTransactionManager} and {@link DefaultTransactionAttribute} for the * {@link MessageHandler}. * @return the spec. */ public S transactional() { return transactional(false); } /** * Specify a {@link TransactionInterceptor} {@link Advice} with default * {@code PlatformTransactionManager} and {@link DefaultTransactionAttribute} for the * {@link MessageHandler}. * @param handleMessageAdvice the flag to indicate the target {@link Advice} type: * {@code false} - regular {@link TransactionInterceptor}; {@code true} - * {@link org.springframework.integration.transaction.TransactionHandleMessageAdvice} * extension. * @return the spec. */ public S transactional(boolean handleMessageAdvice) { TransactionInterceptor transactionInterceptor = new TransactionInterceptorBuilder(handleMessageAdvice).build(); this.componentsToRegister.add(transactionInterceptor); return transactional(transactionInterceptor); } /** * @param requiresReply the requiresReply. * @return the endpoint spec. * @see AbstractReplyProducingMessageHandler#setRequiresReply(boolean) */ public S requiresReply(boolean requiresReply) { assertHandler(); if (this.handler instanceof AbstractReplyProducingMessageHandler) { ((AbstractReplyProducingMessageHandler) this.handler).setRequiresReply(requiresReply); } else { logger.warn("'requiresReply' can be applied only for AbstractReplyProducingMessageHandler"); } return _this(); } /** * @param sendTimeout the send timeout. * @return the endpoint spec. * @see AbstractMessageProducingHandler#setSendTimeout(long) */ public S sendTimeout(long sendTimeout) { assertHandler(); if (this.handler instanceof AbstractMessageProducingHandler) { ((AbstractMessageProducingHandler) this.handler).setSendTimeout(sendTimeout); } else if (this.handler instanceof AbstractMessageRouter) { // This should probably go on the RouterSpec, but we put it here for consistency ((AbstractMessageRouter) this.handler).setSendTimeout(sendTimeout); } else { logger.warn("'sendTimeout' can be applied only for AbstractMessageProducingHandler"); } return _this(); } /** * @param order the order. * @return the endpoint spec. * @see AbstractMessageHandler#setOrder(int) */ public S order(int order) { assertHandler(); if (this.handler instanceof AbstractMessageHandler) { ((AbstractMessageHandler) this.handler).setOrder(order); } else { logger.warn("'order' can be applied only for AbstractMessageHandler"); } return _this(); } /** * Allow async replies. If the handler reply is a * {@code org.springframework.util.concurrent.ListenableFuture}, send the output when * it is satisfied rather than sending the future as the result. Ignored for handler * return types other than * {@link org.springframework.util.concurrent.ListenableFuture}. * @param async true to allow. * @return the endpoint spec. * @see AbstractMessageProducingHandler#setAsync(boolean) */ public S async(boolean async) { assertHandler(); if (this.handler instanceof AbstractMessageProducingHandler) { ((AbstractMessageProducingHandler) this.handler).setAsync(async); } else { logger.warn("'async' can be applied only for AbstractMessageProducingHandler"); } return _this(); } @Override protected Tuple2<ConsumerEndpointFactoryBean, H> doGet() { this.endpointFactoryBean.setHandler(this.handler); return super.doGet(); } }