From 79ce1a4973eba079ba819ba841d906de42f38e40 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Tue, 28 Nov 2017 09:35:32 +0100 Subject: [PATCH] Update Server, breaks API + remove deprecated --- changelog.md | 5 +- src/be/nikiroo/utils/TraceHandler.java | 24 -- .../serial/{ => server}/ConnectAction.java | 14 +- .../{ => server}/ConnectActionClient.java | 56 +--- .../server/ConnectActionClientObject.java | 105 ++++++++ .../server/ConnectActionClientString.java | 95 +++++++ .../{ => server}/ConnectActionServer.java | 78 +----- .../server/ConnectActionServerObject.java | 85 ++++++ .../server/ConnectActionServerString.java | 65 +++++ .../utils/serial/{ => server}/Server.java | 84 ++---- .../utils/serial/server/ServerObject.java | 107 ++++++++ .../utils/serial/server/ServerString.java | 113 ++++++++ src/be/nikiroo/utils/test/SerialTest.java | 248 ++++++++++++++++-- src/be/nikiroo/utils/test/TestCase.java | 2 + src/be/nikiroo/utils/test/TestLauncher.java | 2 + 15 files changed, 852 insertions(+), 231 deletions(-) rename src/be/nikiroo/utils/serial/{ => server}/ConnectAction.java (95%) rename src/be/nikiroo/utils/serial/{ => server}/ConnectActionClient.java (69%) create mode 100644 src/be/nikiroo/utils/serial/server/ConnectActionClientObject.java create mode 100644 src/be/nikiroo/utils/serial/server/ConnectActionClientString.java rename src/be/nikiroo/utils/serial/{ => server}/ConnectActionServer.java (51%) create mode 100644 src/be/nikiroo/utils/serial/server/ConnectActionServerObject.java create mode 100644 src/be/nikiroo/utils/serial/server/ConnectActionServerString.java rename src/be/nikiroo/utils/serial/{ => server}/Server.java (82%) create mode 100644 src/be/nikiroo/utils/serial/server/ServerObject.java create mode 100644 src/be/nikiroo/utils/serial/server/ServerString.java diff --git a/changelog.md b/changelog.md index 34046e8..1df57c7 100644 --- a/changelog.md +++ b/changelog.md @@ -1,10 +1,11 @@ # nikiroo-utils -## Version WIP +## Version 3.0.0 - jDoc - Fix bugs in Server (it was not possible to send objects back to client) -- Improve code in Server (including tests) +- Improve code in Server (including tests), breaks API +- Remove some deprecated things ## Version 2.2.3 diff --git a/src/be/nikiroo/utils/TraceHandler.java b/src/be/nikiroo/utils/TraceHandler.java index 309e8af..6541a8b 100644 --- a/src/be/nikiroo/utils/TraceHandler.java +++ b/src/be/nikiroo/utils/TraceHandler.java @@ -77,28 +77,4 @@ public class TraceHandler { System.out.println(message); } } - - // old stuff: - - /** - * Use the parameters in the constructor instead. - * - * @param showTraces - * show the traces - */ - @Deprecated - public void setShowTraces(boolean showTraces) { - this.showTraces = showTraces; - } - - /** - * Use the parameters in the constructor instead. - * - * @param showErrorDetails - * show the details on errors - */ - @Deprecated - public void setShowErrorDetails(boolean showErrorDetails) { - this.showErrorDetails = showErrorDetails; - } } diff --git a/src/be/nikiroo/utils/serial/ConnectAction.java b/src/be/nikiroo/utils/serial/server/ConnectAction.java similarity index 95% rename from src/be/nikiroo/utils/serial/ConnectAction.java rename to src/be/nikiroo/utils/serial/server/ConnectAction.java index dfc1a2b..8f57c62 100644 --- a/src/be/nikiroo/utils/serial/ConnectAction.java +++ b/src/be/nikiroo/utils/serial/server/ConnectAction.java @@ -1,4 +1,4 @@ -package be.nikiroo.utils.serial; +package be.nikiroo.utils.serial.server; import java.io.BufferedReader; import java.io.IOException; @@ -7,6 +7,8 @@ import java.io.OutputStreamWriter; import java.net.Socket; import be.nikiroo.utils.Version; +import be.nikiroo.utils.serial.Exporter; +import be.nikiroo.utils.serial.Importer; /** * Base class used for the client/server basic handling. @@ -154,7 +156,7 @@ abstract class ConnectAction { * @throws ClassNotFoundException * if a class described in the serialised data cannot be found */ - protected Object send(Object data) throws IOException, + protected Object sendObject(Object data) throws IOException, NoSuchFieldException, NoSuchMethodException, ClassNotFoundException { synchronized (lock) { String rep = sendString(new Exporter().append(data).toString(true)); @@ -190,10 +192,10 @@ abstract class ConnectAction { * @throws java.lang.NullPointerException * if the counter part has no data to send */ - protected Object rec() throws IOException, NoSuchFieldException, + protected Object recObject() throws IOException, NoSuchFieldException, NoSuchMethodException, ClassNotFoundException, java.lang.NullPointerException { - String str = flushString(); + String str = recString(); if (str == null) { throw new NullPointerException("No more data available"); } @@ -225,7 +227,7 @@ abstract class ConnectAction { } contentToSend = true; - return flushString(); + return recString(); } } @@ -243,7 +245,7 @@ abstract class ConnectAction { * @throws IOException * in case of I/O error */ - protected String flushString() throws IOException { + protected String recString() throws IOException { synchronized (lock) { if (server || contentToSend) { if (contentToSend) { diff --git a/src/be/nikiroo/utils/serial/ConnectActionClient.java b/src/be/nikiroo/utils/serial/server/ConnectActionClient.java similarity index 69% rename from src/be/nikiroo/utils/serial/ConnectActionClient.java rename to src/be/nikiroo/utils/serial/server/ConnectActionClient.java index 8353702..626b62f 100644 --- a/src/be/nikiroo/utils/serial/ConnectActionClient.java +++ b/src/be/nikiroo/utils/serial/server/ConnectActionClient.java @@ -1,4 +1,4 @@ -package be.nikiroo.utils.serial; +package be.nikiroo.utils.serial.server; import java.io.IOException; import java.net.Socket; @@ -13,8 +13,13 @@ import be.nikiroo.utils.Version; * * @author niki */ -public class ConnectActionClient { - private ConnectAction action; +abstract class ConnectActionClient { + /** + * The underlying {@link ConnectAction}. + *

