package net.devh.springboot.autoconfigure.grpc.client;

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.grpc.LoadBalancer;
import io.grpc.util.RoundRobinLoadBalancerFactory;

/**
 * User: Michael
 * Email: yidongnan@gmail.com
 * Date: 5/17/16
 */
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({GrpcChannelFactory.class})
public class GrpcClientAutoConfiguration {

    @ConditionalOnMissingBean
    @Bean
    public GrpcChannelsProperties grpcChannelsProperties() {
        return new GrpcChannelsProperties();
    }

    @Bean
    public GlobalClientInterceptorRegistry globalClientInterceptorRegistry() {
        return new GlobalClientInterceptorRegistry();
    }

    @ConditionalOnMissingBean
    @Bean
    public LoadBalancer.Factory grpcLoadBalancerFactory() {
        return RoundRobinLoadBalancerFactory.getInstance();
    }

    @ConditionalOnMissingBean(value = GrpcChannelFactory.class, type = "org.springframework.cloud.client.discovery.DiscoveryClient")
    @Bean
    public GrpcChannelFactory addressChannelFactory(GrpcChannelsProperties channels, LoadBalancer.Factory loadBalancerFactory, GlobalClientInterceptorRegistry globalClientInterceptorRegistry) {
        return new AddressChannelFactory(channels, loadBalancerFactory, globalClientInterceptorRegistry);
    }

    @Bean
    @ConditionalOnClass(GrpcClient.class)
    public GrpcClientBeanPostProcessor grpcClientBeanPostProcessor() {
        return new GrpcClientBeanPostProcessor();
    }

    @Configuration
    @ConditionalOnBean(DiscoveryClient.class)
    protected static class DiscoveryGrpcClientAutoConfiguration {

        @ConditionalOnMissingBean
        @Bean
        public GrpcChannelFactory discoveryClientChannelFactory(GrpcChannelsProperties channels, DiscoveryClient discoveryClient, LoadBalancer.Factory loadBalancerFactory,
                                                                GlobalClientInterceptorRegistry globalClientInterceptorRegistry) {
            return new DiscoveryClientChannelFactory(channels, discoveryClient, loadBalancerFactory, globalClientInterceptorRegistry);
        }
    }

    @Configuration
    @ConditionalOnProperty(value = "spring.sleuth.scheduled.enabled", matchIfMissing = true)
    @ConditionalOnClass(Tracer.class)
    protected static class TraceClientAutoConfiguration {

        @Bean
        public GlobalClientInterceptorConfigurerAdapter globalTraceClientInterceptorConfigurerAdapter(final Tracer tracer) {
            return new GlobalClientInterceptorConfigurerAdapter() {

                @Override
                public void addClientInterceptors(GlobalClientInterceptorRegistry registry) {
                    registry.addClientInterceptors(new TraceClientInterceptor(tracer, new MetadataInjector()));
                }
            };
        }
    }
}

@@ -49,16 +49,132 @@
 lient;%0A%0A
+import org.springframework.beans.BeansException;%0Aimport org.springframework.beans.factory.config.BeanPostProcessor;%0A
 import o
@@ -2535,60 +2535,8 @@
 ry,%0A
-                                                    
     
@@ -3004,118 +3004,269 @@
 lic 
-GlobalClientInterceptorConfigurerAdapter globalTraceClientInterceptorConfigurerAdapter(final Tracer tracer)
+BeanPostProcessor clientInterceptorPostProcessor(GlobalClientInterceptorRegistry registry) %7B%0A            return new ClientInterceptorPostProcessor(registry);%0A        %7D%0A%0A        private static class ClientInterceptorPostProcessor implements BeanPostProcessor
  %7B%0A
+%0A
     
@@ -3269,34 +3269,31 @@
             
-return new
+private
  GlobalClien
@@ -3308,38 +3308,196 @@
 ptor
-ConfigurerAdapter() %7B%0A%0A       
+Registry registry;%0A%0A            public ClientInterceptorPostProcessor(%0A                GlobalClientInterceptorRegistry registry) %7B%0A                this.registry = registry;%0A            %7D%0A%0A
     
@@ -3501,16 +3501,19 @@
         
+   
 @Overrid
@@ -3530,86 +3530,391 @@
     
-    
 public 
-void addClientInterceptors(GlobalClientInterceptorRegistry registry
+Object postProcessBeforeInitialization(Object bean,%0A                String beanName)%0A                throws BeansException %7B%0A                return bean;%0A            %7D%0A%0A            @Override%0A            public Object postProcessAfterInitialization(Object bean,%0A                String beanName)%0A                throws BeansException %7B%0A                if (bean instanceof Tracer
 ) %7B%0A
@@ -3933,16 +3933,21 @@
         
+this.
 registry
@@ -4000,14 +4000,21 @@
 tor(
-t
+(T
 racer
+) bean
 , ne
@@ -4071,10 +4071,38 @@
     
+    return bean;%0A            
 %7D
-;
 %0A   
@@ -4114,10 +4114,11 @@
 %7D%0A    %7D%0A
+%0A
 %7D%0A

Use BeanPostProcessor to avoid early instantiating bean, causing sleth relating beans not getting post-processed.