com.quancheng.saluki.boot.runner.GrpcReferenceRunner.java Source code

Java tutorial

Introduction

Here is the source code for com.quancheng.saluki.boot.runner.GrpcReferenceRunner.java

Source

/*
 * Copyright (c) 2016, Quancheng-ec.com All right reserved. This software is the
 * confidential and proprietary information of Quancheng-ec.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with Quancheng-ec.com.
 */
package com.quancheng.saluki.boot.runner;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.env.Environment;

import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.quancheng.saluki.boot.SalukiReference;
import com.quancheng.saluki.boot.autoconfigure.GrpcProperties;
import com.quancheng.saluki.core.config.RpcReferenceConfig;
import com.quancheng.saluki.core.grpc.service.GenericService;
import com.quancheng.saluki.core.utils.CollectionUtils;

import io.grpc.stub.AbstractStub;

/**
 * @author shimingliu 20161216 ?5:07:02
 * @version ThrallReferenceRunner.java, v 0.0.1 20161216 ?5:07:02 shimingliu
 */
public class GrpcReferenceRunner extends InstantiationAwareBeanPostProcessorAdapter {

    private static final Logger logger = LoggerFactory.getLogger(GrpcReferenceRunner.class);

    private static final Pattern REPLACE_PATTERN = Pattern.compile("#\\{(.*?)\\}");

    private final List<Map<String, String>> servcieReferenceDefintions = Lists.newArrayList();

    private final GrpcProperties thrallProperties;

    @Value("${spring.application.name}")
    private String applicationName;

    @Value("${server.port}")
    private int httpPort;

    @Autowired
    private AbstractApplicationContext applicationContext;

    @Autowired
    private Environment env;

    public GrpcReferenceRunner(GrpcProperties thrallProperties) {
        this.thrallProperties = thrallProperties;
        String referenceDefinPath = thrallProperties.getReferenceDefinition();
        if (StringUtils.isNoneBlank(referenceDefinPath)) {
            InputStream in = GrpcReferenceRunner.class.getClassLoader().getResourceAsStream(referenceDefinPath);
            servcieReferenceDefintions.addAll(
                    new Gson().fromJson(new InputStreamReader(in), new TypeToken<List<Map<String, String>>>() {
                    }.getType()));
        } else {
            logger.warn("Waring! there is no reference config in classpath,You must config in annoation");
        }
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class<?> searchType = bean.getClass();
        while (!Object.class.equals(searchType) && searchType != null) {
            Field[] fields = searchType.getDeclaredFields();
            for (Field field : fields) {
                SalukiReference reference = field.getAnnotation(SalukiReference.class);
                if (reference != null) {
                    Object value = null;
                    try {
                        value = applicationContext.getBean(field.getType());
                    } catch (NoSuchBeanDefinitionException e) {
                        value = null;
                    }
                    if (value == null) {
                        value = refer(reference, field.getType());
                    }
                    try {
                        if (!field.isAccessible()) {
                            field.setAccessible(true);
                        }
                        field.set(bean, value);
                    } catch (Throwable e) {
                        logger.error("Failed to init remote service reference at filed " + field.getName()
                                + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);
                    }
                }
            }
            searchType = searchType.getSuperclass();
        }
        return bean;
    }

    private Object refer(SalukiReference reference, Class<?> referenceClass) {
        RpcReferenceConfig rpcReferenceConfig = new RpcReferenceConfig();
        String serviceName = this.getServiceName(reference, referenceClass);
        rpcReferenceConfig.setServiceName(serviceName);
        rpcReferenceConfig.setApplication(applicationName);
        String group = this.getGroup(reference, serviceName, referenceClass);
        rpcReferenceConfig.setGroup(group);
        String version = this.getVersion(reference, serviceName, referenceClass);
        rpcReferenceConfig.setVersion(version);
        this.addHaRetries(reference, rpcReferenceConfig);
        this.addRegistyAddress(rpcReferenceConfig);
        this.addAsyncAndTimeOut(reference, rpcReferenceConfig);
        this.addMonitorInterval(rpcReferenceConfig);
        this.addHostAndPort(rpcReferenceConfig);
        if (this.isGenericClient(referenceClass)) {
            rpcReferenceConfig.setGeneric(true);
        }
        if (this.isGrpcStubClient(referenceClass)) {
            rpcReferenceConfig.setGrpcStub(true);
            rpcReferenceConfig.setServiceClass(referenceClass);
        }
        return rpcReferenceConfig.getProxyObj();
    }

    private void addHostAndPort(RpcReferenceConfig rpcReferenceConfig) {
        String host = thrallProperties.getHost();
        int registryHttpPort = thrallProperties.getRegistryHttpPort();
        if (StringUtils.isNoneBlank(host)) {
            rpcReferenceConfig.setHost(host);
        }
        if (registryHttpPort == 0) {
            if (this.httpPort != 0) {
                rpcReferenceConfig.setHttpPort(this.httpPort);
                thrallProperties.setRegistryHttpPort(this.httpPort);
            } else {
                throw new java.lang.IllegalArgumentException("http port must be set in properties");
            }
        } else {
            rpcReferenceConfig.setHttpPort(registryHttpPort);
        }

    }

