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

com.xxdb.streaming.client.AbstractClient Maven / Gradle / Ivy

Go to download

The messaging and data conversion protocol between Java and DolphinDB server

There is a newer version: 1.0.27
Show newest version
package com.xxdb.streaming.client;

import java.io.IOException;
import java.net.SocketException;
import java.util.*;
import java.util.concurrent.BlockingQueue;

import com.xxdb.DBConnection;
import com.xxdb.data.BasicInt;
import com.xxdb.data.BasicLong;
import com.xxdb.data.BasicString;
import com.xxdb.data.BasicStringVector;
import com.xxdb.data.BasicAnyVector;
import com.xxdb.data.Entity;
import com.xxdb.data.Vector;
import com.xxdb.streaming.client.IMessage;

abstract class AbstractClient implements MessageDispatcher{
	protected static final int DEFAULT_PORT = 8849;
	protected static final String DEFAULT_HOST = "localhost";
	protected static final String DEFAULT_ACTION_NAME = "javaStreamingApi";
	protected int listeningPort;
	protected QueueManager queueManager = new QueueManager();
	protected HashMap> messageCache = new HashMap<>();
	protected HashMap tableNameToTrueTopic = new HashMap<>();
	protected HashMap HATopicToTrueTopic = new HashMap<>();
	protected HashMap hostEndian = new HashMap<>();
	protected Thread pThread;
	protected HashMap trueTopicToSites = new HashMap<>();
	
	protected class Site {
		String host;
		int port;
		String tableName;
		String actionName;
		MessageHandler handler;
		long msgId;
		boolean reconnect;
		Vector filter = null;
		boolean closed = false;

		Site(String host, int port, String tableName, String actionName,
				MessageHandler handler, long msgId, boolean reconnect, Vector filter) {
			this.host = host;
			this.port = port;
			this.tableName = tableName;
			this.actionName = actionName;
			this.handler = handler;
			this.msgId = msgId;
			this.reconnect = reconnect;
			this.filter = filter;
		}
	}
	
	abstract protected void doReconnect(Site site);
	
	public void setMsgId(String topic, long msgId) {
		synchronized (trueTopicToSites) {
			Site[] sites = trueTopicToSites.get(topic);
			if (sites == null || sites.length == 0)
				return;
			if (sites.length == 1)
				sites[0].msgId = msgId;
		}
	}

	public void tryReconnect(String topic) {
		System.out.println("Trigger reconnect");
    	topic = HATopicToTrueTopic.get(topic);
		queueManager.removeQueue(topic);
    	Site[] sites = null;
    	synchronized (trueTopicToSites) {
			sites = trueTopicToSites.get(topic);
		}
    	if (sites == null || sites.length == 0)
    		return;
    	if (sites.length == 1) {
    		if (!sites[0].reconnect)
    			return;
    	}
		Site site = activeCloseConnection(sites);
		doReconnect(site);
	}
	
	private Site activeCloseConnection(Site[] sites) {
		int siteId = 0;
		int siteNum = sites.length;
		while (true) {
			Site site = sites[siteId];
			siteId = (siteId + 1) % siteNum;
			try {
				DBConnection conn = new DBConnection();
				conn.connect(site.host, site.port);
				try {
					String localIP = conn.getLocalAddress().getHostAddress();
					List params = new ArrayList<>();
					params.add(new BasicString(localIP));
					params.add(new BasicInt(listeningPort));
					conn.run("activeClosePublishConnection", params);
					System.out.println("Successfully closed publish connection");
					return site;
				} catch (IOException ioex) {
					throw ioex;
				} finally {
					conn.close();
				}
			} catch (Exception ex) {
				System.out.println("Unable to actively close the publish connection from site " + site.host + ":" + site.port);
			}
			
			try {
				Thread.sleep(1000);
			} catch (Exception e) {

			}
		}
	}

	public AbstractClient() throws SocketException {
		this(DEFAULT_PORT);
	}
	
	public AbstractClient(int subscribePort) throws SocketException {
		this.listeningPort = subscribePort;
		Daemon daemon = new Daemon(subscribePort, this);
		pThread = new Thread(daemon);
		pThread.start();
	}

	private void addMessageToCache(IMessage msg) {
		String topicString = msg.getTopic();
		String[] topics = topicString.split(",");
		for (String topic:topics) {
			topic = HATopicToTrueTopic.get(topic);
			List cache = messageCache.get(topic);
			if (cache == null) {
				cache = new ArrayList<>();
				messageCache.put(topic, cache);
			}
			cache.add(msg);
		}

	}
	
