diff --git a/src/fr/pandacube/java/util/network/client/TCPClient.java b/src/fr/pandacube/java/util/network/client/TCPClient.java
index 4f82ef1..544ad21 100644
--- a/src/fr/pandacube/java/util/network/client/TCPClient.java
+++ b/src/fr/pandacube/java/util/network/client/TCPClient.java
@@ -7,10 +7,10 @@ import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
-import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.logging.Level;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
import fr.pandacube.java.Pandacube;
import fr.pandacube.java.util.Log;
@@ -18,6 +18,7 @@ import fr.pandacube.java.util.network.packet.Packet;
import fr.pandacube.java.util.network.packet.PacketClient;
import fr.pandacube.java.util.network.packet.PacketException;
import fr.pandacube.java.util.network.packet.PacketServer;
+import fr.pandacube.java.util.network.packet.packets.global.PacketServerException;
public class TCPClient extends Thread implements Closeable {
@@ -40,7 +41,11 @@ public class TCPClient extends Thread implements Closeable {
socket.connect(a);
addr = a;
listener = l;
- listener.onConnect(this);
+ try {
+ listener.onConnect(this);
+ } catch (Exception e) {
+ Log.severe("Exception while calling TCPClientListener.onConnect()", e);
+ }
}
@Override
@@ -61,28 +66,35 @@ public class TCPClient extends Thread implements Closeable {
byte[] packetData = ByteBuffer.allocate(1 + 4 + size).put(code).put(sizeB).put(content).array();
try {
- if (listener == null) throw new InvalidServerMessage(
- "Le serveur ne peut actuellement pas prendre en charge de nouvelles requêtes. Les listeners n'ont pas encore été définis");
-
+
Packet p = Packet.constructPacket(packetData);
- if (!(p instanceof PacketServer)) throw new InvalidServerMessage(
- "Le type de packet reçu n'est pas un packet attendu : " + p.getClass().getCanonicalName());
+ if (!(p instanceof PacketServer))
+ throw new PacketException(p.getClass().getCanonicalName() + " is not a subclass of PacketServer");
+
+ if (p instanceof PacketServerException) {
+ try {
+ listener.onServerException(this, ((PacketServerException)p).getExceptionString());
+ } catch (Exception e) {
+ Log.severe("Exception while calling TCPClientListener.onPacketReceive()", e);
+ }
+ }
+
PacketServer ps = (PacketServer) p;
- listener.onPacketReceive(this, ps);
- } catch (PacketException | InvalidServerMessage e) {
- Log.getLogger().log(Level.SEVERE, "Message du serveur mal formé", e);
+ try {
+ listener.onPacketReceive(this, ps);
+ } catch (Exception e) {
+ Log.severe("Exception while calling TCPClientListener.onPacketReceive()", e);
+ }
} catch (Exception e) {
- Log.getLogger().log(Level.SEVERE, "Erreur lors de la prise en charge du message par le serveur", e);
+ Log.severe("Exception while handling packet from server", e);
}
}
- } catch (SocketTimeoutException e) {
- System.err.println("Le serveur a prit trop de temps à répondre");
} catch (Exception e) {
- e.printStackTrace();
+ Log.severe(e);
}
close();
}
@@ -110,10 +122,15 @@ public class TCPClient extends Thread implements Closeable {
if (isClosed.get()) return;
socket.close();
isClosed.set(true);
- listener.onDisconnect(this);
+
+ try {
+ listener.onDisconnect(this);
+ } catch (Exception e) {
+ Log.severe("Exception while calling TCPClientListener.onDisconnect()", e);
+ }
}
} catch (IOException e) {
- e.printStackTrace();
+ Log.warning(e);
}
}
@@ -130,13 +147,12 @@ public class TCPClient extends Thread implements Closeable {
public boolean isClosed() {
return isClosed.get() || socket.isClosed();
}
-
- public static class InvalidServerMessage extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- public InvalidServerMessage(String message) {
- super(message);
- }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("thread", getName())
+ .append("socket", socket.getRemoteSocketAddress()).toString();
}
}
diff --git a/src/fr/pandacube/java/util/network/client/TCPClientListener.java b/src/fr/pandacube/java/util/network/client/TCPClientListener.java
index 13ef999..4b1615d 100644
--- a/src/fr/pandacube/java/util/network/client/TCPClientListener.java
+++ b/src/fr/pandacube/java/util/network/client/TCPClientListener.java
@@ -1,13 +1,42 @@
package fr.pandacube.java.util.network.client;
+import fr.pandacube.java.util.Log;
import fr.pandacube.java.util.network.packet.PacketServer;
public interface TCPClientListener {
+ /**
+ * Called when a connection is opened
+ * @param connection the connection which is opening
+ */
public void onConnect(TCPClient connection);
+
+ /**
+ * Called when the server send us a PacketServerException when an exception is thrown
+ * server side when handling our packets or eventually when the client is concerned
+ * with this error.
+ * The default implementation of this method just call the internal Logger of PandacubeUtil
+ * to print the stacktrace of the Exception.
+ * @param connection the connection which just received the error
+ * @param exceptionString a string representation of the exception. If the server
+ * use this Java library, it may be a full representation of
+ * {@link Throwable#printStackTrace()}.
+ */
+ public default void onServerException(TCPClient connection, String exceptionString) {
+ Log.severe("Exception thrown by server through " + connection + " : \n"+exceptionString);
+ }
+ /**
+ * Called when the server send us a packet
+ * @param connection the connection where the packet come from
+ * @param packet the packet
+ */
public void onPacketReceive(TCPClient connection, PacketServer packet);
+ /**
+ * Called before the connection closed
+ * @param connection the connection which is closing
+ */
public void onDisconnect(TCPClient connection);
}
diff --git a/src/fr/pandacube/java/util/network/packet/Packet.java b/src/fr/pandacube/java/util/network/packet/Packet.java
index fda089e..c125c71 100644
--- a/src/fr/pandacube/java/util/network/packet/Packet.java
+++ b/src/fr/pandacube/java/util/network/packet/Packet.java
@@ -6,9 +6,31 @@ import java.util.HashMap;
import java.util.Map;
import fr.pandacube.java.Pandacube;
+import fr.pandacube.java.util.Log;
import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
import fr.pandacube.java.util.network.packet.bytebuffer.ByteSerializable;
+import fr.pandacube.java.util.network.packet.packets.global.PacketServerException;
+import fr.pandacube.java.util.network.packet.packets.web.PacketClientWebRequest;
+import fr.pandacube.java.util.network.packet.packets.web.PacketServerWebResponse;
+/**
+ * Identification des packets réseaux
+ * byte (xxxxxxxx)
+ * client : server :
+ * clt / sv (x-------) (0-------) (1-------)
+ * 0x00 - 0x7F 0x80 - 0xFF
+ * use case (-xxx----)
+ * - web (-000----) 0x00 - 0x0F 0x80 - 0x8F (client is Apache, server is PandacubeCore master (PandacubeWeb))
+ * - spigot (-001----) 0x10 - 0x1F 0x90 - 0x9F (client is PandacubeSpigot, server is PandacubeCore master)
+ * - bungee (-010----) 0x20 - 0x2F 0xA0 - 0xAF (client is PandacubeBungee, server is PandacubeCore master)
+ * - global (-101----) 0x50 - 0x5F 0xD0 - 0xDF
+ *
+ * - reserved if not enough packet id in certain use case
+ * (-11x----) 0x60 - 0x7F 0xE0 - 0xFF
+ *
+ * packet id (----xxxx)
+ *
+ */
public abstract class Packet implements ByteSerializable {
private final byte code;
@@ -34,7 +56,8 @@ public abstract class Packet implements ByteSerializable {
public static Packet constructPacket(byte[] data) {
if (!packetTypes.containsKey(data[0]))
- throw new PacketException("l'identifiant du packet ne correspond à aucun type de packet : " + data[0]);
+ throw new PacketException("Packet identifier not recognized: 0x" + String.format("%02X", data[0])
+ + ". Maybe this packet is not registered with Packet.addPacket()");
try {
Packet p = packetTypes.get(data[0]).newInstance();
@@ -42,27 +65,28 @@ public abstract class Packet implements ByteSerializable {
p.deserializeFromByteBuffer(dataBuffer);
return p;
} catch (Exception e) {
- e.printStackTrace();
- throw new PacketException("erreur lors de la construction du packet");
+ throw new PacketException("Error while constructing packet", e);
}
}
- @SuppressWarnings("unused")
private static void addPacket(Class packetClass) {
try {
Packet p = packetClass.newInstance();
packetTypes.put(p.code, packetClass);
} catch (Exception e) {
- e.printStackTrace();
+ Log.severe(e);
}
}
+
static {
/*
* Ajout des types de packets (client + serveur)
*/
- // addPacket(PacketToto.class);
+ addPacket(PacketClientWebRequest.class);
+ addPacket(PacketServerWebResponse.class);
+ addPacket(PacketServerException.class);
}
}
diff --git a/src/fr/pandacube/java/util/network/packet/PacketException.java b/src/fr/pandacube/java/util/network/packet/PacketException.java
index 463c0de..355cb6e 100644
--- a/src/fr/pandacube/java/util/network/packet/PacketException.java
+++ b/src/fr/pandacube/java/util/network/packet/PacketException.java
@@ -1,5 +1,12 @@
package fr.pandacube.java.util.network.packet;
+/**
+ *
+ * Thrown when there is a problem when constructing, sending or handling a packet.
+ *
+ * Only the server may send a string representation of an exception to the client, not the reverse
+ *
+ */
public class PacketException extends RuntimeException {
private static final long serialVersionUID = 1L;
diff --git a/src/fr/pandacube/java/util/network/packet/packets/global/PacketServerException.java b/src/fr/pandacube/java/util/network/packet/packets/global/PacketServerException.java
new file mode 100644
index 0000000..64f4d13
--- /dev/null
+++ b/src/fr/pandacube/java/util/network/packet/packets/global/PacketServerException.java
@@ -0,0 +1,39 @@
+package fr.pandacube.java.util.network.packet.packets.global;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import fr.pandacube.java.util.network.packet.PacketServer;
+import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
+
+public class PacketServerException extends PacketServer {
+
+ private String exception;
+
+ public PacketServerException() {
+ super((byte)0xE0);
+ }
+
+ @Override
+ public void serializeToByteBuffer(ByteBuffer buffer) {
+ buffer.putString(exception);
+ }
+
+ @Override
+ public void deserializeFromByteBuffer(ByteBuffer buffer) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setException(Exception e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ exception = sw.toString();
+ }
+
+ public String getExceptionString() {
+ return exception;
+ }
+
+}
diff --git a/src/fr/pandacube/java/util/network/packet/packets/web/PacketClientWebRequest.java b/src/fr/pandacube/java/util/network/packet/packets/web/PacketClientWebRequest.java
new file mode 100644
index 0000000..5a1a174
--- /dev/null
+++ b/src/fr/pandacube/java/util/network/packet/packets/web/PacketClientWebRequest.java
@@ -0,0 +1,43 @@
+package fr.pandacube.java.util.network.packet.packets.web;
+
+import fr.pandacube.java.util.network.packet.PacketClient;
+import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
+
+public class PacketClientWebRequest extends PacketClient {
+
+ private String password;
+ private String jsonData;
+
+ public PacketClientWebRequest() {
+ super((byte)0x00);
+ }
+
+ @Override
+ public void serializeToByteBuffer(ByteBuffer buffer) {
+ buffer.putString(password);
+ buffer.putString(jsonData);
+ }
+
+ @Override
+ public void deserializeFromByteBuffer(ByteBuffer buffer) {
+ password = buffer.getString();
+ jsonData = buffer.getString();
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getJsonData() {
+ return jsonData;
+ }
+
+ public void setJsonData(String jsonData) {
+ this.jsonData = jsonData;
+ }
+
+}
diff --git a/src/fr/pandacube/java/util/network/packet/packets/web/PacketServerWebResponse.java b/src/fr/pandacube/java/util/network/packet/packets/web/PacketServerWebResponse.java
new file mode 100644
index 0000000..b15c977
--- /dev/null
+++ b/src/fr/pandacube/java/util/network/packet/packets/web/PacketServerWebResponse.java
@@ -0,0 +1,32 @@
+package fr.pandacube.java.util.network.packet.packets.web;
+
+import fr.pandacube.java.util.network.packet.PacketServer;
+import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
+
+public class PacketServerWebResponse extends PacketServer {
+
+ private String jsonData;
+
+ public PacketServerWebResponse() {
+ super((byte)0x80);
+ }
+
+ @Override
+ public void serializeToByteBuffer(ByteBuffer buffer) {
+ buffer.putString(jsonData);
+ }
+
+ @Override
+ public void deserializeFromByteBuffer(ByteBuffer buffer) {
+ jsonData = buffer.getString();
+ }
+
+ public String getJsonData() {
+ return jsonData;
+ }
+
+ public void setJsonData(String jsonData) {
+ this.jsonData = jsonData;
+ }
+
+}
diff --git a/src/fr/pandacube/java/util/network/server/TCPServer.java b/src/fr/pandacube/java/util/network/server/TCPServer.java
index 2a28ab0..18a6f3a 100644
--- a/src/fr/pandacube/java/util/network/server/TCPServer.java
+++ b/src/fr/pandacube/java/util/network/server/TCPServer.java
@@ -17,12 +17,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
import fr.pandacube.java.Pandacube;
import fr.pandacube.java.util.Log;
import fr.pandacube.java.util.network.packet.Packet;
import fr.pandacube.java.util.network.packet.PacketClient;
+import fr.pandacube.java.util.network.packet.PacketException;
import fr.pandacube.java.util.network.packet.PacketServer;
import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
+import fr.pandacube.java.util.network.packet.packets.global.PacketServerException;
/**
*
@@ -50,7 +54,11 @@ public class TCPServer extends Thread implements Closeable {
socket.setPerformancePreferences(0, 2, 1);
socket.bind(new InetSocketAddress(port));
listener = l;
- listener.onSocketOpen(this);
+ try {
+ listener.onSocketOpen(this);
+ } catch(Exception e) {
+ Log.severe("Exception while calling TCPServerListener.onSocketOpen()", e);
+ }
socketName = sckName;
}
@@ -67,7 +75,6 @@ public class TCPServer extends Thread implements Closeable {
TCPServerClientConnection co = new TCPServerClientConnection(socketClient,
connectionCounterId.getAndIncrement());
clients.add(co);
- listener.onClientConnect(this, co);
co.start();
} catch (IOException e) {
Log.getLogger().log(Level.SEVERE, "Connexion impossible avec " + socketClient.getInetAddress());
@@ -91,7 +98,11 @@ public class TCPServer extends Thread implements Closeable {
in = socket.getInputStream();
out = socket.getOutputStream();
address = new InetSocketAddress(socket.getInetAddress(), socket.getPort());
- listener.onClientConnect(TCPServer.this, this);
+ try {
+ listener.onClientConnect(TCPServer.this, this);
+ } catch(Exception e) {
+ Log.severe("Exception while calling TCPServerListener.onClientConnect()", e);
+ }
outThread = new TCPServerConnectionOutputThread(coId);
outThread.start();
}
@@ -102,7 +113,7 @@ public class TCPServer extends Thread implements Closeable {
byte[] code = new byte[1];
while (!socket.isClosed() && in.read(code) != -1) {
byte[] sizeB = new byte[4];
- if (in.read(sizeB) != 4) throw new IOException("Socket " + address + " fermé");
+ if (in.read(sizeB) != 4) throw new IOException("Socket " + address + " closed");
int size = new ByteBuffer(sizeB, Packet.CHARSET).getInt();
@@ -117,17 +128,16 @@ public class TCPServer extends Thread implements Closeable {
try {
interpreteReceivedMessage(this, packetData);
- } catch (InvalidClientMessage e) {
- Log.getLogger().log(Level.SEVERE, "Erreur protocole de : ", e);
} catch (Exception e) {
- Log.getLogger().log(Level.SEVERE, "Erreur lors de la prise en charge du message par le serveur",
- e);
- e.printStackTrace();
+ Log.severe("Exception while handling packet. This exception will be sent to the client with PacketServerException packet.", e);
+ PacketServerException packet = new PacketServerException();
+ packet.setException(e);
+ send(packet);
}
}
} catch (Exception e) {
- Log.getLogger().log(Level.SEVERE, "Fermeture de la connexion de " + address, e);
+ Log.severe("Closing connection " + address, e);
}
close();
@@ -149,7 +159,11 @@ public class TCPServer extends Thread implements Closeable {
public void close() {
if (socket.isClosed()) return;
- listener.onClientDisconnect(TCPServer.this, this);
+ try {
+ listener.onClientDisconnect(TCPServer.this, this);
+ } catch(Exception e) {
+ Log.severe("Exception while calling TCPServerListener.onClientDisconnect()", e);
+ }
clients.remove(this);
try {
@@ -163,9 +177,7 @@ public class TCPServer extends Thread implements Closeable {
});
// provoque une exception dans le thread de sortie, et la
// termine
- } catch (IOException e) {
- e.printStackTrace();
- }
+ } catch (IOException e) { }
}
private class TCPServerConnectionOutputThread extends Thread {
@@ -200,18 +212,30 @@ public class TCPServer extends Thread implements Closeable {
}
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("thread", getName())
+ .append("socket", socket).toString();
+ }
+
}
private void interpreteReceivedMessage(TCPServerClientConnection co, byte[] data) {
Packet p = Packet.constructPacket(data);
- if (!(p instanceof PacketClient)) throw new InvalidClientMessage(
- "Le type de packet reçu n'est pas un packet attendu : " + p.getClass().getCanonicalName());
+ if (!(p instanceof PacketClient))
+ throw new PacketException(p.getClass().getCanonicalName() + " is not an instanceof PacketClient");
PacketClient pc = (PacketClient) p;
- listener.onPacketReceive(this, co, pc);
+ try {
+ listener.onPacketReceive(this, co, pc);
+ } catch(Exception e) {
+ Log.severe("Exception while calling TCPServerListener.onPacketReceive()", e);
+ }
}
@Override
@@ -223,20 +247,25 @@ public class TCPServer extends Thread implements Closeable {
socket.close();
isClosed.set(true);
- listener.onSocketClose(this);
+ try {
+ listener.onSocketClose(this);
+ } catch(Exception e) {
+ Log.severe("Exception while calling TCPServerListener.onSocketClose()", e);
+ }
} catch (IOException e) {}
}
public boolean isClosed() {
return isClosed.get() || socket.isClosed();
}
+
- public static class InvalidClientMessage extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- public InvalidClientMessage(String message) {
- super(message);
- }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("thread", getName())
+ .append("socket", socket).toString();
}
}