+ * Cannot be NULL. + */ + protected ConnectAction action; /** * Create a new {@link ConnectActionClient} with the current application @@ -127,31 +132,6 @@ public class ConnectActionClient { public void action(Version serverVersion) throws Exception { } - /** - * Serialise and send the given object to the server (and return the - * deserialised answer). - * - * @param data - * the data to send - * - * @return the answer, which can be NULL - * - * @throws IOException - * in case of I/O error - * @throws NoSuchFieldException - * if the serialised data contains information about a field - * which does actually not exist in the class we know of - * @throws NoSuchMethodException - * if a class described in the serialised data cannot be created - * because it is not compatible with this code - * @throws ClassNotFoundException - * if a class described in the serialised data cannot be found - */ - public Object send(Object data) throws IOException, NoSuchFieldException, - NoSuchMethodException, ClassNotFoundException { - return action.send(data); - } - /** * Handler called when an unexpected error occurs in the code. *

@@ -162,24 +142,4 @@ public class ConnectActionClient { */ protected void onError(@SuppressWarnings("unused") Exception e) { } - - // old stuff: - - /** - * Do not use. Will never be called. - */ - @SuppressWarnings({ "unused", "javadoc" }) - @Deprecated - protected void onClientVersionReceived(Version clientVersion) { - } - - /** - * Do not use, it is not supposed to be called from the outside. - */ - @SuppressWarnings({ "unused", "javadoc" }) - @Deprecated - public Object flush() throws NoSuchFieldException, NoSuchMethodException, - ClassNotFoundException, IOException, java.lang.NullPointerException { - return null; - } } \ No newline at end of file diff --git a/src/be/nikiroo/utils/serial/server/ConnectActionClientObject.java b/src/be/nikiroo/utils/serial/server/ConnectActionClientObject.java new file mode 100644 index 0000000..e9673ac --- /dev/null +++ b/src/be/nikiroo/utils/serial/server/ConnectActionClientObject.java @@ -0,0 +1,105 @@ +package be.nikiroo.utils.serial.server; + +import java.io.IOException; +import java.net.Socket; + +import be.nikiroo.utils.Version; + +/** + * Class used for the client basic handling. + *

