/* * 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.function.Consumer; import org.reactivestreams.Publisher; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.channel.FluxMessageChannel; import org.springframework.integration.core.MessageSource; import org.springframework.integration.dsl.channel.MessageChannelSpec; import org.springframework.integration.dsl.support.FixedSubscriberChannelPrototype; import org.springframework.integration.dsl.support.MessageChannelReference; import org.springframework.integration.endpoint.MessageProducerSupport; import org.springframework.integration.endpoint.MethodInvokingMessageSource; import org.springframework.integration.gateway.AnnotationGatewayProxyFactoryBean; import org.springframework.integration.gateway.GatewayProxyFactoryBean; import org.springframework.integration.gateway.MessagingGatewaySupport; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.util.Assert; /** * The central factory for fluent {@link IntegrationFlowBuilder} API. * * @author Artem Bilan * @author Gary Russell * * @since 5.0 * * @see org.springframework.integration.config.dsl.IntegrationFlowBeanPostProcessor */ public final class IntegrationFlows { /** * Populate the {@link MessageChannel} name to the new {@link IntegrationFlowBuilder} chain. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code inputChannel}. * @param messageChannelName the name of existing {@link MessageChannel} bean. * The new {@link DirectChannel} bean will be created on context startup * if there is no bean with this name. * @return new {@link IntegrationFlowBuilder}. */ public static IntegrationFlowBuilder from(String messageChannelName) { return from(new MessageChannelReference(messageChannelName)); } /** * Populate the {@link MessageChannel} name to the new {@link IntegrationFlowBuilder} chain. * Typically for the {@link org.springframework.integration.channel.FixedSubscriberChannel} together * with {@code fixedSubscriber = true}. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code inputChannel}. * @param messageChannelName the name for {@link DirectChannel} or * {@link org.springframework.integration.channel.FixedSubscriberChannel} * to be created on context startup, not reference. * The {@link MessageChannel} depends on the {@code fixedSubscriber} boolean argument. * @param fixedSubscriber the boolean flag to determine if result {@link MessageChannel} should * be {@link DirectChannel}, if {@code false} or * {@link org.springframework.integration.channel.FixedSubscriberChannel}, if {@code true}. * @return new {@link IntegrationFlowBuilder}. * @see DirectChannel * @see org.springframework.integration.channel.FixedSubscriberChannel */ public static IntegrationFlowBuilder from(String messageChannelName, boolean fixedSubscriber) { return fixedSubscriber ? from(new FixedSubscriberChannelPrototype(messageChannelName)) : from(messageChannelName); } /** * Populate the {@link MessageChannel} object to the * {@link IntegrationFlowBuilder} chain using the fluent API from {@link MessageChannelSpec}. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code inputChannel}. * @param messageChannelSpec the MessageChannelSpec to populate {@link MessageChannel} instance. * @return new {@link IntegrationFlowBuilder}. * @see org.springframework.integration.dsl.channel.MessageChannels */ public static IntegrationFlowBuilder from(MessageChannelSpec<?, ?> messageChannelSpec) { Assert.notNull(messageChannelSpec, "'messageChannelSpec' must not be null"); return from(messageChannelSpec.get()); } /** * Populate the provided {@link MessageChannel} object to the {@link IntegrationFlowBuilder} chain. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code inputChannel}. * @param messageChannel the {@link MessageChannel} to populate. * @return new {@link IntegrationFlowBuilder}. */ public static IntegrationFlowBuilder from(MessageChannel messageChannel) { return new IntegrationFlowBuilder().channel(messageChannel); } /** * Populate the {@link MessageSource} object to the {@link IntegrationFlowBuilder} chain * using the fluent API from the provided {@link MessageSourceSpec}. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessageSource}. * @param messageSourceSpec the {@link MessageSourceSpec} to use. * @return new {@link IntegrationFlowBuilder}. * @see MessageSourceSpec and its implementations. */ public static IntegrationFlowBuilder from(MessageSourceSpec<?, ? extends MessageSource<?>> messageSourceSpec) { return from(messageSourceSpec, (Consumer<SourcePollingChannelAdapterSpec>) null); } /** * Populate the {@link MessageSource} object to the {@link IntegrationFlowBuilder} chain * using the fluent API from the provided {@link MessageSourceSpec}. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessageSource}. * @param messageSourceSpec the {@link MessageSourceSpec} to use. * @param endpointConfigurer the {@link Consumer} to provide more options for the * {@link org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean}. * @return new {@link IntegrationFlowBuilder}. * @see MessageSourceSpec * @see SourcePollingChannelAdapterSpec */ public static IntegrationFlowBuilder from(MessageSourceSpec<?, ? extends MessageSource<?>> messageSourceSpec, Consumer<SourcePollingChannelAdapterSpec> endpointConfigurer) { Assert.notNull(messageSourceSpec, "'messageSourceSpec' must not be null"); return from(messageSourceSpec.get(), endpointConfigurer, registerComponents(messageSourceSpec)); } /** * Populate the provided {@link MethodInvokingMessageSource} for the method of the provided service. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessageSource}. * @param service the service to use. * @param methodName the method to invoke. * @return new {@link IntegrationFlowBuilder}. * @since 1.1 * @see MethodInvokingMessageSource */ public static IntegrationFlowBuilder from(Object service, String methodName) { return from(service, methodName, null); } /** * Populate the provided {@link MethodInvokingMessageSource} for the method of the provided service. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessageSource}. * @param service the service to use. * @param methodName the method to invoke. * @param endpointConfigurer the {@link Consumer} to provide more options for the * {@link org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean}. * @return new {@link IntegrationFlowBuilder}. * @since 1.1 * @see MethodInvokingMessageSource */ public static IntegrationFlowBuilder from(Object service, String methodName, Consumer<SourcePollingChannelAdapterSpec> endpointConfigurer) { Assert.notNull(service, "'service' must not be null"); Assert.hasText(methodName, "'methodName' must not be empty"); MethodInvokingMessageSource messageSource = new MethodInvokingMessageSource(); messageSource.setObject(service); messageSource.setMethodName(methodName); return from(messageSource, endpointConfigurer); } /** * Populate the provided {@link MessageSource} object to the {@link IntegrationFlowBuilder} chain. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessageSource}. * @param messageSource the {@link MessageSource} to populate. * @return new {@link IntegrationFlowBuilder}. * @see MessageSource */ public static IntegrationFlowBuilder from(MessageSource<?> messageSource) { return from(messageSource, (Consumer<SourcePollingChannelAdapterSpec>) null); } /** * Populate the provided {@link MessageSource} object to the {@link IntegrationFlowBuilder} chain. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessageSource}. * In addition use {@link SourcePollingChannelAdapterSpec} to provide options for the underlying * {@link org.springframework.integration.endpoint.SourcePollingChannelAdapter} endpoint. * @param messageSource the {@link MessageSource} to populate. * @param endpointConfigurer the {@link Consumer} to provide more options for the * {@link org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean}. * @return new {@link IntegrationFlowBuilder}. * @see MessageSource * @see SourcePollingChannelAdapterSpec */ public static IntegrationFlowBuilder from(MessageSource<?> messageSource, Consumer<SourcePollingChannelAdapterSpec> endpointConfigurer) { return from(messageSource, endpointConfigurer, null); } private static IntegrationFlowBuilder from(MessageSource<?> messageSource, Consumer<SourcePollingChannelAdapterSpec> endpointConfigurer, IntegrationFlowBuilder integrationFlowBuilder) { SourcePollingChannelAdapterSpec spec = new SourcePollingChannelAdapterSpec(messageSource); if (endpointConfigurer != null) { endpointConfigurer.accept(spec); } if (integrationFlowBuilder == null) { integrationFlowBuilder = new IntegrationFlowBuilder(); } return integrationFlowBuilder.addComponent(spec) .currentComponent(spec); } /** * Populate the {@link MessageProducerSupport} object to the {@link IntegrationFlowBuilder} chain * using the fluent API from the {@link MessageProducerSpec}. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessageProducer}. * @param messageProducerSpec the {@link MessageProducerSpec} to use. * @return new {@link IntegrationFlowBuilder}. * @see MessageProducerSpec */ public static IntegrationFlowBuilder from(MessageProducerSpec<?, ?> messageProducerSpec) { return from(messageProducerSpec.get(), registerComponents(messageProducerSpec)); } /** * Populate the provided {@link MessageProducerSupport} object to the {@link IntegrationFlowBuilder} chain. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessageProducer}. * @param messageProducer the {@link MessageProducerSupport} to populate. * @return new {@link IntegrationFlowBuilder}. */ public static IntegrationFlowBuilder from(MessageProducerSupport messageProducer) { return from(messageProducer, (IntegrationFlowBuilder) null); } private static IntegrationFlowBuilder from(MessageProducerSupport messageProducer, IntegrationFlowBuilder integrationFlowBuilder) { MessageChannel outputChannel = messageProducer.getOutputChannel(); if (outputChannel == null) { outputChannel = new DirectChannel(); messageProducer.setOutputChannel(outputChannel); } if (integrationFlowBuilder == null) { integrationFlowBuilder = from(outputChannel); } else { integrationFlowBuilder.channel(outputChannel); } return integrationFlowBuilder.addComponent(messageProducer); } /** * Populate the {@link MessagingGatewaySupport} object to the {@link IntegrationFlowBuilder} chain * using the fluent API from the {@link MessagingGatewaySpec}. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessagingGateway}. * @param inboundGatewaySpec the {@link MessagingGatewaySpec} to use. * @return new {@link IntegrationFlowBuilder}. */ public static IntegrationFlowBuilder from(MessagingGatewaySpec<?, ?> inboundGatewaySpec) { return from(inboundGatewaySpec.get(), registerComponents(inboundGatewaySpec)); } /** * Populate the provided {@link MessagingGatewaySupport} object to the {@link IntegrationFlowBuilder} chain. * The {@link org.springframework.integration.dsl.IntegrationFlow} {@code startMessageProducer}. * @param inboundGateway the {@link MessagingGatewaySupport} to populate. * @return new {@link IntegrationFlowBuilder}. */ public static IntegrationFlowBuilder from(MessagingGatewaySupport inboundGateway) { return from(inboundGateway, (IntegrationFlowBuilder) null); } /** * Populate the {@link MessageChannel} to the new {@link IntegrationFlowBuilder} * chain, which becomes as a {@code requestChannel} for the Messaging Gateway(s) built * on the provided service interface. * <p>A gateway proxy bean for provided service interface is registered under a name of * the {@link IntegrationFlow} bean plus {@code .gateway} suffix. * @param serviceInterface the class with a * {@link org.springframework.integration.annotation.MessagingGateway} annotation. * @return new {@link IntegrationFlowBuilder}. */ public static IntegrationFlowBuilder from(Class<?> serviceInterface) { final DirectChannel gatewayRequestChannel = new DirectChannel(); GatewayProxyFactoryBean gatewayProxyFactoryBean = new AnnotationGatewayProxyFactoryBean(serviceInterface) { @Override protected void onInit() { super.onInit(); getGateways() .values() .forEach(gateway -> gateway.setRequestChannel(gatewayRequestChannel)); } }; return from(gatewayRequestChannel) .addComponent(gatewayProxyFactoryBean); } /** * Populate a {@link FluxMessageChannel} to the {@link IntegrationFlowBuilder} chain * and subscribe it to the provided {@link Publisher}. * @param publisher the {@link Publisher} to subscribe to. * @return new {@link IntegrationFlowBuilder}. */ public static IntegrationFlowBuilder from(Publisher<Message<?>> publisher) { FluxMessageChannel reactiveChannel = new FluxMessageChannel(); reactiveChannel.subscribeTo(publisher); return from((MessageChannel) reactiveChannel); } private static IntegrationFlowBuilder from(MessagingGatewaySupport inboundGateway, IntegrationFlowBuilder integrationFlowBuilder) { MessageChannel outputChannel = inboundGateway.getRequestChannel(); if (outputChannel == null) { outputChannel = new DirectChannel(); inboundGateway.setRequestChannel(outputChannel); } if (integrationFlowBuilder == null) { integrationFlowBuilder = from(outputChannel); } else { integrationFlowBuilder.channel(outputChannel); } return integrationFlowBuilder.addComponent(inboundGateway); } private static IntegrationFlowBuilder registerComponents(Object spec) { if (spec instanceof ComponentsRegistration) { return new IntegrationFlowBuilder() .addComponents(((ComponentsRegistration) spec).getComponentsToRegister()); } return null; } private IntegrationFlows() { } }