	private void flushToQueue() {
		Set keySet = messageCache.keySet();
		for(String topic : keySet) {
			try {
				queueManager.getQueue(topic).put(messageCache.get(topic));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		messageCache.clear();
	}

	public void dispatch(IMessage msg) {
		String topicString = msg.getTopic();
		String[] topics = topicString.split(",");
		for (String topic:topics) {
			topic = HATopicToTrueTopic.get(topic);
			BlockingQueue> queue = queueManager.getQueue(topic);
			try {
				queue.put(Arrays.asList(msg));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void batchDispatch(List messags) {
		for (int i = 0; i < messags.size(); ++i) {
			addMessageToCache(messags.get(i));
		}
		flushToQueue();
	}
	
	public boolean isRemoteLittleEndian(String host){
		if(hostEndian.containsKey(host)){
			return hostEndian.get(host);
		}
		else
			return false;
	}
	
	public boolean isClosed(String topic) {
		topic = HATopicToTrueTopic.get(topic);
		synchronized (trueTopicToSites) {
			Site[] sites = trueTopicToSites.get(topic);
			if (sites == null || sites.length == 0)
				return true;
			else
				return sites[0].closed;
		}
	}
	
	private String getTopic(String host, int port, String alias, String tableName, String actionName) {
		return String.format("%s:%d:%s/%s/%s", host, port, alias, tableName, actionName);
	}

	protected BlockingQueue> subscribeInternal(String host, int port,
			String tableName, String actionName, MessageHandler handler,
			long offset, boolean reconnect, Vector filter)
			throws IOException,RuntimeException {
		Entity re;
		String topic = "";
		
		DBConnection dbConn = new DBConnection();
		dbConn.connect(host, port);
		try {
			String localIP = dbConn.getLocalAddress().getHostAddress();
			
			if(!hostEndian.containsKey(host)){
				hostEndian.put(host, dbConn.getRemoteLittleEndian());
			}
			
			List params = new ArrayList();
			params.add(new BasicString(tableName));
			params.add(new BasicString(actionName));
			re = dbConn.run("getSubscriptionTopic", params);
			topic = ((BasicAnyVector)re).getEntity(0).getString();
			params.clear();

			params.add(new BasicString(localIP));
			params.add(new BasicInt(this.listeningPort));
			params.add(new BasicString(tableName));
			params.add(new BasicString(actionName));
			params.add(new BasicLong(offset));
			if (filter != null)
				params.add(filter);
			re = dbConn.run("publishTable", params);
			if (re instanceof BasicAnyVector) {
				BasicStringVector HASiteStrings = (BasicStringVector)(((BasicAnyVector) re).getEntity(1));
				int HASiteNum = HASiteStrings.rows();
				Site[] sites = new Site[HASiteNum];
				for (int i = 0; i < HASiteNum; i++) {
					String HASite = HASiteStrings.getString(i);
					String[] HASiteHostAndPort = HASite.split(":");
					String HASiteHost = HASiteHostAndPort[0];
					int HASitePort = new Integer(HASiteHostAndPort[1]);
					String HASiteAlias = HASiteHostAndPort[2];
					sites[i] = new Site(HASiteHost, HASitePort, tableName, actionName, handler, offset - 1, true, filter);
					synchronized (tableNameToTrueTopic) {
						tableNameToTrueTopic.put(HASiteHost + ":" + HASitePort + ":" + tableName, topic);
					}
					String HATopic = getTopic(HASiteHost, HASitePort, HASiteAlias, tableName, actionName);
					synchronized (HATopicToTrueTopic) {
						HATopicToTrueTopic.put(HATopic, topic);
					}
				}
				synchronized (trueTopicToSites) {
					trueTopicToSites.put(topic, sites);
				}
			}
			else {
				Site[] sites = {new Site(host, port, tableName, actionName, handler, offset - 1, reconnect, filter)};
				synchronized (tableNameToTrueTopic) {
					tableNameToTrueTopic.put(host + ":" + port + ":" + tableName, topic);
				}
				synchronized (HATopicToTrueTopic) {
					HATopicToTrueTopic.put(topic, topic);
				}
				synchronized (trueTopicToSites) {
					trueTopicToSites.put(topic, sites);
				}
			}
		} catch (Exception ex) {
			throw ex;
		} finally {
			dbConn.close();
		}
		BlockingQueue> queue = queueManager.addQueue(topic);
		return queue;
	}
	
	protected BlockingQueue> subscribeInternal(String host, int port,
			String tableName, String actionName, long offset, boolean reconnect)
			throws IOException,RuntimeException {
		return subscribeInternal(host, port, tableName, actionName, null, offset, reconnect, null);
	}

	protected BlockingQueue> subscribeInternal(String host, int port, String tableName, long offset) throws IOException,RuntimeException {
		return subscribeInternal(host,port,tableName,DEFAULT_ACTION_NAME,offset,false);
	}
	
	protected BlockingQueue> subscribeInternal(String host, int port, String tableName, String actionName, long offset) throws IOException,RuntimeException {
		return subscribeInternal(host,port,tableName,actionName,offset,false);
	}
	
	protected void unsubscribeInternal(String host,int port ,String tableName,String actionName) throws IOException {
		DBConnection dbConn = new DBConnection();
		dbConn.connect(host, port);
		try {
			String localIP = dbConn.getLocalAddress().getHostAddress();
			List params = new ArrayList();
			params.add(new BasicString(localIP));
			params.add(new BasicInt(this.listeningPort));
			params.add(new BasicString(tableName));
			params.add(new BasicString(actionName));
			
			dbConn.run("stopPublishTable", params);
			String topic = null;
			String fullTableName = host + ":" + port + ":" + tableName;
			synchronized (tableNameToTrueTopic) {
				topic = tableNameToTrueTopic.get(fullTableName);
			}
			synchronized (trueTopicToSites) {
				Site[] sites = trueTopicToSites.get(topic);
				if (sites == null || sites.length == 0)
					;
				for (int i = 0; i < sites.length; i++)
					sites[i].closed = true;
			}
			System.out.println("Successfully unsubscribed table " + fullTableName);
		} catch (Exception ex) {
			throw ex;
		} finally {
			dbConn.close();
		}
		return;
	}

	protected void unsubscribeInternal(String host,int port ,String tableName) throws IOException {
		unsubscribeInternal(host, port, tableName, DEFAULT_ACTION_NAME);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy