
prerna.tcp.client.SocketClient Maven / Gradle / Ivy
The newest version!
package prerna.tcp.client;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import prerna.auth.User;
import prerna.sablecc2.om.execptions.SemossPixelException;
import prerna.tcp.PayloadStruct;
import prerna.util.Constants;
import prerna.util.FstUtil;
import prerna.util.Settings;
import prerna.util.Utility;
public class SocketClient implements Runnable, Closeable {
private static final Logger classLogger = LogManager.getLogger(SocketClient.class);
private String HOST = null;
private int PORT = -1;
private boolean SSL = false;
Map requestMap = new HashMap<>();
Map responseMap = new HashMap<>();
private boolean ready = false;
private boolean connected = false;
private AtomicInteger count = new AtomicInteger(0);
private long averageMillis = 200;
private boolean killAll = false; // use this if the server is dead or it has crashed
private User user;
private Socket clientSocket = null;
InputStream is = null;
OutputStream os = null;
SocketClientHandler sch = new SocketClientHandler();
/**
*
* @param HOST
* @param PORT
* @param SSL
*/
public void connect(final String HOST, final int PORT, final boolean SSL) {
this.HOST = HOST;
this.PORT = PORT;
this.SSL = SSL;
}
@Override
public void close() {
if(this.requestMap != null) {
this.requestMap.clear();
}
closeStream(this.os);
closeStream(this.is);
closeStream(this.clientSocket);
this.connected = false;
this.killAll = true;
}
@Override
public void run()
{
// Configure SSL.git
int attempt = 1;
int SLEEP_TIME = 800;
if(Utility.getDIHelperProperty("SLEEP_TIME") != null) {
SLEEP_TIME = Integer.parseInt(Utility.getDIHelperProperty("SLEEP_TIME"));
}
classLogger.info("Trying with the sleep time of " + SLEEP_TIME);
while(!connected && attempt < 6) // I do an attempt here too hmm..
{
try
{
final SslContext sslCtx;
if (SSL) {
sslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
} else {
sslCtx = null;
}
// Configure the client.
boolean blocking = Utility.getDIHelperProperty(Settings.BLOCKING) != null && Utility.getDIHelperProperty(Settings.BLOCKING).equalsIgnoreCase("true");
clientSocket = new Socket(this.HOST, this.PORT);
// pick input and output stream and start the threads
this.is = clientSocket.getInputStream();
this.os = clientSocket.getOutputStream();
sch.setClient(this);
sch.setInputStream(this.is);
// start this thread
Thread readerThread = new Thread(sch);
readerThread.start();
classLogger.info("CLIENT Connection complete !!!!!!!");
Thread.sleep(100); // sleep some before executing command
// prime it
//logger.info("First command.. Prime" + executeCommand("2+2"));
connected = true;
ready = true;
killAll = false;
synchronized(this)
{
this.notifyAll();
}
} catch(Exception ex) {
attempt++;
classLogger.info("Attempting Number " + attempt);
// see if sleeping helps ?
try {
// sleeping only for 1 second here
// but the py executor sleeps in 2 second increments
Thread.sleep(attempt*SLEEP_TIME);
} catch(Exception ex2) {
// ignored
}
}
}
if(attempt >= 6) {
classLogger.info("CLIENT Connection Failed !!!!!!!");
killAll = true;
connected = false;
ready = false;
synchronized(this) {
this.notifyAll();
}
throw new IllegalArgumentException("Failed to connect to your isolated analytics engine");
}
}
public Object executeCommand(PayloadStruct ps)
{
if(killAll) {
throw new SemossPixelException("Analytic engine is no longer available. This happened because you exceeded the memory limits provided or performed an illegal operation. Please relook at your recipe");
}
if(!connected) {
throw new SemossPixelException("Your micro-process is not available. Please logout and try again. !");
}
String id = ps.epoc;
if(!ps.response || id == null)
{
id = "ps"+ count.getAndIncrement();
ps.epoc = id;
}
ps.longRunning = true;
synchronized(ps) // going back to single threaded .. earlier it was ps
{
//if(ps.hasReturn)
// put it into request map
if(!ps.response) {
requestMap.put(id, ps);
}
classLogger.info("Outgoing epoc " + ps.epoc);
writePayload(ps);
// send the message
// time to wait = average time * 10
// if this is a request wait for it
if(!ps.response) // this is a response to something the socket has asked
{
int pollNum = 1; // 1 second
while(!responseMap.containsKey(ps.epoc) && (pollNum < 10 || ps.longRunning) && !killAll)
{
//logger.info("Checking to see if there was a response");
try
{
if(pollNum < 10) {
ps.wait(averageMillis);
} else { //if(ps.longRunning) // this is to make sure the kill all is being checked
ps.wait(); // wait eternally - we dont know how long some of the load operations would take besides, I am not sure if the null gets us anything
}
pollNum++;
}catch (InterruptedException e)
{
// TODO Auto-generated catch block
classLogger.error(Constants.STACKTRACE, e);
}
/*
// trigger after 400 milliseconds
if(pollNum == 2 && !ps.longRunning)
{
logger.info("Writing empty message " + ps.epoc);
writeEmptyPayload();
}
*/
}
if(!responseMap.containsKey(ps.epoc) && ps.hasReturn)
{
classLogger.info("Timed out for epoc " + ps.epoc + " " + ps.methodName);
}
}
// after 10 seconds give up
//printUnprocessed();
return responseMap.remove(ps.epoc);
}
}
private void writePayload(PayloadStruct ps)
{
byte [] psBytes = FstUtil.packBytes(ps);
try {
os.write(psBytes);
} catch(IOException ex) {
classLogger.error(Constants.STACKTRACE, ex);
crash();
}
}
private void writeEmptyPayload()
{
PayloadStruct ps = new PayloadStruct();
ps.epoc=Utility.getRandomString(8);
ps.methodName = "EMPTYEMPTYEMPTY";
writePayload(ps);
}
public void writeReleaseAllPayload()
{
PayloadStruct ps = new PayloadStruct();
ps.epoc=Utility.getRandomString(8);
ps.methodName = "RELEASE_ALL";
writePayload(ps);
}
/**
*
* @return
*/
public boolean stopServer() {
try {
if(isConnected()) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable callableTask = () -> {
PayloadStruct ps = new PayloadStruct();
ps.methodName = "CLOSE_ALL_LOGOUT";
ps.payload = new String[] { "CLOSE_ALL_LOGOUT"};
writePayload(ps);
return true;
};
Future future = executor.submit(callableTask);
try {
// wait 1 minute at most
boolean result = future.get(60, TimeUnit.SECONDS);
classLogger.info("Stop PyServe result = " + result);
return result;
} catch (TimeoutException e) {
classLogger.warn("Not able to release the payload structs within a timely fashion");
future.cancel(true);
return false;
} catch (InterruptedException | ExecutionException e) {
classLogger.error(Constants.STACKTRACE, e);
return false;
} finally {
executor.shutdown();
}
} else {
return true;
}
} finally {
// always call close on the IO
close();
}
}
/**
*
*/
public void crash() {
// this happens when the client has completely crashed
// make the connected to be false
// take everything that is waiting on it
// go through request map and start pushing
// run as executor since it is synchronized
// and dont want to get stuck if an issue occurs and the notify never happens
// we will close and kill process anyway
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable callableTask = () -> {
try {
for(Object k : this.requestMap.keySet()) {
PayloadStruct ps = (PayloadStruct) this.requestMap.get(k);
classLogger.debug("Releasing <" + k + "> <" + ps.methodName + ">");
ps.ex = "Server has crashed. This happened because you exceeded the memory limits provided or performed an illegal operation. Please relook at your recipe";
synchronized(ps) {
ps.notifyAll();
}
}
} catch(Exception e) {
classLogger.error(Constants.STACKTRACE, e);
}
return "Successfully released the payload structs";
};
Future future = executor.submit(callableTask);
try {
// wait 1 minute at most
String result = future.get(60, TimeUnit.SECONDS);
classLogger.info(result);
} catch (TimeoutException e) {
classLogger.warn("Not able to release the payload structs within a timely fashion");
future.cancel(true);
} catch (InterruptedException | ExecutionException e) {
classLogger.error(Constants.STACKTRACE, e);
} finally {
executor.shutdown();
}
this.close();
throw new SemossPixelException("Analytic engine is no longer available. This happened because you exceeded the memory limits provided or performed an illegal operation. Please relook at your recipe");
}
/**
*
* @param closeThis
*/
private void closeStream(Closeable closeThis) {
if(closeThis != null) {
try {
closeThis.close();
} catch (IOException e) {
classLogger.error(Constants.STACKTRACE, e);
}
}
}
/**
*
* @param user
*/
public void setUser(User user) {
this.user = user;
}
/**
*
* @return
*/
public User getUser() {
return this.user;
}
/**
*
* @return
*/
public boolean isConnected() {
return this.connected;
}
/**
*
* @return
*/
public boolean isKillAll() {
return killAll;
}
/**
*
* @return
*/
public boolean isReady() {
return this.ready;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy