All Downloads are FREE. Search and download functionalities are using the official Maven repository.
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.jukusoft.vertx.connection.clientserver.TCPClient Maven / Gradle / Ivy
package com.jukusoft.vertx.connection.clientserver;
import com.carrotsearch.hppc.ObjectObjectHashMap;
import com.carrotsearch.hppc.ObjectObjectMap;
import com.jukusoft.vertx.connection.exception.NoHandlerException;
import com.jukusoft.vertx.serializer.SerializableObject;
import com.jukusoft.vertx.serializer.Serializer;
import com.jukusoft.vertx.serializer.exceptions.NetworkException;
import com.jukusoft.vertx.connection.stream.BufferStream;
import com.jukusoft.vertx.connection.utils.SocketUtils;
import io.vertx.core.*;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetClientOptions;
import io.vertx.core.net.NetSocket;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
public class TCPClient implements Client {
//vert.x variables
protected VertxOptions vertxOptions = new VertxOptions();
protected Vertx vertx = null;
protected NetClientOptions options = new NetClientOptions();
protected NetClient client = null;
//options
protected int sendDelay = 0;
protected int receiveDelay = 0;
protected int connectTimeout = 500;
protected int reconnectAttempts = 3;
protected int reconnectInterval = 500;
protected boolean logsEnabled = true;
//message handler lookup manager
protected HandlerManager handlerManager = new HandlerManagerImpl<>();
//buffer stream is responsible for reconstructing fragmented tcp messages to original sized packages
protected BufferStream bufferStream = null;
protected AtomicBoolean initialized = new AtomicBoolean(false);
protected int eventThreads = 1;
protected int workerThreads = 1;
protected RemoteConnection conn = null;
protected NetSocket socket = null;
//channel attributes, like login state and so on
protected ObjectObjectMap attributes = new ObjectObjectHashMap<>();
protected Runnable onConnClosedHandler = null;
//handler to override message handler functionality
protected MessageHandler customMessageHandler = null;
@Override
public void init() {
//set thread count
vertxOptions.setEventLoopPoolSize(eventThreads);
vertxOptions.setWorkerPoolSize(workerThreads);
//set thread pool timeouts
vertxOptions.setMaxEventLoopExecuteTime(5000);
vertxOptions.setMaxWorkerExecuteTime(5000);
//create new NetClient
this.vertx = Vertx.vertx(vertxOptions);
this.init(this.vertx);
}
@Override
public void init (Vertx vertx) {
//set timeouts
options.setConnectTimeout(this.connectTimeout);
//set reconnect options
options.setReconnectAttempts(this.reconnectAttempts);
options.setReconnectInterval(this.reconnectInterval);
//set TCP_NODELAY
options.setTcpNoDelay(true);
//set logging options
options.setLogActivity(this.logsEnabled);
this.client = vertx.createNetClient(options);
this.initialized.set(true);
this.vertx = vertx;
}
@Override
public void connect(final ServerData server, final Handler> handler) {
if (!this.initialized.get()) {
throw new IllegalStateException("Before connecting, initialization is required. Call TCPClient.init() first!");
}
Objects.requireNonNull(server);
Objects.requireNonNull(handler);
//check, if server is available
if (!SocketUtils.checkRemoteTCPPort(server.ip, server.port, this.connectTimeout)) {
//server isn't available
throw new NetworkException("Server is currently not available! Maybe server is down?");
}
//try to connect to server
this.client.connect(server.port, server.ip, res -> this.connectHandler(server, res, handler));
}
protected void connectHandler (final ServerData server, final AsyncResult res, final Handler> handler) {
if (res.succeeded()) {
//connection established
//get socket
this.socket = res.result();
this.bufferStream = new BufferStream(socket, socket);
//pause reading data
bufferStream.pause();
//initialize socket
this.initSocket(bufferStream);
//resume reading data
bufferStream.resume();
System.out.println("Connected to server " + server.ip + ":" + server.port + " (own port: " + socket.localAddress().port() + ").");
this.createRemoteConnection();
Objects.requireNonNull(handler);
Objects.requireNonNull(this.conn);
//call handler, so UI can be updated
handler.handle(Future.succeededFuture(this.conn));
} else {
//connection failed
handler.handle(Future.failedFuture("connection failed!"));
}
}
protected void createRemoteConnection () {
this.conn = new RemoteConnection() {
@Override
public void send(SerializableObject msg) {
TCPClient.this.send(msg);
}
@Override
public void sendRaw(Buffer content) {
TCPClient.this.sendRaw(content);
}
@Override
public ObjectObjectMap attributes() {
return TCPClient.this.attributes();
}
@Override
public V getAttribute(String key, Class cls) {
return TCPClient.this.getAttribute(key, cls);
}
@Override
public void putAttribute(String key, Object obj) {
TCPClient.this.putAttribute(key, obj);
}
@Override
public String remoteHost() {
return TCPClient.this.socket.remoteAddress().host();
}
@Override
public int remotePort() {
return TCPClient.this.socket.remoteAddress().port();
}
@Override
public void disconnect() {
TCPClient.this.disconnect();
}
@Override
public void setRawHandler(MessageHandler rawHandler) {
throw new UnsupportedOperationException("setRawHandler() isnt supported for client, use TCPClient class directly!");
}
@Override
public void setCloseHandler(Handler closeHandler) {
throw new UnsupportedOperationException("setCloseHandler() isnt supported for client, use TCPClient class directly!");
}
@Override
public void setMessageHandler(MessageHandler handler) {
throw new UnsupportedOperationException("setMessageHandler() isnt supported for client, use TCPClient class directly!");
}
};
}
protected void initSocket (BufferStream bufferStream) {
//set handler
bufferStream.handler(this::handleMessageWithDelay);
//bufferStream.endHandler(this::onConnectionClosed);
this.socket.closeHandler(this::onConnectionClosed);
}
protected void handleMessageWithDelay (Buffer content) {
//https://github.com/vert-x3/vertx-examples/blob/master/core-examples/src/main/java/io/vertx/example/core/net/stream/BatchStream.java
if (this.receiveDelay > 0) {
//delay message and handle them
vertx.setTimer(this.receiveDelay, timerID -> handleMessage(content));
} else {
//handle message without delay
handleMessage(content);
}
}
protected void handleMessage (Buffer buf) {
try {
if (this.customMessageHandler != null) {
// use custom message handler instead of serializer
this.customMessageHandler.handle(buf, this.conn);
return;
}
//first, unserialize object
SerializableObject msg = Serializer.unserialize(buf);
//get handler
MessageHandler handler = this.handlers().findHandler(msg.getClass());
if (handler == null) {
throw new NoHandlerException("No handler registered for message class '" + msg.getClass().getCanonicalName() + "'!");
}
handler.handle(msg, this.conn);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void connect(List serverList, Handler> handler) {
if (!initialized.get()) {
throw new IllegalStateException("TCPClient wasn't initialized before, call TCPClient.init() first!");
}
//first, shuffle list
//Collections.shuffle(serverList);
if (serverList.isEmpty()) {
throw new IllegalArgumentException("server list is empty or all servers are down!");
}
//get first entry
ServerData server = serverList.get(0);
//remove server from list, so if server isn't available, client doesn't connects to this server twice
serverList.remove(server);
//check, if server is available
if (!SocketUtils.checkRemoteTCPPort(server.ip, server.port, this.connectTimeout)) {
//server isn't available
if (!serverList.isEmpty()) {
//try another server
this.connect(serverList, handler);
return;
}
throw new NetworkException("All servers in list are currently down!");
}
//connect to one of these servers
this.connect(server, handler);
}
@Override
public void disconnect() {
if (this.socket != null) {
this.socket.close();
} else {
throw new IllegalStateException("Cannot call disconnect() if socket wasn't initialized.");
}
}
@Override
public void setDelay(int sendDelay, int receiveDelay) {
this.sendDelay = sendDelay;
this.receiveDelay = receiveDelay;
}
@Override
public HandlerManager handlers() {
return this.handlerManager;
}
@Override
public void send(SerializableObject msg) {
//serialize message object
Buffer content = Serializer.serialize(msg);
this.sendRaw(content);
}
@Override
public void sendRaw(Buffer content) {
if (this.bufferStream == null) {
throw new IllegalStateException("no connection is established.");
}
//if configuration has send delay enable, delay sending message to simulate external server
if (this.sendDelay > 0) {
TCPClient.this.vertx.setTimer(this.sendDelay, timerID -> this.bufferStream.write(content));
} else {
this.bufferStream.write(content);
}
}
@Override
public ObjectObjectMap attributes() {
return this.attributes;
}
@Override
public V getAttribute(String key, Class cls) {
Object obj = this.attributes.get(key);
if (obj == null) {
//attribute key doesn't exists
return null;
}
return cls.cast(obj);
}
@Override
public void putAttribute(String key, Object obj) {
this.attributes.put(key, obj);
}
@Override
public void setThreadPoolSize(int eventThreads, int workerThreads) {
if (this.initialized.get()) {
throw new IllegalStateException("You have to call this method before TCPClient was initialized with init() call!");
}
this.eventThreads = eventThreads;
this.workerThreads = workerThreads;
}
@Override
public void setOnConnectionClosedHandler(Runnable runnable) {
this.onConnClosedHandler = runnable;
}
@Override
public void setCustomMessageHandler(MessageHandler handler) {
this.customMessageHandler = handler;
}
@Override
public long setTimer(long delay, Handler handler) {
if (!this.initialized.get() || this.vertx == null) {
throw new IllegalStateException("vertx isn't initialized yet.");
}
Objects.requireNonNull(handler);
return this.vertx.setTimer(delay, handler);
}
@Override
public long setPeriodic(long delay, Handler handler) {
return this.vertx.setPeriodic(delay, handler);
}
@Override
public void shutdown() {
if (!this.initialized.get() || this.vertx == null) {
return;
}
this.client.close();
this.vertx.close();
}
protected void onConnectionClosed(Void v) {
//TODO: call handlers
if (this.onConnClosedHandler != null) {
this.onConnClosedHandler.run();
}
}
public NetClient getVertxClient () {
return this.client;
}
}