package art.servers.controller;
import art.library.interop.InteropParameter;
import art.library.interop.InteropParameters;
import art.library.interop.InteropResponse;
import art.library.interop.serialization.Serialization;
import art.library.interop.serialization.SerializationException;
import art.library.utils.licence.Licence;
import art.servers.ServerException;
import art.servers.Shared;
import art.servers.configuration.ConfigurationListenerHttp;
import art.servers.types.HttpAuthentication;
import com.sun.net.httpserver.BasicAuthenticator;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Executors;
public class ControllerListenerHttp extends Controller
{
protected String name = null;
protected HttpServer server = null;
protected ConfigurationListenerHttp configuration = null;
protected ListenerImplementation implementation = null;
public ControllerListenerHttp(ConfigurationListenerHttp configuration)
{
this.name = Shared.getMessage("Listener http");
this.setName(this.getClass().getName() + " : " + name);
this.configuration = configuration;
start();
}
public ListenerImplementation getListenerImplementation()
{
if (implementation != null) return implementation;
return Shared.controllerListener.getListenerImplementation();
}
public void setListenerImplementation(ListenerImplementation implementation)
{
this.implementation = implementation;
}
public void run()
{
Shared.traceInformation(name, "Starting");
while ((isInterrupted() == false) && (exit == false))
{
try
{
if (server == null)
{
connect();
}
sleep(1000);
}
catch (Exception e)
{
}
}
Shared.traceInformation(name, "Finishing");
}
protected void connect()
{
try
{
server = HttpServer.create(new InetSocketAddress(configuration.port), 0);
contexts();
server.setExecutor(Executors.newCachedThreadPool());
server.start();
Shared.traceInformation(name, "Disconnecting", Shared.getMessage("Port") + " = " + configuration.port);
return;
}
catch (Exception exception)
{
Shared.traceError(name, "Disconnecting", Shared.getMessage("Port") + " = " + configuration.port, exception);
}
}
protected void contexts()
{
HttpContext context1 = server.createContext("/login", new login());
HttpContext context2 = server.createContext("/art", new artic());
HttpContext context3 = server.createContext("/get", new get());
HttpContext context4 = server.createContext("/set", new set());
HttpContext context5 = server.createContext("/session", new session());
HttpContext context6 = server.createContext("/gis", new gis());
HttpContext context7 = server.createContext("/saml", new saml());
HttpContext context8 = server.createContext("/logout", new logout());
if (configuration.readUser != null)
{
context3.setAuthenticator(new BasicAuthenticator(configuration.readUser)
{
public boolean checkCredentials(String user, String pwd)
{
return user.equals(configuration.readUser) && pwd.equals(configuration.readPassword);
}
});
}
if (configuration.writeUser != null)
{
context4.setAuthenticator(new BasicAuthenticator(configuration.writeUser)
{
public boolean checkCredentials(String user, String pwd)
{
return user.equals(configuration.writeUser) && pwd.equals(configuration.writePassword);
}
});
}
}
protected class login implements HttpHandler
{
public void handle(HttpExchange httpExchange) throws IOException
{
String language = null;
try
{
InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
String type = (parameters.hasParameter("type") == true) ? (String)parameters.getParameterValue("type") : "text";
parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
InteropResponse response = getListenerImplementation().login(parameters, type, httpExchange.getRemoteAddress().getHostName());
result(httpExchange, response);
}
catch (Exception e)
{
result(httpExchange, 400, language, e);
}
}
}
protected class logout implements HttpHandler
{
public void handle(HttpExchange httpExchange) throws IOException
{
String language = null;
try
{
InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
InteropResponse response = getListenerImplementation().logout(parameters, httpExchange.getRemoteAddress().getHostName());
result(httpExchange, response);
}
catch (Exception e)
{
result(httpExchange, 400, language, e);
}
}
}
protected class artic implements HttpHandler
{
String language = null;
public void handle(HttpExchange httpExchange) throws IOException
{
try
{
InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
int tokenStatus = checkToken(parameters, httpExchange.getRemoteAddress().getHostName());
if (tokenStatus != 200)
{
result(httpExchange, tokenStatus, "Invalid authentication or invalid token");
}
InteropResponse response = getListenerImplementation().artic(parameters);
result(httpExchange, response);
}
catch (Exception exception)
{
Shared.println(Shared.getMessage("Model"), exception);
result(httpExchange, 400, language, exception);
}
}
}
protected class gis implements HttpHandler
{
public void handle(HttpExchange httpExchange) throws IOException
{
try
{
String uri = httpExchange.getRequestURI().getRawQuery();
InteropResponse response = getListenerImplementation().gis(uri);
result(httpExchange, response);
}
catch (Exception exception)
{
result(httpExchange, 400, "", exception);
}
}
}
protected class saml implements HttpHandler
{
public void handle(HttpExchange httpExchange) throws IOException
{
try
{
InteropParameters parameters = new InteropParameters();
parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
InteropResponse response = getListenerImplementation().saml(parameters);
result(httpExchange, response);
}
catch (Exception exception)
{
result(httpExchange, 400, "", exception);
}
}
}
private int checkToken(InteropParameters parameters, String remoteAddress)
{
try
{
HttpAuthentication authentication = Serialization.deserialize(HttpAuthentication.class, Licence.decrypt((String)parameters.getParameterValue("token")));
if (authentication.isTokenValid(remoteAddress) == false)
{
return 401; // Page expired
}
parameters.addParameter("username", authentication.username);
parameters.addParameter("computer", authentication.address);
authentication.lastRequestTimestamp = System.currentTimeMillis();
return 200;
}
catch (Exception e)
{
}
try
{
String[] login = ((String)parameters.getParameterValue("token")).split(",");
String username = login[0];
String password = login[1];
HttpAuthentication authentication = getListenerImplementation().login(username, password, remoteAddress);
String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
parameters.setParameter("token", token);
authentication.lastRequestTimestamp = System.currentTimeMillis();
parameters.addParameter("username", authentication.username);
parameters.addParameter("computer", authentication.address);
return 200;
}
catch (Exception exception)
{
Shared.println(Shared.getMessage("Model"), exception);
}
return 401; // Invalid token, unauthorized
}
protected class get implements HttpHandler
{
String language = null;
public void handle(HttpExchange httpExchange) throws IOException
{
try
{
InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
InteropResponse response = getListenerImplementation().get(parameters);
result(httpExchange, response);
}
catch (Exception exception)
{
result(httpExchange, 400, language, exception);
}
}
}
protected class set implements HttpHandler
{
public void handle(HttpExchange httpExchange) throws IOException
{
String language = null;
try
{
InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
InteropResponse response = getListenerImplementation().set(parameters);
result(httpExchange, response);
}
catch (Exception exception)
{
result(httpExchange, 400, language, exception);
}
}
}
protected class session implements HttpHandler
{
public void handle(HttpExchange httpExchange) throws IOException
{
String language = null;
try
{
InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
String token = (parameters.hasParameter("token") == true) ? (String)parameters.getParameterValue("token") : "";
if (checkToken(language, token) == false)
{
throw new SerializationException(Shared.getMessage(language, "Invalid session"));
}
parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
InteropResponse response = getListenerImplementation().session(parameters);
result(httpExchange, response);
}
catch (Exception exception)
{
result(httpExchange, 400, language, exception);
}
}
}
private boolean checkToken(String language, String token)
{
try
{
InteropParameters parameters = new InteropParameters();
parameters.addParameter(new InteropParameter("service", "transactions"));
parameters.addParameter(new InteropParameter("operation", "checkToken"));
parameters.addParameter(new InteropParameter("language", language));
parameters.addParameter(new InteropParameter("token", token));
InteropResponse response = Shared.controllerTransactions.set(parameters);
boolean result = (Boolean)response.getValue()[0];
if (result == true) return true;
}
catch (Exception e)
{
}
return false;
}
//
private byte[] getRequestBody(HttpExchange httpExchange) throws Exception
{
ByteArrayOutputStream bos = null;
try
{
InputStream input = httpExchange.getRequestBody();
bos = new ByteArrayOutputStream();
byte[] buffer = new byte[8196];
int length;
while ((length = input.read(buffer)) != -1)
{
bos.write(buffer, 0, length);
}
return bos.toByteArray();
}
catch (Exception exception)
{
Shared.println(Shared.getMessage("Model"), exception);
throw exception;
}
finally
{
try { bos.close(); } catch (Exception ex) {};
httpExchange.getRequestBody().close();
}
}
//
//
protected void result(HttpExchange httpExchange, int httpErrorCode, byte[] data) throws Exception
{
try
{
httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
httpExchange.sendResponseHeaders(httpErrorCode, data.length);
httpExchange.getResponseBody().write(data);
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
httpExchange.getResponseBody().close();
}
}
protected void result(HttpExchange httpExchange, InteropResponse response)
{
// https://www.sitepoint.com/mime-types-complete-list/
// httpExchange.getResponseHeaders().set("Content-Type", "text/html; charset=" + StandardCharsets.UTF_8);
// httpExchange.getResponseHeaders().set("Content-Type", "application/pdf"; charset=" + StandardCharsets.UTF_8);
// httpExchange.getResponseHeaders().set("Content-Type", "application/vnd.ms-excel"; charset=" + StandardCharsets.UTF_8);
httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
if (httpExchange.getRequestMethod().equalsIgnoreCase("OPTIONS"))
{
httpExchange.getResponseHeaders().add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
httpExchange.getResponseHeaders().add("Access-Control-Allow-Headers", "Content-Type,Authorization");
try
{
httpExchange.sendResponseHeaders(204, -1);
}
catch (Exception e)
{
}
httpExchange.close();
return;
}
if (response.mime == null)
{
httpExchange.getResponseHeaders().set("Content-Type", "application/json; charset=" + StandardCharsets.UTF_8);
}
else
{
httpExchange.getResponseHeaders().set("Content-Type", response.mime + "; charset=" + StandardCharsets.UTF_8);
}
// Check if response is a file
if (response.name != null)
{
try
{
// For filenames with polish characters
byte[] filenameBytes = response.name.getBytes("UTF-8");
String filename = "";
for (byte character : filenameBytes) filename += (char)(character & 0xFF);
httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + filename + "\"");
}
catch (Exception e)
{
httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + response.name + "\"");
}
}
// Check mime text/plain
if (response.mime != null)
{
if (response.mime.equalsIgnoreCase("text/plain"))
{
try
{
byte[] data = ((String)response.getValue()[0]).getBytes();
result(httpExchange, 200, data);
httpExchange.close();
return;
}
catch (Exception exception)
{
manageException(httpExchange, exception);
}
return;
}
else if (response.mime.equalsIgnoreCase("application/json"))
{
try
{
if (response.array == true)
{
String message = Serialization.toString(response.getValue());
result(httpExchange, 200, message.getBytes());
}
else
{
String message = Serialization.toString(response.getValue()[0]);
result(httpExchange, 200, message.getBytes());
}
}
catch (Exception e)
{
manageException(httpExchange, e);
}
return;
}
}
// Try send raw bytes
try
{
if (response.getValue().length == 0)
{
String message = Serialization.toString(response.getValue());
result(httpExchange, 200, message.getBytes());
httpExchange.close();
return;
}
byte[] data = (byte[])response.getValue()[0];
result(httpExchange, 200, data);
httpExchange.close();
return;
}
catch (ClassCastException exception)
{
}
catch (Exception exception)
{
manageException(httpExchange, exception);
}
// Default JSON
try
{
if (response.array == false)
{
String message = Serialization.toString(response.getValue()[0]);
result(httpExchange, 200, message.getBytes());
httpExchange.close();
return;
}
else
{
if (response.getValue().length == 0)
{
String message = Serialization.toString(response.getValue());
result(httpExchange, 200, message.getBytes());
httpExchange.close();
return;
}
else
{
String message = Serialization.toString(response.getValue());
result(httpExchange, 200, message.getBytes());
httpExchange.close();
return;
}
}
}
catch (Exception exception)
{
manageException(httpExchange, exception);
}
}
protected void result (HttpExchange httpExchange, int httpErrorCode, String language, Exception exception)
{
if (((exception instanceof SerializationException) || (exception instanceof ServerException)) && (exception.getMessage() != null))
{
result(httpExchange, httpErrorCode, Shared.getMessage(language, exception.getMessage()));
}
else if ((exception instanceof SerializationException) && (((SerializationException)exception).getStackMessage() != null))
{
result(httpExchange, httpErrorCode, ((SerializationException)exception).getStackMessage());
}
else if ((exception instanceof ServerException) && (((ServerException)exception).getStackMessage() != null))
{
result(httpExchange, httpErrorCode, ((ServerException)exception).getStackMessage());
}
else
{
StringWriter sw = new StringWriter();
exception.printStackTrace(new PrintWriter(sw));
String message = sw.toString();
result(httpExchange, httpErrorCode, message);
}
}
protected void result (HttpExchange httpExchange, int httpErrorCode, String message)
{
try
{
if (message != null)
{
result(httpExchange, httpErrorCode, message.getBytes());
}
else
{
result(httpExchange, httpErrorCode, new String().getBytes());
}
}
catch (Exception e)
{
manageException(httpExchange, e);
}
}
//
//
private void manageException (HttpExchange httpExchange, Exception exception)
{
try
{
httpExchange.close();
}
catch (Exception e)
{
}
if (exception instanceof IOException)
{
String message = exception.toString().toLowerCase();
if (message.contains("an established connection was aborted by the software in your host machine") == true)
{
if (server != null)
{
Shared.traceError(name, "Disconnecting", exception);
try{server.stop(10);} catch (Exception ex){};
server = null;
connect();
}
}
}
}
//
}