All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gateway.connector.tcp.client.GateWayApi Maven / Gradle / Ivy

package com.gateway.connector.tcp.client;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.gateway.connector.proto.Cmd;
import com.gateway.connector.proto.Format;
import com.gateway.connector.proto.Proto;
import com.gateway.connector.utils.Consts;
import com.gateway.connector.utils.ProtoUtils;
import com.gateway.connector.utils.SSLClient;
import com.gateway.connector.utils.TopicUtils;

public class GateWayApi {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private ConcurrentHashMap htRequest = new ConcurrentHashMap();

	private void htRequestRemove(int seq, boolean isPrint) {
		ProtoReq pr = htRequest.remove(seq);
		if (pr != null && isPrint) {
			Proto msg = pr.getReqProto();
			byte[] body = msg.getBody();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String content = body != null ? new String(body) : "";
			logger.warn("RequestRemove cmd:{},format:{},seq:{},sessionid:{},body:{},beginTime:{},timeOut:{}",
					msg.getCmd(), msg.getFormat(), msg.getSeq(), msg.getSessionId(), content,
					sdf.format(new Date(pr.getBeginTime())), pr.getTimeOut());

		}
	}

	private ProtoReq htRequestGet(int seq) {

		return htRequest.get(seq);
	}

	private void htRequestAdd(ProtoReq req) {
		req.setBeginTime(System.currentTimeMillis());
		htRequest.put(req.getReqProto().getSeq(), req);
	}

	private boolean reconnectFlag = true;

	public boolean isReconnectFlag() {
		return reconnectFlag;
	}

	public void setReconnectFlag(boolean reconnectFlag) {
		this.reconnectFlag = reconnectFlag;
	}

	private ConcurrentHashMap>> topicHm = new ConcurrentHashMap>>();
	private ConcurrentHashMap reTopicHm = new ConcurrentHashMap();
	private boolean isConnected;
	private final String _loginTopic = "SYS.ATS.LOGIN";
	private boolean isLogOut = false;
	private boolean isGzip = false;
	private ProxyInfo proxyInfo;

	public ProxyInfo getProxyInfo() {
		return proxyInfo;
	}

	public void setProxyInfo(ProxyInfo proxyInfo) {
		this.proxyInfo = proxyInfo;
	}
	public boolean isGzip() {
		return isGzip;
	}

	public void setGzip(boolean isGzip) {
		this.isGzip = isGzip;
		client.setGzip(isGzip);
	}

	public void setLogOut(boolean isLogOut) {
		this.isLogOut = isLogOut;
	}

	public boolean isConnected() {
		return isConnected;
	}

	private boolean isLogin;

	public boolean isLogin() {
		return isLogin;
	}

	private IEventListener eventlistener = null;

	public IEventListener getEventlistener() {
		return eventlistener;
	}

	public void setEventlistener(IEventListener eventlistener) {
		this.eventlistener = eventlistener;
	}

	public class PRspCallBack {
		public IRspCallBack rspCallBack;

		public String serverName;
		public String method;

		public void onRspMessage(Proto proto) {
			String result = null;
			if (proto != null && proto.getBody() != null) {
				try {
					result = new String(proto.getBody(), "UTF-8");
				} catch (UnsupportedEncodingException e) {
					logger.error("", e);
				}
			}
			if (rspCallBack != null) {
				rspCallBack.onRspMessage(result);
			}
			logger.debug(String.format("response->%s[%s] content:%s", serverName, method, result));

		}
	}

	private IClientListener listener = new IClientListener() {

		@Override
		public void onMessage(Proto msg) {
			_sendHeartInterval = System.currentTimeMillis();
			if (msg.getFormat() == Format.REPLY || msg.getCmd() == Cmd.CONNECT) {
				ProtoReq req = htRequestGet(msg.getSeq());
				if (req != null) {
					htRequestRemove(msg.getSeq(), false);
					req.setRspProto(msg);
					if (req.isSyncFlag()) {
						req.cnotify();
					} else {
						req.notifyRspCallBack();
					}

				} else {
					byte[] body = msg.getBody();
					String content = body != null ? new String(body) : "";
					logger.warn("drop cmd:{},format:{},seq:{},sessionid:{},body:{}", msg.getCmd(), msg.getFormat(),
							msg.getSeq(), msg.getSessionId(), content);

				}
			} else if (msg.getFormat() == Format.NOTIFY) {
				byte[] body = msg.getBody();
				if (body != null) {
					HashMap hm = ProtoUtils.getNotify(body);
					String topic = hm.get("topic") + "";
					String content = hm.get("content") + "";
					onMessage(topic, content);
					// 适配强制登出操作
					if (isLogOut && topic.equals(_loginTopic)) {
						onEvent(IEventListener.CONNECTION_LOGOUT);
					}
				}
			}
		}

		private void onMessage(String topic, String content) {
			for (Entry>> entry : topicHm.entrySet()) {
				String stopic = entry.getKey();
				CopyOnWriteArraySet> cas = entry.getValue();
				if (TopicUtils.matchTopic(stopic, topic)) {
					for (IMessage iMessage : cas) {
						long begin = System.currentTimeMillis();
                        iMessage.onMessage(topic, content);
                        long end = System.currentTimeMillis();
                        long ts = end - begin;
                        if (ts >= 100)
                        {
                            logger.warn("onMessage 耗时:{}:{}:{}", stopic, iMessage,ts);
                        }
					}
				}
			}
		}

		@Override
		public void onLoginResult(Proto proto) {
			sid = proto.getSessionId();
			if (!StringUtils.isEmpty(sid)) {
				isLogin = true;
				reSubscribe();
				startHeartBeat();
				onEvent(IEventListener.CONNECTION_LOGIN_SUCCESS);
			}
		}

		@Override
		public void onException(Throwable throwable) {
			// onDisConnect();

		}

		@Override
		public void onDisConnect() {
			isConnected = false;
			isLogin = false;
			sid = "";
			onEvent(IEventListener.CONNECTION_CLOSED);
		}

		@Override
		public void onConnect() {
			isConnected = true;

			onEvent(IEventListener.CONNECTION_SUCCESS);
		}
	};

	private Proto sendLogin() {
		try {
			ProtoReq req = ProtoUtils.generateConnect(sid, userName, pwd, _extendParamDic);

			this.htRequestAdd(req);
			client.sendMessage(req.getReqProto());
			req.cwait(Consts.WaitTime);
			htRequest.remove(req.getReqProto().getSeq());
			return req.getRspProto();
		} catch (Exception e) {
			logger.error("sendLogin error.", e);
		}
		return null;
	}

	private TcpClient client = new TcpClient(listener);
	private String sid = "";
	private Thread hbThread;
	private String userName;
	private String pwd;
	@SuppressWarnings("rawtypes")
	private Map _extendParamDic = null;

	public String connect(String host, int port, String userName, String pwd, boolean isencryption, int protocal,
			@SuppressWarnings("rawtypes") Map... dic) {
		String result = null;
		this.userName = userName;
		this.pwd = pwd;
		if (dic != null && dic.length > 0) {
			this._extendParamDic = dic[0];
		}
		client.setProxyInfo(getProxyInfo());
		boolean flag = client.connect(host, port, protocal);
		if (flag) {
			Proto proto = sendLogin();
			if (proto != null) {
				if (proto.getBody() != null) {
					try {
						result = new String(proto.getBody(), "UTF-8");
					} catch (UnsupportedEncodingException e) {
						logger.error("connect error",e);
					}
				} else {
					result = "";
				}
			}
		}
		return result;
	}