    private void addMonitorInterval(RpcReferenceConfig rpcReferenceConfig) {
        if (thrallProperties.getMonitorinterval() != 0) {
            rpcReferenceConfig.setMonitorinterval(thrallProperties.getMonitorinterval());
        }
    }

    private void addAsyncAndTimeOut(SalukiReference reference, RpcReferenceConfig rpcReferenceConfig) {
        rpcReferenceConfig.setAsync(reference.async());
        if (reference.timeOut() != 0) {
            rpcReferenceConfig.setTimeout(reference.timeOut());
        }
    }

    private void addRegistyAddress(RpcReferenceConfig rpcReferenceConfig) {
        String registryAddress = thrallProperties.getRegistryAddress();
        if (StringUtils.isBlank(registryAddress)) {
            throw new java.lang.IllegalArgumentException("registry address can not be null or empty");
        } else {
            String[] registryHostAndPort = StringUtils.split(registryAddress, ":");
            if (registryHostAndPort.length < 2) {
                throw new java.lang.IllegalArgumentException("the pattern of registry address is host:port");
            }
            rpcReferenceConfig.setRegistryAddress(registryHostAndPort[0]);
            rpcReferenceConfig.setRegistryPort(Integer.valueOf(registryHostAndPort[1]));
        }
    }

    private void addHaRetries(SalukiReference reference, RpcReferenceConfig rpcReferenceConfig) {
        if (reference.retries() > 1) {
            if (CollectionUtils.isEmpty(reference.retryMethods())) {
                logger.warn("Have set retries,but not have set method,will set all method to retry");
                rpcReferenceConfig.setRetryMethods(new HashSet<String>(Arrays.asList(reference.retryMethods())));
                rpcReferenceConfig.setReties(reference.retries());
            }
        }
    }

    private String getServiceName(SalukiReference reference, Class<?> referenceClass) {
        String serviceName = reference.service();
        if (StringUtils.isBlank(serviceName)) {
            if (this.isGrpcStubClient(referenceClass)) {
                throw new java.lang.IllegalArgumentException("reference service can not be null or empty");
            } else {
                serviceName = referenceClass.getName();
            }
        }
        return serviceName;
    }

    private String getGroup(SalukiReference reference, String serviceName, Class<?> referenceClass) {
        Pair<String, String> groupVersion = findGroupAndVersionByServiceName(serviceName);
        if (StringUtils.isNoneBlank(reference.group())) {
            return reference.group();
        } else if (StringUtils.isNoneBlank(groupVersion.getLeft())) {
            String replaceGroup = groupVersion.getLeft();
            Matcher matcher = REPLACE_PATTERN.matcher(replaceGroup);
            if (matcher.find()) {
                String replace = matcher.group().substring(2, matcher.group().length() - 1).trim();
                String[] replaces = StringUtils.split(replace, ":");
                if (replaces.length == 2) {
                    String realGroup = env.getProperty(replaces[0], replaces[1]);
                    return realGroup;
                } else {
                    throw new IllegalArgumentException("replaces formater is #{XXXgroup:groupName}");
                }
            } else {
                return replaceGroup;
            }
        } else if (this.isGenericClient(referenceClass)) {
            return StringUtils.EMPTY;
        }
        throw new java.lang.IllegalArgumentException(
                String.format("reference group can not be null or empty,the servicName is %s", serviceName));

    }

    private String getVersion(SalukiReference reference, String serviceName, Class<?> referenceClass) {
        Pair<String, String> groupVersion = findGroupAndVersionByServiceName(serviceName);
        if (StringUtils.isNoneBlank(reference.version())) {
            return reference.version();
        } else if (StringUtils.isNoneBlank(groupVersion.getRight())) {
            String replaceVersion = groupVersion.getRight();
            Matcher matcher = REPLACE_PATTERN.matcher(replaceVersion);
            if (matcher.find()) {
                String replace = matcher.group().substring(2, matcher.group().length() - 1).trim();
                String[] replaces = StringUtils.split(replace, ":");
                if (replaces.length == 2) {
                    String realVersion = env.getProperty(replaces[0], replaces[1]);
                    return realVersion;
                } else {
                    throw new IllegalArgumentException("replaces formater is #{XXXservice:1.0.0}");
                }
            } else {
                return replaceVersion;
            }
        } else if (this.isGenericClient(referenceClass)) {
            return StringUtils.EMPTY;
        } else {
            throw new java.lang.IllegalArgumentException("reference version can not be null or empty");
        }
    }

    private Pair<String, String> findGroupAndVersionByServiceName(String serviceName) {
        for (Map<String, String> referenceDefintion : servcieReferenceDefintions) {
            String servcieDefineName = referenceDefintion.get("service");
            if (servcieDefineName.equals(serviceName)) {
                String group = referenceDefintion.get("group");
                String version = referenceDefintion.get("version");
                return new ImmutablePair<String, String>(group, version);
            }
        }
        return new ImmutablePair<String, String>(null, null);
    }

    private boolean isGrpcStubClient(Class<?> referenceClass) {
        if (AbstractStub.class.isAssignableFrom(referenceClass)) {
            return true;
        } else {
            return false;
        }
    }

    private boolean isGenericClient(Class<?> referenceClass) {
        if (GenericService.class.isAssignableFrom(referenceClass)) {
            return true;
        } else {
            return false;
        }
    }

}