Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.baidu.discovery.client.api.TianluApi Maven / Gradle / Ivy
package com.baidu.discovery.client.api;
import com.baidu.discovery.client.FormulaContext;
import com.baidu.discovery.client.auth.Authorization;
import com.baidu.discovery.client.bean.InstanceBean;
import com.baidu.discovery.client.bean.ServiceAddBean;
import com.baidu.discovery.client.bean.ServiceBean;
import com.baidu.discovery.client.exception.ServerCommunicationException;
import com.baidu.discovery.client.exception.ServerStatusException;
import com.baidu.discovery.client.model.Instance;
import com.baidu.discovery.client.model.ServiceInfo;
import com.baidu.discovery.client.model.Token;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* @author Bowu Dong ([email protected] )
*/
public class TianluApi {
private static final Logger logger = LoggerFactory.getLogger(TianluApi.class);
public static final String X_BMS_HEADER_PRODUCT_LINE = "X-BMS-PRODUCTLINE-NAME";
private CloseableHttpClient httpClient;
private ObjectMapper objectMapper;
private Authorization authorization;
public TianluApi() {
httpClient = HttpClientBuilder.create()
.build();
objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
authorization = new Authorization();
}
public List getServiceInstances(FormulaContext context, String serviceName) {
String url = String.format("%s/registry/services/%s/instances",
context.getClientConfig().getServiceUrl(), serviceId(context, serviceName));
HttpGet get = new HttpGet(url);
processHeaders(get);
addAuthInfo(get, context);
try (CloseableHttpResponse response = httpClient.execute(get)) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) {
return Collections.emptyList();
} else if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new ServerStatusException("get service instances error", response);
}
byte[] json = EntityUtils.toByteArray(response.getEntity());
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, InstanceBean.class);
List beans = objectMapper.readValue(json, javaType);
return beans.stream()
.map(InstanceBean::getData)
.map(data -> {
Instance.InstanceBuilder builder = Instance.builder();
builder.instanceId(data.getId())
.scheme(data.getScheme())
.host(data.getHost())
.port(data.getPort())
.path(data.getPath())
.type(data.getRpcType())
.status(data.getStatus())
.customs(data.getRpcDesc())
.tags(data.getTags())
.startTime(data.getStartTime());
return builder.build();
}).collect(Collectors.toList());
} catch (IOException e) {
throw new ServerCommunicationException("get service instances error!", e);
}
}
public Instance registerInstance(FormulaContext context, Instance instance) {
prepare(context, instance);
String url = String.format("%s/registry/services/%s/instances",
context.getClientConfig().getServiceUrl(),
serviceId(context, instance.getAppName()));
HttpPost post = new HttpPost(url);
processHeaders(post);
addAuthInfo(post, context);
InstanceBean.InstanceData data = InstanceBean.InstanceData.builder()
.id(instance.getInstanceId())
.scheme(instance.getScheme())
.host(instance.getHost())
.port(instance.getPort())
.rpcType(instance.getType())
.rpcDesc(instance.getCustoms())
.startTime(new Date())
.status(instance.getStatus())
.idc(instance.getZone())
.path(instance.getPath())
.productName(context.getClientConfig().getProductName())
.serviceId(serviceId(context, instance.getAppName()))
.tags(instance.getTags())
.build();
try {
byte[] body = objectMapper.writeValueAsBytes(data);
post.setEntity(new ByteArrayEntity(body));
} catch (IOException e) {
throw new ServerCommunicationException("register instance error!", e);
}
try (CloseableHttpResponse response = httpClient.execute(post)) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
logger.warn("server returns 401, force refresh product token");
getProductToken(context, true);
}
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) {
throw new ServerStatusException("register instance error", data, response);
}
} catch (IOException e) {
throw new ServerCommunicationException("register instance error!", e);
}
return instance;
}
private void prepare(FormulaContext context, Instance instance) {
if (!StringUtils.hasText(instance.getZone())) {
instance.setZone("unknown");
}
}
public Instance removeInstance(FormulaContext context, Instance instance) {
String url = String.format("%s/registry/services/%s/instances/%s",
context.getClientConfig().getServiceUrl(),
serviceId(context, instance.getAppName()),
instance.getInstanceId());
HttpDelete delete = new HttpDelete(url);
processHeaders(delete);
addAuthInfo(delete, context);
try (CloseableHttpResponse response = httpClient.execute(delete)) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) {
return instance;
} else if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new ServerStatusException("delete instance error", response);
}
} catch (IOException e) {
throw new ServerCommunicationException("delete instance error!", e);
}
return instance;
}
public Token getProductToken(FormulaContext context) {
return getProductToken(context, false);
}
public Token getProductToken(FormulaContext context, boolean force) {
if (context.getClientConfig().getProductKey() == null) {
return null;
}
String productName = context.getClientConfig().getProductName();
if (!force && context.getToken(productName) != null
&& context.getToken(productName).getInvalidTime().getTime() > System.currentTimeMillis()) {
return context.getToken(productName);
}
Token prev = force ? context.getToken(productName) : null;
String url;
try {
url = String.format("%s/registry/authentication/http?productKey=%s",
context.getClientConfig().getServiceUrl(),
URLEncoder.encode(context.getClientConfig().getProductKey(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
HttpUriRequest request = new HttpGet(url);
processHeaders(request);
try (CloseableHttpResponse response = httpClient.execute(request)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) {
throw new ServerStatusException("get product token error", response);
}
byte[] entity = EntityUtils.toByteArray(response.getEntity());
Token token = objectMapper.readValue(entity, Token.class);
context.putToken(productName, token);
if (force) {
logger.info("FORCE get product key, prev={}, current={}", prev, token);
}
return token;
} catch (UnsupportedEncodingException e) {
throw new ServerCommunicationException("utf-8 not support", e);
} catch (IOException e) {
throw new ServerCommunicationException(e);
}
}
private void processHeaders(HttpUriRequest request) {
String agent = String.format("Tianlu-Discovery/1.0.0 (Java/%s)", System.getProperty("java.version"));
request.setHeader("User-Agent", agent);
request.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
request.setHeader(HttpHeaders.ACCEPT_ENCODING, "gzip");
}
private void addAuthInfo(HttpUriRequest request, FormulaContext context) {
if (context.getClientConfig().getHeaders() != null) {
context.getClientConfig().getHeaders().forEach(request::setHeader);
}
if (context.getClientConfig().getProductKey() != null) {
// 天路认证
String productName = context.getClientConfig().getProductName();
String auth = String.format("Basic %s", context.getToken(productName).getToken());
request.setHeader(HttpHeaders.AUTHORIZATION, auth);
}
// else {
// // 云上AK/SK认证
// authorization.sign(request, context.getClientConfig().getAccessKey(),
// context.getClientConfig().getSecretKey());
// }
if (request instanceof HttpRequestBase) {
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(context.getClientConfig().getSocketTimeoutMs())
.setConnectTimeout(context.getClientConfig().getConnectTimeoutMs())
.build();
((HttpRequestBase) request).setConfig(requestConfig);
}
}
public ServiceAddBean addService(FormulaContext context, String serviceName) {
// 因注册服务时需要携带custom信息,天路registry暂无法使用,改用management接口
String url = String.format("%s/management/products/%s/services",
context.getClientConfig().getServiceUrl(),
context.getClientConfig().getProductName());
HttpPost request = new HttpPost(url);
processHeaders(request);
addAuthInfo(request, context);
Map service = new HashMap<>();
service.put("id", serviceId(context, serviceName));
service.put("productName", context.getClientConfig().getProductName());
service.put("desc", serviceId(context, serviceName));
service.put("doc", serviceId(context, serviceName));
service.put("status", 1);
service.put("contacts", Collections.singletonList("jarvis"));
service.put("createTime", new Date());
service.put("updateTime", new Date());
service.put("createUser", "jarvis");
service.put("updateUser", "jarvis");
Map custom = new HashMap<>();
// serviceType: SpringCloud or ServiceMesh.
custom.put("serviceType", "SpringCloud");
service.put("custom", custom);
try {
byte[] json = objectMapper.writeValueAsBytes(service);
request.setEntity(new ByteArrayEntity(json));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
try (CloseableHttpResponse response = httpClient.execute(request)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) {
throw new ServerStatusException("add service", Collections.singletonList(service), response);
}
String body = EntityUtils.toString(response.getEntity());
logger.debug("add Service return: {}", body);
return objectMapper.readValue(body, ServiceAddBean.class);
} catch (IOException e) {
throw new ServerCommunicationException("add service failed! ", e);
}
}
/**
* 实例ID采用
* @param context
* @param instance
* @return
*/
private String serviceId(FormulaContext context, Instance instance) {
return serviceId(context, instance.getAppName());
}
private String serviceId(FormulaContext context, String serviceName) {
String productName = context.getClientConfig().getProductName();
ServiceInfo serviceInfo = getServiceInfo(serviceName);
String resourceIsolation = serviceInfo.getResourceIsolation();
String originServiceName = serviceInfo.getOriginServiceName();
// 服务名中不存在时,默认采用配置中的隔离信息
if (StringUtils.isEmpty(resourceIsolation)) {
resourceIsolation = context.getClientConfig().getResourceIsolation();
}
return String.format("%s_%s_%s", productName, resourceIsolation, originServiceName);
}
/**
* 获取原生服务名
* @param serviceName eg.workspaceName.serviceName
* @return The origin ServiceName
*/
public String getOriginServiceName(String serviceName) {
return getServiceInfo(serviceName).getOriginServiceName();
}
/**
* 获取服务信息
* @param serviceName eg.workspaceName.serviceName
* @return The ServiceInfo contains resource isolation && the origin service name.
*/
public ServiceInfo getServiceInfo(String serviceName) {
String resourceIsolation = "";
String originServiceName = serviceName;
// 跨workspace交互方式: workspaceName.serviceName
if (serviceName.contains(".")) {
String[] serviceInfoArray = serviceName.split("\\.");
if (serviceInfoArray.length != 2) {
throw new IllegalArgumentException("Illegal serviceName argument: " + serviceName);
}
resourceIsolation = serviceInfoArray[0];
originServiceName = serviceInfoArray[1];
}
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.setResourceIsolation(resourceIsolation);
serviceInfo.setOriginServiceName(originServiceName);
return serviceInfo;
}
public ServiceBean.ServiceData heartBeat(FormulaContext context, Instance instance) {
String url = String.format("%s/registry/provider/heartbeat?time=%s",
context.getClientConfig().getServiceUrl(),
60
);
HttpPut request = new HttpPut(url);
processHeaders(request);
addAuthInfo(request, context);
try {
String body = objectMapper.writeValueAsString(Collections.singletonList(instance.getInstanceId()));
request.setEntity(new StringEntity(body));
} catch (IOException e) {
throw new RuntimeException(e);
}
try (CloseableHttpResponse response = httpClient.execute(request)) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
logger.warn("server returns 401, force refresh product token");
getProductToken(context, true);
} else if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new ServerStatusException("heart beat", url, response);
}
String json = EntityUtils.toString(response.getEntity());
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class,
ServiceBean.ServiceData.class);
List list = objectMapper.readValue(json, javaType);
logger.debug("heart beat response: {}", json);
if (list == null || list.stream()
.noneMatch(d -> d.getServiceId().contains(serviceId(context, instance)))) {
// instance fail, registering
logger.warn("instance {} failed, registering", instance.getInstanceId());
registerInstance(context, instance);
return null;
}
return CollectionUtils.isEmpty(list) ? null : list.get(0);
} catch (IOException e) {
throw new ServerCommunicationException("heart beat error!, url=" + url, e);
}
}
public ServiceBean getService(FormulaContext context, String serviceName) {
String url = String.format("%s/registry/services/%s",
context.getClientConfig().getServiceUrl(),
serviceId(context, serviceName));
HttpGet get = new HttpGet(url);
processHeaders(get);
addAuthInfo(get, context);
try (CloseableHttpResponse response = httpClient.execute(get)) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) {
return null;
} else if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new ServerStatusException("get service", response);
}
byte[] json = EntityUtils.toByteArray(response.getEntity());
return objectMapper.readValue(json, ServiceBean.class);
} catch (IOException e) {
throw new ServerCommunicationException("get service error!", e);
}
}
public void close() {
try {
httpClient.close();
} catch (IOException e) {
// do nothing
}
}
public List getServices(FormulaContext context) {
String url = String.format("%s/management/products/%s/services",
context.getClientConfig().getServiceUrl(),
context.getClientConfig().getProductName());
HttpGet get = new HttpGet(url);
addAuthInfo(get, context);
processHeaders(get);
try (CloseableHttpResponse response = httpClient.execute(get)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new ServerStatusException("get services error!", response);
}
JavaType type = objectMapper.getTypeFactory().constructParametricType(List.class, ServiceBean.class);
List serviceBeans = objectMapper.readValue(
EntityUtils.toByteArray(response.getEntity()), type);
return serviceBeans.stream()
.filter(bean -> belongsTo(bean, context))
.map(bean -> bean.getData().getId().replace(serviceId(context, ""), ""))
.collect(Collectors.toList());
} catch (IOException e) {
throw new ServerCommunicationException("get services error!", e);
}
}
private boolean belongsTo(ServiceBean bean, FormulaContext context) {
String prefix = serviceId(context, "");
return bean.getData().getId().startsWith(prefix);
}
}