	/**
	 * 同步请求
	 *
	 * @param serverName 请求的服务名
	 * @param method     请求的方法
	 * @param content    请求参数
	 * @param clazz      返回结果对象
	 * @param waitTime   超时等待时间
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public  T requestSync(String serverName, String method, String content, Class clazz, long... waitTime)
			throws Exception {
		T t = null;
		long wtime = Consts.WaitTime;
		if (waitTime != null && waitTime.length > 0) {
			wtime = waitTime[0];
		}

		logger.debug(String.format("requestSync->%s[%s] content:%s", serverName, method, content));
		Proto proto = requestSync(serverName, method, content, wtime);
		if (proto != null && proto.getBody() != null) {
			if (String.class.equals(clazz)) {
				t = (T) new String(proto.getBody(), "UTF-8");
			} else {
				t = JSON.parseObject(proto.getBody(), clazz);
			}
		}

		logger.debug(String.format("%s[%s]->response content:%s", serverName, method, content));

		return t;
	}

	/**
	 * 带usid同步请求
	 * @param sid
	 * @param serverName
	 * @param method
	 * @param content
	 * @param clazz
	 * @param waitTime
	 * @param 
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public  T requestSync(String sid, String serverName, String method, String content, Class clazz, long... waitTime)
			throws Exception {
		T t = null;
		long wtime = Consts.WaitTime;
		if (waitTime != null && waitTime.length > 0) {
			wtime = waitTime[0];
		}

		logger.debug(String.format("requestSync->%s[%s] content:%s", serverName, method, content));
		Proto proto = requestSync(serverName, method, content, wtime, new String[] {sid});
		if (proto != null && proto.getBody() != null) {
			if (String.class.equals(clazz)) {
				t = (T) new String(proto.getBody(), "UTF-8");
			} else {
				t = JSON.parseObject(proto.getBody(), clazz);
			}
		}

		logger.debug(String.format("%s[%s]->response content:%s", serverName, method, content));

		return t;
	}

	@SuppressWarnings("unchecked")
	public  T requestHttpSync(String url, String serverName, String method, String content, Class clazz)
			throws Exception {
		T t = null;

		String str = requestHttp(url, serverName, method, content);
		if (!StringUtils.isEmpty(str)) {
			if (String.class.equals(clazz)) {
				t = (T) str;
			} else {
				t = JSON.parseObject(str, clazz);
			}
		}
		return t;
	}

	@SuppressWarnings({ "resource", "deprecation" })
	private String requestHttp(String url, String serverName, String method, String content) throws Exception {

		SSLClient httpclient = new SSLClient();
		HttpPost httppost = new HttpPost(url);
		HashMap hm = new HashMap();
		hm.put("serverName", serverName);
		hm.put("method", method);
		hm.put("content", content);
		String body = JSON.toJSONString(hm);
		httppost.addHeader("sessionId", sid);

		StringEntity entity = new StringEntity(body.toString(), "utf-8");// 解决中文乱码问题
		entity.setContentEncoding("UTF-8");
		entity.setContentType("application/json");
		httppost.setEntity(entity);
		ResponseHandler responseHandler = new BasicResponseHandler();

		String result = httpclient.execute(httppost, responseHandler);

		httppost.releaseConnection();
		httpclient.getConnectionManager().shutdown();
		return result;

	}

	public void requestAsync(String serverName, String method, String content, long waitTime, IRspCallBack rspCallBack,
			String... sid) throws Exception {

		logger.debug("requestAsync->%s[%s] content:%s", serverName, method, content);

		PRspCallBack pcb = new PRspCallBack();
		pcb.serverName = serverName;
		pcb.method = method;
		pcb.rspCallBack = rspCallBack;
		requestAsync(serverName, method, content, waitTime, pcb, sid);

	}

	private void requestAsync(String serverName, String method, String content, long waitTime, PRspCallBack rspCallBack,
			String... sids) throws Exception {

		if (isLogin()) {
			String tsid = sid;
			if (sids != null && sids.length > 0) {
				tsid = sid + "=NOP=" + sids[0];
			}
			ProtoReq req = ProtoUtils.generateRequest(tsid, serverName, method, content);
			req.setRspCallBack(rspCallBack);
			req.setTimeOut(waitTime);
			htRequestAdd(req);
			client.sendMessage(req.getReqProto());
			return;
		}
		if (rspCallBack != null) {
			rspCallBack.onRspMessage(null);
		}
	}

	private Proto requestSync(String serverName, String method, String content, long waitTime, String... sids)
			throws Exception {
		if (this.isLogin()) {
			String tsid = sid;
			if (sids != null && sids.length > 0) {
				tsid = sid + "=NOP=" + sids[0];
			}
			ProtoReq req = ProtoUtils.generateRequest(tsid, serverName, method, content);
			req.setTimeOut(waitTime);
			htRequestAdd(req);
			client.sendMessage(req.getReqProto());

			if (!req.cwait(waitTime)) {
				htRequestRemove(req.getReqProto().getSeq(), true);
				logger.warn("seq:{} requestSync timeout", req.getReqProto().getSeq());
			}
			return req.getRspProto();
		}
		return null;
	}

	/**
	 * 连接状态码:连接中,连接成功,重连,关闭
	 *
	 * @param code
	 */
	private void onEvent(int code) {// 连接状态
		if (eventlistener != null) {
			eventlistener.onEvent(code);
		}
	}

