Commit 46436322 authored by Quentin DRUAULT-AUBIN's avatar Quentin DRUAULT-AUBIN

Merge branch 'develop' into 'master'

First successful integration (with game working)

See merge request qdruault/lo23-project!156
parents 9994d270 53f7328d
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="src" path="Battleship/src/main/resources"/>
<classpathentry kind="src" path="Battleship/src/test/java"/>
<classpathentry kind="src" path="Battleship/src/main/java"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>lo23-project</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
......@@ -25,7 +25,7 @@ public class MainApp extends Application {
*/
@Override
public void start(Stage stage) throws Exception {
// DataFacade creation
DataFacade dataFacade = new DataFacade();
IDataCom iDataCom = dataFacade;
......@@ -54,6 +54,9 @@ public class MainApp extends Application {
// set link from IhmMain, Ihmtable and Communication Facade to Data
dataFacade.setFacadeLinks(comFacade, iIHMTableToData, ihmMainFacade);
// Just for IHM-Table tests, comment for real integration.
//ihmTableFacade.createInGameGUI(stage);
}
/**
......
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.utclo23.com;
import java.net.Inet4Address;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Thomas
*/
public class DiscoveryController {
// TODO: add a lock on this one
private List<Inet4Address> getIpIssuedList;
private DiscoveryController() {
getIpIssuedList = new ArrayList<Inet4Address>();
}
// SINGLETON
// Holder
private static class SingletonHolder {
private final static DiscoveryController instance = new DiscoveryController();
}
// Access point for unique instance of the singleton class
public static DiscoveryController getInstance() {
return SingletonHolder.instance;
}
public void addIP(Inet4Address ip) {
getIpIssuedList.add(ip);
}
public boolean isIn(Inet4Address Ip) {
return getIpIssuedList.contains(Ip);
}
public List<Inet4Address> getGetIpIssuedList() {
return getIpIssuedList;
}
}
......@@ -7,118 +7,102 @@ package com.utclo23.com;
import java.util.HashMap;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import com.utclo23.data.facade.IDataCom;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Class containing a hashmap with UID and corresponding IP address of the known
* players. Singleton class,only one instance can be instantiate in the
* application.
*
* @author Thomas
* @author Thomas Michel
*/
public class KnownIPController {
// All IP known by this node
// TODO: add a lock on this one
private final HashMap<String, Inet4Address> knownIp;
IDataCom iDataCom;
InterfaceAddress usedInterface;
// private constructor
protected IDataCom iDataCom;
private InterfaceAddress usedInterface;
private static final int PORT = 25000;
private KnownIPController() {
knownIp = new HashMap<>();
}
// SINGLETON
// Holder
/**
* Called to instantiate the unique instance of KnowIPController class in
* the application.
*/
private static class SingletonHolder {
private SingletonHolder(){
throw new IllegalStateException("Utility class");
}
private final static KnownIPController INSTANCE = new KnownIPController();
private static final KnownIPController INSTANCE = new KnownIPController();
}
// Access point for unique INSTANCE of the singleton class
/**
* Called to return the unique INSTANCE of the singleton class
* KnownIPController.
*
* @return singleton instnce of KnowIPController
*/
public static KnownIPController getInstance() {
return SingletonHolder.INSTANCE;
}
public Inet4Address getMyInetAddress(){
return (Inet4Address)this.usedInterface.getAddress();
public Inet4Address getMyInetAddress() {
return (Inet4Address) this.usedInterface.getAddress();
}
public void setUsedInterface(InterfaceAddress uif){
public void setUsedInterface(InterfaceAddress uif) {
this.usedInterface = uif;
}
// used to put our own IP in the hashmap of IP
/**
* Called to put our own IP in attribute "knownIP" and initialize iDataCom
* attribute.
*
* @param iDataCom is the Value affected to attribute iDataCom of the class
*/
public void initIpList(IDataCom iDataCom) {
try {
this.iDataCom = iDataCom;
knownIp.put(
iDataCom.getMyPublicUserProfile().getId(),
(Inet4Address) Inet4Address.getLocalHost());
} catch (UnknownHostException e) {}
}
this.iDataCom = iDataCom;
knownIp.put(
iDataCom.getMyPublicUserProfile().getId(),
getMyInetAddress());
public String getKeyFromValue(
HashMap<String, Inet4Address> tmphash,
Inet4Address value
) {
String key = null;
for (Map.Entry<String, Inet4Address> entry : tmphash.entrySet()) {
if (value.equals(entry.getValue())) {
return entry.getKey();
}
}
return null;
}
/**
* Called to return attribute "knownIp" value without our own node.
*
* @return Hashmap value
*/
public HashMap<String, Inet4Address> getHashMap() {
try {
Inet4Address ourIpAddress = (Inet4Address) Inet4Address.getLocalHost();
HashMap<String, Inet4Address> tmphash = knownIp;
tmphash.remove(iDataCom.getMyPublicUserProfile().getLightPublicUser().getId()); // to avoid sending back our own Ip adress (cuz it already got it).
return tmphash;
} catch (UnknownHostException e) {
// No good
return null;
}
}
public HashMap<String, Inet4Address> getNewIpHashMap() {
DiscoveryController discoCtrl = DiscoveryController.getInstance();
try {
Inet4Address ourIpAddress = (Inet4Address) Inet4Address.getLocalHost();
HashMap<String, Inet4Address> tmphash = knownIp;
tmphash.remove(iDataCom.getMyPublicUserProfile().getLightPublicUser().getId()); // to avoid sending back our own Ip adress (cuz it already got it).
List<Inet4Address> getIpIssuedList = discoCtrl.getGetIpIssuedList();
String key;
for (int i = 0; i < getIpIssuedList.size(); i++) {
key = getKeyFromValue(tmphash, getIpIssuedList.get(i));
tmphash.remove(key);
}
return tmphash;
} catch (UnknownHostException e) {
// No good
return null;
}
String id = iDataCom.getMyPublicUserProfile().getLightPublicUser().getId();
knownIp.remove(id); // to avoid sending back our own Ip adress (cuz it already got it).
return knownIp;
}
/**
* Called to add a new node in the attribute "knownIP".
*
* @param id is the "id", of type string, of the new node
* @param ip is the Inet4address of the new node
*/
public void addNode(String id, Inet4Address ip) {
knownIp.put(id, ip);
}
public void addNonExistingNodes(HashMap<String, Inet4Address> hashToCheck) {
Iterator it = hashToCheck.entrySet().iterator();
while (it.hasNext()) {
HashMap.Entry pair = (HashMap.Entry) it.next();
if (!knownIp.containsKey(pair.getKey())) {
knownIp.put((String) pair.getKey(), (Inet4Address) pair.getValue());
}
it.remove(); // avoids a ConcurrentModificationException
}
/**
* Acessor
* @return the network port number
*/
public int getPort(){
return PORT;
}
}
......@@ -8,12 +8,16 @@ package com.utclo23.com;
import java.net.Socket;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import com.utclo23.com.messages.Message;
import com.utclo23.data.facade.IDataCom;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* This class implements a serverSocket to receive messages from another
* machines. An unique instance of Receiver should be running. Running in a
* different thread from the main thread.
* @author Thomas MICHEL
* @author Grégoire MARTINACHE
*/
......@@ -25,12 +29,19 @@ public class Receiver implements Runnable {
ObjectInputStream in;
IDataCom iDataCom;
/**
* Construction of Receiver. Initialize attributes "serverSocket" and
* "iDataCom" with the specified parameters.
* @param port Number of the port used by the serverSocket
* @param dataCom Access of the IDataCom interface used by the others COM
* modules
*/
public Receiver(int port, IDataCom dataCom){
try {
serverSocket = new ServerSocket(port);
iDataCom = dataCom;
}catch(IOException e){
e.printStackTrace();
}catch(IOException ex){
Logger.getLogger(ComFacade.class.getName()).log(Level.INFO, null, ex);
}
}
......@@ -40,24 +51,15 @@ public class Receiver implements Runnable {
try {
client = serverSocket.accept();
in = new ObjectInputStream(client.getInputStream());
System.out.println(in.available());
request = (Message) in.readObject();
request.callback(iDataCom);
/*while((request = (Message) in.readObject()) != null)
{
request.callback(iDataCom);
break;
}*/
//Logger.getLogger(Receiver.class.getName()).log(Level.INFO, null, "Message received : " + request.getClass().toString());
System.out.println("Message received :" + request.getClass().toString());
client.close();
in.close();
} catch (IOException e) {
} catch (ClassNotFoundException e) {
} catch (IOException|ClassNotFoundException ex) {
Logger.getLogger(ComFacade.class.getName()).log(Level.INFO, null, ex);
}
}
}
}
......@@ -5,30 +5,37 @@
*/
package com.utclo23.com;
import com.utclo23.com.messages.M_Connexion;
import java.net.Socket;
import java.net.UnknownHostException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import com.utclo23.com.messages.Message;
import com.utclo23.data.structure.PublicUser;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This class is used to send an object to a recipient. The object is sent by a
* different thread thanks to a socket. Thread and socket are closed after
* sending. A sender should be instantiate every time an object has to be sent.
*
* @author Thomas MICHEL
* @author Grégoire MARTINACHE
*/
public class Sender implements Runnable {
Socket socket;
int port;
String ip;
Message request;
ObjectOutputStream out;
//ObjectInputStream in;
/**
* Constructor of Sender class. Initialize attributes ip, port and request
* message with the specified parameters.
*
* @param ip IP destination
* @param port Number of the port
* @param request Message instance to send
*/
public Sender(String ip, int port, Message request) {
this.ip = ip;
this.port = port;
......@@ -41,18 +48,16 @@ public class Sender implements Runnable {
KnownIPController kIpCtrl = KnownIPController.getInstance();
socket = new Socket();
socket.setSoTimeout(2000);
socket.connect(new InetSocketAddress(ip, port), 2000);
socket.connect(new InetSocketAddress(ip, port), kIpCtrl.getPort());
out = new ObjectOutputStream(socket.getOutputStream());
//in = new ObjectInputStream(socket.getInputStream());
request.setIpSender(kIpCtrl.getMyInetAddress());
out.writeObject(request);
//in.close();
//Logger.getLogger(ComFacade.class.getName()).log(Level.INFO, null, "Message sent : " + request.getClass().toString());
System.out.println("Message sent : " + request.getClass().toString() + " to "+ ip);
out.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IOException ex) {
Logger.getLogger(ComFacade.class.getName()).log(Level.INFO, null, ex);
}
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.utclo23.com.messages;
import com.utclo23.com.KnownIPController;
import com.utclo23.com.Sender;
import com.utclo23.data.facade.IDataCom;
import com.utclo23.data.structure.LightPublicUser;
import com.utclo23.data.structure.PublicUser;
import com.utclo23.data.structure.StatGame;
import java.net.Inet4Address;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Thibault Chiche
*/
public class M_Bleu extends Message {
private final HashMap<String, Inet4Address> hashMapReceived;
private final List<LightPublicUser> usersReceived;
private final List<StatGame> listGamesReceived;
private final List<Inet4Address> otherTargets;
public M_Bleu(PublicUser user, HashMap<String, Inet4Address> hashMap,
List<LightPublicUser> users, List<StatGame> listGames, List<Inet4Address> oTargets) {
super(user);
this.hashMapReceived = hashMap;
this.usersReceived = users;
this.listGamesReceived = listGames;
this.otherTargets = oTargets;
}
@Override
public void callback(IDataCom iDataCom) {
Logger.getLogger(M_Bleu.class.getName()).log(Level.INFO, null, "Blue message received");
List<String> myUsersId = new ArrayList(KnownIPController.getInstance().getHashMap().keySet());
List<LightPublicUser> myUsersProfile = new ArrayList(iDataCom.getConnectedUsers());
HashMap<String, Inet4Address> newPairs = new HashMap();
List<LightPublicUser> newUsersProfile = new ArrayList();
// Envoi message bleu aux autres targets afin que tout le monde ait
// les mêmes joueurs connectés. Les premiers qui recevront ces messages
// seront prioritaires
HashMap<String, Inet4Address> tmpHash = new HashMap(KnownIPController.getInstance().getHashMap());
tmpHash.put(iDataCom.getMyPublicUserProfile().getId(), KnownIPController.getInstance().getMyInetAddress());
List<LightPublicUser> tmp = new ArrayList(iDataCom.getConnectedUsers());
tmp.add(iDataCom.getMyPublicUserProfile().getLightPublicUser());
if (this.otherTargets != null) {
for (Inet4Address ipDest : this.otherTargets) {
// On envoie pas si on avait déjà l'IP dans le hashMap
if (!KnownIPController.getInstance().getHashMap().containsValue(ipDest)) {
M_Bleu m_Bleu = new M_Bleu(iDataCom.getMyPublicUserProfile(),
tmpHash, tmp, iDataCom.getGameList(), null);
Sender os = new Sender(ipDest.getHostAddress(), KnownIPController.getInstance().getPort(), m_Bleu);
new Thread(os).start();
}
}
}
// Envoi message rouge à ceux non déjà présents dans nos joueurs connectés
for (Map.Entry<String, Inet4Address> entry : this.hashMapReceived.entrySet()) {
if (!entry.getKey().equals(iDataCom.getMyPublicUserProfile().getId())
&& !myUsersId.contains(entry.getKey())) {
M_Rouge mRouge = new M_Rouge(iDataCom.getMyPublicUserProfile(), tmpHash, tmp, iDataCom.getGameList());
Sender os = new Sender(entry.getValue().getHostAddress(), KnownIPController.getInstance().getPort(), mRouge);
Thread thread = new Thread(os);
thread.start();
newPairs.put(entry.getKey(), entry.getValue());
}
}
for (LightPublicUser key : this.usersReceived) {
if (!key.getId().equals(iDataCom.getMyPublicUserProfile().getLightPublicUser().getId())
&& !myUsersProfile.contains(key)) {
newUsersProfile.add(key);
}
}
// Maj de nos listes avec les nouvelles données reçues
// maj de la liste des games
for (StatGame game : this.listGamesReceived) {
if (!iDataCom.getGameList().contains(game)) {
iDataCom.addNewGame(game);
}
}
for (Map.Entry<String, Inet4Address> entry : newPairs.entrySet()) {
KnownIPController.getInstance().getHashMap().put(entry.getKey(), entry.getValue());
}
for (LightPublicUser key : newUsersProfile) {
iDataCom.addConnectedUser(key);
}
}
}
......@@ -6,21 +6,25 @@
package com.utclo23.com.messages;
import com.utclo23.data.facade.IDataCom;
import com.utclo23.data.structure.PublicUser;
import java.util.Date;
/**
*
* @author thibault
* M_Chat is a Message generated when a user sends a new chat message.
* @author Thibault CHICHE
*/
public class M_Chat extends Message {
private com.utclo23.data.structure.Message message;
private Date timeStamp;
private final com.utclo23.data.structure.Message message;
public M_Chat(PublicUser user, com.utclo23.data.structure.Message m, Date t){
/**
* Constructor.
* @param user is the message's sender
* @param messageContent is the content of the message
*/
public M_Chat(PublicUser user, com.utclo23.data.structure.Message messageContent){
super(user);
message = m;
timeStamp = t;
message = messageContent;
}
@Override
public void callback(IDataCom iDataCom){
iDataCom.forwardMessage(this.message);
......
......@@ -9,10 +9,16 @@ import com.utclo23.data.facade.IDataCom;
import com.utclo23.data.structure.PublicUser;
/**
*
* @author thibault
* M_ConnexionLost is a Message generated when a user looses connection,
* sent to all connected users.
* @author Thibault CHICHE
*/
public class M_ConnexionLost extends Message{
/**
* Constructor.
* @param user is the message's sender
*/
public M_ConnexionLost(PublicUser user){
super(user);
}
......
......@@ -8,15 +8,21 @@ import com.utclo23.data.facade.IDataCom;
import com.utclo23.data.structure.PublicUser;
import com.utclo23.data.structure.StatGame;
/**
*
* @author thibault
* M_CreationGame is a Message generated when a game is created,
* sent to all connected users.
* @author Thibault CHICHE
*/
public class M_CreationGame extends Message{
public StatGame game;
public final StatGame game;
public M_CreationGame(PublicUser user, StatGame g){
/**
* Constructor.
* @param user is the message's sender
* @param game is the created game
*/
public M_CreationGame(PublicUser user, StatGame game){
super(user);
game = g;
this.game = game;
}
@Override
......
......@@ -4,20 +4,27 @@
* and open the template in the editor.
*/
package com.utclo23.com.messages;
import com.utclo23.com.KnownIPController;
import com.utclo23.data.facade.IDataCom;
import com.utclo23.data.structure.PublicUser;
/**
*
* @author thibault
* M_Deconnection is a Message generated when a user disconnects,
sent to all connected users.
* @author Thibault CHICHE
*/
public class M_Deconnexion extends Message {
public M_Deconnexion(PublicUser user){
public class M_Deconnection extends Message {
/**
* Constructor.
* @param user is the message's sender
*/
public M_Deconnection(PublicUser user){
super(user);
}
@Override
public void callback(IDataCom iDataCom){
iDataCom.removeConnectedUser(user.getLightPublicUser());
KnownIPController.getInstance().getHashMap().remove(user.getId());