org.sdn.api.DefaultOpenClient Maven / Gradle / Ivy
package org.sdn.api;
import com.alibaba.fastjson.JSON;
import org.apache.log4j.BasicConfigurator;
import org.sdn.api.constants.ErrorMsgEnum;
import org.sdn.api.constants.OpenApiConstants;
import org.sdn.api.domain.OpenClientDO;
import org.sdn.api.event.MessageEvent;
import org.sdn.api.request.OpenAuthRequest;
import org.sdn.api.request.OpenRequest;
import org.sdn.api.response.OpenAuthResponse;
import org.sdn.api.response.OpenResponse;
import org.sdn.api.utils.Signature;
import org.sdn.api.utils.StringUtils;
import org.sdn.api.utils.http.rest.RestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
/**
* @author gaosong
* @date 2018/10/15.
*/
public class DefaultOpenClient implements OpenClient {
private Logger logger = LoggerFactory.getLogger(DefaultOpenClient.class);
private static ConcurrentHashMap clientConcurrentHashMap = new ConcurrentHashMap<>();
/**
* http请求工具
*/
private RestTemplate restTemplate;
/**
* 服务端url
*/
private String serverUrl;
/**
* 客户id
*/
private String appKey;
/**
* 客户密钥
*/
private String appSecret;
/**
* token
*/
private String authToken;
private String charset;
private String authEvent;
/**
* 接口请求超时时间,单位毫秒,如果访问一个接口,多少时间内无法返回数据,就直接放弃此次调用
* 默认在6s内接口未返回报超时
*/
private int socketTimeout = 6000;
ConcurrentHashMap futureMap = new ConcurrentHashMap<>();
/**
* 初始化token,默认启动事件监听器
*
* @param serverUrl
* @param appKey
* @param appSecret
* @throws OpenApiException
*/
public DefaultOpenClient(String serverUrl, String appKey, String appSecret) throws OpenApiException {
this(serverUrl, appKey, appSecret, true);
}
public OpenClientDO getOpenClientDO() {
OpenClientDO openClientDO = new OpenClientDO();
openClientDO.setAuthEvent(this.authEvent);
openClientDO.setAuthToken(this.authToken);
openClientDO.setAppSecret(this.appSecret);
return openClientDO;
}
/**
* 初始化
*
* @param serverUrl
* @param appKey
* @param appSecret
* @param needSubscribe 是否需要启动事件监听器
* @throws OpenApiException
*/
public DefaultOpenClient(String serverUrl, String appKey, String appSecret, boolean needSubscribe) throws OpenApiException {
this.restTemplate = new RestTemplate();
this.serverUrl = serverUrl;
this.appKey = appKey;
this.appSecret = appSecret;
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
try {
if (needSubscribe) {
initTokenAndSub();
} else {
initToken();
}
String checkKey = serverUrl + ":" + appKey;
if (clientConcurrentHashMap.containsKey(checkKey)) {
throw new OpenApiException(ErrorMsgEnum.DUPLICATE_ERROR.getErrno(), String.format("serverUrl[%s],app[%s] has been inited.", serverUrl, appKey));
} else {
clientConcurrentHashMap.put(checkKey, this);
}
} catch (OpenApiException e) {
if (e.getErrno() == ErrorMsgEnum.DUPLICATE_ERROR.getErrno()) {
throw e;
}
// 非重复注册异常,创建重新初始化job
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
if (futureMap.get(true)) {
logger.info("定时任务,初始化token成功,关闭定时任务 token ={}", authToken);
scheduler.shutdown();
} else {
boolean isTrue = false;
if (needSubscribe) {
isTrue = initTokenAndSub();
} else {
isTrue = initToken();
}
futureMap.put(true, isTrue);
}
} catch (OpenApiException e) {
}
}
};
// 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
scheduler.scheduleAtFixedRate(runnable, 10, 10, TimeUnit.SECONDS);
futureMap.put(true, false);
logger.info("初始化token失败,启动定时任务初始化token");
}
}
/**
* 取消初始化client
*
* @param serverUrl
* @param appKey
*/
@Override
public boolean removeClient(String serverUrl, String appKey) {
String checkKey = serverUrl + ":" + appKey;
boolean remove = false;
if (clientConcurrentHashMap.containsKey(checkKey)) {
DefaultOpenClient defaultOpenClient = clientConcurrentHashMap.get(checkKey);
remove = clientConcurrentHashMap.remove(checkKey, defaultOpenClient);
}
return remove;
}
public static DefaultOpenClient getClient(String serverUrl, String appKey) {
String checkKey = serverUrl + ":" + appKey;
return clientConcurrentHashMap.get(checkKey);
}
/**
* 更新 appSecret 同时更新 authToken
*
* @param appSecret
* @return
* @throws OpenApiException
*/
public boolean updateSecret(String appSecret) throws OpenApiException {
boolean result = false;
this.appSecret = appSecret;
initToken();
return result;
}
/**
* 初始化token并订阅事件
*/
public boolean initToken() throws OpenApiException {
boolean isTrue = false;
try {
OpenAuthRequest openAuthRequest = new OpenAuthRequest();
OpenAuthResponse openAuthResponse = defaultExecute(openAuthRequest);
if (openAuthResponse.isSuccess()) {
if (StringUtils.isEmpty(openAuthResponse.getAccess_token())) {
throw new OpenApiException(ErrorMsgEnum.INITCLIENT_ERROR.getErrno(), openAuthResponse.getMsg());
}
this.authEvent = openAuthResponse.getAuth_event();
this.socketTimeout = openAuthResponse.getSocketTimeout() == 0 ? this.socketTimeout : openAuthResponse.getSocketTimeout();
this.authToken = openAuthResponse.getAccess_token();
isTrue = true;
}
} catch (OpenApiException e) {
logger.error("initToken() error={}", e.getMessage());
throw e;
} catch (Exception e) {
logger.error("initToken() error={}", e.getMessage());
throw new OpenApiException(ErrorMsgEnum.INITCLIENT_ERROR.getErrno(), ErrorMsgEnum.INITCLIENT_ERROR.getErrmsg());
}
return isTrue;
}
/**
* 初始化token并订阅事件
*/
public boolean initTokenAndSub() throws OpenApiException {
boolean isTrue = false;
try {
initToken();
MessageEvent.start(this, this.authToken);
isTrue = true;
} catch (Exception e) {
logger.error("initTokenAndSub() error={}", e.getMessage());
throw new OpenApiException(e);
}
return isTrue;
}
@Override
public T defaultExecute(OpenRequest request) throws OpenApiException {
return doDefaultExecute(request, this.authToken);
}
@Override
public T defaultExecute(OpenRequest request, String authToken) throws OpenApiException {
return doDefaultExecute(request, authToken);
}
/**
* 执行
*
* @param request
* @param
* @return
* @throws OpenApiException
*/
private T doDefaultExecute(OpenRequest request, String authToken) throws OpenApiException {
Map result = doExecute(request, authToken);
T rsp = null;
try {
Class clazz = request.getResponseClass();
rsp = clazz.newInstance();
} catch (InstantiationException e) {
logger.error("doDefaultExecute() InstantiationException error={}", e.getMessage());
throw new OpenApiException(e);
} catch (IllegalAccessException e) {
logger.error("doDefaultExecute() IllegalAccessException error={}", e.getMessage());
throw new OpenApiException(e);
}
String body = (String) result.get("rsp");
rsp = JSON.parseObject(body, request.getResponseClass());
rsp.setBody(body);
return rsp;
}
/**
* @param request
* @param accessToken
* @return
* @throws OpenApiException
*/
private Map doExecute(OpenRequest request,
String accessToken) throws OpenApiException {
if (appKey == null) {
throw new OpenApiException(ErrorMsgEnum.MISSING_APPKEY);
}
if (appSecret == null) {
throw new OpenApiException(ErrorMsgEnum.LACK_PARAMS.getErrno(), ErrorMsgEnum.LACK_PARAMS.getErrmsg() + ":appSecret");
}
/**请求url*/
String url = getRequestUrl(request);
Map result = new HashMap();
String rsp = null;
try {
if (accessToken == null || accessToken.equals("")) {
accessToken = this.authToken;
}
Map reqMap = getRequestWithSign(request, accessToken);
/**设置header*/
Map headers = request.getHeaderMap();
if (headers == null) {
headers = new HashMap<>();
}
headers.put(OpenApiConstants.METHOD, request.getApiMethodName());
if (!StringUtils.isEmpty(accessToken)) {
headers.put(OpenApiConstants.ACCESS_TOKEN, accessToken);
}
String method = request.getRequestMethod();
if (method.equalsIgnoreCase(OpenApiConstants.REQUEST_METHOD)) {
rsp = restTemplate.post(url, JSON.toJSONString(reqMap), headers, socketTimeout, method);
} else if (method.equalsIgnoreCase(OpenApiConstants.REQUEST_METHOD_PUT)) {
rsp = restTemplate.post(url, JSON.toJSONString(reqMap), headers, socketTimeout, method);
} else {
rsp = restTemplate.get(url, reqMap, headers, socketTimeout, method);
}
} catch (Exception e) {
logger.error("doExecute() error={}", e.getMessage());
throw new OpenApiException(e);
}
result.put("rsp", rsp);
return result;
}
/**
* 组装接口参数,处理加密、签名逻辑
*
* @param request
* @param accessToken
* @return
* @throws OpenApiException
*/
public Map getRequestWithSign(OpenRequest> request, String accessToken)
throws OpenApiException {
/**过滤请求参数*/
Map reqMap = Signature.paraFilter(request.getMapParams());
if (StringUtils.isEmpty(charset)) {
charset = OpenApiConstants.CHARSET_UTF8;
}
if (request.getApiMethodName().contains("?")) {
reqMap = StringUtils.getUrlParams(request.getApiMethodName());
}
reqMap.put(OpenApiConstants.METHOD, request.getApiMethodName());
if (request instanceof OpenAuthRequest) {
reqMap.put(OpenApiConstants.APP_ID, this.appKey);
reqMap.put(OpenApiConstants.CLIENT_SECRET, this.appSecret);
} else {
reqMap.put(OpenApiConstants.SIGN, Signature.getSign(reqMap, appSecret));
}
return reqMap;
}
/**
* 获取POST请求的base url
*
* @param request
* @return
* @throws OpenApiException
*/
public String getRequestUrl(OpenRequest> request) throws OpenApiException {
StringBuffer urlSb = new StringBuffer(serverUrl);
try {
if (!serverUrl.endsWith("/")) {
urlSb.append("/");
}
String method = request.getApiMethodName().replace(".", "/");
int len = method.indexOf("?");
if (len > 0) {
urlSb.append(method.substring(0, len));
} else {
urlSb.append(method);
}
} catch (Exception e) {
logger.error("getRequestUrl() error={}", e.getMessage());
throw new OpenApiException(e);
}
return urlSb.toString();
}
}