	private void reSubscribe() {
		if (!StringUtils.isEmpty(sid)) {
			Runnable target = new Runnable() {
				@Override
				public void run() {
					for (Entry entry : reTopicHm.entrySet()) {
						String topic = entry.getKey();
						String serverName = entry.getValue();
						try {
							requestSync(serverName, "subscribe", topic, String.class);
						} catch (Exception e) {
							logger.error("reSubscribe error",e);
						}
					}
				}
			};
			Thread t = new Thread(target);
			t.setName("reSubscribe thread");
			t.start();
		}
	}

	/**
	 * 订阅实时消息
	 *
	 * @param topic   订阅topic,mq推送的topic
	 * @param message 回调消息接口
	 * @param clazz   消息对象
	 */

	public synchronized  boolean subscribe(String serverName, String topic, final IMessage message,
			final Class clazz) throws Exception {
		boolean flag = false;
		if (this.isLogin()) {
			flag = true;
			CopyOnWriteArraySet> cas = topicHm.get(topic);
			if (cas == null) {
				cas = new CopyOnWriteArraySet>();
				topicHm.put(topic, cas);
			}
			cas.add(message);
			if (cas.size() == 1) {// 第一次订阅
				String result = requestSync(serverName, "subscribe", topic, String.class);
				if (!StringUtils.isEmpty(result)) {
					reTopicHm.put(topic, serverName);
				} else {
					flag = false;
				}
			}
			if (!flag) {
				cas.remove(message);
			}
		}
		return flag;
	}

	public synchronized  boolean subscribe(String topic, final IMessage message, final Class clazz)
			throws Exception {
		return subscribe("gateway", topic, message, clazz);
	}

	/**
	 * 退订实时消息
	 *
	 * @param topics  退订topic
	 * @param message 退订回调接口
	 * @param clazz   消息对象
	 * @throws Exception
	 */
	public synchronized  boolean unSubscribe(String topic, final IMessage message, final Class clazz)
			throws Exception {
		boolean flag = false;
		CopyOnWriteArraySet> cas = topicHm.get(topic);
		if (cas != null) {
			cas.remove(message);
		}
		if (cas != null && cas.size() <= 0) {// 没有订阅
			reTopicHm.remove(topic);
			topicHm.remove(topic);
			String result = requestSync("gateway", "unsubscribe", topic, String.class);
			if (!StringUtils.isEmpty(result)) {
				flag = true;
			}
		}

		return flag;
	}

	private void reConnect() {
		if (reconnectFlag && !isConnected()) {
			client.connect();
		}
		if (isConnected && !isLogin()) {
			sendLogin();
		}
	}

	private long _sendHeartInterval;

	private void checkRequestAsyncTimeOut()// 异步请求超时处理
	{
		try {
			List lt = new ArrayList();
			for (Entry entry : htRequest.entrySet()) {
				ProtoReq req = entry.getValue();
				if (!req.isSyncFlag()) {
					if ((System.currentTimeMillis() - req.getBeginTime()) >= req.getTimeOut()) {
						lt.add(req);
					}
				}
			}
			for (ProtoReq req : lt) {
				htRequestRemove(req.getReqProto().getSeq(), true);
				logger.warn("seq:{} requestAsync timeout", req.getReqProto().getSeq());
				req.notifyRspCallBack();
			}

		} catch (Exception e) {

			logger.error("checkRequestAsyncTimeOut", e);
		}

	}

	private Object lockObj = new Object();

	private void startHeartBeat() {
		synchronized (lockObj) {

			if (hbThread == null || !hbThread.isAlive()) {
				Runnable target = new Runnable() {

					@Override
					public void run() {
						while (!client.isStop()) {

							try {

								if (!StringUtils.isEmpty(sid) && isLogin()) {
									long interval = (System.currentTimeMillis() - _sendHeartInterval) / 1000;

									if (interval > Consts.HeartInterval) {
										client.sendMessage(ProtoUtils.generateHeartbeat(sid));
									}
								}
								checkRequestAsyncTimeOut();
								reConnect();
								Thread.sleep(1000);
							} catch (Exception e) {

							}
						}

					}
				};

				hbThread = new Thread(target);
				hbThread.setName("heartbeat thread");
				hbThread.start();
			}
		}

	}

	public void disconnect() {
		synchronized (this) {
			reTopicHm.clear();
			topicHm.clear();
			htRequest.clear();
			if (client != null) {
				reconnectFlag = false;
				client.disConnect();
			}
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy