Search in sources :

Example 1 with FunctionCatalog

use of org.springframework.cloud.function.context.FunctionCatalog in project spring-cloud-stream by spring-cloud.

the class FunctionConfiguration method supplierInitializer.

/*
	 * Binding initializer responsible only for Suppliers
	 */
@Bean
InitializingBean supplierInitializer(FunctionCatalog functionCatalog, StreamFunctionProperties functionProperties, GenericApplicationContext context, BindingServiceProperties serviceProperties, @Nullable List<BindableFunctionProxyFactory> proxyFactories, StreamBridge streamBridge, TaskScheduler taskScheduler) {
    if (CollectionUtils.isEmpty(proxyFactories)) {
        return null;
    }
    return new InitializingBean() {

        @SuppressWarnings("rawtypes")
        @Override
        public void afterPropertiesSet() throws Exception {
            for (BindableFunctionProxyFactory proxyFactory : proxyFactories) {
                FunctionInvocationWrapper functionWrapper = functionCatalog.lookup(proxyFactory.getFunctionDefinition());
                if (functionWrapper != null && functionWrapper.isSupplier()) {
                    // gather output content types
                    List<String> contentTypes = new ArrayList<String>();
                    if (proxyFactory.getOutputs().size() == 0) {
                        return;
                    }
                    Assert.isTrue(proxyFactory.getOutputs().size() == 1, "Supplier with multiple outputs is not supported at the moment.");
                    String outputName = proxyFactory.getOutputs().iterator().next();
                    BindingProperties bindingProperties = serviceProperties.getBindingProperties(outputName);
                    ProducerProperties producerProperties = bindingProperties.getProducer();
                    if (!(bindingProperties.getProducer() != null && producerProperties.isUseNativeEncoding())) {
                        contentTypes.add(bindingProperties.getContentType());
                    }
                    // see https://github.com/spring-cloud/spring-cloud-stream/issues/2027
                    String functionDefinition = proxyFactory.getFunctionDefinition();
                    String[] functionNames = StringUtils.delimitedListToStringArray(functionDefinition.replaceAll(",", "|").trim(), "|");
                    Function supplier = null;
                    Function function = null;
                    if (!ObjectUtils.isEmpty(functionNames) && functionNames.length > 1) {
                        String supplierName = functionNames[0];
                        String remainingFunctionDefinition = StringUtils.arrayToCommaDelimitedString(Arrays.copyOfRange(functionNames, 1, functionNames.length));
                        supplier = functionCatalog.lookup(supplierName);
                        function = functionCatalog.lookup(remainingFunctionDefinition, contentTypes.toArray(new String[0]));
                        if (!((FunctionInvocationWrapper) supplier).isOutputTypePublisher() && ((FunctionInvocationWrapper) function).isInputTypePublisher()) {
                            functionWrapper = null;
                        } else {
                            functionWrapper = functionCatalog.lookup(proxyFactory.getFunctionDefinition(), contentTypes.toArray(new String[0]));
                        }
                    } else {
                        functionWrapper = functionCatalog.lookup(proxyFactory.getFunctionDefinition(), contentTypes.toArray(new String[0]));
                    }
                    Publisher<Object> beginPublishingTrigger = setupBindingTrigger(context);
                    if (!functionProperties.isComposeFrom() && !functionProperties.isComposeTo()) {
                        String integrationFlowName = proxyFactory.getFunctionDefinition() + "_integrationflow";
                        PollableBean pollable = extractPollableAnnotation(functionProperties, context, proxyFactory);
                        if (functionWrapper != null) {
                            // Type functionType = functionWrapper.getFunctionType();
                            IntegrationFlow integrationFlow = integrationFlowFromProvidedSupplier(new PartitionAwareFunctionWrapper(functionWrapper, context, producerProperties), beginPublishingTrigger, pollable, context, taskScheduler, producerProperties, outputName).route(Message.class, message -> {
                                if (message.getHeaders().get("spring.cloud.stream.sendto.destination") != null) {
                                    String destinationName = (String) message.getHeaders().get("spring.cloud.stream.sendto.destination");
                                    return streamBridge.resolveDestination(destinationName, producerProperties, null);
                                }
                                return outputName;
                            }).get();
                            IntegrationFlow postProcessedFlow = (IntegrationFlow) context.getAutowireCapableBeanFactory().applyBeanPostProcessorsBeforeInitialization(integrationFlow, integrationFlowName);
                            context.registerBean(integrationFlowName, IntegrationFlow.class, () -> postProcessedFlow);
                        } else {
                            // Type functionType = ((FunctionInvocationWrapper) supplier).getFunctionType();
                            IntegrationFlow integrationFlow = integrationFlowFromProvidedSupplier(new PartitionAwareFunctionWrapper(supplier, context, producerProperties), beginPublishingTrigger, pollable, context, taskScheduler, producerProperties, outputName).channel(c -> c.direct()).fluxTransform((Function<? super Flux<Message<Object>>, ? extends Publisher<Object>>) function).route(Message.class, message -> {
                                if (message.getHeaders().get("spring.cloud.stream.sendto.destination") != null) {
                                    String destinationName = (String) message.getHeaders().get("spring.cloud.stream.sendto.destination");
                                    return streamBridge.resolveDestination(destinationName, producerProperties, null);
                                }
                                return outputName;
                            }).get();
                            IntegrationFlow postProcessedFlow = (IntegrationFlow) context.getAutowireCapableBeanFactory().applyBeanPostProcessorsBeforeInitialization(integrationFlow, integrationFlowName);
                            context.registerBean(integrationFlowName, IntegrationFlow.class, () -> postProcessedFlow);
                        }
                    }
                }
            }
        }
    };
}
Also used : GenericArrayType(java.lang.reflect.GenericArrayType) Arrays(java.util.Arrays) BindingCreatedEvent(org.springframework.cloud.stream.binder.BindingCreatedEvent) DirectWithAttributesChannel(org.springframework.cloud.stream.messaging.DirectWithAttributesChannel) IntegrationFlow(org.springframework.integration.dsl.IntegrationFlow) IntegrationFlowBuilder(org.springframework.integration.dsl.IntegrationFlowBuilder) BindingServiceConfiguration(org.springframework.cloud.stream.config.BindingServiceConfiguration) Tuples(reactor.util.function.Tuples) FluxMessageChannel(org.springframework.integration.channel.FluxMessageChannel) BeanDefinitionRegistry(org.springframework.beans.factory.support.BeanDefinitionRegistry) ContextFunctionCatalogAutoConfiguration(org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration) ProducerProperties(org.springframework.cloud.stream.binder.ProducerProperties) AbstractMessageChannel(org.springframework.integration.channel.AbstractMessageChannel) ConfigurableListableBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) MessagingTemplate(org.springframework.integration.core.MessagingTemplate) RoutingFunction(org.springframework.cloud.function.context.config.RoutingFunction) Map(java.util.Map) EnableConfigurationProperties(org.springframework.boot.context.properties.EnableConfigurationProperties) ConfigurableApplicationContext(org.springframework.context.ConfigurableApplicationContext) MessageUtils(org.springframework.cloud.function.context.message.MessageUtils) Method(java.lang.reflect.Method) ClassUtils(org.springframework.util.ClassUtils) MethodMetadata(org.springframework.core.type.MethodMetadata) AbstractSubscribableChannel(org.springframework.integration.channel.AbstractSubscribableChannel) ConsumerProperties(org.springframework.cloud.stream.binder.ConsumerProperties) AnnotationUtils(org.springframework.core.annotation.AnnotationUtils) Set(java.util.Set) TaskScheduler(org.springframework.scheduling.TaskScheduler) Instant(java.time.Instant) MessageChannel(org.springframework.messaging.MessageChannel) SupportedBindableFeatures(org.springframework.cloud.stream.binding.SupportedBindableFeatures) Configuration(org.springframework.context.annotation.Configuration) List(java.util.List) Type(java.lang.reflect.Type) Environment(org.springframework.core.env.Environment) CollectionUtils(org.springframework.util.CollectionUtils) LogFactory(org.apache.commons.logging.LogFactory) FunctionCatalog(org.springframework.cloud.function.context.FunctionCatalog) IntegrationReactiveUtils(org.springframework.integration.util.IntegrationReactiveUtils) CloudEventMessageUtils(org.springframework.cloud.function.cloudevent.CloudEventMessageUtils) FunctionInvocationWrapper(org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper) BindingProperties(org.springframework.cloud.stream.config.BindingProperties) ApplicationContextAware(org.springframework.context.ApplicationContextAware) RootBeanDefinition(org.springframework.beans.factory.support.RootBeanDefinition) MessagingException(org.springframework.messaging.MessagingException) BinderFactory(org.springframework.cloud.stream.binder.BinderFactory) BindingServiceProperties(org.springframework.cloud.stream.config.BindingServiceProperties) SubscribableChannel(org.springframework.messaging.SubscribableChannel) MonoSink(reactor.core.publisher.MonoSink) PollableBean(org.springframework.cloud.function.context.PollableBean) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) Supplier(java.util.function.Supplier) InitializingBean(org.springframework.beans.factory.InitializingBean) ArrayList(java.util.ArrayList) AutoConfigureAfter(org.springframework.boot.autoconfigure.AutoConfigureAfter) MessageBuilder(org.springframework.integration.support.MessageBuilder) NewDestinationBindingCallback(org.springframework.cloud.stream.binding.NewDestinationBindingCallback) BinderFactoryAutoConfiguration(org.springframework.cloud.stream.config.BinderFactoryAutoConfiguration) ConfigurableEnvironment(org.springframework.core.env.ConfigurableEnvironment) FunctionTypeUtils(org.springframework.cloud.function.context.catalog.FunctionTypeUtils) BeanDefinition(org.springframework.beans.factory.config.BeanDefinition) IntegrationFlows(org.springframework.integration.dsl.IntegrationFlows) Nullable(org.springframework.lang.Nullable) Message(org.springframework.messaging.Message) BindableProxyFactory(org.springframework.cloud.stream.binding.BindableProxyFactory) ConditionalOnBean(org.springframework.boot.autoconfigure.condition.ConditionalOnBean) Iterator(java.util.Iterator) Publisher(org.reactivestreams.Publisher) BeanFactoryPostProcessor(org.springframework.beans.factory.config.BeanFactoryPostProcessor) ObjectUtils(org.springframework.util.ObjectUtils) Import(org.springframework.context.annotation.Import) Mono(reactor.core.publisher.Mono) BeansException(org.springframework.beans.BeansException) AbstractMessageHandler(org.springframework.integration.handler.AbstractMessageHandler) Field(java.lang.reflect.Field) FunctionProperties(org.springframework.cloud.function.context.FunctionProperties) ApplicationContext(org.springframework.context.ApplicationContext) MessageHeaders(org.springframework.messaging.MessageHeaders) GenericApplicationContext(org.springframework.context.support.GenericApplicationContext) Flux(reactor.core.publisher.Flux) ParameterizedType(java.lang.reflect.ParameterizedType) FunctionContextUtils(org.springframework.cloud.function.context.config.FunctionContextUtils) EnvironmentAware(org.springframework.context.EnvironmentAware) ReflectionUtils(org.springframework.util.ReflectionUtils) Log(org.apache.commons.logging.Log) FunctionRegistry(org.springframework.cloud.function.context.FunctionRegistry) Bean(org.springframework.context.annotation.Bean) AutoConfigureBefore(org.springframework.boot.autoconfigure.AutoConfigureBefore) Collections(java.util.Collections) Assert(org.springframework.util.Assert) StringUtils(org.springframework.util.StringUtils) ProducerProperties(org.springframework.cloud.stream.binder.ProducerProperties) Message(org.springframework.messaging.Message) BindingProperties(org.springframework.cloud.stream.config.BindingProperties) ArrayList(java.util.ArrayList) IntegrationFlow(org.springframework.integration.dsl.IntegrationFlow) RoutingFunction(org.springframework.cloud.function.context.config.RoutingFunction) Function(java.util.function.Function) FunctionInvocationWrapper(org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper) InitializingBean(org.springframework.beans.factory.InitializingBean) PollableBean(org.springframework.cloud.function.context.PollableBean) PollableBean(org.springframework.cloud.function.context.PollableBean) InitializingBean(org.springframework.beans.factory.InitializingBean) ConditionalOnBean(org.springframework.boot.autoconfigure.condition.ConditionalOnBean) Bean(org.springframework.context.annotation.Bean)

