diff --git a/data/src/main/java/core/DataProvider.java b/data/src/main/java/core/DataProvider.java index 070b574d179d4cbca946eefd950ff69afce6ff3d..f714dadeacdc85800d7b4303380e932d2dea3bbe 100644 --- a/data/src/main/java/core/DataProvider.java +++ b/data/src/main/java/core/DataProvider.java @@ -11,19 +11,19 @@ import interfaces.Net; public class DataProvider { private static volatile Datacore dc; - void initData(Net net, Ihm ihm) throws DataException { - if (DataProvider.dc != null) { + public void initData(Net net, Ihm ihm) throws DataException { + if (DataProvider.dc == null) { DataProvider.dc = new Datacore(net, ihm); } else { throw new DataException("Datacore already initialized."); } } - DataForNet getDataForNet() { + public DataForNet getDataForNet() { return new DataForNetImpl(); } - DataForIhm getDataForIhm() { + public DataForIhm getDataForIhm() { return new DataForIhmImpl(); } } diff --git a/data/src/main/java/core/Datacore.java b/data/src/main/java/core/Datacore.java index 1874e95efab8c018244c59171b5a4bfae024e30c..98d81921e3a1c101296e06c27018b1fa5db41ac2 100644 --- a/data/src/main/java/core/Datacore.java +++ b/data/src/main/java/core/Datacore.java @@ -12,6 +12,7 @@ import java.util.UUID; import java.util.stream.Stream; public class Datacore { + public static final String LOCAL_USERS_FILENAME = "lo23-users.ser"; public Net net; public Ihm ihm; private volatile HashMap<UUID, User> users; diff --git a/data/src/main/java/features/CreateUser.java b/data/src/main/java/features/CreateUser.java new file mode 100644 index 0000000000000000000000000000000000000000..5080585d5615ea41f52b7c6e5fcf56d4f1f17303 --- /dev/null +++ b/data/src/main/java/features/CreateUser.java @@ -0,0 +1,67 @@ +package features; + +import core.Datacore; +import datamodel.LocalUser; + +import java.io.EOFException; +import java.io.File; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Properties; +import javax.security.auth.login.LoginException; + +public abstract class CreateUser { + /** + * Check if there is a config.properties file in the user's save path. + * If there is no config file + * yet, create a config.properties file by copy of default-config.properties + * default-config.properties is located in resources/ + * Then the function is calling Login.run function by giving + * the Datacore object and the LocalUser + * + * @param user LocalUser given by IHM + */ + public static void run(LocalUser user, Datacore dc, InputStream defaultPropInputStream) + throws IOException, LoginException { + //Create file config.properties + Properties defaultProp = new Properties(); + Path userPropFilePath = user.getSavePath().resolve(user.getUsername() + "-config.properties"); + File userConfigFile = new File(userPropFilePath.toString()); + + //If there is no config file for our user in the his path + if (!userConfigFile.exists()) { + if (defaultPropInputStream != null) { + defaultProp.load(defaultPropInputStream); + } else { + throw new FileNotFoundException( + "Warning: default property file not found in the resources path"); + } + defaultProp.store(new FileOutputStream(userPropFilePath.toString()), null); + } + + FileInputStream file = new FileInputStream(Paths.get(Datacore.LOCAL_USERS_FILENAME).toFile()); + ObjectInputStream reader = new ObjectInputStream(file); + LocalUser otherUser; + try { + do { + otherUser = (LocalUser) reader.readObject(); + } while (!(user.getUsername().equals(otherUser.getUsername()))); + } catch (EOFException e) { + //Log user immediately after creation + Login.run(dc, user); + return; + } catch (ClassNotFoundException e) { + throw new LoginException("Local save may be corrupted or outdated"); + } + throw new LoginException(("Username already exists")); + } +} + + diff --git a/data/src/main/java/features/Login.java b/data/src/main/java/features/Login.java index 58cac192de318c126fdecab8b06ca37e0b46da38..86332597e13cbcc74a78328acf98c95ab818430a 100644 --- a/data/src/main/java/features/Login.java +++ b/data/src/main/java/features/Login.java @@ -73,7 +73,8 @@ public abstract class Login { public static void run(Datacore dc, String username, String password) throws IOException, LoginException { Path savePath = Paths.get("").toAbsolutePath(); - LocalUser user = loadUserFromDisk(savePath.resolve("lo23-users.ser"), username, password); + LocalUser user = loadUserFromDisk(savePath.resolve(dc.LOCAL_USERS_FILENAME), + username, password); run(dc, user); } diff --git a/data/src/main/java/interfaces/DataForIhmImpl.java b/data/src/main/java/interfaces/DataForIhmImpl.java index 7f521e151502c122e3246997442b758dd3a4b7f1..e720a531d46132d472e7ad5a4960ba8eebf375a1 100644 --- a/data/src/main/java/interfaces/DataForIhmImpl.java +++ b/data/src/main/java/interfaces/DataForIhmImpl.java @@ -7,14 +7,17 @@ import datamodel.Music; import datamodel.MusicMetadata; import datamodel.SearchQuery; import datamodel.User; +import features.CreateUser; import features.Login; import features.ShareMusicsPayload; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.util.Collection; import java.util.Collections; import java.util.List; + import java.util.stream.Stream; import javax.security.auth.login.LoginException; @@ -45,8 +48,10 @@ public class DataForIhmImpl implements DataForIhm { } @Override - public void createUser(LocalUser user) { - throw new UnsupportedOperationException("Not implemented yet"); + public void createUser(LocalUser user) throws IOException, LoginException { + InputStream defaultPropInputStream = getClass().getClassLoader() + .getResourceAsStream("default-config.properties"); + CreateUser.run(user, this.dc, defaultPropInputStream); } @Override @@ -90,6 +95,12 @@ public class DataForIhmImpl implements DataForIhm { throw new UnsupportedOperationException("Not implemented yet"); } + @Override + public MusicMetadata parseMusicMetadata(String path) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Override public void rateMusic(Music music, int rating) { throw new UnsupportedOperationException("Not implemented yet"); diff --git a/data/src/resources/default-config.properties b/data/src/resources/default-config.properties new file mode 100644 index 0000000000000000000000000000000000000000..b8c3a66198733345afbabe24e202aed142a9f4a8 --- /dev/null +++ b/data/src/resources/default-config.properties @@ -0,0 +1 @@ +ips="" \ No newline at end of file diff --git a/ihm/src/main/java/core/IhmCore.java b/ihm/src/main/java/core/IhmCore.java index e23f25b01eb8c0181e1b967bf9c932c67819400f..ed7a4c413c634fed30850c8e0c8fbea21004a9d3 100644 --- a/ihm/src/main/java/core/IhmCore.java +++ b/ihm/src/main/java/core/IhmCore.java @@ -5,6 +5,7 @@ import controllers.LoginController; import controllers.MainController; import controllers.SignUpController; +import interfaces.DataForIhm; import java.awt.Toolkit; import javafx.application.Application; @@ -16,74 +17,77 @@ import javafx.stage.Screen; import javafx.stage.Stage; /** - * the IhmCore will start the HCI of the Application, manages controllers and stage changes. + * the IhmCore will start the HCI of the Application, manages controllers and stage changes. */ public class IhmCore extends Application { private Scene loginScene; private Scene signupScene; private Scene forgottenPasswordScene; - + /** * the general scene. */ private Stage primaryStage; - + private MainController mainController; private LoginController loginController; private SignUpController signUpController; private ForgottenPasswordController forgottenPasswordController; - + //private DataInterface dataInterface - - private IhmForData ihmForData; - + private IhmForData ihmForData; + private DataForIhm dataForIhm; private double width = Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2; private double height = Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2; - + public IhmCore() { this.ihmForData = new IhmForData(this); } - /** - * Setter for @see IhmForData. - * @param ihmForData the integration of ihm interface - */ + * Setter for @see IhmForData. + * + * @param ihmForData the integration of ihm interface + */ public void setIhmForData(IhmForData ihmForData) { this.ihmForData = ihmForData; } - + /** - * Setter of @see MainController. - * @param mainController the main Controller - */ + * Setter of @see MainController. + * + * @param mainController the main Controller + */ public void setMainController(MainController mainController) { this.mainController = mainController; } /** * Setter of @see LoginController. + * * @param loginController the login Controller - */ + */ public void setLoginController(LoginController loginController) { this.loginController = loginController; } /** * Setter of @see SignUpController. + * * @param signUpController the signup Controller - */ + */ public void setSignUpController(SignUpController signUpController) { this.signUpController = signUpController; } /** * Setter of @see ForgottenPasswordController. + * * @param forgottenPwdController the forgotten password Controller */ public void setForgottenPasswordController(ForgottenPasswordController forgottenPwdController) { @@ -92,38 +96,43 @@ public class IhmCore extends Application { /** * Getter of @see IhmForData. + * * @return @see IhmForData */ public IhmForData getIhmForData() { return ihmForData; } - + /** * Getter of @see MainController. + * * @return @see MainController - */ + */ public MainController getMainController() { return this.mainController; } /** * Getter of @see LoginController. + * * @return @see LoginController - */ + */ public LoginController getLoginController() { return this.loginController; } /** * Getter of @see SignUpController. + * * @return @see SignUpController - */ + */ public SignUpController getSignUpController() { return this.signUpController; } /** * Getter of @see ForgottenPasswordController. + * * @return @see ForgottenPasswordController */ public ForgottenPasswordController getForgottenPasswordController() { @@ -197,12 +206,12 @@ public class IhmCore extends Application { ForgottenPasswordController forgottenPasswordController = forgottenPasswordLoader.getController(); - + //set the Controllers link to acces from the controllers setLoginController(loginController); setSignUpController(signUpController); setForgottenPasswordController(forgottenPasswordController); - + //set the IgmCore link into Controllers loginController.setIhmCore(this); signUpController.setIhmCore(this); @@ -212,12 +221,12 @@ public class IhmCore extends Application { this.primaryStage = primaryStage; //primaryStage.initStyle(StageStyle.UNDECORATED); - + //add the root scene (login) primaryStage.setScene(loginScene); primaryStage.setResizable(false); primaryStage.show(); - + Rectangle2D primScreenBounds = Screen.getPrimary().getVisualBounds(); primaryStage.setX((primScreenBounds.getWidth() - primaryStage.getWidth()) / 2); primaryStage.setY((primScreenBounds.getHeight() - primaryStage.getHeight()) / 2); @@ -225,6 +234,7 @@ public class IhmCore extends Application { /** * function who is called from Main to start the HCI. + * * @param args the arguments of the Application from Main method */ public void run(String[] args) { @@ -235,4 +245,7 @@ public class IhmCore extends Application { } + public void setDataForIhm(DataForIhm dataForIhm) { + this.dataForIhm = dataForIhm; + } } diff --git a/ihm/src/main/java/core/IhmForData.java b/ihm/src/main/java/core/IhmForData.java index 613885ba9a0ec8576919e8f640d0090d765f2442..a0294515f5e3a70e19bdc9db621c22772399b8ba 100644 --- a/ihm/src/main/java/core/IhmForData.java +++ b/ihm/src/main/java/core/IhmForData.java @@ -1,8 +1,11 @@ package core; +import datamodel.Music; +import datamodel.User; +import interfaces.Ihm; + /** * integration for Ihm interface. - * */ public class IhmForData implements Ihm { @@ -11,7 +14,7 @@ public class IhmForData implements Ihm { public IhmForData(IhmCore ihmCore) { this.ihmCore = ihmCore; } - + public IhmCore getIhmCore() { return this.ihmCore; } @@ -19,66 +22,73 @@ public class IhmForData implements Ihm { /** * Notify IHM that a new User is connected. This is just a change update, there is no user list * exchange. + * * @param user User recently connected. */ @Override - void notifyUserConnection(User user) { - throw new Exception("La fonction n'est pas encore implémentée"); + public void notifyUserConnection(User user) { + throw new UnsupportedOperationException("La fonction n'est pas encore implémentée"); } /** * Notify IHM that a User disconnected. This is just a change update, there is no user list * exchange. + * * @param user User recently disconnected. */ @Override - void notifyUserDisconnection(User user) { - throw new Exception("La fonction n'est pas encore implémentée"); + public void notifyUserDisconnection(User user) { + throw new UnsupportedOperationException("La fonction n'est pas encore implémentée"); } /** * Update the IHM progress bar by giving the percentage of the download progression. - * @param music Music considered. + * + * @param music Music considered. * @param integer Percentage progression, between 0 and 100. */ @Override - void notifyDownloadProgress(Music music, int integer) { - throw new Exception("La fonction n'est pas encore implémentée"); + public void notifyDownloadProgress(Music music, int integer) { + throw new UnsupportedOperationException("La fonction n'est pas encore implémentée"); } /** * Trigger the update of all the occurrences of the modified music. + * * @param music Music to update. */ @Override - void updateMusic(Music music) { - throw new Exception("La fonction n'est pas encore implémentée"); + public void updateMusic(Music music) { + throw new UnsupportedOperationException("La fonction n'est pas encore implémentée"); } /** * Notify that a music has been deleted. + * * @param music Deleted music. */ @Override - void notifyMusicDeletion(Music music) { - throw new Exception("La fonction n'est pas encore implémentée"); + public void notifyMusicDeletion(Music music) { + throw new UnsupportedOperationException("La fonction n'est pas encore implémentée"); } /** * Trigger the update of all the occurrences of the modified user. + * * @param user User to update */ @Override - void updateUser(User user) { - throw new Exception("La fonction n'est pas encore implémentée"); + public void updateUser(User user) { + throw new UnsupportedOperationException("La fonction n'est pas encore implémentée"); } /** * Notify that a User has been deleted. + * * @param user Deleted user. */ @Override - void notifyUserDeletion(User user) { - throw new Exception("La fonction n'est pas encore implémentée"); + public void notifyUserDeletion(User user) { + throw new UnsupportedOperationException("La fonction n'est pas encore implémentée"); } } \ No newline at end of file diff --git a/interfaces/src/main/java/interfaces/DataForIhm.java b/interfaces/src/main/java/interfaces/DataForIhm.java index b46663fcf33a9bf0671f659b13112e56414031c8..d177898aee3979058878fc1fa6f02e07906903a3 100644 --- a/interfaces/src/main/java/interfaces/DataForIhm.java +++ b/interfaces/src/main/java/interfaces/DataForIhm.java @@ -24,7 +24,15 @@ public interface DataForIhm { void addComment(Music music, String comment); - void createUser(LocalUser user); + /** + * Check if there is a config.properties file in the user's save path. If there is no config file + * yet, create a config.properties file by copy of default-config.properties + * default-config.properties is located in resources/ + * Then the function is calling Login.run function by giving the Datacore object and the LocalUser + * + * @param user LocalUser given by IHM + */ + void createUser(LocalUser user) throws IOException, LoginException; void deleteAccount(); diff --git a/interfaces/src/main/java/interfaces/Ihm.java b/interfaces/src/main/java/interfaces/Ihm.java index ae4f41c6cb61f005381d578edb640e09c1f0cf95..cc03db1cf320f3bd64300639ad67708f678253d2 100644 --- a/interfaces/src/main/java/interfaces/Ihm.java +++ b/interfaces/src/main/java/interfaces/Ihm.java @@ -14,7 +14,7 @@ public interface Ihm { * * @param user User recently connected. */ - void notifyUserConnection(User user); + public void notifyUserConnection(User user); /** * Notify IHM that a User disconnected. This is just a change update, there is no user list @@ -22,7 +22,7 @@ public interface Ihm { * * @param user User recently disconnected. */ - void notifyUserDisconnection(User user); + public void notifyUserDisconnection(User user); /** * Update the IHM progress bar by giving the percentage of the download progression. @@ -30,34 +30,34 @@ public interface Ihm { * @param music Music considered. * @param integer Percentage progression, between 0 and 100. */ - void notifyDownloadProgress(Music music, int integer); + public void notifyDownloadProgress(Music music, int integer); /** * Trigger the update of all the occurrences of the modified music. * * @param music Music to update. */ - void updateMusic(Music music); + public void updateMusic(Music music); /** * Notify that a music has been deleted. * * @param music Deleted music. */ - void notifyMusicDeletion(Music music); + public void notifyMusicDeletion(Music music); /** * Trigger the update of all the occurrences of the modified user. * * @param user User to update */ - void updateUser(User user); + public void updateUser(User user); /** * Notify that a User has been deleted. * * @param user Deleted user. */ - void notifyUserDeletion(User user); + public void notifyUserDeletion(User user); } diff --git a/main/pom.xml b/main/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..53ca9aee3a37f1c9fae6061e9095b988ae70b7ed --- /dev/null +++ b/main/pom.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>lo23-root</artifactId> + <groupId>lo23</groupId> + <version>1.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>main</artifactId> + <dependencies> + <dependency> + <groupId>lo23</groupId> + <artifactId>data</artifactId> + <version>1.0-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>lo23</groupId> + <artifactId>network</artifactId> + <version>1.0-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>lo23</groupId> + <artifactId>interfaces</artifactId> + <version>1.0-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>lo23</groupId> + <artifactId>ihm</artifactId> + <version>1.0-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + </dependencies> + + +</project> \ No newline at end of file diff --git a/main/src/main/java/Main.java b/main/src/main/java/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..e4599b17e6ee5312bf093fdbb30407d13c6dde81 --- /dev/null +++ b/main/src/main/java/Main.java @@ -0,0 +1,25 @@ +import core.DataProvider; +import core.IhmCore; +import exceptions.DataException; +import provider.NetworkProvider; + +public class Main { + /** + * Initialize all the modules and starts the application. + */ + public static void main(String[] args) { + IhmCore ihmCore = new IhmCore(); + NetworkProvider networkProvider = new NetworkProvider(); + DataProvider dataProvider = new DataProvider(); + + try { + dataProvider.initData(networkProvider.getNetwork(), ihmCore.getIhmForData()); + } catch (DataException e) { + e.printStackTrace(); + } + ihmCore.setDataForIhm(dataProvider.getDataForIhm()); + networkProvider.setDataImpl(dataProvider.getDataForNet()); + + ihmCore.run(args); + } +} diff --git a/network/src/main/java/implementation/NetworkImpl.java b/network/src/main/java/implementation/NetworkImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..1658519398cd6e5e93cbb1e55ff2ef42813c2d2f --- /dev/null +++ b/network/src/main/java/implementation/NetworkImpl.java @@ -0,0 +1,105 @@ +package implementation; + +import interfaces.Net; + +import java.io.Serializable; +import java.net.InetAddress; +import java.util.Collection; +import java.util.stream.Stream; + +import provider.NetworkProvider; +import threads.ThreadExtend; + +/** + * Implements the Net interface that provides useful methods to send messages through the + * network. Most of the times, simply redirect the request to the network provider because + * every thread-management is processed in provider. + * + * @author Antoine + * + */ +public class NetworkImpl implements Net { + + private NetworkProvider netProvider; + + /** + * Constructor that initializes the networkprovider, used to create the threads. + * + * @param np current instance of the network provider + */ + public NetworkImpl(NetworkProvider np) { + this.netProvider = np; + } + + /** + * Sends a message containing the string payload to the given ip. + * + * @param payload content of the message + * @param ipDest ip address of the receiver + */ + @Override + public void sendToUser(Serializable payload, InetAddress ipDest) { + this.netProvider.createSendToUserThread(payload, ipDest); + } + + /** + * Sends a message containing the string payload to the given ipS. + * + * @param payload content of the message + * @param ipsDest ip addresses of the receivers + */ + @Override + public void sendToUsers(Serializable payload, Stream<InetAddress> ipsDest) { + ipsDest.forEach((ip) -> netProvider.createSendToUserThread(payload, ip)); + } + + /** + * TODO. + * + * @param sourcesIPs ips where the music can be downloaded + * @param musicHash hash of the music to download + */ + @Override + public void requestDownload(Stream<InetAddress> sourcesIPs, String musicHash) { + return; + } + + /** + * Connect the user to the network. Create a server thread to listen network and + * sends a payload to the known network. + * + * @param payload data to transmit to the network + * @param knownIPs known nodes of the network + */ + @Override + public void connect(Serializable payload, Collection<InetAddress> knownIPs) { + this.netProvider.createServer(); + sendToUsers(payload, knownIPs.stream()); + } + + /** + * Stop all interactions between user and network and notifies the network that + * the user has been disconnected. + * + * @param payload data to inform the network we are disconnected + * @param knownIPs known ips in the network + */ + @Override + public void disconnect(Serializable payload, Collection<InetAddress> knownIPs) { + //Kill server thread (we don't want to receive any messages) + this.netProvider.createServer().kill(); + + //Wait for the network to be fully notified + this.netProvider.getNetwork().sendToUsers(payload, knownIPs.stream()); + + //Then kill every running threads + for (ThreadExtend thread : this.netProvider.getThreads()) { + if (thread.isAlive()) { + thread.kill(); + } + } + + //Clears the list of threads + this.netProvider.getThreads().clear(); + } +} diff --git a/network/src/main/java/message/DownloadFile.java b/network/src/main/java/message/DownloadFile.java new file mode 100644 index 0000000000000000000000000000000000000000..cbf14abd3650147b639ee0362201a2f210a96021 --- /dev/null +++ b/network/src/main/java/message/DownloadFile.java @@ -0,0 +1,39 @@ +package message; + +import interfaces.DataForNet; + +import java.io.Serializable; +import java.net.InetAddress; +import java.net.Socket; + +public class DownloadFile extends Message { + + private String hashMusic; + private InetAddress ip; + + public DownloadFile(Serializable p) { + super(p); //Call constructor for mother class + // To be define initialisation for hashMusic and ip + } + + @Override + public void process(DataForNet data, Socket socket) { + //To be define + } + + public String getHashMusic() { + return hashMusic; + } + + public void setHashMusic(String hashMusic) { + this.hashMusic = hashMusic; + } + + public InetAddress getIp() { + return ip; + } + + public void setIp(InetAddress ip) { + this.ip = ip; + } +} diff --git a/network/src/main/java/message/Message.java b/network/src/main/java/message/Message.java new file mode 100644 index 0000000000000000000000000000000000000000..1138e6f0f29ef43f6b590c37db60073ba2fe4a9f --- /dev/null +++ b/network/src/main/java/message/Message.java @@ -0,0 +1,25 @@ +package message; + +import interfaces.DataForNet; + +import java.io.Serializable; +import java.net.Socket; + +public class Message { + + private Serializable payload; + + public Message(Serializable p) { + this.payload = p; + } + + public void process(DataForNet data, Socket socket){ + //To be define + } + + public Serializable getPayload() { + return payload; + } +} + + diff --git a/network/src/main/java/message/SendFile.java b/network/src/main/java/message/SendFile.java new file mode 100644 index 0000000000000000000000000000000000000000..501d1198f62a8bf25791eb6c45c94038baff809d --- /dev/null +++ b/network/src/main/java/message/SendFile.java @@ -0,0 +1,28 @@ +package message; + +import interfaces.DataForNet; + +import java.io.Serializable; +import java.net.Socket; + +public class SendFile extends Message { + private String hashMusic; + + public SendFile(Serializable p) { + super(p); + // To be define + } + + @Override + public void process(DataForNet data, Socket socket) { + //To be define + } + + public String getHashMusic() { + return hashMusic; + } + + public void setHashMusic(String hashMusic) { + this.hashMusic = hashMusic; + } +} diff --git a/network/src/main/java/provider/NetworkProvider.java b/network/src/main/java/provider/NetworkProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..6b6645570138a47ed29704a7a4c333de0d8a9e2b --- /dev/null +++ b/network/src/main/java/provider/NetworkProvider.java @@ -0,0 +1,135 @@ +package provider; + +import implementation.NetworkImpl; +import interfaces.DataForNet; + +import java.io.Serializable; +import java.net.InetAddress; +import java.net.Socket; +import java.util.ArrayList; +import java.util.Collection; +import java.util.stream.Stream; + +import message.Message; + +import threads.MessageProcess; +import threads.RequestDownloadThread; +import threads.SendToUserThread; +import threads.Server; +import threads.ThreadExtend; + +/** + * Core class of network module. It stores references to every created threads + * and provide interface to interact with the module. + * + * @author Antoine + * + */ +public class NetworkProvider { + + public static final int N_PORT = 1026; + private DataForNet dataInterface; + private Server server; + private NetworkImpl netImpl; + private Collection<ThreadExtend> threads; + + public NetworkProvider() { + this.netImpl = new NetworkImpl(this); + this.threads = new ArrayList<ThreadExtend>(); + } + + /** + * Simple getter for network implementation. + * + * @return Current instance of the network implementation + */ + public NetworkImpl getNetwork() { + return this.netImpl; + } + + /** + * Create the server/listener thread and return the instance. If a server thread + * is already running, does not create a new instance but return the running one. + * + * @return current instance of the server thread + */ + public Server createServer() { + if (server == null || !server.isAlive()) { + this.server = new Server(this); + this.server.start(); + } + //No need to recreate server + return this.server; + } + + /** + * Simple getter for data interface implementation. + * + * @return current instance of the implemetation of data interface + */ + public DataForNet getDataImpl() { + return this.dataInterface; + } + + /** + * Allows users to set the instance bind to the DataInterface interface. + * + * @param dataInterface implementation of DataInterface + */ + public void setDataImpl(DataForNet dataInterface) { + this.dataInterface = dataInterface; + } + + + /** + * Create a new thread to process a given message. It adds the thread to the list of the + * running threads and return the instance. + * + * @param m message to process + * @param s socket through which the message has been received + * @return created instance of the new thread + */ + public MessageProcess createMessageProcess(Message m, Socket s) { + MessageProcess newThread = new MessageProcess(m, s, this); + threads.add(newThread); + newThread.start(); + return newThread; + } + + /** + * Create a new dedicated thread to send a message to a given user, and returns the + * instance of the newly created thread. + * + * @param p payload to be sent in the message + * @param ip ip address of the receiver + * @return instance of the newly created thread + */ + public SendToUserThread createSendToUserThread(Serializable p, InetAddress ip) { + SendToUserThread newThread = new SendToUserThread(p, ip); + threads.add(newThread); + newThread.start(); + return newThread; + } + + /** + * Create a new dedicated thread to send a download request to a given set of users, + * and returns the instance of the newly created thread. + * + * @param ownersIps ips where the music can be downloaded + * @param musicHash hash of the desired music + * @return instance of the newly created thread + */ + public RequestDownloadThread createRequestDownloadThread(Stream<InetAddress> ownersIps, + String musicHash) { + return null; + } + + /** + * Simple getter for threads. + * + * @return collection of the current running threads + */ + public Collection<ThreadExtend> getThreads() { + return this.threads; + } +} diff --git a/network/src/main/java/threads/MessageProcess.java b/network/src/main/java/threads/MessageProcess.java new file mode 100644 index 0000000000000000000000000000000000000000..fbc721549433a590bd468ebf6a69f62481108067 --- /dev/null +++ b/network/src/main/java/threads/MessageProcess.java @@ -0,0 +1,46 @@ +package threads; + +import java.net.Socket; + +import message.Message; +import provider.NetworkProvider; + +/** + * Class that will execute the appropriate behaviour depending on the given message + * given in constructor. It is just supposed to execute message.process(...) in a + * separate thread in order not to block the application. + * + * @author Antoine + * + */ +public class MessageProcess extends ThreadExtend { + + private Message message; + private Socket socket; + private NetworkProvider netProvider; + + + /** + * Simple constructor. + * + * @param m : message received, will call m.process + * @param s : socket through which the message has been received + * @param np : current instance of the networkProvider + */ + public MessageProcess(Message m, Socket s, NetworkProvider np) { + this.message = m; + this.socket = s; + this.netProvider = np; + } + + @Override + public void run() { + // TODO Auto-generated method stub + } + + @Override + public void kill() { + // TODO Auto-generated method stub + } + +} diff --git a/network/src/main/java/threads/RequestDownloadThread.java b/network/src/main/java/threads/RequestDownloadThread.java new file mode 100644 index 0000000000000000000000000000000000000000..75db1b29ce733f5c6284f00d17bbfe72f0df2fc9 --- /dev/null +++ b/network/src/main/java/threads/RequestDownloadThread.java @@ -0,0 +1,25 @@ +package threads; + +import java.net.InetAddress; +import java.util.stream.Stream; + +public class RequestDownloadThread extends ThreadExtend { + + private Stream<InetAddress> ownersIps; + private String musicHash; + + public RequestDownloadThread(Stream<InetAddress> ownersIps, String musicHash) { + this.ownersIps = ownersIps; + this.musicHash = musicHash; + } + + @Override + public void run() { + + } + + @Override + public void kill() { + + } +} diff --git a/network/src/main/java/threads/SendToUserThread.java b/network/src/main/java/threads/SendToUserThread.java new file mode 100644 index 0000000000000000000000000000000000000000..6d40668b89f92250ce6afdb21ca97152f3bc39c9 --- /dev/null +++ b/network/src/main/java/threads/SendToUserThread.java @@ -0,0 +1,43 @@ +package threads; + +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.net.InetAddress; +import java.net.Socket; +import message.Message; +import provider.NetworkProvider; + +public class SendToUserThread extends ThreadExtend { + private Serializable payload; + private InetAddress ipDest; + + /** + * create a socket to send a payload to a user. + * @param p payload of message to send + * @param ip ip address of the destination + */ + public SendToUserThread(Serializable p, InetAddress ip) { + this.payload = p; + this.ipDest = ip; + } + + @Override + public void run() { + System.out.println("Send message to a user"); + try { + Socket socket = new Socket(this.ipDest, NetworkProvider.N_PORT); + OutputStream outputStream = socket.getOutputStream(); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); + objectOutputStream.writeObject(new Message(this.payload)); + socket.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void kill() { + System.out.println("Stop Sending payload to a user"); + } +} diff --git a/network/src/main/java/threads/Server.java b/network/src/main/java/threads/Server.java new file mode 100644 index 0000000000000000000000000000000000000000..2f30b23442ab136dd98bc39b1d7268ca0a6a62c2 --- /dev/null +++ b/network/src/main/java/threads/Server.java @@ -0,0 +1,68 @@ +package threads; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.net.ServerSocket; +import java.net.Socket; + +import message.Message; +import provider.NetworkProvider; + +/** + * Server class running in a different thread. It listens to the default + * port and will ask network provider to process messages in another thread when + * a message is received. + * + * @author Antoine + */ +public class Server extends Thread { + + private ServerSocket listeningSocket; + private NetworkProvider netProvider; + private boolean serverRunning = true; + + /** + * Constructor that initiates the network provider with the current instance. + * + * @param n current instance of the NetworkProvider + */ + public Server(NetworkProvider n) { + this.netProvider = n; + } + + /** + * Should end 'properly' the thread execution. + */ + public void kill() { + this.serverRunning = false; + try { + this.listeningSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Infinite loop that wait for messages to be received and request the network + * provider to process the message in another thread. + */ + @Override + public void run() { + try { + this.listeningSocket = new ServerSocket(NetworkProvider.N_PORT); + while (this.serverRunning) { + System.out.println("Waiting for connection..."); + + Socket socket = this.listeningSocket.accept(); + + ObjectInputStream receivedObject = new ObjectInputStream(socket.getInputStream()); + + Message receivedMessage = (Message) receivedObject.readObject(); + this.netProvider.createMessageProcess(receivedMessage, socket); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/network/src/main/java/threads/ThreadExtend.java b/network/src/main/java/threads/ThreadExtend.java new file mode 100644 index 0000000000000000000000000000000000000000..47001202479629df020287081c30f0a3a7cf609b --- /dev/null +++ b/network/src/main/java/threads/ThreadExtend.java @@ -0,0 +1,9 @@ +package threads; + +/** + * Abstract class that only adds a method 'kill' to the Thread class. The method 'kill' + * should be used to stop properly a thread. + */ +public abstract class ThreadExtend extends Thread { + public abstract void kill(); +} diff --git a/pom.xml b/pom.xml index 027032846fd9266acedfda462fb75e6ee0710238..57461598bdb32f8e2ad5725fe8d3bd8eda53e597 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,7 @@ <module>ihm</module> <module>interfaces</module> <module>data-model</module> + <module>main</module> </modules> <build>