packages communication,observers cleaned and commented

This commit is contained in:
Cavailles Kevin 2021-02-03 09:36:28 +01:00
parent 0dcfca4937
commit 15a618ec50
16 changed files with 514 additions and 246 deletions

View file

@ -1,34 +1,45 @@
package communication.filetransfer;
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import observers.ObserverInputMessage;
public class FileTransferClient {
private int port;
private ArrayList<File> files = null;
private ArrayList<File> files;
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.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 {
for(File f: this.files) {
FileTransferSendingThread ftc = new FileTransferSendingThread(this.port, f,this.obsInput);
for (File f : this.files) {
FileTransferSendingThread ftc = new FileTransferSendingThread(this.port, f, this.obsInput);
ftc.start();
ftc.join();
}

View file

@ -1,6 +1,5 @@
package communication.filetransfer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@ -19,16 +18,27 @@ public class FileTransferReceivingThread extends Thread {
private SocketChannel sockTransfert;
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.obsInput = obs;
this.obsInput = o;
}
public void run() {
try {
int nbByteRead = 0;
// Buffer to receive a chunk of the file
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(
this.sockTransfert.socket().getInputStream());
@ -42,9 +52,10 @@ public class FileTransferReceivingThread extends Thread {
String filePath = FileTransferUtils.DOWNLOADS_RELATIVE_PATH + fileInfo[0];
long fileSize = Long.parseLong(fileInfo[1]);
// OutputStream to create the file if it does not exist
FileOutputStream fOutStream = new FileOutputStream(filePath);
// Channel to write the data received in the file
FileChannel fileWriter = fOutStream.getChannel();
while (nbTotalBytesRead < fileSize && (nbByteRead = this.sockTransfert.read(fileData)) > 0) {
@ -58,11 +69,13 @@ public class FileTransferReceivingThread extends Thread {
fileWriter.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));
mUpdate.setSender("other");
this.obsInput.update(this, mUpdate);
this.obsInput.updateInput(this, mUpdate);
} catch (IOException | ClassNotFoundException e) {
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) {
return m.getContenu().split(";");
}

View file

@ -17,33 +17,46 @@ import messages.MessageFichier;
import messages.Message.TypeMessage;
import observers.ObserverInputMessage;
public class FileTransferSendingThread extends Thread{
public class FileTransferSendingThread extends Thread {
private SocketChannel sockTransfert;
private File file;
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();
SocketAddress addr = new InetSocketAddress(port);
sock.connect(addr);
this.sockTransfert = sock;
this.file = fileToSend;
this.obsInput = obs;
this.obsInput = o;
}
public void run() {
try {
// Buffer to send a chunk of the file
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(
this.sockTransfert.socket().getOutputStream());
// Channel to read the data of the file
FileChannel fileReader = FileChannel.open(Paths.get(file.getPath()));
String str = file.getName() + ";" + file.getTotalSpace();
// Send file datas (name + size);
// Send file data (name + size);
outputFileInformation.writeObject(new MessageFichier(TypeMessage.FICHIER, str, ""));
while (fileReader.read(fileData) > 0) {
@ -53,10 +66,13 @@ public class FileTransferSendingThread extends Thread{
}
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);
mUpdate.setSender("Moi");
this.obsInput.update(this, mUpdate);
this.obsInput.updateInput(this, mUpdate);
} catch (IOException | MauvaisTypeMessageException e) {
e.printStackTrace();
@ -69,6 +85,4 @@ public class FileTransferSendingThread extends Thread{
}
}
}

View file

@ -8,21 +8,32 @@ import java.nio.channels.SocketChannel;
import observers.ObserverInputMessage;
public class FileTransferServer extends Thread {
private ServerSocketChannel sockFTListen;
private int nbFile;
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.socket().bind(new InetSocketAddress(0));
this.nbFile = nbFile;
this.obsInput = obs;
this.obsInput = o;
}
/**
* @return The port binded to the ServerSocketChannel.
*/
public int getPort() {
return this.sockFTListen.socket().getLocalPort();
}

View file

@ -23,55 +23,76 @@ import messages.Message.TypeMessage;
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 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;
/**
* 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 {
String nameFile = file.getName();
String extension = processFileExtension(nameFile);
TypeMessage type;
String contenu;
if(IMAGE_EXTENSIONS.contains(extension)) {
if (IMAGE_EXTENSIONS.contains(extension)) {
type = TypeMessage.IMAGE;
BufferedImage img = ImageIO.read(file);
contenu = encodeImage(createThumbnail(img), extension) ;
contenu = encodeImage(createThumbnail(img), extension);
}else {
} else {
type = TypeMessage.FICHIER;
contenu = nameFile;
}
try {
//return new MessageFichier(type, contenu, extension);
return new MessageFichier(type, contenu, extension);
} catch (MauvaisTypeMessageException e) {
System.out.println("Should never go in");
e.printStackTrace();
}
return null;
}
/**
* @param fileName The name of the file (with its extension).
* @return The extension of the file.
*/
protected static String processFileExtension(String fileName) {
String extension = "";
int i = fileName.indexOf('.');
if (i >= 0 || i != -1) {
extension = fileName.substring(i+1).toLowerCase();
extension = fileName.substring(i + 1).toLowerCase();
}
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 ratio = (w > 150) ? (150F/w) : 1;
float ratio = (w > 150) ? (150F / w) : 1;
BufferedImage scaled = scale(image, ratio);
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 {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(img, extension, bos);
@ -80,15 +101,20 @@ public class FileTransferUtils {
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 {
byte[] imgData = Base64.getDecoder().decode(imageString);
InputStream is = new ByteArrayInputStream(imgData);
BufferedImage img = ImageIO.read(is);
is.close();
return img;
BufferedImage img = ImageIO.read(is);
is.close();
return img;
}
// Used to scale an image with a given ratio
private static BufferedImage scale(BufferedImage source, double ratio) {
int w = (int) (source.getWidth() * ratio);
int h = (int) (source.getHeight() * ratio);
@ -110,10 +136,14 @@ public class FileTransferUtils {
return image;
}
/**
* Create the folder with the path "DOWNLOADS_RELATIVE_PATH" if it does not
* exist.
*/
public static void createDownloads() {
File downloads = new File(FileTransferUtils.DOWNLOADS_RELATIVE_PATH);
if(!downloads.exists()) {
if (!downloads.exists()) {
downloads.mkdir();
}
}

View file

@ -5,63 +5,86 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import observers.ObserverInputMessage;
import observers.ObserverSocketState;
import messages.MauvaisTypeMessageException;
import messages.Message;
public class TCPClient {
private Socket sockTCP;
private ObjectOutputStream output;
private ObjectInputStream input;
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 {
this.sockTCP = sockTCP;
this.output = new ObjectOutputStream(sockTCP.getOutputStream());
ObjectInputStream input = new ObjectInputStream(sockTCP.getInputStream());
this.inputThread = new TCPInputThread(input);
}
public TCPClient(InetAddress addr, int port) throws IOException {
this(new Socket(addr, port));
this.input = new ObjectInputStream(sockTCP.getInputStream());
this.inputThread = new TCPInputThread(this.input);
}
/**
* Start the thread that will continuously read from the socket.
*/
public void startInputThread() {
this.inputThread.start();
}
public void sendMessage(Message message) throws IOException, MauvaisTypeMessageException {
System.out.println("dans write");
/**
* Send a message by writing it in the ObjectOutputStream of the socket
*
* @param message
* @throws IOException
*/
public void sendMessage(Message message) throws IOException {
this.output.writeObject(message);
}
/**
* Set the observer to notify when a message is received
*
* @param o The observer
*/
public void setObserverInputThread(ObserverInputMessage 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) {
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() {
try {
if (!this.sockTCP.isClosed()) {
this.inputThread.setObserverSocketState(null);
this.inputThread.interrupt();
this.input.close();
this.output.close();
this.sockTCP.close();
this.inputThread.setObserverSocketState(null);
}
this.inputThread = null;
this.sockTCP = null;

View file

@ -12,7 +12,12 @@ public class TCPInputThread extends Thread {
private ObserverInputMessage obsInput;
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.running = true;
}
@ -22,10 +27,9 @@ public class TCPInputThread extends Thread {
while (this.running) {
try {
System.out.println("dans read");
Object o = this.input.readObject();
this.obsInput.update(this, o);
Object o = this.input.readObject();
// Notify the observer a message was received
this.obsInput.updateInput(this, o);
} catch (IOException | ClassNotFoundException e) {
this.interrupt();
@ -37,34 +41,35 @@ public class TCPInputThread extends Thread {
@Override
public void interrupt() {
// Stop the thread
this.running = false;
// Close the stream and the socket
try {
//Stop the thread
this.running = false;
//Close the stream and the socket
this.input.close();
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();
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;
}
/**
* Set the observer to notify when a message is received
*
* @param o The observer
*/
protected void setObserverInputMessage(ObserverInputMessage o) {
this.obsInput = o;
}
/**
* Set the observer to notify when the session is cut/closed.
*
* @param o The observer
*/
protected void setObserverSocketState(ObserverSocketState o) {
this.obsState = o;
}

View file

@ -8,36 +8,45 @@ import java.net.UnknownHostException;
import observers.ObserverInputMessage;
public class TCPServer extends Thread {
//****
public static int PORT_SERVER = 7000;
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 {
this.sockListenTCP = new ServerSocket(port, 50, InetAddress.getLocalHost());
}
@Override
public void run() {
System.out.println("TCP running");
Socket sockAccept;
while(true) {
while (true) {
try {
sockAccept = this.sockListenTCP.accept();
this.obs.update(this, sockAccept);
// Notify the observer of the new connexion
this.obsInput.updateInput(this, sockAccept);
} catch (IOException e) {
// TODO Auto-generated catch block
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;
}
}

View file

@ -2,7 +2,6 @@ package communication.udp;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
@ -13,18 +12,23 @@ import observers.ObserverUserList;
public class CommunicationUDP extends Thread {
// ****
protected static int PORT_SERVEUR = 3000;
// ****
protected static int PORT_CLIENT = 2000;
private UDPClient client;
private UDPServer server;
private int portServer;
private ArrayList<Integer> portOthers;
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 {
this.portServer = portServer;
this.portOthers = this.getArrayListFromArray(portsOther);
@ -33,14 +37,13 @@ public class CommunicationUDP extends Thread {
this.client = new UDPClient(portClient);
}
// ****
public CommunicationUDP() throws SocketException, UnknownHostException {
this.portServer = PORT_SERVEUR;
this.server = new UDPServer(portServer, this);
this.server.start();
this.client = new UDPClient(PORT_CLIENT);
}
/**
* Create an ArrayList<Integer> from the int[] list of every servers' ports and
* remove the port of this application UDPServer.
*
* @param ports The UDPServer port numbers.
* @return An ArrayList<Integer> without the port of this UDPServer.
*/
private ArrayList<Integer> getArrayListFromArray(int ports[]) {
ArrayList<Integer> tmp = new ArrayList<Integer>();
for (int port : ports) {
@ -51,42 +54,83 @@ public class CommunicationUDP extends Thread {
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 --------------//
protected synchronized void addUser(String idClient, String pseudoClient, InetAddress ipClient, int port)
throws IOException {
users.add(new Utilisateur(idClient, pseudoClient, ipClient, port));
/**
* Add a new user to the userlist and notify the observer.
*
* @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();
}
protected synchronized void changePseudoUser(String idClient, String pseudoClient, InetAddress ipClient, int port) {
int index = getIndexFromID(idClient);
users.get(index).setPseudo(pseudoClient);
this.sendUpdate();
/**
* Change the pseudo of an user and notify the observer if it exists in the
* userlist. Do nothing otherwise.
*
* @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) {
users.remove(index);
this.sendUpdate();
}
this.sendUpdate();
}
public void removeAll() {
int oSize = users.size();
for (int i = 0; i < oSize; i++) {
users.remove(0);
}
public void removeAllUsers() {
this.users.clear();
}
// -------------- 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) {
for (Utilisateur u : users) {
if (u.getId().equals(id)) {
@ -96,6 +140,13 @@ public class CommunicationUDP extends Thread {
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) {
for (Utilisateur u : users) {
if (u.getPseudo().toLowerCase().equals(pseudo)) {
@ -108,6 +159,13 @@ public class CommunicationUDP extends Thread {
// -------------- 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) {
for (int i = 0; i < users.size(); i++) {
if (users.get(i).getPseudo().equals(pseudo)) {
@ -117,6 +175,13 @@ public class CommunicationUDP extends Thread {
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) {
for (int i = 0; i < users.size(); i++) {
if (users.get(i).getId().equals(id)) {
@ -128,79 +193,100 @@ public class CommunicationUDP extends Thread {
// -------------- 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 {
for (int port : this.portOthers) {
try {
this.client.sendMessageUDP_local(new MessageSysteme(Message.TypeMessage.JE_SUIS_CONNECTE), port,
InetAddress.getLocalHost());
} catch (MauvaisTypeMessageException e) {
/* Si ça marche pas essayer là */}
try {
Message msgOut = new MessageSysteme(Message.TypeMessage.JE_SUIS_CONNECTE);
for (int port : this.portOthers) {
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"
// This allows the receivers' agent (portOthers) to create or modify an entry
// with the
// data of this agent
// Typically used to notify of a name change
/**
* Send a message containing this application's user's data to every UDPServer.
* This method is used to first add this user in the userlist or update this
* user's pseudo.
*
* @throws UnknownHostException
* @throws IOException
*/
public void sendMessageInfoPseudo() throws UnknownHostException, IOException {
Utilisateur self = Utilisateur.getSelf();
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) {
this.client.sendMessageUDP_local(msgOut, port, InetAddress.getLocalHost());
this.client.sendMessageUDP_local(msgOut, port);
}
} catch (Exception e) {
} catch (MauvaisTypeMessageException e) {
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 {
Utilisateur self = Utilisateur.getSelf();
try {
Message msgOut = new MessageSysteme(Message.TypeMessage.INFO_PSEUDO, self.getPseudo(), self.getId(),
self.getPort());
this.client.sendMessageUDP_local(msgOut, portOther, InetAddress.getLocalHost());
this.client.sendMessageUDP_local(msgOut, portOther);
} catch (MauvaisTypeMessageException e) {
e.printStackTrace();
}
}
// Send the message "del,id,pseudo" to localhost on all the ports in
// "portOthers"
// This allows the receivers' agent (portOthers) to delete the entry
// corresponding to this agent
/**
* Send a message indicating this application's user is disconnected to every
* UDPServer.
*
* @throws UnknownHostException
* @throws IOException
*/
public void sendMessageDelete() throws UnknownHostException, IOException {
Utilisateur self = Utilisateur.getSelf();
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) {
this.client.sendMessageUDP_local(msgOut, port, InetAddress.getLocalHost());
this.client.sendMessageUDP_local(msgOut, port);
}
} catch (MauvaisTypeMessageException e) {
e.printStackTrace();
}
}
/**
* Notify the observer with the updated list
*/
private void sendUpdate() {
if(this.observer != null) {
this.observer.updateList(this, users);
if (this.obsList != null) {
this.obsList.updateList(this, users);
}
}
public void destroyAll() {
this.client.destroyAll();
this.server.interrupt();
}
}

View file

@ -4,40 +4,52 @@ import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import messages.*;
public class UDPClient {
class UDPClient {
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 {
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 to the specified port on localhost.
*
* @param message
* @param port
* @throws IOException
*/
protected void sendMessageUDP_local(Message message, int port) throws IOException {
sendMessageUDP(message, port, InetAddress.getLocalHost());
}
//Send a message casted as string to the specified port on localhost
protected void sendMessageUDP_local(Message message, int port, InetAddress clientAddress) throws IOException {
String messageString= message.toString();
DatagramPacket outpacket = new DatagramPacket(messageString.getBytes(), messageString.length(), clientAddress, port);
/**
* 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);
}
protected void destroyAll() {
this.sockUDP.close();
this.sockUDP = null;
this.broadcast = null;
}
}

View file

@ -8,13 +8,22 @@ import java.net.SocketException;
import main.Utilisateur;
import messages.*;
public class UDPServer extends Thread {
class UDPServer extends Thread {
private DatagramSocket sockUDP;
private CommunicationUDP commUDP;
private byte[] buffer;
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 {
this.running = true;
this.commUDP = commUDP;
@ -28,11 +37,13 @@ public class UDPServer extends Thread {
try {
//When a datagram is received, converts its data in a Message
DatagramPacket inPacket = new DatagramPacket(buffer, buffer.length);
this.sockUDP.receive(inPacket);
String msgString = new String(inPacket.getData(), 0, inPacket.getLength());
Message msg = Message.stringToMessage(msgString);
//Depending on the type of the message
switch (msg.getTypeMessage()) {
case JE_SUIS_CONNECTE:
@ -40,34 +51,38 @@ public class UDPServer extends Thread {
int portClient = inPacket.getPort();
int portServer = portClient+1;
//Answer back with this application's user data
this.commUDP.sendMessageInfoPseudo(portServer);
}
break;
case INFO_PSEUDO:
MessageSysteme m = (MessageSysteme) msg;
//Update the userlist with the data received (Add the user or update it)
if (this.commUDP.containsUserFromID(m.getId())) {
this.commUDP.changePseudoUser(m.getId(), m.getPseudo(), inPacket.getAddress(), m.getPort());
} else {
this.commUDP.addUser(m.getId(), m.getPseudo(), inPacket.getAddress(), m.getPort());
System.out.println(m.getId() + ", " + m.getPseudo());
}
break;
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;
default: // Others types of messages are ignored because they are supposed to be
// transmitted by TCP and not UDP
//Do nothing
default:
}
} catch (IOException e) {
System.out.println("receive exception");
e.printStackTrace();
}
}

View file

@ -1,5 +1,12 @@
package observers;
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);
}

View file

@ -2,6 +2,12 @@ package observers;
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);
}

View file

@ -6,6 +6,12 @@ import main.Utilisateur;
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);
}

View file

@ -39,6 +39,16 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
private SQLiteManager sqlManager;
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 {
this.vue = vue;
this.tcpClient = new TCPClient(socketComm);
@ -60,7 +70,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
@Override
public void actionPerformed(ActionEvent e) {
//Quand le bouton envoyer est presse
//If the button "Envoyer" is pressed
if ((JButton) e.getSource() == this.vue.getButtonEnvoyer()) {
String messageContent = this.vue.getInputedText();
System.out.println(messageContent);
@ -92,8 +102,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
try {
this.tcpClient.sendMessage(messageOut);
} catch (MauvaisTypeMessageException | IOException e1) {
// TODO Auto-generated catch block
} catch (IOException e1) {
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()) {
//Display a file chooser to select one or several files
JFileChooser fc = new JFileChooser();
fc.setMultiSelectionEnabled(true);
int returVal = fc.showDialog(this.vue, "Importer");
@ -126,10 +137,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public void keyTyped(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {
@ -142,10 +150,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
public void keyReleased(KeyEvent e) {}
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
public void update(Object o, Object arg) {
public void updateInput(Object o, Object arg) {
Message message = (Message) arg;
switch(message.getTypeMessage()) {
case TEXTE:
System.out.println(message.toString());
@ -217,6 +223,7 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
this.messagesIn.add(message);
}
break;
case FICHIER_INIT:
try {
MessageFichier mFichier = (MessageFichier) arg;
@ -245,16 +252,23 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
}
break;
//Do nothing
default:
}
}
//If the other user closes the session or the communication is broken
//Disable the view (TextArea, Buttons..) and display a message
@Override
public void updateSocketState(Object o, Object arg) {
this.vue.endSession(this.pseudoOther);
}
/**
*
*/
protected void destroyAll() {
String idSelf = Utilisateur.getSelf().getId();
String idOther = this.idOther;
@ -263,11 +277,9 @@ public class ControleurSession implements ActionListener, ObserverInputMessage,
this.sqlManager.insertAllMessages(messagesOut, idSelf, idOther);
this.sqlManager.insertAllMessages(messagesIn, idOther, idSelf);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.vue = null;
this.tcpClient.destroyAll();
this.tcpClient = null;

View file

@ -245,7 +245,7 @@ public class ControleurStandard implements ActionListener, ListSelectionListener
// ------------OBSERVERS-------------//
@Override
public void update(Object o, Object arg) {
public void updateInput(Object o, Object arg) {
if (o == this.tcpServ) {
@ -304,6 +304,7 @@ public class ControleurStandard implements ActionListener, ListSelectionListener
private void setVueConnexion() throws UnknownHostException, IOException {
this.commUDP.sendMessageDelete();
this.commUDP.removeAllUsers();
this.vue.removeAllUsers();
this.vue.closeAllSession();
this.idsSessionEnCours.clear();