jDoc, tests, Server fixes
authorNiki Roo <niki@nikiroo.be>
Mon, 27 Nov 2017 21:44:35 +0000 (22:44 +0100)
committerNiki Roo <niki@nikiroo.be>
Mon, 27 Nov 2017 21:44:35 +0000 (22:44 +0100)
changelog.md
src/be/nikiroo/utils/TraceHandler.java
src/be/nikiroo/utils/serial/ConnectAction.java
src/be/nikiroo/utils/serial/ConnectActionClient.java
src/be/nikiroo/utils/serial/ConnectActionServer.java
src/be/nikiroo/utils/serial/Exporter.java
src/be/nikiroo/utils/serial/Importer.java
src/be/nikiroo/utils/serial/Server.java
src/be/nikiroo/utils/test/SerialTest.java

index ab1be9e537f5967bb5f6d99ac7872b915ee5b2ab..34046e81b71f22fc25654675104b86cd596578fe 100644 (file)
@@ -1,5 +1,11 @@
 # nikiroo-utils
 
+## Version WIP
+
+- jDoc
+- Fix bugs in Server (it was not possible to send objects back to client)
+- Improve code in Server (including tests)
+
 ## Version 2.2.3
 
 - Fix in readSmallStream
index d7f604667f8976c8afe595a81620b5665d4981aa..309e8af6d393f31823a4200e719ec051e1570ad3 100644 (file)
@@ -67,7 +67,7 @@ public class TraceHandler {
        /**
         * A trace happened, show it.
         * <p>
-        * Will only be effective if {@link TraceHandler#isShowTraces()} is true.
+        * Will only be effective if {@link TraceHandler#showTraces} is true.
         * 
         * @param message
         *            the trace message
@@ -77,4 +77,28 @@ 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;
+       }
 }
index 2a25c5b1c62e9f6a15778e200b04603637fa747a..dfc1a2bb422138ea8acbf930a831d0c6d7a7a0da 100644 (file)
@@ -8,20 +8,71 @@ import java.net.Socket;
 
 import be.nikiroo.utils.Version;
 
+/**
+ * Base class used for the client/server basic handling.
+ * <p>
+ * It represents a single action: a client is expected to only execute one
+ * action, while a server is expected to execute one action for each client
+ * action.
+ * 
+ * @author niki
+ */
 abstract class ConnectAction {
        private Socket s;
        private boolean server;
        private Version version;
+       private Version clientVersion;
 
        private Object lock = new Object();
        private BufferedReader in;
        private OutputStreamWriter out;
        private boolean contentToSend;
 
-       // serverVersion = null on server (or bad clients)
-       abstract public void action(Version serverVersion) throws Exception;
+       /**
+        * Method that will be called when an action is performed on either the
+        * client or server this {@link ConnectAction} represent.
+        * 
+        * @param version
+        *            the counter part version
+        * 
+        * @throws Exception
+        *             in case of I/O error
+        */
+       abstract protected void action(Version version) throws Exception;
+
+       /**
+        * Method called when we negotiate the version with the client.
+        * <p>
+        * Thus, it is only called on the server.
+        * <p>
+        * Will return the actual server version by default.
+        * 
+        * @param clientVersion
+        *            the client version
+        * 
+        * @return the version to send to the client
+        */
+       abstract protected Version negotiateVersion(Version clientVersion);
+
+       /**
+        * Handler called when an unexpected error occurs in the code.
+        * 
+        * @param e
+        *            the exception that occurred
+        */
+       abstract protected void onError(Exception e);
 
-       // server = version NULL
+       /**
+        * Create a new {@link ConnectAction}.
+        * 
+        * @param s
+        *            the socket to bind to
+        * @param server
+        *            TRUE for a server action, FALSE for a client action (will
+        *            impact the process)
+        * @param version
+        *            the version of this client-or-server
+        */
        protected ConnectAction(Socket s, boolean server, Version version) {
                this.s = s;
                this.server = server;
@@ -31,18 +82,22 @@ abstract class ConnectAction {
                } else {
                        this.version = version;
                }
+
+               clientVersion = new Version();
        }
 
-       public void connectAsync() {
-               new Thread(new Runnable() {
-                       @Override
-                       public void run() {
-                               connect();
-                       }
-               }).start();
+       /**
+        * The version of this client-or-server.
+        * 
+        * @return the version
+        */
+       public Version getVersion() {
+               return version;
        }
 
-       // connect, do the action (sync)
+       /**
+        * Actually start the process (this is synchronous).
+        */
        public void connect() {
                try {
                        in = new BufferedReader(new InputStreamReader(s.getInputStream(),
@@ -51,7 +106,7 @@ abstract class ConnectAction {
                                out = new OutputStreamWriter(s.getOutputStream(), "UTF-8");
                                try {
                                        if (server) {
-                                               action(version);
+                                               action(clientVersion);
                                        } else {
                                                String v = sendString("VERSION " + version.toString());
                                                if (v != null && v.startsWith("VERSION ")) {
@@ -77,9 +132,30 @@ abstract class ConnectAction {
                }
        }
 
-       // (also, server never get anything)
-       public Object send(Object data) throws IOException, NoSuchFieldException,
-                       NoSuchMethodException, ClassNotFoundException {
+       /**
+        * Serialise and send the given object to the counter part (and, only for
+        * client, return the deserialised answer -- the server will always receive
+        * NULL).
+        * 
+        * @param data
+        *            the data to send
+        * 
+        * @return the answer (which can be NULL) if this action is a client, always
+        *         NULL if it is a server
+        * 
+        * @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
+        */
+       protected Object send(Object data) throws IOException,
+                       NoSuchFieldException, NoSuchMethodException, ClassNotFoundException {
                synchronized (lock) {
                        String rep = sendString(new Exporter().append(data).toString(true));
                        if (rep != null) {
@@ -90,37 +166,55 @@ abstract class ConnectAction {
                }
        }
 
-       public Object flush() throws NoSuchFieldException, NoSuchMethodException,
-                       ClassNotFoundException, IOException, java.lang.NullPointerException {
+       /**
+        * Reserved for the server: flush the data to the client and retrieve its
+        * answer.
+        * <p>
+        * Also used internally for the client (only do something if there is
+        * contentToSend).
+        * <p>
+        * Will only flush the data if there is contentToSend.
+        * 
+        * @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
+        */
+       protected Object rec() throws IOException, NoSuchFieldException,
+                       NoSuchMethodException, ClassNotFoundException,
+                       java.lang.NullPointerException {
                String str = flushString();
                if (str == null) {
-                       throw new NullPointerException("No more data from client");
+                       throw new NullPointerException("No more data available");
                }
 
                return new Importer().read(str).getValue();
        }
 
        /**
-        * Handler called when the client {@link Version} is received.
+        * Send the given string to the counter part (and, only for client, return
+        * the answer -- the server will always receive NULL).
         * 
-        * @param clientVersion
-        *            the client {@link Version}
-        */
-       protected void onClientVersionReceived(
-                       @SuppressWarnings("unused") Version clientVersion) {
-       }
-
-       /**
-        * Handler called when an unexpected error occurs in the code.
+        * @param line
+        *            the data to send (we will add a line feed)
         * 
-        * @param e
-        *            the exception that occurred
+        * @return the answer if this action is a client (without the added line
+        *         feed), NULL if it is a server
+        * 
+        * @throws IOException
+        *             in case of I/O error
         */
-       protected void onError(@SuppressWarnings("unused") Exception e) {
-       }
-
-       // \n included in line, but not in rep (also, server never get anything)
-       private String sendString(String line) throws IOException {
+       protected String sendString(String line) throws IOException {
                synchronized (lock) {
                        out.write(line);
                        out.write("\n");
@@ -135,8 +229,21 @@ abstract class ConnectAction {
                }
        }
 
-       // server can receive something even without pending content
-       private String flushString() throws IOException {
+       /**
+        * Reserved for the server (externally): flush the data to the client and
+        * retrieve its answer.
+        * <p>
+        * Also used internally for the client (only do something if there is
+        * contentToSend).
+        * <p>
+        * Will only flush the data if there is contentToSend.
+        * 
+        * @return the answer (which can be NULL)
+        * 
+        * @throws IOException
+        *             in case of I/O error
+        */
+       protected String flushString() throws IOException {
                synchronized (lock) {
                        if (server || contentToSend) {
                                if (contentToSend) {
@@ -149,8 +256,12 @@ abstract class ConnectAction {
                                        // "VERSION client-version" (VERSION 1.0.0)
                                        Version clientVersion = new Version(
                                                        line.substring("VERSION ".length()));
-                                       onClientVersionReceived(clientVersion);
-                                       sendString("VERSION " + version.toString());
+                                       this.clientVersion = clientVersion;
+                                       Version v = negotiateVersion(clientVersion);
+                                       if (v == null) {
+                                               v = new Version();
+                                       }
+                                       sendString("VERSION " + v.toString());
 
                                        line = in.readLine();
                                }
index 5b982021fe60bc9c2633ed3283b41ad6b4629288..83537025d00e103adc127ebad31b096129609f85 100644 (file)
@@ -5,27 +5,181 @@ import java.net.Socket;
 
 import be.nikiroo.utils.Version;
 
-public class ConnectActionClient extends ConnectAction {
-       protected ConnectActionClient(Socket s) {
-               super(s, false, Version.getCurrentVersion());
-       }
+/**
+ * Base class used for the client basic handling.
+ * <p>
+ * It represents a single action: a client is expected to only execute one
+ * action.
+ * 
+ * @author niki
+ */
+public class ConnectActionClient {
+       private ConnectAction action;
 
-       protected ConnectActionClient(Socket s, Version version) {
-               super(s, false, version);
+       /**
+        * Create a new {@link ConnectActionClient} with the current application
+        * version (see {@link Version#getCurrentVersion()}) as the client version.
+        * 
+        * @param s
+        *            the socket to bind to
+        */
+       public ConnectActionClient(Socket s) {
+               this(s, Version.getCurrentVersion());
        }
 
-       protected ConnectActionClient(String host, int port, boolean ssl)
+       /**
+        * Create a new {@link ConnectActionClient} 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 ConnectActionClient(String host, int port, boolean ssl)
                        throws IOException {
-               super(Server.createSocket(host, port, ssl), false, Version
-                               .getCurrentVersion());
+               this(Server.createSocket(host, port, ssl), Version.getCurrentVersion());
        }
 
-       protected ConnectActionClient(String host, int port, boolean ssl,
+       /**
+        * Create a new {@link ConnectActionClient}.
+        * 
+        * @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 ConnectActionClient(String host, int port, boolean ssl,
                        Version version) throws IOException {
-               super(Server.createSocket(host, port, ssl), false, version);
+               this(Server.createSocket(host, port, ssl), version);
+       }
+
+       /**
+        * Create a new {@link ConnectActionClient}.
+        * 
+        * @param s
+        *            the socket to bind to
+        * @param version
+        *            the client version
+        */
+       public ConnectActionClient(Socket s, Version version) {
+               action = new ConnectAction(s, false, version) {
+                       @Override
+                       protected void action(Version serverVersion) throws Exception {
+                               ConnectActionClient.this.action(serverVersion);
+                       }
+
+                       @Override
+                       protected void onError(Exception e) {
+                               ConnectActionClient.this.onError(e);
+                       }
+
+                       @Override
+                       protected Version negotiateVersion(Version clientVersion) {
+                               new Exception("Should never be called on a client")
+                                               .printStackTrace();
+                               return null;
+                       }
+               };
+       }
+
+       /**
+        * Actually start the process and call the action (synchronous).
+        */
+       public void connect() {
+               action.connect();
+       }
+
+       /**
+        * Actually start the process and call the action (asynchronous).
+        */
+       public void connectAsync() {
+               new Thread(new Runnable() {
+                       @Override
+                       public void run() {
+                               connect();
+                       }
+               }).start();
        }
 
-       @Override
+       /**
+        * Method that will be called when an action is performed on the client.
+        * 
+        * @param serverVersion
+        *            the server version
+        * 
+        * @throws Exception
+        *             in case of I/O error
+        */
+       @SuppressWarnings("unused")
        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.
+        * <p>
+        * Will just ignore the error by default.
+        * 
+        * @param e
+        *            the exception that occurred
+        */
+       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
index 7c0406520a1cd60fdc0e6dfa4575aa5fabcf1350..2d85c79c86f41b2d7807bb3fcc3ad6b508a3cddc 100644 (file)
 package be.nikiroo.utils.serial;
 
+import java.io.IOException;
 import java.net.Socket;
 
 import be.nikiroo.utils.Version;
 
-public class ConnectActionServer extends ConnectAction {
-       protected ConnectActionServer(Socket s) {
-               super(s, true, Version.getCurrentVersion());
+/**
+ * Base class used for the server basic handling.
+ * <p>
+ * It represents a single action: a server is expected to execute one action for
+ * each client action.
+ * 
+ * @author niki
+ */
+public class ConnectActionServer {
+       private ConnectAction action;
+
+       /**
+        * Create a new {@link ConnectActionServer} with the current application
+        * version (see {@link Version#getCurrentVersion()}) as the server version.
+        * 
+        * @param s
+        *            the socket to bind to
+        */
+       public ConnectActionServer(Socket s) {
+               this(s, Version.getCurrentVersion());
+       }
+
+       /**
+        * Create a new {@link ConnectActionServer}.
+        * 
+        * @param s
+        *            the socket to bind to
+        * @param version
+        *            the server version
+        */
+       public ConnectActionServer(Socket s, Version version) {
+               action = new ConnectAction(s, true, version) {
+                       @Override
+                       protected void action(Version clientVersion) throws Exception {
+                               ConnectActionServer.this.action(clientVersion);
+                       }
+
+                       @Override
+                       protected void onError(Exception e) {
+                               ConnectActionServer.this.onError(e);
+                       }
+
+                       @Override
+                       protected Version negotiateVersion(Version clientVersion) {
+                               return ConnectActionServer.this.negotiateVersion(clientVersion);
+                       }
+               };
+       }
+
+       /**
+        * Actually start the process and call the action (synchronous).
+        */
+       public void connect() {
+               action.connect();
+       }
+
+       /**
+        * Actually start the process and call the action (asynchronous).
+        */
+       public void connectAsync() {
+               new Thread(new Runnable() {
+                       @Override
+                       public void run() {
+                               connect();
+                       }
+               }).start();
+       }
+
+       /**
+        * Method that will be called when an action is performed on the server.
+        * 
+        * @param clientVersion
+        *            the client version
+        * 
+        * @throws Exception
+        *             in case of I/O error
+        */
+       @SuppressWarnings("unused")
+       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();
        }
 
-       protected ConnectActionServer(Socket s, Version version) {
-               super(s, true, version);
+       /**
+        * Handler called when an unexpected error occurs in the code.
+        * <p>
+        * Will just ignore the error by default.
+        * 
+        * @param e
+        *            the exception that occurred
+        */
+       protected void onError(@SuppressWarnings("unused") Exception e) {
+       }
+
+       /**
+        * Method called when we negotiate the version with the client.
+        * <p>
+        * Will return the actual server version by default.
+        * 
+        * @param clientVersion
+        *            the client version
+        * 
+        * @return the version to send to the client
+        */
+       protected Version negotiateVersion(
+                       @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();
        }
 
-       @Override
-       public void action(Version serverVersion) throws Exception {
+       /**
+        * Not used anymore. See
+        * {@link ConnectActionServer#negotiateVersion(Version)}.
+        */
+       @SuppressWarnings({ "unused", "javadoc" })
+       @Deprecated
+       protected void onClientVersionReceived(Version clientVersion) {
        }
 }
\ No newline at end of file
index 8b522e9556054dea43572f6a5e4226f738e116b8..90939880f6f29e0e2ba1488f274db1daed932f7b 100644 (file)
@@ -18,22 +18,52 @@ public class Exporter {
        private Map<Integer, Object> map;
        private StringBuilder builder;
 
+       /**
+        * Create a new {@link Exporter}.
+        */
        public Exporter() {
                map = new HashMap<Integer, Object>();
                builder = new StringBuilder();
        }
 
+       /**
+        * Serialise the given object and add it to the list.
+        * <p>
+        * <b>Important: </b>If the operation fails (with a
+        * {@link NotSerializableException}), the {@link Exporter} will be corrupted
+        * (will contain bad, most probably not importable data).
+        * 
+        * @param o
+        *            the object to serialise
+        * @return this (for easier appending of multiple values)
+        * 
+        * @throws NotSerializableException
+        *             if the object cannot be serialised (in this case, the
+        *             {@link Exporter} can contain bad, most probably not
+        *             importable data)
+        */
        public Exporter append(Object o) throws NotSerializableException {
                SerialUtils.append(builder, o, map);
                return this;
        }
 
+       /**
+        * Clear the current content.
+        */
        public void clear() {
                builder.setLength(0);
                map.clear();
        }
 
-       // null = auto
+       /**
+        * The exported items in a serialised form.
+        * 
+        * @param zip
+        *            TRUE to have zipped content, FALSE to have raw content, NULL
+        *            to let the system decide
+        * 
+        * @return the items currently in this {@link Exporter}
+        */
        public String toString(Boolean zip) {
                if (zip == null) {
                        zip = builder.length() > 128;
@@ -47,9 +77,9 @@ public class Exporter {
        }
 
        /**
-        * The exported items in a serialised form.
+        * The exported items in a serialised form (possibly zipped).
         * 
-        * @return the items currently in this {@link Exporter}.
+        * @return the items currently in this {@link Exporter}
         */
        @Override
        public String toString() {
index d21f1dd341c9085af11a08015a05c5fb04fc5c14..a159ddedf4763859aefe8fc51ac82479d567ce0f 100644 (file)
@@ -26,6 +26,9 @@ public class Importer {
 
        private String currentFieldName;
 
+       /**
+        * Create a new {@link Importer}.
+        */
        public Importer() {
                map = new HashMap<String, Object>();
                map.put("NULL", null);
index e15680e5862d799291a732c52e7877b5fcad6c7a..f2a01c5deaa6a2db2f970d041f5b0b8178444e2c 100644 (file)
@@ -114,6 +114,8 @@ abstract public class Server implements Runnable {
 
        /**
         * Return the assigned port.
+        * 
+        * @return the assigned port
         */
        public int getPort() {
                return port;
@@ -189,13 +191,8 @@ abstract public class Server implements Runnable {
                                exiting = true;
 
                                try {
-                                       new ConnectActionClient(createSocket(null, port, ssl)) {
-                                               @Override
-                                               public void action(Version serverVersion)
-                                                               throws Exception {
-                                               }
-                                       }.connect();
-
+                                       new ConnectActionClient(createSocket(null, port, ssl))
+                                                       .connect();
                                        long time = 0;
                                        while (ss != null && timeout > 0 && timeout > time) {
                                                Thread.sleep(10);
@@ -222,17 +219,14 @@ abstract public class Server implements Runnable {
        @Override
        public void run() {
                try {
-                       tracer.trace(name + ": server starting on port " + port);
                        while (started && !exiting) {
                                count(1);
                                Socket s = ss.accept();
                                new ConnectActionServer(s) {
-                                       private Version clientVersion = new Version();
-
                                        @Override
-                                       public void action(Version dummy) throws Exception {
+                                       public void action(Version clientVersion) throws Exception {
                                                try {
-                                                       for (Object data = flush(); true; data = flush()) {
+                                                       for (Object data = rec(); true; data = rec()) {
                                                                Object rep = null;
                                                                try {
                                                                        rep = onRequest(this, clientVersion, data);
@@ -243,6 +237,7 @@ abstract public class Server implements Runnable {
                                                        }
                                                } catch (NullPointerException e) {
                                                        // Client has no data any more, we quit
+                                                       tracer.trace("Client has data no more, stopping connection");
                                                }
                                        }
 
@@ -254,11 +249,6 @@ abstract public class Server implements Runnable {
                                                        count(-1);
                                                }
                                        }
-
-                                       @Override
-                                       protected void onClientVersionReceived(Version clientVersion) {
-                                               this.clientVersion = clientVersion;
-                                       }
                                }.connectAsync();
                        }
 
index 4233a7bde2bd336f875ce1a29cc464e8d487acde..e66bda8df9444b1706c71b1ec0e39b1a5c1ca0dd 100644 (file)
@@ -1,5 +1,6 @@
 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;
@@ -8,230 +9,212 @@ import be.nikiroo.utils.serial.Importer;
 import be.nikiroo.utils.serial.Server;
 
 class SerialTest extends TestLauncher {
-       @SuppressWarnings("unused")
-       private void not_used() {
-               // TODO: test Server ; but this will at least help dependency checking
-               try {
-                       Server server = new Server(0, false) {
-                               @Override
-                               protected Object onRequest(ConnectActionServer action,
-                                               Version clientVersion, Object data) throws Exception {
-                                       return null;
-                               }
-                       };
-               } catch (Exception e) {
-               }
-       }
-
        private SerialTest() {
                super("Serial test", null);
        }
 
-       private TestCase[] createServerTestCases(final boolean ssl) {
+       private TestLauncher createServerTestCases(final String[] args,
+                       final boolean ssl) {
                final String ssls = (ssl ? "(ssl)" : "(plain text)");
-               return new TestCase[] {
-                               new TestCase("Client/Server simple connection " + ssls) {
+               TestLauncher series = new TestLauncher("Client/Server " + ssls, args);
+
+               series.addTest(new TestCase("Simple connection " + ssls) {
+                       @Override
+                       public void test() throws Exception {
+                               final Object[] rec = new Object[1];
+
+                               Server server = new Server(this.getName(), 0, ssl) {
                                        @Override
-                                       public void test() throws Exception {
-                                               final Object[] rec = new Object[1];
-
-                                               Server server = new Server("testy", 0, ssl) {
-                                                       @Override
-                                                       protected Object onRequest(
-                                                                       ConnectActionServer action,
-                                                                       Version clientVersion, Object data)
-                                                                       throws Exception {
-                                                               return null;
-                                                       }
-                                               };
-
-                                               assertEquals("A port should have been assigned", true,
-                                                               server.getPort() > 0);
-
-                                               server.start();
-
-                                               try {
-                                                       new ConnectActionClient(null, server.getPort(), ssl) {
-                                                               @Override
-                                                               public void action(Version serverVersion)
-                                                                               throws Exception {
-                                                                       rec[0] = true;
-                                                               }
-                                                       }.connect();
-                                               } finally {
-                                                       server.stop();
+                                       protected Object onRequest(ConnectActionServer action,
+                                                       Version clientVersion, Object data)
+                                                       throws Exception {
+                                               return null;
+                                       }
+                               };
+
+                               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) {
+                                               @Override
+                                               public void action(Version serverVersion)
+                                                               throws Exception {
+                                                       rec[0] = true;
                                                }
+                                       }.connect();
+                               } finally {
+                                       server.stop();
+                               }
 
-                                               assertNotNull("The client action was not run", rec[0]);
-                                               assertEquals(true, (boolean) ((Boolean) rec[0]));
+                               assertNotNull("The client action was not run", rec[0]);
+                               assertEquals(true, (boolean) ((Boolean) rec[0]));
+                       }
+               });
+
+               series.addTest(new TestCase("Simple exchange " + ssls) {
+                       final Object[] sent = new Object[1];
+                       final Object[] recd = new Object[1];
+                       final Exception[] err = new Exception[1];
+
+                       @Override
+                       public void test() throws Exception {
+                               Server server = new Server(this.getName(), 0, ssl) {
+                                       @Override
+                                       protected Object onRequest(ConnectActionServer action,
+                                                       Version clientVersion, Object data)
+                                                       throws Exception {
+                                               sent[0] = data;
+                                               return "pong";
                                        }
-                               }, //
-                               new TestCase("Client/Server simple exchange " + ssls) {
-                                       final Object[] rec = new Object[3];
 
                                        @Override
-                                       public void test() throws Exception {
-                                               Server server = new Server("testy", 0, ssl) {
-                                                       @Override
-                                                       protected Object onRequest(
-                                                                       ConnectActionServer action,
-                                                                       Version clientVersion, Object data)
-                                                                       throws Exception {
-                                                               rec[0] = data;
-                                                               return "pong";
-                                                       }
+                                       protected void onError(Exception e) {
+                                               super.onError(e);
+                                               err[0] = e;
+                                       }
+                               };
 
-                                                       @Override
-                                                       protected void onError(Exception e) {
-                                                               super.onError(e);
-                                                               rec[2] = e;
-                                                       }
-                                               };
-
-                                               assertEquals("A port should have been assigned", true,
-                                                               server.getPort() > 0);
-
-                                               server.start();
-
-                                               try {
-                                                       new ConnectActionClient(null, server.getPort(), ssl) {
-                                                               @Override
-                                                               public void action(Version serverVersion)
-                                                                               throws Exception {
-                                                                       rec[1] = send("ping");
-                                                               }
-                                                       }.connect();
-                                               } finally {
-                                                       server.stop();
-                                               }
+                               server.start();
 
-                                               if (rec[2] != null) {
-                                                       fail("An exception was thrown: "
-                                                                       + ((Exception) rec[2]).getMessage());
+                               try {
+                                       new ConnectActionClient(null, server.getPort(), ssl) {
+                                               @Override
+                                               public void action(Version serverVersion)
+                                                               throws Exception {
+                                                       recd[0] = send("ping");
                                                }
+                                       }.connect();
+                               } finally {
+                                       server.stop();
+                               }
 
-                                               assertEquals("ping", rec[0]);
-                                               assertEquals("pong", rec[1]);
+                               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 Object[] sent = new Object[3];
+                       final Object[] recd = new Object[3];
+                       final Exception[] err = new Exception[1];
+
+                       @Override
+                       public void test() throws Exception {
+                               Server server = new Server(this.getName(), 0, ssl) {
+                                       @Override
+                                       protected Object onRequest(ConnectActionServer action,
+                                                       Version clientVersion, Object data)
+                                                       throws Exception {
+                                               sent[0] = data;
+                                               action.send("pong");
+                                               sent[1] = action.flush();
+                                               return "pong2";
                                        }
-                               }, //
-                               new TestCase("Client/Server multiple exchanges " + ssls) {
-                                       final Object[] sent = new Object[3];
-                                       final Object[] recd = new Object[3];
-                                       final Exception[] err = new Exception[1];
 
                                        @Override
-                                       public void test() throws Exception {
-                                               Server server = new Server("testy", 0, ssl) {
-                                                       @Override
-                                                       protected Object onRequest(
-                                                                       ConnectActionServer action,
-                                                                       Version clientVersion, Object data)
-                                                                       throws Exception {
-                                                               sent[0] = data;
-                                                               action.send("pong");
-                                                               sent[1] = action.flush();
-                                                               return "pong2";
-                                                       }
+                                       protected void onError(Exception e) {
+                                               super.onError(e);
+                                               err[0] = e;
+                                       }
+                               };
 
-                                                       @Override
-                                                       protected void onError(Exception e) {
-                                                               super.onError(e);
-                                                               err[0] = e;
-                                                       }
-                                               };
-
-                                               server.start();
-
-                                               try {
-                                                       new ConnectActionClient(null, server.getPort(), ssl) {
-                                                               @Override
-                                                               public void action(Version serverVersion)
-                                                                               throws Exception {
-                                                                       recd[0] = send("ping");
-                                                                       recd[1] = send("ping2");
-                                                               }
-                                                       }.connect();
-                                               } finally {
-                                                       server.stop();
-                                               }
+                               server.start();
 
-                                               if (err[0] != null) {
-                                                       fail("An exception was thrown: "
-                                                                       + err[0].getMessage());
+                               try {
+                                       new ConnectActionClient(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 Object[] sent = new Object[3];
+                       final Object[] recd = new Object[3];
+                       final Exception[] err = new Exception[1];
 
-                                               assertEquals("ping", sent[0]);
-                                               assertEquals("pong", recd[0]);
-                                               assertEquals("ping2", sent[1]);
-                                               assertEquals("pong2", recd[1]);
+                       @Override
+                       public void test() throws Exception {
+                               Server server = new Server(this.getName(), 0, ssl) {
+                                       @Override
+                                       protected Object onRequest(ConnectActionServer action,
+                                                       Version clientVersion, Object data)
+                                                       throws Exception {
+                                               sent[(Integer) data] = data;
+                                               return ((Integer) data) * 2;
                                        }
-                               }, //
-                               new TestCase("Client/Server multiple call from client " + ssls) {
-                                       final Object[] sent = new Object[3];
-                                       final Object[] recd = new Object[3];
-                                       final Exception[] err = new Exception[1];
 
                                        @Override
-                                       public void test() throws Exception {
-                                               Server server = new Server("testy", 0, ssl) {
-                                                       @Override
-                                                       protected Object onRequest(
-                                                                       ConnectActionServer action,
-                                                                       Version clientVersion, Object data)
-                                                                       throws Exception {
-                                                               sent[(Integer) data] = data;
-                                                               return ((Integer) data) * 2;
-                                                       }
+                                       protected void onError(Exception e) {
+                                               super.onError(e);
+                                               err[0] = e;
+                                       }
+                               };
+
+                               server.start();
 
-                                                       @Override
-                                                       protected void onError(Exception e) {
-                                                               super.onError(e);
-                                                               err[0] = e;
+                               try {
+                                       new ConnectActionClient(null, server.getPort(), ssl) {
+                                               @Override
+                                               public void action(Version serverVersion)
+                                                               throws Exception {
+                                                       for (int i = 0; i < 3; i++) {
+                                                               recd[i] = send(i);
                                                        }
-                                               };
-
-                                               server.start();
-
-                                               try {
-                                                       new ConnectActionClient(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();
                                                }
+                                       }.connect();
+                               } finally {
+                                       server.stop();
+                               }
 
-                                               if (err[0] != null) {
-                                                       fail("An exception was thrown: "
-                                                                       + err[0].getMessage());
-                                               }
+                               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]);
-                                       }
-                               }, //
-               };
+                               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;
        }
 
        public SerialTest(String[] args) {
                super("Serial test", args);
 
-               for (TestCase test : createServerTestCases(false)) {
-                       addTest(test);
-               }
+               addSeries(createServerTestCases(args, false));
 
-               for (TestCase test : createServerTestCases(true)) {
-                       addTest(test);
-               }
+               addSeries(createServerTestCases(args, true));
 
                addTest(new TestCase("Simple class Import/Export") {
                        @Override