renamed modules dir
This commit is contained in:
22
pandalib-netapi/pom.xml
Normal file
22
pandalib-netapi/pom.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pandalib-parent</artifactId>
|
||||
<groupId>fr.pandacube.lib</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>pandalib-netapi</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>fr.pandacube.lib</groupId>
|
||||
<artifactId>pandalib-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@@ -0,0 +1,29 @@
|
||||
package fr.pandacube.lib.netapi.client;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public abstract class AbstractRequest {
|
||||
|
||||
private final String pass;
|
||||
private final String command;
|
||||
private String data;
|
||||
|
||||
protected AbstractRequest(String cmd, String p) {
|
||||
if (cmd == null || cmd.isEmpty()) throw new IllegalArgumentException("Un message doit-être défini");
|
||||
command = cmd;
|
||||
pass = p;
|
||||
}
|
||||
|
||||
protected void setData(String d) {
|
||||
if (d == null) d = "";
|
||||
data = d;
|
||||
}
|
||||
|
||||
public void sendPacket(PrintStream out) {
|
||||
out.print(pass + "\n");
|
||||
out.print(command + "\n");
|
||||
out.print(data.getBytes().length + "\n");
|
||||
out.print(data);
|
||||
out.flush();
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package fr.pandacube.lib.netapi.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
public class NetworkAPISender {
|
||||
|
||||
public static ResponseAnalyser sendRequest(InetSocketAddress cible, AbstractRequest request) throws IOException {
|
||||
Socket s = new Socket(cible.getAddress(), cible.getPort());
|
||||
|
||||
PrintStream out = new PrintStream(s.getOutputStream());
|
||||
|
||||
request.sendPacket(out);
|
||||
s.shutdownOutput();
|
||||
|
||||
ResponseAnalyser response = new ResponseAnalyser(s);
|
||||
|
||||
s.close();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package fr.pandacube.lib.netapi.client;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.Socket;
|
||||
|
||||
public class ResponseAnalyser {
|
||||
/**
|
||||
* Indique si la requête s'est bien exécutée (l'entête de la réponse est
|
||||
* 'ok')
|
||||
*/
|
||||
public final boolean good;
|
||||
|
||||
public final String data;
|
||||
|
||||
public ResponseAnalyser(Socket socket) throws IOException {
|
||||
if (socket == null || socket.isClosed() || socket.isInputShutdown())
|
||||
throw new IllegalArgumentException("le socket doit être non null et doit être ouvert sur le flux d'entrée");
|
||||
|
||||
// on lis la réponse
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
String line;
|
||||
|
||||
// lecture de la première ligne
|
||||
line = in.readLine();
|
||||
if (line == null)
|
||||
throw new IOException("Not enough data to read first line of response.");
|
||||
good = line.equalsIgnoreCase("OK");
|
||||
|
||||
// lecture de la deuxième ligne
|
||||
line = in.readLine();
|
||||
if (line == null)
|
||||
throw new IOException("Not enough data to read second line of response.");
|
||||
|
||||
int data_size;
|
||||
try {
|
||||
data_size = Integer.parseInt(line);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RuntimeException("Réponse mal formée : la deuxième ligne doit-être un nombre entier");
|
||||
}
|
||||
|
||||
// lecture du reste
|
||||
StringBuilder sB_data = new StringBuilder();
|
||||
char[] c = new char[100];
|
||||
int nbC;
|
||||
while ((nbC = in.read(c)) != -1)
|
||||
sB_data.append(c, 0, nbC);
|
||||
data = sB_data.toString();
|
||||
|
||||
if (data.getBytes().length != data_size) throw new RuntimeException("Réponse mal formée : " + data_size
|
||||
+ " caractères annoncée dans la requête, mais " + data.getBytes().length + " s'y trouvent.");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package fr.pandacube.lib.netapi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
public abstract class AbstractRequestExecutor {
|
||||
|
||||
public final String command;
|
||||
|
||||
public AbstractRequestExecutor(String cmd, NetworkAPIListener napiListener) {
|
||||
command = cmd.toLowerCase();
|
||||
napiListener.registerRequestExecutor(command, this);
|
||||
}
|
||||
|
||||
public void execute(String data, Socket socket) throws IOException {
|
||||
if (socket == null || socket.isClosed() || socket.isOutputShutdown())
|
||||
throw new IllegalArgumentException("le socket doit être non null et doit être ouvert sur le flux d'entrée");
|
||||
|
||||
try {
|
||||
|
||||
Response rep = run(socket.getInetAddress(), data);
|
||||
rep.sendPacket(new PrintStream(socket.getOutputStream()));
|
||||
|
||||
} catch (Exception e) {
|
||||
new Response(false, e.toString()).sendPacket(new PrintStream(socket.getOutputStream()));
|
||||
Log.severe(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data La représentation sous forme de String des données envoyés
|
||||
* dans la requête
|
||||
* @return La réponse à retourner au client
|
||||
*/
|
||||
protected abstract Response run(InetAddress source, String data);
|
||||
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
package fr.pandacube.lib.netapi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
public class NetworkAPIListener implements Runnable {
|
||||
|
||||
private final int port;
|
||||
final String pass;
|
||||
private ServerSocket serverSocket;
|
||||
private final HashMap<String, AbstractRequestExecutor> requestExecutors = new HashMap<>();
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Instencie le côté serveur du NetworkAPI
|
||||
*
|
||||
* @param n nom du networkAPI (permet l'identification dans les logs)
|
||||
* @param p le port d'écoute
|
||||
* @param pa le mot de passe réseau
|
||||
*/
|
||||
public NetworkAPIListener(String n, int p, String pa) {
|
||||
port = p;
|
||||
pass = pa;
|
||||
name = n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (this) {
|
||||
try {
|
||||
serverSocket = new ServerSocket(port);
|
||||
} catch (IOException e) {
|
||||
System.err.println(e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log.info("NetworkAPI '" + name + "' à l'écoute sur le port " + port);
|
||||
|
||||
try {
|
||||
// réception des connexion client
|
||||
while (!serverSocket.isClosed()) {
|
||||
Thread t = new Thread(new PacketExecutor(serverSocket.accept(), this));
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
|
||||
synchronized (this) {
|
||||
try {
|
||||
if (!serverSocket.isClosed())
|
||||
serverSocket.close();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
Log.info("NetworkAPI '" + name + "' ferme le port " + port);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ferme le ServerSocket. Ceci provoque l'arrêt du thread associé à
|
||||
* l'instance de la classe
|
||||
*/
|
||||
public synchronized void closeServerSocket() {
|
||||
if (serverSocket != null) try {
|
||||
serverSocket.close();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void registerRequestExecutor(String command, AbstractRequestExecutor executor) {
|
||||
requestExecutors.put(command, executor);
|
||||
}
|
||||
|
||||
public AbstractRequestExecutor getRequestExecutor(String command) {
|
||||
return requestExecutors.get(command);
|
||||
}
|
||||
|
||||
public String getCommandList() {
|
||||
return Arrays.toString(requestExecutors.keySet().toArray());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
package fr.pandacube.lib.netapi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import fr.pandacube.lib.netapi.server.RequestAnalyser.BadRequestException;
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
/**
|
||||
* Prends en charge un socket client et le transmet au gestionnaire de paquet
|
||||
* correspondant.<br/>
|
||||
* La connexion est fermée après chaque requête du client (règle pouvant
|
||||
* évoluer)
|
||||
*
|
||||
* @author Marc Baloup
|
||||
*
|
||||
*/
|
||||
public class PacketExecutor implements Runnable {
|
||||
private final Socket socket;
|
||||
private final NetworkAPIListener networkAPIListener;
|
||||
|
||||
public PacketExecutor(Socket s, NetworkAPIListener napiListener) {
|
||||
socket = s;
|
||||
networkAPIListener = napiListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
// analyse de la requête
|
||||
RequestAnalyser analyse = new RequestAnalyser(socket, networkAPIListener);
|
||||
|
||||
AbstractRequestExecutor executor = networkAPIListener.getRequestExecutor(analyse.command);
|
||||
|
||||
executor.execute(analyse.data, socket);
|
||||
|
||||
} catch (Throwable e) {
|
||||
Response rep = new Response();
|
||||
rep.good = false;
|
||||
rep.data = e.toString();
|
||||
try {
|
||||
rep.sendPacket(new PrintStream(socket.getOutputStream()));
|
||||
} catch (IOException ignored) {}
|
||||
if (e instanceof IOException)
|
||||
Log.warning("Unable to read packet from socket " + socket + ": " + e);
|
||||
else if(e instanceof BadRequestException) {
|
||||
if (e.getMessage().equals("wrong_password"))
|
||||
Log.warning("Wrong password received from socket " + socket);
|
||||
else if (e.getMessage().equals("command_not_exists"))
|
||||
Log.severe("The command requested from the socket " + socket + " does not exist");
|
||||
else
|
||||
Log.severe(e);
|
||||
}
|
||||
else
|
||||
Log.severe(e);
|
||||
}
|
||||
|
||||
try {
|
||||
socket.close();
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
package fr.pandacube.lib.netapi.server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.Socket;
|
||||
|
||||
public class RequestAnalyser {
|
||||
|
||||
public final String command;
|
||||
public final String data;
|
||||
|
||||
public RequestAnalyser(Socket socket, NetworkAPIListener napiListener) throws IOException, BadRequestException {
|
||||
if (socket == null || socket.isClosed() || socket.isInputShutdown() || napiListener == null)
|
||||
throw new IllegalArgumentException(
|
||||
"le socket doit être non null et doit être ouvert sur le flux d'entrée et napiListener ne doit pas être null");
|
||||
|
||||
// on lis la réponse
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
String line;
|
||||
|
||||
// lecture de la première ligne
|
||||
line = in.readLine();
|
||||
if (line == null || !line.equals(napiListener.pass)) throw new BadRequestException("wrong_password");
|
||||
|
||||
// lecture de la deuxième ligne
|
||||
line = in.readLine();
|
||||
if (line == null || napiListener.getRequestExecutor(line) == null)
|
||||
throw new BadRequestException("command_not_exists");
|
||||
command = line;
|
||||
|
||||
// lecture de la troisième ligne
|
||||
line = in.readLine();
|
||||
|
||||
int data_size;
|
||||
try {
|
||||
data_size = Integer.parseInt(line);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new BadRequestException("wrong_data_size_format");
|
||||
}
|
||||
|
||||
// lecture du reste
|
||||
StringBuilder sB_data = new StringBuilder();
|
||||
char[] c = new char[100];
|
||||
int nbC;
|
||||
while ((nbC = in.read(c)) != -1)
|
||||
sB_data.append(c, 0, nbC);
|
||||
|
||||
data = sB_data.toString();
|
||||
|
||||
if (data.getBytes().length != data_size) throw new BadRequestException("wrong_data_size");
|
||||
|
||||
socket.shutdownInput();
|
||||
}
|
||||
|
||||
public static class BadRequestException extends Exception {
|
||||
|
||||
public BadRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package fr.pandacube.lib.netapi.server;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class Response {
|
||||
public boolean good = true;
|
||||
public String data = "";
|
||||
|
||||
public Response(boolean good, String data) {
|
||||
this.good = good;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construit une réponse positive avec aucune donnée. Équivaut à
|
||||
* <code>new Response(true, "")</code>
|
||||
*/
|
||||
public Response() {}
|
||||
|
||||
public void sendPacket(PrintStream out) {
|
||||
|
||||
if (data == null) data = "";
|
||||
|
||||
out.print((good ? "OK" : "ERROR") + "\n");
|
||||
out.print(data.getBytes().length + "\n");
|
||||
out.print(data);
|
||||
out.flush();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user