+ * It represents a single action: a client is expected to only execute one + * action. + * + * @author niki + */ +public class ConnectActionClientObject extends ConnectActionClient { + /** + * Create a new {@link ConnectActionClientObject} with the current + * application version (see {@link Version#getCurrentVersion()}) as the + * client version. + * + * @param s + * the socket to bind to + */ + public ConnectActionClientObject(Socket s) { + super(s); + } + + /** + * Create a new {@link ConnectActionClientObject} with the current + * application version (see {@link Version#getCurrentVersion()}) as the + * client version. + * + * @param host + * the host to bind to + * @param port + * the port to bind to + * @param ssl + * TRUE for an SSL connection, FALSE for plain text + * + * @throws IOException + * in case of I/O error when creating the socket + */ + public ConnectActionClientObject(String host, int port, boolean ssl) + throws IOException { + super(host, port, ssl); + } + + /** + * Create a new {@link ConnectActionClientObject}. + * + * @param host + * the host to bind to + * @param port + * the port to bind to + * @param ssl + * TRUE for an SSL connection, FALSE for plain text + * @param version + * the client version + * + * @throws IOException + * in case of I/O error when creating the socket + */ + public ConnectActionClientObject(String host, int port, boolean ssl, + Version version) throws IOException { + super(host, port, ssl, version); + } + + /** + * Create a new {@link ConnectActionClientObject}. + * + * @param s + * the socket to bind to + * @param version + * the client version + */ + public ConnectActionClientObject(Socket s, Version version) { + super(s, version); + } + + /** + * Serialise and send the given object to the server (and return the + * deserialised answer). + * + * @param data + * the data to send + * + * @return the answer, which can be NULL + * + * @throws IOException + * in case of I/O error + * @throws NoSuchFieldException + * if the serialised data contains information about a field + * which does actually not exist in the class we know of + * @throws NoSuchMethodException + * if a class described in the serialised data cannot be created + * because it is not compatible with this code + * @throws ClassNotFoundException + * if a class described in the serialised data cannot be found + */ + public Object send(Object data) throws IOException, NoSuchFieldException, + NoSuchMethodException, ClassNotFoundException { + return action.sendObject(data); + } +} \ No newline at end of file diff --git a/src/be/nikiroo/utils/serial/server/ConnectActionClientString.java b/src/be/nikiroo/utils/serial/server/ConnectActionClientString.java new file mode 100644 index 0000000..f9402cb --- /dev/null +++ b/src/be/nikiroo/utils/serial/server/ConnectActionClientString.java @@ -0,0 +1,95 @@ +package be.nikiroo.utils.serial.server; + +import java.io.IOException; +import java.net.Socket; + +import be.nikiroo.utils.Version; + +/** + * Class used for the client basic handling. + *

+ * It represents a single action: a client is expected to only execute one + * action. + * + * @author niki + */ +public class ConnectActionClientString extends ConnectActionClient { + /** + * Create a new {@link ConnectActionClientString} with the current + * application version (see {@link Version#getCurrentVersion()}) as the + * client version. + * + * @param s + * the socket to bind to + */ + public ConnectActionClientString(Socket s) { + super(s); + } + + /** + * Create a new {@link ConnectActionClientString} with the current + * application version (see {@link Version#getCurrentVersion()}) as the + * client version. + * + * @param host + * the host to bind to + * @param port + * the port to bind to + * @param ssl + * TRUE for an SSL connection, FALSE for plain text + * + * @throws IOException + * in case of I/O error when creating the socket + */ + public ConnectActionClientString(String host, int port, boolean ssl) + throws IOException { + super(host, port, ssl); + } + + /** + * Create a new {@link ConnectActionClientString}. + * + * @param host + * the host to bind to + * @param port + * the port to bind to + * @param ssl + * TRUE for an SSL connection, FALSE for plain text + * @param version + * the client version + * + * @throws IOException + * in case of I/O error when creating the socket + */ + public ConnectActionClientString(String host, int port, boolean ssl, + Version version) throws IOException { + super(host, port, ssl, version); + } + + /** + * Create a new {@link ConnectActionClientString}. + * + * @param s + * the socket to bind to + * @param version + * the client version + */ + public ConnectActionClientString(Socket s, Version version) { + super(s, version); + } + + /** + * Send the given object to the server (and return the answer). + * + * @param data + * the data to send + * + * @return the answer, which can be NULL + * + * @throws IOException + * in case of I/O error + */ + public String send(String data) throws IOException { + return action.sendString(data); + } +} \ No newline at end of file diff --git a/src/be/nikiroo/utils/serial/ConnectActionServer.java b/src/be/nikiroo/utils/serial/server/ConnectActionServer.java similarity index 51% rename from src/be/nikiroo/utils/serial/ConnectActionServer.java rename to src/be/nikiroo/utils/serial/server/ConnectActionServer.java index 2d85c79..85b46a2 100644 --- a/src/be/nikiroo/utils/serial/ConnectActionServer.java +++ b/src/be/nikiroo/utils/serial/server/ConnectActionServer.java @@ -1,6 +1,5 @@ -package be.nikiroo.utils.serial; +package be.nikiroo.utils.serial.server; -import java.io.IOException; import java.net.Socket; import be.nikiroo.utils.Version; @@ -13,8 +12,13 @@ import be.nikiroo.utils.Version; * * @author niki */ -public class ConnectActionServer { - private ConnectAction action; +abstract class ConnectActionServer { + /** + * The underlying {@link ConnectAction}. + *

+ * Cannot be NULL. + */ + protected ConnectAction action; /** * Create a new {@link ConnectActionServer} with the current application @@ -86,51 +90,6 @@ public class ConnectActionServer { public void action(Version clientVersion) throws Exception { } - /** - * Serialise and send the given object to the client. - * - * @param data - * the data to send - * - * @throws IOException - * in case of I/O error - * @throws NoSuchFieldException - * if the serialised data contains information about a field - * which does actually not exist in the class we know of - * @throws NoSuchMethodException - * if a class described in the serialised data cannot be created - * because it is not compatible with this code - * @throws ClassNotFoundException - * if a class described in the serialised data cannot be found - */ - public void send(Object data) throws IOException, NoSuchFieldException, - NoSuchMethodException, ClassNotFoundException { - action.send(data); - } - - /** - * (Flush the data to the client if needed and) retrieve its answer. - * - * @return the deserialised answer (which can actually be NULL) - * - * @throws IOException - * in case of I/O error - * @throws NoSuchFieldException - * if the serialised data contains information about a field - * which does actually not exist in the class we know of - * @throws NoSuchMethodException - * if a class described in the serialised data cannot be created - * because it is not compatible with this code - * @throws ClassNotFoundException - * if a class described in the serialised data cannot be found - * @throws java.lang.NullPointerException - * if the counter part has no data to send - */ - public Object rec() throws NoSuchFieldException, NoSuchMethodException, - ClassNotFoundException, IOException, java.lang.NullPointerException { - return action.rec(); - } - /** * Handler called when an unexpected error occurs in the code. *

@@ -156,25 +115,4 @@ public class ConnectActionServer { @SuppressWarnings("unused") Version clientVersion) { return action.getVersion(); } - - // old stuff: - - /** - * Not used anymore. See {@link ConnectActionServer#rec()}. - */ - @SuppressWarnings("javadoc") - @Deprecated - public Object flush() throws NoSuchFieldException, NoSuchMethodException, - ClassNotFoundException, IOException, java.lang.NullPointerException { - return rec(); - } - - /** - * Not used anymore. See - * {@link ConnectActionServer#negotiateVersion(Version)}. - */ - @SuppressWarnings({ "unused", "javadoc" }) - @Deprecated - protected void onClientVersionReceived(Version clientVersion) { - } } \ No newline at end of file diff --git a/src/be/nikiroo/utils/serial/server/ConnectActionServerObject.java b/src/be/nikiroo/utils/serial/server/ConnectActionServerObject.java new file mode 100644 index 0000000..e0e4276 --- /dev/null +++ b/src/be/nikiroo/utils/serial/server/ConnectActionServerObject.java @@ -0,0 +1,85 @@ +package be.nikiroo.utils.serial.server; + +import java.io.IOException; +import java.net.Socket; + +import be.nikiroo.utils.Version; + +/** + * Class used for the server basic handling. + *

+ * It represents a single action: a server is expected to execute one action for + * each client action. + * + * @author niki + */ +public class ConnectActionServerObject extends ConnectActionServer { + /** + * Create a new {@link ConnectActionServerObject} with the current + * application version (see {@link Version#getCurrentVersion()}) as the + * server version. + * + * @param s + * the socket to bind to + */ + public ConnectActionServerObject(Socket s) { + super(s); + } + + /** + * Create a new {@link ConnectActionServerObject}. + * + * @param s + * the socket to bind to + * @param version + * the server version + */ + public ConnectActionServerObject(Socket s, Version version) { + super(s, version); + } + + /** + * Serialise and send the given object to the client. + * + * @param data + * the data to send + * + * @throws IOException + * in case of I/O error + * @throws NoSuchFieldException + * if the serialised data contains information about a field + * which does actually not exist in the class we know of + * @throws NoSuchMethodException + * if a class described in the serialised data cannot be created + * because it is not compatible with this code + * @throws ClassNotFoundException + * if a class described in the serialised data cannot be found + */ + public void send(Object data) throws IOException, NoSuchFieldException, + NoSuchMethodException, ClassNotFoundException { + action.sendObject(data); + } + + /** + * (Flush the data to the client if needed and) retrieve its answer. + * + * @return the deserialised answer (which can actually be NULL) + * + * @throws IOException + * in case of I/O error + * @throws NoSuchFieldException + * if the serialised data contains information about a field + * which does actually not exist in the class we know of + * @throws NoSuchMethodException + * if a class described in the serialised data cannot be created + * because it is not compatible with this code + * @throws ClassNotFoundException + * if a class described in the serialised data cannot be found + * @throws java.lang.NullPointerException + * if the counter part has no data to send + */ + public Object rec() throws NoSuchFieldException, NoSuchMethodException, + ClassNotFoundException, IOException, java.lang.NullPointerException { + return action.recObject(); + } +} diff --git a/src/be/nikiroo/utils/serial/server/ConnectActionServerString.java b/src/be/nikiroo/utils/serial/server/ConnectActionServerString.java new file mode 100644 index 0000000..35dd4dd --- /dev/null +++ b/src/be/nikiroo/utils/serial/server/ConnectActionServerString.java @@ -0,0 +1,65 @@ +package be.nikiroo.utils.serial.server; + +import java.io.IOException; +import java.net.Socket; + +import be.nikiroo.utils.Version; + +/** + * Class used for the server basic handling. + *

+ * It represents a single action: a server is expected to execute one action for + * each client action. + * + * @author niki + */ +public class ConnectActionServerString extends ConnectActionServer { + /** + * Create a new {@link ConnectActionServerString} with the current + * application version (see {@link Version#getCurrentVersion()}) as the + * server version. + * + * @param s + * the socket to bind to + */ + public ConnectActionServerString(Socket s) { + super(s); + } + + /** + * Create a new {@link ConnectActionServerString}. + * + * @param s + * the socket to bind to + * @param version + * the server version + */ + public ConnectActionServerString(Socket s, Version version) { + super(s, version); + } + + /** + * Serialise and send the given object to the client. + * + * @param data + * the data to send + * + * @throws IOException + * in case of I/O error + */ + public void send(String data) throws IOException { + action.sendString(data); + } + + /** + * (Flush the data to the client if needed and) retrieve its answer. + * + * @return the answer if it is available, or NULL if not + * + * @throws IOException + * in case of I/O error + */ + public String rec() throws IOException { + return action.recString(); + } +} diff --git a/src/be/nikiroo/utils/serial/Server.java b/src/be/nikiroo/utils/serial/server/Server.java similarity index 82% rename from src/be/nikiroo/utils/serial/Server.java rename to src/be/nikiroo/utils/serial/server/Server.java index 934be33..36806d6 100644 --- a/src/be/nikiroo/utils/serial/Server.java +++ b/src/be/nikiroo/utils/serial/server/Server.java @@ -1,4 +1,4 @@ -package be.nikiroo.utils.serial; +package be.nikiroo.utils.serial.server; import java.io.IOException; import java.net.ServerSocket; @@ -12,7 +12,6 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import be.nikiroo.utils.TraceHandler; -import be.nikiroo.utils.Version; /** * This class implements a simple server that can listen for connections and @@ -23,7 +22,7 @@ import be.nikiroo.utils.Version; * * @author niki */ -abstract public class Server implements Runnable { +abstract class Server implements Runnable { static private final String[] ANON_CIPHERS = getAnonCiphers(); private final String name; @@ -40,11 +39,15 @@ abstract public class Server implements Runnable { private TraceHandler tracer = new TraceHandler(); - @Deprecated - public Server(@SuppressWarnings("unused") Version notUsed, int port, - boolean ssl) throws IOException { - this(port, ssl); - } + /** + * Create a new {@link ConnectActionServer} to handle a request. + * + * @param s + * the socket to service + * + * @return the action + */ + abstract ConnectActionServer createConnectActionServer(Socket s); /** * Create a new server that will start listening on the network when @@ -112,6 +115,17 @@ abstract public class Server implements Runnable { this.tracer = tracer; } + /** + * The name of this {@link Server} if any. + *

+ * Used for traces and debug purposes only. + * + * @return the name or NULL + */ + public String getName() { + return name; + } + /** * Return the assigned port. * @@ -171,35 +185,7 @@ abstract public class Server implements Runnable { while (started && !exiting) { count(1); Socket s = ss.accept(); - new ConnectActionServer(s) { - @Override - public void action(Version clientVersion) throws Exception { - try { - for (Object data = rec(); true; data = rec()) { - Object rep = null; - try { - rep = onRequest(this, clientVersion, data); - } catch (Exception e) { - onError(e); - } - send(rep); - } - } catch (NullPointerException e) { - // Client has no data any more, we quit - tracer.trace(name - + ": client has data no more, stopping connection"); - } - } - - @Override - public void connect() { - try { - super.connect(); - } finally { - count(-1); - } - } - }.connectAsync(); + createConnectActionServer(s).connectAsync(); } // Will be covered by @link{Server#stop(long)} for timeouts @@ -272,7 +258,7 @@ abstract public class Server implements Runnable { exiting = true; try { - new ConnectActionClient(createSocket(null, port, ssl)) + new ConnectActionClientObject(createSocket(null, port, ssl)) .connect(); long time = 0; while (ss != null && timeout > 0 && timeout > time) { @@ -297,26 +283,6 @@ abstract public class Server implements Runnable { } } - /** - * This is the method that is called on each client request. - *

- * You are expected to react to it and return an answer (which can be NULL). - * - * @param action - * the client action - * @param clientVersion - * the client version - * @param data - * the data sent by the client (which can be NULL) - * - * @return the answer to return to the client (which can be NULL) - * - * @throws Exception - * in case of an exception, the error will only be logged - */ - abstract protected Object onRequest(ConnectActionServer action, - Version clientVersion, Object data) throws Exception; - /** * This method will be called on errors. *

@@ -338,7 +304,7 @@ abstract public class Server implements Runnable { * * @return the current number after this operation */ - private int count(int change) { + int count(int change) { synchronized (counterLock) { counter += change; return counter; diff --git a/src/be/nikiroo/utils/serial/server/ServerObject.java b/src/be/nikiroo/utils/serial/server/ServerObject.java new file mode 100644 index 0000000..6ff81f5 --- /dev/null +++ b/src/be/nikiroo/utils/serial/server/ServerObject.java @@ -0,0 +1,107 @@ +package be.nikiroo.utils.serial.server; + +import java.io.IOException; +import java.net.Socket; + +import be.nikiroo.utils.Version; + +/** + * This class implements a simple server that can listen for connections and + * send/receive objects. + *

+ * Note: this {@link ServerObject} has to be discarded after use (cannot be + * started twice). + * + * @author niki + */ +abstract public class ServerObject extends Server { + /** + * Create a new server that will start listening on the network when + * {@link ServerObject#start()} is called. + * + * @param port + * the port to listen on, or 0 to assign any unallocated port + * found (which can later on be queried via + * {@link ServerObject#getPort()} + * @param ssl + * use a SSL connection (or not) + * + * @throws IOException + * in case of I/O error + */ + public ServerObject(int port, boolean ssl) throws IOException { + super(port, ssl); + } + + /** + * Create a new server that will start listening on the network when + * {@link ServerObject#start()} is called. + * + * @param name + * the server name (only used for debug info and traces) + * @param port + * the port to listen on + * @param ssl + * use a SSL connection (or not) + * + * @throws IOException + * in case of I/O error + */ + public ServerObject(String name, int port, boolean ssl) throws IOException { + super(name, port, ssl); + } + + @Override + protected ConnectActionServer createConnectActionServer(Socket s) { + return new ConnectActionServerObject(s) { + @Override + public void action(Version clientVersion) throws Exception { + try { + for (Object data = rec(); true; data = rec()) { + Object rep = null; + try { + rep = onRequest(this, clientVersion, data); + } catch (Exception e) { + onError(e); + } + send(rep); + } + } catch (NullPointerException e) { + // Client has no data any more, we quit + getTraceHandler() + .trace(getName() + + ": client has data no more, stopping connection"); + } + } + + @Override + public void connect() { + try { + super.connect(); + } finally { + count(-1); + } + } + }; + } + + /** + * This is the method that is called on each client request. + *

+ * You are expected to react to it and return an answer (which can be NULL). + * + * @param action + * the client action + * @param clientVersion + * the client version + * @param data + * the data sent by the client (which can be NULL) + * + * @return the answer to return to the client (which can be NULL) + * + * @throws Exception + * in case of an exception, the error will only be logged + */ + abstract protected Object onRequest(ConnectActionServerObject action, + Version clientVersion, Object data) throws Exception; +} diff --git a/src/be/nikiroo/utils/serial/server/ServerString.java b/src/be/nikiroo/utils/serial/server/ServerString.java new file mode 100644 index 0000000..4a185da --- /dev/null +++ b/src/be/nikiroo/utils/serial/server/ServerString.java @@ -0,0 +1,113 @@ +package be.nikiroo.utils.serial.server; + +import java.io.IOException; +import java.net.Socket; + +import be.nikiroo.utils.Version; + +/** + * This class implements a simple server that can listen for connections and + * send/receive Strings. + *

+ * Note: this {@link ServerString} has to be discarded after use (cannot be + * started twice). + * + * @author niki + */ +abstract public class ServerString extends Server { + /** + * Create a new server that will start listening on the network when + * {@link ServerString#start()} is called. + * + * @param port + * the port to listen on, or 0 to assign any unallocated port + * found (which can later on be queried via + * {@link ServerString#getPort()} + * @param ssl + * use a SSL connection (or not) + * + * @throws IOException + * in case of I/O error + */ + public ServerString(int port, boolean ssl) throws IOException { + super(port, ssl); + } + + /** + * Create a new server that will start listening on the network when + * {@link ServerString#start()} is called. + * + * @param name + * the server name (only used for debug info and traces) + * @param port + * the port to listen on + * @param ssl + * use a SSL connection (or not) + * + * @throws IOException + * in case of I/O error + */ + public ServerString(String name, int port, boolean ssl) throws IOException { + super(name, port, ssl); + } + + @Override + protected ConnectActionServer createConnectActionServer(Socket s) { + return new ConnectActionServerString(s) { + @Override + public void action(Version clientVersion) throws Exception { + try { + for (String data = rec(); data != null; data = rec()) { + String rep = null; + try { + rep = onRequest(this, clientVersion, data); + } catch (Exception e) { + onError(e); + } + + if (rep == null) { + rep = ""; + } + + send(rep); + } + } catch (NullPointerException e) { + // Client has no data any more, we quit + getTraceHandler() + .trace(getName() + + ": client has data no more, stopping connection"); + } + } + + @Override + public void connect() { + try { + super.connect(); + } finally { + count(-1); + } + } + }; + } + + /** + * This is the method that is called on each client request. + *

+ * You are expected to react to it and return an answer (NULL will be + * converted to an empty {@link String}). + * + * @param action + * the client action + * @param clientVersion + * the client version + * @param data + * the data sent by the client + * + * @return the answer to return to the client + * + * @throws Exception + * in case of an exception, the error will only be logged + */ + abstract protected String onRequest(ConnectActionServerString action, + Version clientVersion, String data) throws Exception; +} diff --git a/src/be/nikiroo/utils/test/SerialTest.java b/src/be/nikiroo/utils/test/SerialTest.java index e3171c2..b1b5c8b 100644 --- a/src/be/nikiroo/utils/test/SerialTest.java +++ b/src/be/nikiroo/utils/test/SerialTest.java @@ -1,19 +1,218 @@ package be.nikiroo.utils.test; -import be.nikiroo.utils.TraceHandler; import be.nikiroo.utils.Version; -import be.nikiroo.utils.serial.ConnectActionClient; -import be.nikiroo.utils.serial.ConnectActionServer; import be.nikiroo.utils.serial.Exporter; import be.nikiroo.utils.serial.Importer; -import be.nikiroo.utils.serial.Server; +import be.nikiroo.utils.serial.server.ConnectActionClientObject; +import be.nikiroo.utils.serial.server.ConnectActionClientString; +import be.nikiroo.utils.serial.server.ConnectActionServerObject; +import be.nikiroo.utils.serial.server.ConnectActionServerString; +import be.nikiroo.utils.serial.server.ServerObject; +import be.nikiroo.utils.serial.server.ServerString; class SerialTest extends TestLauncher { private SerialTest() { super("Serial test", null); } - private TestLauncher createServerTestCases(final String[] args, + private TestLauncher createServerStringTestCases(final String[] args, + final boolean ssl) { + final String ssls = (ssl ? "(ssl)" : "(plain text)"); + TestLauncher series = new TestLauncher("Client/Server " + ssls, args); + + series.addTest(new TestCase("Simple connection " + ssls) { + @Override + public void test() throws Exception { + final String[] rec = new String[1]; + + ServerString server = new ServerString(this.getName(), 0, ssl) { + @Override + protected String onRequest( + ConnectActionServerString action, + Version clientVersion, String data) + throws Exception { + return null; + } + }; + + assertEquals("A port should have been assigned", true, + server.getPort() > 0); + + server.start(); + + try { + new ConnectActionClientObject(null, server.getPort(), ssl) { + @Override + public void action(Version serverVersion) + throws Exception { + rec[0] = "ok"; + } + }.connect(); + } finally { + server.stop(); + } + + assertNotNull("The client action was not run", rec[0]); + assertEquals("ok", rec[0]); + } + }); + + series.addTest(new TestCase("Simple exchange " + ssls) { + final String[] sent = new String[1]; + final String[] recd = new String[1]; + final Exception[] err = new Exception[1]; + + @Override + public void test() throws Exception { + ServerString server = new ServerString(this.getName(), 0, ssl) { + @Override + protected String onRequest( + ConnectActionServerString action, + Version clientVersion, String data) + throws Exception { + sent[0] = data; + return "pong"; + } + + @Override + protected void onError(Exception e) { + super.onError(e); + err[0] = e; + } + }; + + server.start(); + + try { + new ConnectActionClientString(null, server.getPort(), ssl) { + @Override + public void action(Version serverVersion) + throws Exception { + recd[0] = send("ping"); + } + }.connect(); + } finally { + server.stop(); + } + + if (err[0] != null) { + fail("An exception was thrown: " + err[0].getMessage()); + } + + assertEquals("ping", sent[0]); + assertEquals("pong", recd[0]); + } + }); + + series.addTest(new TestCase("Multiple exchanges " + ssls) { + final String[] sent = new String[3]; + final String[] recd = new String[3]; + final Exception[] err = new Exception[1]; + + @Override + public void test() throws Exception { + ServerString server = new ServerString(this.getName(), 0, ssl) { + @Override + protected String onRequest( + ConnectActionServerString action, + Version clientVersion, String data) + throws Exception { + sent[0] = data; + action.send("pong"); + sent[1] = action.rec(); + return "pong2"; + } + + @Override + protected void onError(Exception e) { + super.onError(e); + err[0] = e; + } + }; + + server.start(); + + try { + new ConnectActionClientString(null, server.getPort(), ssl) { + @Override + public void action(Version serverVersion) + throws Exception { + recd[0] = send("ping"); + recd[1] = send("ping2"); + } + }.connect(); + } finally { + server.stop(); + } + + if (err[0] != null) { + fail("An exception was thrown: " + err[0].getMessage()); + } + + assertEquals("ping", sent[0]); + assertEquals("pong", recd[0]); + assertEquals("ping2", sent[1]); + assertEquals("pong2", recd[1]); + } + }); + + series.addTest(new TestCase("Multiple call from client " + ssls) { + final String[] sent = new String[3]; + final String[] recd = new String[3]; + final Exception[] err = new Exception[1]; + + @Override + public void test() throws Exception { + ServerString server = new ServerString(this.getName(), 0, ssl) { + @Override + protected String onRequest( + ConnectActionServerString action, + Version clientVersion, String data) + throws Exception { + sent[Integer.parseInt(data)] = data; + return "" + (Integer.parseInt(data) * 2); + } + + @Override + protected void onError(Exception e) { + super.onError(e); + err[0] = e; + } + }; + + server.start(); + + try { + new ConnectActionClientString(null, server.getPort(), ssl) { + @Override + public void action(Version serverVersion) + throws Exception { + for (int i = 0; i < 3; i++) { + recd[i] = send("" + i); + } + } + }.connect(); + } finally { + server.stop(); + } + + if (err[0] != null) { + fail("An exception was thrown: " + err[0].getMessage()); + } + + assertEquals("0", sent[0]); + assertEquals("0", recd[0]); + assertEquals("1", sent[1]); + assertEquals("2", recd[1]); + assertEquals("2", sent[2]); + assertEquals("4", recd[2]); + } + }); + + return series; + } + + private TestLauncher createServerObjectTestCases(final String[] args, final boolean ssl) { final String ssls = (ssl ? "(ssl)" : "(plain text)"); TestLauncher series = new TestLauncher("Client/Server " + ssls, args); @@ -23,9 +222,10 @@ class SerialTest extends TestLauncher { public void test() throws Exception { final Object[] rec = new Object[1]; - Server server = new Server(this.getName(), 0, ssl) { + ServerObject server = new ServerObject(this.getName(), 0, ssl) { @Override - protected Object onRequest(ConnectActionServer action, + protected Object onRequest( + ConnectActionServerObject action, Version clientVersion, Object data) throws Exception { return null; @@ -35,13 +235,10 @@ class SerialTest extends TestLauncher { assertEquals("A port should have been assigned", true, server.getPort() > 0); - // TODO: remove - server.setTraceHandler(new TraceHandler(true, true, true)); - server.start(); try { - new ConnectActionClient(null, server.getPort(), ssl) { + new ConnectActionClientObject(null, server.getPort(), ssl) { @Override public void action(Version serverVersion) throws Exception { @@ -64,9 +261,10 @@ class SerialTest extends TestLauncher { @Override public void test() throws Exception { - Server server = new Server(this.getName(), 0, ssl) { + ServerObject server = new ServerObject(this.getName(), 0, ssl) { @Override - protected Object onRequest(ConnectActionServer action, + protected Object onRequest( + ConnectActionServerObject action, Version clientVersion, Object data) throws Exception { sent[0] = data; @@ -83,7 +281,7 @@ class SerialTest extends TestLauncher { server.start(); try { - new ConnectActionClient(null, server.getPort(), ssl) { + new ConnectActionClientObject(null, server.getPort(), ssl) { @Override public void action(Version serverVersion) throws Exception { @@ -110,9 +308,10 @@ class SerialTest extends TestLauncher { @Override public void test() throws Exception { - Server server = new Server(this.getName(), 0, ssl) { + ServerObject server = new ServerObject(this.getName(), 0, ssl) { @Override - protected Object onRequest(ConnectActionServer action, + protected Object onRequest( + ConnectActionServerObject action, Version clientVersion, Object data) throws Exception { sent[0] = data; @@ -131,7 +330,7 @@ class SerialTest extends TestLauncher { server.start(); try { - new ConnectActionClient(null, server.getPort(), ssl) { + new ConnectActionClientObject(null, server.getPort(), ssl) { @Override public void action(Version serverVersion) throws Exception { @@ -161,9 +360,10 @@ class SerialTest extends TestLauncher { @Override public void test() throws Exception { - Server server = new Server(this.getName(), 0, ssl) { + ServerObject server = new ServerObject(this.getName(), 0, ssl) { @Override - protected Object onRequest(ConnectActionServer action, + protected Object onRequest( + ConnectActionServerObject action, Version clientVersion, Object data) throws Exception { sent[(Integer) data] = data; @@ -180,7 +380,7 @@ class SerialTest extends TestLauncher { server.start(); try { - new ConnectActionClient(null, server.getPort(), ssl) { + new ConnectActionClientObject(null, server.getPort(), ssl) { @Override public void action(Version serverVersion) throws Exception { @@ -212,9 +412,13 @@ class SerialTest extends TestLauncher { public SerialTest(String[] args) { super("Serial test", args); - addSeries(createServerTestCases(args, false)); + addSeries(createServerObjectTestCases(args, false)); + + addSeries(createServerObjectTestCases(args, true)); + + addSeries(createServerStringTestCases(args, false)); - addSeries(createServerTestCases(args, true)); + addSeries(createServerStringTestCases(args, true)); addTest(new TestCase("Simple class Import/Export") { @Override diff --git a/src/be/nikiroo/utils/test/TestCase.java b/src/be/nikiroo/utils/test/TestCase.java index 490edbb..9d0caaa 100644 --- a/src/be/nikiroo/utils/test/TestCase.java +++ b/src/be/nikiroo/utils/test/TestCase.java @@ -42,6 +42,7 @@ abstract public class TestCase { * @throws Exception * in case of error */ + @SuppressWarnings("unused") public void setUp() throws Exception { } @@ -51,6 +52,7 @@ abstract public class TestCase { * @throws Exception * in case of error */ + @SuppressWarnings("unused") public void tearDown() throws Exception { } diff --git a/src/be/nikiroo/utils/test/TestLauncher.java b/src/be/nikiroo/utils/test/TestLauncher.java index 62f3f6f..bee3071 100644 --- a/src/be/nikiroo/utils/test/TestLauncher.java +++ b/src/be/nikiroo/utils/test/TestLauncher.java @@ -96,6 +96,7 @@ public class TestLauncher { * @throws Exception * in case of error */ + @SuppressWarnings("unused") protected void start() throws Exception { } @@ -105,6 +106,7 @@ public class TestLauncher { * @throws Exception * in case of error */ + @SuppressWarnings("unused") protected void stop() throws Exception { } -- 2.27.0