packages communication,observers cleaned and commented
This commit is contained in:
parent
0dcfca4937
commit
15a618ec50
16 changed files with 514 additions and 246 deletions
|
@ -1,38 +1,49 @@
|
||||||
package communication.filetransfer;
|
package communication.filetransfer;
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import observers.ObserverInputMessage;
|
import observers.ObserverInputMessage;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class FileTransferClient {
|
public class FileTransferClient {
|
||||||
|
|
||||||
private int port;
|
private int port;
|
||||||
private ArrayList<File> files = null;
|
private ArrayList<File> files;
|
||||||
private ObserverInputMessage obsInput;
|
private ObserverInputMessage obsInput;
|
||||||
|
|
||||||
|
/**
|
||||||
public FileTransferClient(int port, ArrayList<File> filesToSend, ObserverInputMessage obs) throws UnknownHostException, IOException {
|
* Create a client to transfer one or several files on the specified port of
|
||||||
|
* localhost. A new Thread is created for each file. The files are sent one by
|
||||||
|
* one to save bandwidth and avoid issues.
|
||||||
|
*
|
||||||
|
* @param port The port of localhost on which to send the files.
|
||||||
|
* @param filesToSend The file(s) to send.
|
||||||
|
* @param o The observer to notify each time a file is fully sent.
|
||||||
|
*/
|
||||||
|
public FileTransferClient(int port, ArrayList<File> filesToSend, ObserverInputMessage o) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.files = filesToSend;
|
this.files = filesToSend;
|
||||||
this.obsInput = obs;
|
this.obsInput = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to send every file on localhost on the specified port with a new thread.
|
||||||
|
* An observer is passed to the thread and it is notified each time a file is
|
||||||
|
* fully sent.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
public void sendFiles() throws IOException, InterruptedException {
|
public void sendFiles() throws IOException, InterruptedException {
|
||||||
for(File f: this.files) {
|
for (File f : this.files) {
|
||||||
FileTransferSendingThread ftc = new FileTransferSendingThread(this.port, f,this.obsInput);
|
FileTransferSendingThread ftc = new FileTransferSendingThread(this.port, f, this.obsInput);
|
||||||
ftc.start();
|
ftc.start();
|
||||||
ftc.join();
|
ftc.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package communication.filetransfer;
|
package communication.filetransfer;
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -15,20 +14,31 @@ import messages.MessageFichier;
|
||||||
import observers.ObserverInputMessage;
|
import observers.ObserverInputMessage;
|
||||||
|
|
||||||
public class FileTransferReceivingThread extends Thread {
|
public class FileTransferReceivingThread extends Thread {
|
||||||
|
|
||||||
private SocketChannel sockTransfert;
|
private SocketChannel sockTransfert;
|
||||||
private ObserverInputMessage obsInput;
|
private ObserverInputMessage obsInput;
|
||||||
|
|
||||||
public FileTransferReceivingThread(SocketChannel sock, ObserverInputMessage obs) {
|
/**
|
||||||
|
* Create the thread that will receive one file during a file transfer. This
|
||||||
|
* allows users to write in the chat while sending/receiving files.
|
||||||
|
*
|
||||||
|
* @param sock The SocketChannel returned by ServerSocketChannel.accept().
|
||||||
|
* @param o The observer to notify once the file is fully received.
|
||||||
|
*/
|
||||||
|
public FileTransferReceivingThread(SocketChannel sock, ObserverInputMessage o) {
|
||||||
this.sockTransfert = sock;
|
this.sockTransfert = sock;
|
||||||
this.obsInput = obs;
|
this.obsInput = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
int nbByteRead = 0;
|
int nbByteRead = 0;
|
||||||
|
|
||||||
|
// Buffer to receive a chunk of the file
|
||||||
ByteBuffer fileData = ByteBuffer.allocate(4 * FileTransferUtils.KB_SIZE);
|
ByteBuffer fileData = ByteBuffer.allocate(4 * FileTransferUtils.KB_SIZE);
|
||||||
|
|
||||||
|
// InputStream to read the first object which is a message containing the name
|
||||||
|
// and size of the file
|
||||||
ObjectInputStream inputFileInformation = new ObjectInputStream(
|
ObjectInputStream inputFileInformation = new ObjectInputStream(
|
||||||
this.sockTransfert.socket().getInputStream());
|
this.sockTransfert.socket().getInputStream());
|
||||||
|
|
||||||
|
@ -41,10 +51,11 @@ public class FileTransferReceivingThread extends Thread {
|
||||||
String[] fileInfo = this.processFileInformation(m);
|
String[] fileInfo = this.processFileInformation(m);
|
||||||
String filePath = FileTransferUtils.DOWNLOADS_RELATIVE_PATH + fileInfo[0];
|
String filePath = FileTransferUtils.DOWNLOADS_RELATIVE_PATH + fileInfo[0];
|
||||||
long fileSize = Long.parseLong(fileInfo[1]);
|
long fileSize = Long.parseLong(fileInfo[1]);
|
||||||
|
|
||||||
|
|
||||||
|
// OutputStream to create the file if it does not exist
|
||||||
FileOutputStream fOutStream = new FileOutputStream(filePath);
|
FileOutputStream fOutStream = new FileOutputStream(filePath);
|
||||||
|
|
||||||
|
// Channel to write the data received in the file
|
||||||
FileChannel fileWriter = fOutStream.getChannel();
|
FileChannel fileWriter = fOutStream.getChannel();
|
||||||
|
|
||||||
while (nbTotalBytesRead < fileSize && (nbByteRead = this.sockTransfert.read(fileData)) > 0) {
|
while (nbTotalBytesRead < fileSize && (nbByteRead = this.sockTransfert.read(fileData)) > 0) {
|
||||||
|
@ -58,11 +69,13 @@ public class FileTransferReceivingThread extends Thread {
|
||||||
|
|
||||||
fileWriter.close();
|
fileWriter.close();
|
||||||
fOutStream.close();
|
fOutStream.close();
|
||||||
|
inputFileInformation.close();
|
||||||
|
|
||||||
|
// Process the message to display (thumbnails in the case of images) and notify
|
||||||
|
// the observer
|
||||||
Message mUpdate = FileTransferUtils.processMessageToDisplay(new File(filePath));
|
Message mUpdate = FileTransferUtils.processMessageToDisplay(new File(filePath));
|
||||||
mUpdate.setSender("other");
|
mUpdate.setSender("other");
|
||||||
this.obsInput.update(this, mUpdate);
|
this.obsInput.updateInput(this, mUpdate);
|
||||||
|
|
||||||
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -75,6 +88,13 @@ public class FileTransferReceivingThread extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split the content of a message with the separator ";". This function is only
|
||||||
|
* used to read the name and the size of the file to receive.
|
||||||
|
*
|
||||||
|
* @param m message containing the file's information (name and size).
|
||||||
|
* @return An array with the file's name and the file's size respectively.
|
||||||
|
*/
|
||||||
private String[] processFileInformation(MessageFichier m) {
|
private String[] processFileInformation(MessageFichier m) {
|
||||||
return m.getContenu().split(";");
|
return m.getContenu().split(";");
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,33 +17,46 @@ import messages.MessageFichier;
|
||||||
import messages.Message.TypeMessage;
|
import messages.Message.TypeMessage;
|
||||||
import observers.ObserverInputMessage;
|
import observers.ObserverInputMessage;
|
||||||
|
|
||||||
public class FileTransferSendingThread extends Thread{
|
public class FileTransferSendingThread extends Thread {
|
||||||
|
|
||||||
private SocketChannel sockTransfert;
|
private SocketChannel sockTransfert;
|
||||||
private File file;
|
private File file;
|
||||||
private ObserverInputMessage obsInput;
|
private ObserverInputMessage obsInput;
|
||||||
|
|
||||||
public FileTransferSendingThread(int port, File fileToSend, ObserverInputMessage obs) throws IOException {
|
/**
|
||||||
|
* Create the thread that will send one file during a file transfer. This allows
|
||||||
|
* users to write in the chat while sending/receiving files.
|
||||||
|
*
|
||||||
|
* @param port The port on localhost to which the SocketChannel will connect.
|
||||||
|
* @param fileToSend The file to send.
|
||||||
|
* @param o The observer to notify once the file is fully received.
|
||||||
|
* @throws IOException if the socket's creation fails.
|
||||||
|
*/
|
||||||
|
public FileTransferSendingThread(int port, File fileToSend, ObserverInputMessage o) throws IOException {
|
||||||
SocketChannel sock = SocketChannel.open();
|
SocketChannel sock = SocketChannel.open();
|
||||||
SocketAddress addr = new InetSocketAddress(port);
|
SocketAddress addr = new InetSocketAddress(port);
|
||||||
sock.connect(addr);
|
sock.connect(addr);
|
||||||
this.sockTransfert = sock;
|
this.sockTransfert = sock;
|
||||||
this.file = fileToSend;
|
this.file = fileToSend;
|
||||||
this.obsInput = obs;
|
this.obsInput = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
// Buffer to send a chunk of the file
|
||||||
ByteBuffer fileData = ByteBuffer.allocate(4 * FileTransferUtils.KB_SIZE);
|
ByteBuffer fileData = ByteBuffer.allocate(4 * FileTransferUtils.KB_SIZE);
|
||||||
|
|
||||||
|
// OutputStream to write the first object which is a message containing the name
|
||||||
|
// and size of the file
|
||||||
ObjectOutputStream outputFileInformation = new ObjectOutputStream(
|
ObjectOutputStream outputFileInformation = new ObjectOutputStream(
|
||||||
this.sockTransfert.socket().getOutputStream());
|
this.sockTransfert.socket().getOutputStream());
|
||||||
|
|
||||||
|
// Channel to read the data of the file
|
||||||
FileChannel fileReader = FileChannel.open(Paths.get(file.getPath()));
|
FileChannel fileReader = FileChannel.open(Paths.get(file.getPath()));
|
||||||
String str = file.getName() + ";" + file.getTotalSpace();
|
String str = file.getName() + ";" + file.getTotalSpace();
|
||||||
|
|
||||||
// Send file datas (name + size);
|
// Send file data (name + size);
|
||||||
outputFileInformation.writeObject(new MessageFichier(TypeMessage.FICHIER, str, ""));
|
outputFileInformation.writeObject(new MessageFichier(TypeMessage.FICHIER, str, ""));
|
||||||
|
|
||||||
while (fileReader.read(fileData) > 0) {
|
while (fileReader.read(fileData) > 0) {
|
||||||
|
@ -53,11 +66,14 @@ public class FileTransferSendingThread extends Thread{
|
||||||
}
|
}
|
||||||
|
|
||||||
fileReader.close();
|
fileReader.close();
|
||||||
|
outputFileInformation.close();
|
||||||
|
|
||||||
|
// Process the message to display (thumbnails in the case of images) and notify
|
||||||
|
// the observer
|
||||||
Message mUpdate = FileTransferUtils.processMessageToDisplay(this.file);
|
Message mUpdate = FileTransferUtils.processMessageToDisplay(this.file);
|
||||||
mUpdate.setSender("Moi");
|
mUpdate.setSender("Moi");
|
||||||
this.obsInput.update(this, mUpdate);
|
this.obsInput.updateInput(this, mUpdate);
|
||||||
|
|
||||||
} catch (IOException | MauvaisTypeMessageException e) {
|
} catch (IOException | MauvaisTypeMessageException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -68,7 +84,5 @@ public class FileTransferSendingThread extends Thread{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,21 +8,32 @@ import java.nio.channels.SocketChannel;
|
||||||
|
|
||||||
import observers.ObserverInputMessage;
|
import observers.ObserverInputMessage;
|
||||||
|
|
||||||
|
|
||||||
public class FileTransferServer extends Thread {
|
public class FileTransferServer extends Thread {
|
||||||
|
|
||||||
private ServerSocketChannel sockFTListen;
|
private ServerSocketChannel sockFTListen;
|
||||||
private int nbFile;
|
private int nbFile;
|
||||||
private ObserverInputMessage obsInput;
|
private ObserverInputMessage obsInput;
|
||||||
|
|
||||||
|
/**
|
||||||
public FileTransferServer(int nbFile, ObserverInputMessage obs) throws UnknownHostException, IOException {
|
* Create a server to transfer one or several files. A new socket and thread is
|
||||||
|
* created for each file to receive. The files are received one by one to save
|
||||||
|
* bandwidth and avoid issues.
|
||||||
|
*
|
||||||
|
* @param nbFile The number of file to receive.
|
||||||
|
* @param o The observer to notify once a file is fully received.
|
||||||
|
* @throws UnknownHostException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public FileTransferServer(int nbFile, ObserverInputMessage o) throws UnknownHostException, IOException {
|
||||||
this.sockFTListen = ServerSocketChannel.open();
|
this.sockFTListen = ServerSocketChannel.open();
|
||||||
this.sockFTListen.socket().bind(new InetSocketAddress(0));
|
this.sockFTListen.socket().bind(new InetSocketAddress(0));
|
||||||
this.nbFile = nbFile;
|
this.nbFile = nbFile;
|
||||||
this.obsInput = obs;
|
this.obsInput = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The port binded to the ServerSocketChannel.
|
||||||
|
*/
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
return this.sockFTListen.socket().getLocalPort();
|
return this.sockFTListen.socket().getLocalPort();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,55 +23,76 @@ import messages.Message.TypeMessage;
|
||||||
|
|
||||||
public class FileTransferUtils {
|
public class FileTransferUtils {
|
||||||
|
|
||||||
|
// Relative path of the folder where are put the received files
|
||||||
protected static final String DOWNLOADS_RELATIVE_PATH = "../downloads/";
|
protected static final String DOWNLOADS_RELATIVE_PATH = "../downloads/";
|
||||||
protected static final ArrayList<String> IMAGE_EXTENSIONS = new ArrayList<String>(List.of("tif","tiff","bmp","jpg","jpeg","gif", "png", "eps", "svg"));
|
protected static final ArrayList<String> IMAGE_EXTENSIONS = new ArrayList<String>(
|
||||||
|
List.of("tif", "tiff", "bmp", "jpg", "jpeg", "gif", "png", "eps", "svg"));
|
||||||
protected static final int KB_SIZE = 1024;
|
protected static final int KB_SIZE = 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process what to display on the chat depending on the file sent/received. A
|
||||||
|
* thumbnail will be created in the case of an image, A String with the file's
|
||||||
|
* name will be created otherwise.
|
||||||
|
*
|
||||||
|
* @param file The file to process.
|
||||||
|
* @return A message of which content is either a thumbnail or the file's name.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
protected static MessageFichier processMessageToDisplay(File file) throws IOException {
|
protected static MessageFichier processMessageToDisplay(File file) throws IOException {
|
||||||
String nameFile = file.getName();
|
String nameFile = file.getName();
|
||||||
String extension = processFileExtension(nameFile);
|
String extension = processFileExtension(nameFile);
|
||||||
TypeMessage type;
|
TypeMessage type;
|
||||||
String contenu;
|
String contenu;
|
||||||
|
|
||||||
if(IMAGE_EXTENSIONS.contains(extension)) {
|
if (IMAGE_EXTENSIONS.contains(extension)) {
|
||||||
type = TypeMessage.IMAGE;
|
type = TypeMessage.IMAGE;
|
||||||
BufferedImage img = ImageIO.read(file);
|
BufferedImage img = ImageIO.read(file);
|
||||||
contenu = encodeImage(createThumbnail(img), extension) ;
|
contenu = encodeImage(createThumbnail(img), extension);
|
||||||
|
|
||||||
}else {
|
} else {
|
||||||
type = TypeMessage.FICHIER;
|
type = TypeMessage.FICHIER;
|
||||||
contenu = nameFile;
|
contenu = nameFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//return new MessageFichier(type, contenu, extension);
|
|
||||||
return new MessageFichier(type, contenu, extension);
|
return new MessageFichier(type, contenu, extension);
|
||||||
} catch (MauvaisTypeMessageException e) {
|
} catch (MauvaisTypeMessageException e) {
|
||||||
System.out.println("Should never go in");
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fileName The name of the file (with its extension).
|
||||||
|
* @return The extension of the file.
|
||||||
|
*/
|
||||||
protected static String processFileExtension(String fileName) {
|
protected static String processFileExtension(String fileName) {
|
||||||
String extension = "";
|
String extension = "";
|
||||||
|
|
||||||
int i = fileName.indexOf('.');
|
int i = fileName.indexOf('.');
|
||||||
if (i >= 0 || i != -1) {
|
if (i >= 0 || i != -1) {
|
||||||
extension = fileName.substring(i+1).toLowerCase();
|
extension = fileName.substring(i + 1).toLowerCase();
|
||||||
}
|
}
|
||||||
return extension;
|
return extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
private static BufferedImage createThumbnail(BufferedImage image){
|
* @param image A buffered image.
|
||||||
|
* @return A thumbnail of the image.
|
||||||
|
*/
|
||||||
|
private static BufferedImage createThumbnail(BufferedImage image) {
|
||||||
float w = image.getWidth();
|
float w = image.getWidth();
|
||||||
float ratio = (w > 150) ? (150F/w) : 1;
|
float ratio = (w > 150) ? (150F / w) : 1;
|
||||||
BufferedImage scaled = scale(image, ratio);
|
BufferedImage scaled = scale(image, ratio);
|
||||||
return scaled;
|
return scaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param img A buffered image.
|
||||||
|
* @param extension The extension of the image.
|
||||||
|
* @return The base64 encoded string corresponding to the given image.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private static String encodeImage(BufferedImage img, String extension) throws IOException {
|
private static String encodeImage(BufferedImage img, String extension) throws IOException {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
ImageIO.write(img, extension, bos);
|
ImageIO.write(img, extension, bos);
|
||||||
|
@ -79,16 +100,21 @@ public class FileTransferUtils {
|
||||||
bos.close();
|
bos.close();
|
||||||
return imgString;
|
return imgString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param imageString The base64 encoded string of an image.
|
||||||
|
* @return A buffered image corresponding to the given base64 encoded string.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public static BufferedImage decodeImage(String imageString) throws IOException {
|
public static BufferedImage decodeImage(String imageString) throws IOException {
|
||||||
byte[] imgData = Base64.getDecoder().decode(imageString);
|
byte[] imgData = Base64.getDecoder().decode(imageString);
|
||||||
InputStream is = new ByteArrayInputStream(imgData);
|
InputStream is = new ByteArrayInputStream(imgData);
|
||||||
BufferedImage img = ImageIO.read(is);
|
BufferedImage img = ImageIO.read(is);
|
||||||
is.close();
|
is.close();
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used to scale an image with a given ratio
|
||||||
private static BufferedImage scale(BufferedImage source, double ratio) {
|
private static BufferedImage scale(BufferedImage source, double ratio) {
|
||||||
int w = (int) (source.getWidth() * ratio);
|
int w = (int) (source.getWidth() * ratio);
|
||||||
int h = (int) (source.getHeight() * ratio);
|
int h = (int) (source.getHeight() * ratio);
|
||||||
|
@ -109,11 +135,15 @@ public class FileTransferUtils {
|
||||||
BufferedImage image = gc.createCompatibleImage(w, h);
|
BufferedImage image = gc.createCompatibleImage(w, h);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the folder with the path "DOWNLOADS_RELATIVE_PATH" if it does not
|
||||||
|
* exist.
|
||||||
|
*/
|
||||||
public static void createDownloads() {
|
public static void createDownloads() {
|
||||||
File downloads = new File(FileTransferUtils.DOWNLOADS_RELATIVE_PATH);
|
File downloads = new File(FileTransferUtils.DOWNLOADS_RELATIVE_PATH);
|
||||||
|
|
||||||
if(!downloads.exists()) {
|
if (!downloads.exists()) {
|
||||||
downloads.mkdir();
|
downloads.mkdir();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,63 +5,86 @@ import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
import observers.ObserverInputMessage;
|
import observers.ObserverInputMessage;
|
||||||
import observers.ObserverSocketState;
|
import observers.ObserverSocketState;
|
||||||
|
|
||||||
import messages.MauvaisTypeMessageException;
|
|
||||||
import messages.Message;
|
import messages.Message;
|
||||||
|
|
||||||
public class TCPClient {
|
public class TCPClient {
|
||||||
|
|
||||||
private Socket sockTCP;
|
private Socket sockTCP;
|
||||||
private ObjectOutputStream output;
|
private ObjectOutputStream output;
|
||||||
|
private ObjectInputStream input;
|
||||||
private TCPInputThread inputThread;
|
private TCPInputThread inputThread;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TCP client from an existing socket. It will ensure the transmission
|
||||||
|
* of messages during a session. Two ObjectStream are created in order to
|
||||||
|
* read/write messages. The ObjectInputStream is given to a thread to read
|
||||||
|
* continuously the incoming message and allowing the user to write a message
|
||||||
|
* anytime.
|
||||||
|
*
|
||||||
|
* @param sockTCP
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public TCPClient(Socket sockTCP) throws IOException {
|
public TCPClient(Socket sockTCP) throws IOException {
|
||||||
this.sockTCP = sockTCP;
|
this.sockTCP = sockTCP;
|
||||||
|
|
||||||
this.output = new ObjectOutputStream(sockTCP.getOutputStream());
|
this.output = new ObjectOutputStream(sockTCP.getOutputStream());
|
||||||
ObjectInputStream input = new ObjectInputStream(sockTCP.getInputStream());
|
this.input = new ObjectInputStream(sockTCP.getInputStream());
|
||||||
this.inputThread = new TCPInputThread(input);
|
this.inputThread = new TCPInputThread(this.input);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TCPClient(InetAddress addr, int port) throws IOException {
|
|
||||||
this(new Socket(addr, port));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the thread that will continuously read from the socket.
|
||||||
|
*/
|
||||||
public void startInputThread() {
|
public void startInputThread() {
|
||||||
this.inputThread.start();
|
this.inputThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
public void sendMessage(Message message) throws IOException, MauvaisTypeMessageException {
|
* Send a message by writing it in the ObjectOutputStream of the socket
|
||||||
System.out.println("dans write");
|
*
|
||||||
|
* @param message
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void sendMessage(Message message) throws IOException {
|
||||||
this.output.writeObject(message);
|
this.output.writeObject(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the observer to notify when a message is received
|
||||||
|
*
|
||||||
|
* @param o The observer
|
||||||
|
*/
|
||||||
public void setObserverInputThread(ObserverInputMessage o) {
|
public void setObserverInputThread(ObserverInputMessage o) {
|
||||||
this.inputThread.setObserverInputMessage(o);
|
this.inputThread.setObserverInputMessage(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the observer to notify when the session is closed/the communication is
|
||||||
|
* broken.
|
||||||
|
*
|
||||||
|
* @param o The observer
|
||||||
|
*/
|
||||||
public void setObserverSocketState(ObserverSocketState o) {
|
public void setObserverSocketState(ObserverSocketState o) {
|
||||||
this.inputThread.setObserverSocketState(o);
|
this.inputThread.setObserverSocketState(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method used when the session is over. Set all attribute references to null,
|
||||||
|
* interrupt the inputThread and close the streams and the socket.
|
||||||
|
*/
|
||||||
public void destroyAll() {
|
public void destroyAll() {
|
||||||
try {
|
try {
|
||||||
if (!this.sockTCP.isClosed()) {
|
if (!this.sockTCP.isClosed()) {
|
||||||
|
this.inputThread.setObserverSocketState(null);
|
||||||
|
this.inputThread.interrupt();
|
||||||
|
this.input.close();
|
||||||
this.output.close();
|
this.output.close();
|
||||||
this.sockTCP.close();
|
this.sockTCP.close();
|
||||||
this.inputThread.setObserverSocketState(null);
|
|
||||||
}
|
}
|
||||||
this.inputThread = null;
|
this.inputThread = null;
|
||||||
this.sockTCP = null;
|
this.sockTCP = null;
|
||||||
|
|
|
@ -12,7 +12,12 @@ public class TCPInputThread extends Thread {
|
||||||
private ObserverInputMessage obsInput;
|
private ObserverInputMessage obsInput;
|
||||||
private ObserverSocketState obsState;
|
private ObserverSocketState obsState;
|
||||||
|
|
||||||
public TCPInputThread(ObjectInputStream input) {
|
/**
|
||||||
|
* Create the thread used to read the messages
|
||||||
|
*
|
||||||
|
* @param input The ObjectInputStream to read data from
|
||||||
|
*/
|
||||||
|
protected TCPInputThread(ObjectInputStream input) {
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.running = true;
|
this.running = true;
|
||||||
}
|
}
|
||||||
|
@ -22,10 +27,9 @@ public class TCPInputThread extends Thread {
|
||||||
|
|
||||||
while (this.running) {
|
while (this.running) {
|
||||||
try {
|
try {
|
||||||
|
Object o = this.input.readObject();
|
||||||
System.out.println("dans read");
|
// Notify the observer a message was received
|
||||||
Object o = this.input.readObject();
|
this.obsInput.updateInput(this, o);
|
||||||
this.obsInput.update(this, o);
|
|
||||||
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
this.interrupt();
|
this.interrupt();
|
||||||
|
@ -37,34 +41,35 @@ public class TCPInputThread extends Thread {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void interrupt() {
|
public void interrupt() {
|
||||||
|
// Stop the thread
|
||||||
try {
|
this.running = false;
|
||||||
//Stop the thread
|
// Close the stream and the socket
|
||||||
this.running = false;
|
|
||||||
//Close the stream and the socket
|
if (this.obsState != null) {
|
||||||
this.input.close();
|
// Send an update to the controller
|
||||||
|
this.obsState.updateSocketState(this, true);
|
||||||
if(this.obsState != null) {
|
|
||||||
//Send an update to the controller
|
|
||||||
this.obsState.updateSocketState(this, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Set every attribute to null so they're collected by the GC
|
|
||||||
this.obsInput = null;
|
|
||||||
this.obsState = null;
|
|
||||||
this.input = null;
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set every attribute to null so they're collected by the GC
|
||||||
|
this.obsInput = null;
|
||||||
|
this.obsState = null;
|
||||||
|
this.input = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the observer to notify when a message is received
|
||||||
|
*
|
||||||
|
* @param o The observer
|
||||||
|
*/
|
||||||
protected void setObserverInputMessage(ObserverInputMessage o) {
|
protected void setObserverInputMessage(ObserverInputMessage o) {
|
||||||
this.obsInput = o;
|
this.obsInput = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the observer to notify when the session is cut/closed.
|
||||||
|
*
|
||||||
|
* @param o The observer
|
||||||
|
*/
|
||||||
protected void setObserverSocketState(ObserverSocketState o) {
|
protected void setObserverSocketState(ObserverSocketState o) {
|
||||||
this.obsState = o;
|
this.obsState = o;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,36 +8,45 @@ import java.net.UnknownHostException;
|
||||||
|
|
||||||
import observers.ObserverInputMessage;
|
import observers.ObserverInputMessage;
|
||||||
|
|
||||||
|
|
||||||
public class TCPServer extends Thread {
|
public class TCPServer extends Thread {
|
||||||
|
|
||||||
//****
|
|
||||||
public static int PORT_SERVER = 7000;
|
|
||||||
|
|
||||||
private ServerSocket sockListenTCP;
|
private ServerSocket sockListenTCP;
|
||||||
private ObserverInputMessage obs;
|
private ObserverInputMessage obsInput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TCP Server on the specified port. It will listen continuously for
|
||||||
|
* connections in order to create new sessions between users.
|
||||||
|
*
|
||||||
|
* @param port The port on which the server will listen
|
||||||
|
* @throws UnknownHostException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public TCPServer(int port) throws UnknownHostException, IOException {
|
public TCPServer(int port) throws UnknownHostException, IOException {
|
||||||
this.sockListenTCP = new ServerSocket(port, 50, InetAddress.getLocalHost());
|
this.sockListenTCP = new ServerSocket(port, 50, InetAddress.getLocalHost());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
System.out.println("TCP running");
|
|
||||||
Socket sockAccept;
|
Socket sockAccept;
|
||||||
while(true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
sockAccept = this.sockListenTCP.accept();
|
sockAccept = this.sockListenTCP.accept();
|
||||||
this.obs.update(this, sockAccept);
|
|
||||||
|
// Notify the observer of the new connexion
|
||||||
|
this.obsInput.updateInput(this, sockAccept);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addObserver(ObserverInputMessage obs) {
|
/**
|
||||||
this.obs = obs;
|
* Set the observer to notify when a new connection is made.
|
||||||
|
*
|
||||||
|
* @param o The observer
|
||||||
|
*/
|
||||||
|
public void addObserver(ObserverInputMessage o) {
|
||||||
|
this.obsInput = o;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package communication.udp;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.SocketException;
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@ -13,18 +12,23 @@ import observers.ObserverUserList;
|
||||||
|
|
||||||
public class CommunicationUDP extends Thread {
|
public class CommunicationUDP extends Thread {
|
||||||
|
|
||||||
// ****
|
|
||||||
protected static int PORT_SERVEUR = 3000;
|
|
||||||
// ****
|
|
||||||
protected static int PORT_CLIENT = 2000;
|
|
||||||
|
|
||||||
private UDPClient client;
|
private UDPClient client;
|
||||||
private UDPServer server;
|
private UDPServer server;
|
||||||
private int portServer;
|
private int portServer;
|
||||||
private ArrayList<Integer> portOthers;
|
private ArrayList<Integer> portOthers;
|
||||||
private ArrayList<Utilisateur> users = new ArrayList<Utilisateur>();
|
private ArrayList<Utilisateur> users = new ArrayList<Utilisateur>();
|
||||||
private ObserverUserList observer;
|
private ObserverUserList obsList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the class that will manage the userlist and contain a UDPClient and a
|
||||||
|
* UDPServer. Since the applications will run on localhost, it needs to know
|
||||||
|
* every UDPServer ports used in order to replicate a broadcast behaviour.
|
||||||
|
*
|
||||||
|
* @param portClient The port number for the UDPClient
|
||||||
|
* @param portServer The port number for the UDPServer
|
||||||
|
* @param portsOther The port numbers for every other application's UDPServer
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public CommunicationUDP(int portClient, int portServer, int[] portsOther) throws IOException {
|
public CommunicationUDP(int portClient, int portServer, int[] portsOther) throws IOException {
|
||||||
this.portServer = portServer;
|
this.portServer = portServer;
|
||||||
this.portOthers = this.getArrayListFromArray(portsOther);
|
this.portOthers = this.getArrayListFromArray(portsOther);
|
||||||
|
@ -33,14 +37,13 @@ public class CommunicationUDP extends Thread {
|
||||||
this.client = new UDPClient(portClient);
|
this.client = new UDPClient(portClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****
|
/**
|
||||||
public CommunicationUDP() throws SocketException, UnknownHostException {
|
* Create an ArrayList<Integer> from the int[] list of every servers' ports and
|
||||||
this.portServer = PORT_SERVEUR;
|
* remove the port of this application UDPServer.
|
||||||
this.server = new UDPServer(portServer, this);
|
*
|
||||||
this.server.start();
|
* @param ports The UDPServer port numbers.
|
||||||
this.client = new UDPClient(PORT_CLIENT);
|
* @return An ArrayList<Integer> without the port of this UDPServer.
|
||||||
}
|
*/
|
||||||
|
|
||||||
private ArrayList<Integer> getArrayListFromArray(int ports[]) {
|
private ArrayList<Integer> getArrayListFromArray(int ports[]) {
|
||||||
ArrayList<Integer> tmp = new ArrayList<Integer>();
|
ArrayList<Integer> tmp = new ArrayList<Integer>();
|
||||||
for (int port : ports) {
|
for (int port : ports) {
|
||||||
|
@ -51,42 +54,83 @@ public class CommunicationUDP extends Thread {
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setObserver(ObserverUserList obs) {
|
/**
|
||||||
this.observer = obs;
|
* Set the observer to notify when the userList is updated.
|
||||||
|
*
|
||||||
|
* @param obs The observer
|
||||||
|
*/
|
||||||
|
public void setObserver(ObserverUserList o) {
|
||||||
|
this.obsList = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------- USER LIST UPDATE FUNCTION --------------//
|
// -------------- USER LIST UPDATE FUNCTION --------------//
|
||||||
|
|
||||||
protected synchronized void addUser(String idClient, String pseudoClient, InetAddress ipClient, int port)
|
/**
|
||||||
throws IOException {
|
* Add a new user to the userlist and notify the observer.
|
||||||
users.add(new Utilisateur(idClient, pseudoClient, ipClient, port));
|
*
|
||||||
|
* @param idClient
|
||||||
|
* @param pseudoClient
|
||||||
|
* @param ipClient
|
||||||
|
* @param port
|
||||||
|
* @throws UnknownHostException
|
||||||
|
*/
|
||||||
|
protected synchronized void addUser(String idUser, String pseudoUser, InetAddress ipUser, int portTCPServer)
|
||||||
|
throws UnknownHostException {
|
||||||
|
users.add(new Utilisateur(idUser, pseudoUser, ipUser, portTCPServer));
|
||||||
this.sendUpdate();
|
this.sendUpdate();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void changePseudoUser(String idClient, String pseudoClient, InetAddress ipClient, int port) {
|
/**
|
||||||
int index = getIndexFromID(idClient);
|
* Change the pseudo of an user and notify the observer if it exists in the
|
||||||
users.get(index).setPseudo(pseudoClient);
|
* userlist. Do nothing otherwise.
|
||||||
this.sendUpdate();
|
*
|
||||||
|
* @param idClient
|
||||||
|
* @param pseudoClient
|
||||||
|
* @param ipClient
|
||||||
|
* @param port
|
||||||
|
*/
|
||||||
|
protected synchronized void changePseudoUser(String idUser, String pseudoUser, InetAddress ipUser,
|
||||||
|
int portTCPServer) {
|
||||||
|
int index = getIndexFromID(idUser);
|
||||||
|
if (index != -1) {
|
||||||
|
users.get(index).setPseudo(pseudoUser);
|
||||||
|
this.sendUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void removeUser(String idClient, String pseudoClient, InetAddress ipClient, int port) {
|
/**
|
||||||
int index = getIndexFromID(idClient);
|
* Remove an user from the userlist and notify the observer if it exists in the
|
||||||
|
* userlist. Do nothing otherwise.
|
||||||
|
*
|
||||||
|
* @param idUser
|
||||||
|
* @param pseudoUser
|
||||||
|
* @param ipUser
|
||||||
|
* @param portTCPServer
|
||||||
|
*/
|
||||||
|
protected synchronized void removeUser(String idUser, String pseudoUser, InetAddress ipUser, int portTCPServer) {
|
||||||
|
int index = getIndexFromID(idUser);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
users.remove(index);
|
users.remove(index);
|
||||||
|
this.sendUpdate();
|
||||||
}
|
}
|
||||||
this.sendUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeAll() {
|
public void removeAllUsers() {
|
||||||
int oSize = users.size();
|
this.users.clear();
|
||||||
for (int i = 0; i < oSize; i++) {
|
|
||||||
users.remove(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------- CHECKERS --------------//
|
// -------------- CHECKERS --------------//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there is an user in the list that has the given id.
|
||||||
|
*
|
||||||
|
* @param id The user's id.
|
||||||
|
* @return true if the user is in the list
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
protected boolean containsUserFromID(String id) {
|
protected boolean containsUserFromID(String id) {
|
||||||
for (Utilisateur u : users) {
|
for (Utilisateur u : users) {
|
||||||
if (u.getId().equals(id)) {
|
if (u.getId().equals(id)) {
|
||||||
|
@ -96,6 +140,13 @@ public class CommunicationUDP extends Thread {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there is an user in the list that has the given pseudo.
|
||||||
|
*
|
||||||
|
* @param pseudo The user's pseudo.
|
||||||
|
* @return true if the user is in the list
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
public boolean containsUserFromPseudo(String pseudo) {
|
public boolean containsUserFromPseudo(String pseudo) {
|
||||||
for (Utilisateur u : users) {
|
for (Utilisateur u : users) {
|
||||||
if (u.getPseudo().toLowerCase().equals(pseudo)) {
|
if (u.getPseudo().toLowerCase().equals(pseudo)) {
|
||||||
|
@ -108,6 +159,13 @@ public class CommunicationUDP extends Thread {
|
||||||
|
|
||||||
// -------------- GETTERS --------------//
|
// -------------- GETTERS --------------//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the user with the given pseudo if it exists in the list.
|
||||||
|
*
|
||||||
|
* @param pseudo The user's pseudo.
|
||||||
|
* @return The user if it exists in the list.
|
||||||
|
* null otherwise.
|
||||||
|
*/
|
||||||
public Utilisateur getUserFromPseudo(String pseudo) {
|
public Utilisateur getUserFromPseudo(String pseudo) {
|
||||||
for (int i = 0; i < users.size(); i++) {
|
for (int i = 0; i < users.size(); i++) {
|
||||||
if (users.get(i).getPseudo().equals(pseudo)) {
|
if (users.get(i).getPseudo().equals(pseudo)) {
|
||||||
|
@ -117,6 +175,13 @@ public class CommunicationUDP extends Thread {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the index of the user with the given id if it exists in the list.
|
||||||
|
*
|
||||||
|
* @param id The user's id.
|
||||||
|
* @return The index if the user exists in the list.
|
||||||
|
* null otherwise
|
||||||
|
*/
|
||||||
private int getIndexFromID(String id) {
|
private int getIndexFromID(String id) {
|
||||||
for (int i = 0; i < users.size(); i++) {
|
for (int i = 0; i < users.size(); i++) {
|
||||||
if (users.get(i).getId().equals(id)) {
|
if (users.get(i).getId().equals(id)) {
|
||||||
|
@ -128,79 +193,100 @@ public class CommunicationUDP extends Thread {
|
||||||
|
|
||||||
// -------------- SEND MESSAGES --------------//
|
// -------------- SEND MESSAGES --------------//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message indicating this application's user is connected to every
|
||||||
|
* UDPServer.
|
||||||
|
*
|
||||||
|
* @throws UnknownHostException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void sendMessageConnecte() throws UnknownHostException, IOException {
|
public void sendMessageConnecte() throws UnknownHostException, IOException {
|
||||||
for (int port : this.portOthers) {
|
|
||||||
try {
|
try {
|
||||||
this.client.sendMessageUDP_local(new MessageSysteme(Message.TypeMessage.JE_SUIS_CONNECTE), port,
|
Message msgOut = new MessageSysteme(Message.TypeMessage.JE_SUIS_CONNECTE);
|
||||||
InetAddress.getLocalHost());
|
for (int port : this.portOthers) {
|
||||||
} catch (MauvaisTypeMessageException e) {
|
|
||||||
/* Si ça marche pas essayer là */}
|
this.client.sendMessageUDP_local(msgOut, port);
|
||||||
|
}
|
||||||
|
} catch (MauvaisTypeMessageException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the message "add,id,pseudo" to localhost on all the ports in
|
/**
|
||||||
// "portOthers"
|
* Send a message containing this application's user's data to every UDPServer.
|
||||||
// This allows the receivers' agent (portOthers) to create or modify an entry
|
* This method is used to first add this user in the userlist or update this
|
||||||
// with the
|
* user's pseudo.
|
||||||
// data of this agent
|
*
|
||||||
// Typically used to notify of a name change
|
* @throws UnknownHostException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void sendMessageInfoPseudo() throws UnknownHostException, IOException {
|
public void sendMessageInfoPseudo() throws UnknownHostException, IOException {
|
||||||
|
|
||||||
Utilisateur self = Utilisateur.getSelf();
|
Utilisateur self = Utilisateur.getSelf();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Message msgOut = new MessageSysteme(Message.TypeMessage.INFO_PSEUDO, self.getPseudo(), self.getId(), self.getPort());
|
Message msgOut = new MessageSysteme(Message.TypeMessage.INFO_PSEUDO, self.getPseudo(), self.getId(),
|
||||||
|
self.getPort());
|
||||||
for (int port : this.portOthers) {
|
for (int port : this.portOthers) {
|
||||||
this.client.sendMessageUDP_local(msgOut, port, InetAddress.getLocalHost());
|
this.client.sendMessageUDP_local(msgOut, port);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (MauvaisTypeMessageException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same, but on only one port
|
/**
|
||||||
// Typically used to give your current name and id to a newly arrived host
|
* Send a message containing this application's user's data to one user. This
|
||||||
|
* method is used to answer back when receiving a message with the type
|
||||||
|
* "JE_SUIS_CONNECTE"
|
||||||
|
*
|
||||||
|
* @param portOther The port on which the other user's UDPServer is listening
|
||||||
|
* @throws UnknownHostException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void sendMessageInfoPseudo(int portOther) throws UnknownHostException, IOException {
|
public void sendMessageInfoPseudo(int portOther) throws UnknownHostException, IOException {
|
||||||
|
|
||||||
Utilisateur self = Utilisateur.getSelf();
|
Utilisateur self = Utilisateur.getSelf();
|
||||||
try {
|
try {
|
||||||
Message msgOut = new MessageSysteme(Message.TypeMessage.INFO_PSEUDO, self.getPseudo(), self.getId(),
|
Message msgOut = new MessageSysteme(Message.TypeMessage.INFO_PSEUDO, self.getPseudo(), self.getId(),
|
||||||
self.getPort());
|
self.getPort());
|
||||||
this.client.sendMessageUDP_local(msgOut, portOther, InetAddress.getLocalHost());
|
this.client.sendMessageUDP_local(msgOut, portOther);
|
||||||
} catch (MauvaisTypeMessageException e) {
|
} catch (MauvaisTypeMessageException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the message "del,id,pseudo" to localhost on all the ports in
|
/**
|
||||||
// "portOthers"
|
* Send a message indicating this application's user is disconnected to every
|
||||||
// This allows the receivers' agent (portOthers) to delete the entry
|
* UDPServer.
|
||||||
// corresponding to this agent
|
*
|
||||||
|
* @throws UnknownHostException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void sendMessageDelete() throws UnknownHostException, IOException {
|
public void sendMessageDelete() throws UnknownHostException, IOException {
|
||||||
Utilisateur self = Utilisateur.getSelf();
|
Utilisateur self = Utilisateur.getSelf();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Message msgOut = new MessageSysteme(Message.TypeMessage.JE_SUIS_DECONNECTE, self.getPseudo(), self.getId(), self.getPort());
|
Message msgOut = new MessageSysteme(Message.TypeMessage.JE_SUIS_DECONNECTE, self.getPseudo(), self.getId(),
|
||||||
|
self.getPort());
|
||||||
for (int port : this.portOthers) {
|
for (int port : this.portOthers) {
|
||||||
this.client.sendMessageUDP_local(msgOut, port, InetAddress.getLocalHost());
|
this.client.sendMessageUDP_local(msgOut, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (MauvaisTypeMessageException e) {
|
} catch (MauvaisTypeMessageException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the observer with the updated list
|
||||||
|
*/
|
||||||
private void sendUpdate() {
|
private void sendUpdate() {
|
||||||
if(this.observer != null) {
|
if (this.obsList != null) {
|
||||||
this.observer.updateList(this, users);
|
this.obsList.updateList(this, users);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroyAll() {
|
|
||||||
this.client.destroyAll();
|
|
||||||
this.server.interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,40 +4,52 @@ import java.io.IOException;
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
import messages.*;
|
import messages.*;
|
||||||
|
|
||||||
public class UDPClient {
|
class UDPClient {
|
||||||
|
|
||||||
private DatagramSocket sockUDP;
|
private DatagramSocket sockUDP;
|
||||||
private InetAddress broadcast;
|
|
||||||
|
/**
|
||||||
|
* Create a UDP client on the specified port. It will be used to notify the
|
||||||
|
* other users of this application's user state (Connected/Disconnected/Pseudo
|
||||||
|
* changed).
|
||||||
|
*
|
||||||
|
* @param port
|
||||||
|
* @throws SocketException
|
||||||
|
* @throws UnknownHostException
|
||||||
|
*/
|
||||||
public UDPClient(int port) throws SocketException, UnknownHostException {
|
public UDPClient(int port) throws SocketException, UnknownHostException {
|
||||||
this.sockUDP = new DatagramSocket(port);
|
this.sockUDP = new DatagramSocket(port);
|
||||||
|
|
||||||
InetAddress localHost = InetAddress.getLocalHost();
|
|
||||||
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(localHost);
|
|
||||||
this.broadcast = networkInterface.getInterfaceAddresses().get(0).getBroadcast();
|
|
||||||
System.out.println(this.broadcast);
|
|
||||||
System.out.println(InetAddress.getLocalHost());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
//Send a message casted as string to the specified port on localhost
|
* Send a message to the specified port on localhost.
|
||||||
protected void sendMessageUDP_local(Message message, int port, InetAddress clientAddress) throws IOException {
|
*
|
||||||
String messageString= message.toString();
|
* @param message
|
||||||
DatagramPacket outpacket = new DatagramPacket(messageString.getBytes(), messageString.length(), clientAddress, port);
|
* @param port
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
protected void sendMessageUDP_local(Message message, int port) throws IOException {
|
||||||
|
sendMessageUDP(message, port, InetAddress.getLocalHost());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to the given address on the specified port.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* @param port
|
||||||
|
* @param clientAddress
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void sendMessageUDP(Message message, int port, InetAddress clientAddress) throws IOException {
|
||||||
|
String messageString = message.toString();
|
||||||
|
DatagramPacket outpacket = new DatagramPacket(messageString.getBytes(), messageString.length(), clientAddress,
|
||||||
|
port);
|
||||||
this.sockUDP.send(outpacket);
|
this.sockUDP.send(outpacket);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void destroyAll() {
|
|
||||||
this.sockUDP.close();
|
|
||||||
this.sockUDP = null;
|
|
||||||
this.broadcast = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,13 +8,22 @@ import java.net.SocketException;
|
||||||
import main.Utilisateur;
|
import main.Utilisateur;
|
||||||
import messages.*;
|
import messages.*;
|
||||||
|
|
||||||
public class UDPServer extends Thread {
|
class UDPServer extends Thread {
|
||||||
|
|
||||||
private DatagramSocket sockUDP;
|
private DatagramSocket sockUDP;
|
||||||
private CommunicationUDP commUDP;
|
private CommunicationUDP commUDP;
|
||||||
private byte[] buffer;
|
private byte[] buffer;
|
||||||
private boolean running;
|
private boolean running;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a UDP Server on the specified port. It will be used to read the
|
||||||
|
* other users states (Connected/Disconnected/Pseudo).
|
||||||
|
*
|
||||||
|
* @param port
|
||||||
|
* @param commUDP
|
||||||
|
* @throws SocketException
|
||||||
|
*/
|
||||||
public UDPServer(int port, CommunicationUDP commUDP) throws SocketException {
|
public UDPServer(int port, CommunicationUDP commUDP) throws SocketException {
|
||||||
this.running = true;
|
this.running = true;
|
||||||
this.commUDP = commUDP;
|
this.commUDP = commUDP;
|
||||||
|
@ -27,12 +36,14 @@ public class UDPServer extends Thread {
|
||||||
while (this.running) {
|
while (this.running) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
//When a datagram is received, converts its data in a Message
|
||||||
DatagramPacket inPacket = new DatagramPacket(buffer, buffer.length);
|
DatagramPacket inPacket = new DatagramPacket(buffer, buffer.length);
|
||||||
this.sockUDP.receive(inPacket);
|
this.sockUDP.receive(inPacket);
|
||||||
String msgString = new String(inPacket.getData(), 0, inPacket.getLength());
|
String msgString = new String(inPacket.getData(), 0, inPacket.getLength());
|
||||||
Message msg = Message.stringToMessage(msgString);
|
Message msg = Message.stringToMessage(msgString);
|
||||||
|
|
||||||
|
//Depending on the type of the message
|
||||||
switch (msg.getTypeMessage()) {
|
switch (msg.getTypeMessage()) {
|
||||||
case JE_SUIS_CONNECTE:
|
case JE_SUIS_CONNECTE:
|
||||||
|
|
||||||
|
@ -40,34 +51,38 @@ public class UDPServer extends Thread {
|
||||||
|
|
||||||
int portClient = inPacket.getPort();
|
int portClient = inPacket.getPort();
|
||||||
int portServer = portClient+1;
|
int portServer = portClient+1;
|
||||||
|
|
||||||
|
//Answer back with this application's user data
|
||||||
this.commUDP.sendMessageInfoPseudo(portServer);
|
this.commUDP.sendMessageInfoPseudo(portServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INFO_PSEUDO:
|
case INFO_PSEUDO:
|
||||||
|
|
||||||
MessageSysteme m = (MessageSysteme) msg;
|
MessageSysteme m = (MessageSysteme) msg;
|
||||||
|
|
||||||
|
//Update the userlist with the data received (Add the user or update it)
|
||||||
if (this.commUDP.containsUserFromID(m.getId())) {
|
if (this.commUDP.containsUserFromID(m.getId())) {
|
||||||
this.commUDP.changePseudoUser(m.getId(), m.getPseudo(), inPacket.getAddress(), m.getPort());
|
this.commUDP.changePseudoUser(m.getId(), m.getPseudo(), inPacket.getAddress(), m.getPort());
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
this.commUDP.addUser(m.getId(), m.getPseudo(), inPacket.getAddress(), m.getPort());
|
this.commUDP.addUser(m.getId(), m.getPseudo(), inPacket.getAddress(), m.getPort());
|
||||||
System.out.println(m.getId() + ", " + m.getPseudo());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JE_SUIS_DECONNECTE:
|
case JE_SUIS_DECONNECTE:
|
||||||
this.commUDP.removeUser(((MessageSysteme) msg).getId(), ((MessageSysteme) msg).getPseudo(),
|
|
||||||
inPacket.getAddress(), inPacket.getPort());
|
MessageSysteme m2 = (MessageSysteme) msg;
|
||||||
|
//Remove the user from the userlist
|
||||||
|
this.commUDP.removeUser(m2.getId(), m2.getPseudo(), inPacket.getAddress(), m2.getPort());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // Others types of messages are ignored because they are supposed to be
|
//Do nothing
|
||||||
// transmitted by TCP and not UDP
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("receive exception");
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
package observers;
|
package observers;
|
||||||
|
|
||||||
public interface ObserverInputMessage {
|
public interface ObserverInputMessage {
|
||||||
public void update(Object o, Object arg);
|
|
||||||
|
/**
|
||||||
|
* Method called when data is received from a TCP socket
|
||||||
|
*
|
||||||
|
* @param o : The observer to notify
|
||||||
|
* @param arg : An object
|
||||||
|
*/
|
||||||
|
public void updateInput(Object o, Object arg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,12 @@ package observers;
|
||||||
|
|
||||||
public interface ObserverSocketState {
|
public interface ObserverSocketState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when a TCP socket is closed/a communication is broken
|
||||||
|
*
|
||||||
|
* @param o : The observer to notify
|
||||||
|
* @param arg : An object
|
||||||
|
*/
|
||||||
public void updateSocketState(Object o, Object arg);
|
public void updateSocketState(Object o, Object arg);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,12 @@ import main.Utilisateur;
|
||||||
|
|
||||||
public interface ObserverUserList {
|
public interface ObserverUserList {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when the userlist is updated
|
||||||
|
*
|
||||||
|
* @param o : The observer to notify
|
||||||
|
* @param userList : The userlist
|
||||||
|
*/
|
||||||
public void updateList(Object o, ArrayList<Utilisateur> userList);
|
public void updateList(Object o, ArrayList<Utilisateur> userList);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,16 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
private SQLiteManager sqlManager;
|
private SQLiteManager sqlManager;
|
||||||
private ArrayList<File> files;
|
private ArrayList<File> files;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param vue
|
||||||
|
* @param socketComm
|
||||||
|
* @param idOther
|
||||||
|
* @param pseudoOther
|
||||||
|
* @param sqlManager
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
protected ControleurSession(VueSession vue, Socket socketComm, String idOther, String pseudoOther, SQLiteManager sqlManager) throws IOException {
|
protected ControleurSession(VueSession vue, Socket socketComm, String idOther, String pseudoOther, SQLiteManager sqlManager) throws IOException {
|
||||||
this.vue = vue;
|
this.vue = vue;
|
||||||
this.tcpClient = new TCPClient(socketComm);
|
this.tcpClient = new TCPClient(socketComm);
|
||||||
|
@ -60,7 +70,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
||||||
//Quand le bouton envoyer est presse
|
//If the button "Envoyer" is pressed
|
||||||
if ((JButton) e.getSource() == this.vue.getButtonEnvoyer()) {
|
if ((JButton) e.getSource() == this.vue.getButtonEnvoyer()) {
|
||||||
String messageContent = this.vue.getInputedText();
|
String messageContent = this.vue.getInputedText();
|
||||||
System.out.println(messageContent);
|
System.out.println(messageContent);
|
||||||
|
@ -92,8 +102,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.tcpClient.sendMessage(messageOut);
|
this.tcpClient.sendMessage(messageOut);
|
||||||
} catch (MauvaisTypeMessageException | IOException e1) {
|
} catch (IOException e1) {
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +114,9 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If the button "Importer" is pressed
|
||||||
if((JButton) e.getSource() == this.vue.getButtonImportFile()) {
|
if((JButton) e.getSource() == this.vue.getButtonImportFile()) {
|
||||||
|
//Display a file chooser to select one or several files
|
||||||
JFileChooser fc = new JFileChooser();
|
JFileChooser fc = new JFileChooser();
|
||||||
fc.setMultiSelectionEnabled(true);
|
fc.setMultiSelectionEnabled(true);
|
||||||
int returVal = fc.showDialog(this.vue, "Importer");
|
int returVal = fc.showDialog(this.vue, "Importer");
|
||||||
|
@ -126,10 +137,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyTyped(KeyEvent e) {
|
public void keyTyped(KeyEvent e) {}
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyPressed(KeyEvent e) {
|
public void keyPressed(KeyEvent e) {
|
||||||
|
@ -142,10 +150,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(KeyEvent e) {
|
public void keyReleased(KeyEvent e) {}
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected ArrayList<Message> getHistorique(){
|
protected ArrayList<Message> getHistorique(){
|
||||||
|
@ -189,10 +194,11 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Methode appelee quand l'inputStream de la socket de communication recoit des donnees
|
//Method called when a message is received from the TCP socket
|
||||||
@Override
|
@Override
|
||||||
public void update(Object o, Object arg) {
|
public void updateInput(Object o, Object arg) {
|
||||||
Message message = (Message) arg;
|
Message message = (Message) arg;
|
||||||
|
|
||||||
switch(message.getTypeMessage()) {
|
switch(message.getTypeMessage()) {
|
||||||
case TEXTE:
|
case TEXTE:
|
||||||
System.out.println(message.toString());
|
System.out.println(message.toString());
|
||||||
|
@ -217,6 +223,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
this.messagesIn.add(message);
|
this.messagesIn.add(message);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FICHIER_INIT:
|
case FICHIER_INIT:
|
||||||
try {
|
try {
|
||||||
MessageFichier mFichier = (MessageFichier) arg;
|
MessageFichier mFichier = (MessageFichier) arg;
|
||||||
|
@ -245,16 +252,23 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
//Do nothing
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If the other user closes the session or the communication is broken
|
||||||
|
//Disable the view (TextArea, Buttons..) and display a message
|
||||||
@Override
|
@Override
|
||||||
public void updateSocketState(Object o, Object arg) {
|
public void updateSocketState(Object o, Object arg) {
|
||||||
this.vue.endSession(this.pseudoOther);
|
this.vue.endSession(this.pseudoOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
protected void destroyAll() {
|
protected void destroyAll() {
|
||||||
String idSelf = Utilisateur.getSelf().getId();
|
String idSelf = Utilisateur.getSelf().getId();
|
||||||
String idOther = this.idOther;
|
String idOther = this.idOther;
|
||||||
|
@ -263,11 +277,9 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
|
||||||
this.sqlManager.insertAllMessages(messagesOut, idSelf, idOther);
|
this.sqlManager.insertAllMessages(messagesOut, idSelf, idOther);
|
||||||
this.sqlManager.insertAllMessages(messagesIn, idOther, idSelf);
|
this.sqlManager.insertAllMessages(messagesIn, idOther, idSelf);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.vue = null;
|
this.vue = null;
|
||||||
this.tcpClient.destroyAll();
|
this.tcpClient.destroyAll();
|
||||||
this.tcpClient = null;
|
this.tcpClient = null;
|
||||||
|
|
|
@ -245,7 +245,7 @@ public class ControleurStandard implements ActionListener, ListSelectionListener
|
||||||
// ------------OBSERVERS-------------//
|
// ------------OBSERVERS-------------//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Object o, Object arg) {
|
public void updateInput(Object o, Object arg) {
|
||||||
|
|
||||||
if (o == this.tcpServ) {
|
if (o == this.tcpServ) {
|
||||||
|
|
||||||
|
@ -304,6 +304,7 @@ public class ControleurStandard implements ActionListener, ListSelectionListener
|
||||||
|
|
||||||
private void setVueConnexion() throws UnknownHostException, IOException {
|
private void setVueConnexion() throws UnknownHostException, IOException {
|
||||||
this.commUDP.sendMessageDelete();
|
this.commUDP.sendMessageDelete();
|
||||||
|
this.commUDP.removeAllUsers();
|
||||||
this.vue.removeAllUsers();
|
this.vue.removeAllUsers();
|
||||||
this.vue.closeAllSession();
|
this.vue.closeAllSession();
|
||||||
this.idsSessionEnCours.clear();
|
this.idsSessionEnCours.clear();
|
||||||
|
|
Loading…
Reference in a new issue