Amélioration librairie réseau et ajout de packet pour PandacubeWeb
This commit is contained in:
		| @@ -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(); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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.<br/> | ||||
| 	 * 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); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
| /** <pre> | ||||
|  * 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) | ||||
|  * </pre> | ||||
|  */ | ||||
| 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 <T extends Packet> void addPacket(Class<T> 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); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
| @@ -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; | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -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; | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -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(); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user