Example 2 with FunctionCatalog

use of org.springframework.cloud.function.context.FunctionCatalog in project spring-cloud-stream by spring-cloud.

the class DefaultBinderFactory method getBinderInstance.

@SuppressWarnings("unchecked")
private <T> Binder<T, ConsumerProperties, ProducerProperties> getBinderInstance(String configurationName) {
    if (!this.binderInstanceCache.containsKey(configurationName)) {
        logger.info("Creating binder: " + configurationName);
        BinderConfiguration binderConfiguration = this.binderConfigurations.get(configurationName);
        Assert.state(binderConfiguration != null, "Unknown binder configuration: " + configurationName);
        BinderType binderType = this.binderTypeRegistry.get(binderConfiguration.getBinderType());
        Assert.notNull(binderType, "Binder type " + binderConfiguration.getBinderType() + " is not defined");
        Map<String, Object> binderProperties = new HashMap<>();
        this.flatten(null, binderConfiguration.getProperties(), binderProperties);
        ConfigurableApplicationContext binderProducingContext = this.initializeBinderContextSimple(configurationName, binderProperties, binderType, binderConfiguration);
        Map<String, MessageConverter> messageConverters = binderProducingContext.getBeansOfType(MessageConverter.class);
        if (!CollectionUtils.isEmpty(messageConverters) && !ObjectUtils.isEmpty(context.getBeansOfType(FunctionCatalog.class))) {
            FunctionCatalog functionCatalog = this.context.getBean(FunctionCatalog.class);
            if (functionCatalog instanceof SimpleFunctionRegistry) {
                ((SimpleFunctionRegistry) functionCatalog).addMessageConverters(messageConverters.values());
            }
        }
        Binder<T, ?, ?> binder = binderProducingContext.getBean(Binder.class);
        /*
			 * This will ensure that application defined errorChannel and other beans are
			 * accessible within binder's context (see
			 * https://github.com/spring-cloud/spring-cloud-stream/issues/1384)
			 */
        if (this.context != null && binder instanceof ApplicationContextAware) {
            ((ApplicationContextAware) binder).setApplicationContext(this.context);
        }
        if (!CollectionUtils.isEmpty(this.listeners)) {
            for (Listener binderFactoryListener : this.listeners) {
                binderFactoryListener.afterBinderContextInitialized(configurationName, binderProducingContext);
            }
        }
        logger.info("Caching the binder: " + configurationName);
        this.binderInstanceCache.put(configurationName, new SimpleImmutableEntry<>(binder, binderProducingContext));
    }
    logger.info("Retrieving cached binder: " + configurationName);
    return (Binder<T, ConsumerProperties, ProducerProperties>) this.binderInstanceCache.get(configurationName).getKey();
}
Also used : ConfigurableApplicationContext(org.springframework.context.ConfigurableApplicationContext) FunctionCatalog(org.springframework.cloud.function.context.FunctionCatalog) ApplicationContextAware(org.springframework.context.ApplicationContextAware) ApplicationListener(org.springframework.context.ApplicationListener) HashMap(java.util.HashMap) SimpleFunctionRegistry(org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry) MessageConverter(org.springframework.messaging.converter.MessageConverter)

Aggregations

FunctionCatalog (org.springframework.cloud.function.context.FunctionCatalog)2 Field (java.lang.reflect.Field)1 GenericArrayType (java.lang.reflect.GenericArrayType)1 Method (java.lang.reflect.Method)1 ParameterizedType (java.lang.reflect.ParameterizedType)1 Type (java.lang.reflect.Type)1 Instant (java.time.Instant)1 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 Collections (java.util.Collections)1 HashMap (java.util.HashMap)1 Iterator (java.util.Iterator)1 List (java.util.List)1 Map (java.util.Map)1 Set (java.util.Set)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 Function (java.util.function.Function)1 Supplier (java.util.function.Supplier)1 Log (org.apache.commons.logging.Log)1 LogFactory (org.apache.commons.logging.LogFactory)1