diff --git a/.gitignore b/.gitignore
index 0e13eeb..00e1a7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.idea/
target/
pom.xml.tag
pom.xml.releaseBackup
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..e7e9d11
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,2 @@
+# Default ignored files
+/workspace.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..1763e15
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..1eb6dac
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Teaching-HEIGVD-RES-2020-Exercise-Protocol-Design.iml b/Teaching-HEIGVD-RES-2020-Exercise-Protocol-Design.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/Teaching-HEIGVD-RES-2020-Exercise-Protocol-Design.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/specs/jul0105/PROTOCOL.md b/specs/jul0105/PROTOCOL.md
new file mode 100644
index 0000000..1a170ac
--- /dev/null
+++ b/specs/jul0105/PROTOCOL.md
@@ -0,0 +1,119 @@
+# Specification
+
+## 1. What transport protocol do we use?
+
+We use TCP.
+
+## 2. How does the client find the server (addresses and ports)?
+
+The port used is 25566.
+
+The IP address is dynamic.
+
+## 3. Who speaks first?
+
+The client initialize the communication
+
+## 4. What is the sequence of messages exchanged by the client and the server? (flow)
+
+client open connection
+
+**client -> server** : handshake
+
+**server -> client** : handshake response
+
+**client -> server** : send operation
+
+**server -> client** : send result or error
+
+client close connection
+
+## 5. What happens when a message is received from the other party? (semantics)
+
+**Server :**
+
+1. **Receive handshake** :
+ 1. Send handshake response with supported operations
+2. **Receive operation** :
+ 1. Check if the operation is supported
+ 2. Execute calculation
+ 3. Send result or error if any
+
+**Client :**
+
+1. **Receive handshake response** :
+ 1. Check if desired operation is supported by the server
+ 2. If yes, send operation
+ 3. If no, close connection
+2. **Receive operation result or error** :
+ 1. Print result or error if any
+
+## 6. What is the syntax of the messages? How we generate and parse them? (syntax)
+
+**handshake :**
+
+```
+CALC CLIENT
+```
+
+
+
+**handshake response :**
+
+```
+CALC SERVER;
+```
+
+Example :
+
+```
+CALC SERVER;ADD SUB MUL DIV
+```
+
+
+
+**send operation :**
+
+```
+
+```
+
+Example :
+
+```
+6 + 4
+5 - 1
+2 * 4
+10 / 0
+```
+
+
+
+**send result or error :**
+
+If the operation is correct :
+
+```
+RES
+```
+
+If the operation is incorrect or there is an error :
+
+```
+ERR
+```
+
+Example :
+
+```
+RES 10
+RES 4
+RES 8
+ERR Cannot divide by 0
+```
+
+
+
+## 6. Who closes the connection and when?
+
+The client close the connection when he receive the response of the operation from the server.
\ No newline at end of file
diff --git a/src/client/jul0105/Client.java b/src/client/jul0105/Client.java
new file mode 100644
index 0000000..66d4f78
--- /dev/null
+++ b/src/client/jul0105/Client.java
@@ -0,0 +1,141 @@
+package client.jul0105;
+
+import java.io.*;
+import java.net.Socket;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+
+public class Client {
+ private static final String SERVER_IP = "";
+ private static final int SERVER_PORT = 25566;
+ private static final String HANDSHAKE = "CALC CLIENT";
+ private static final String HANDSHAKE_RESPONSE = "CALC SERVER";
+
+ private static final Logger LOG = Logger.getLogger(Client.class.getName());
+
+ private Socket clientSocket;
+ private PrintWriter out;
+ private BufferedReader in;
+ private boolean isConnected = false;
+ private String supportedOperations;
+
+ public double calculate(double op1, char operator, double op2) {
+ String response = null;
+
+ // Test if there is an active connection with the server
+ if (!isConnected) {
+ throw new RuntimeException("Cannot execute calculation. No active connection.");
+ }
+
+ // Test if the server support the desired operation
+ if (supportedOperations.indexOf(operator) < 0) {
+ throw new RuntimeException("Operation unsupported by the server.");
+ }
+
+ // Send operation
+ out.println(String.format("%s %s %s", op2, operator, op2));
+
+ // Read response
+ try {
+ response = in.readLine();
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+
+ // Return response
+ if (response != null && response.contains("RES")) {
+ return Double.parseDouble(response.split("\\s")[1]);
+ } else {
+ throw new RuntimeException(response);
+ }
+ }
+
+ public void connect() {
+ String response;
+ LOG.log(Level.INFO, "Initialize new connection...");
+ if (isConnected) {
+ LOG.log(Level.WARNING, "Already connected.");
+ } else {
+ try {
+ // Initialize connection
+ clientSocket = new Socket(SERVER_IP, SERVER_PORT);
+ out = new PrintWriter(clientSocket.getOutputStream());
+ in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+
+ // Handshake
+ out.println(HANDSHAKE);
+ response = in.readLine();
+ if (response.contains(HANDSHAKE_RESPONSE)) {
+ isConnected = true;
+
+ // Set supported operations
+ supportedOperations = response.split(";")[1];
+
+ LOG.log(Level.INFO, "Connected with success.");
+ } else {
+ LOG.log(Level.WARNING, "Handshake failed. Abort connection.");
+ cleanup();
+ }
+
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ cleanup();
+ }
+ }
+
+ }
+ public void disconnect() {
+ LOG.log(Level.INFO, "Disconnection request.");
+ if (isConnected) {
+ cleanup();
+ isConnected = false;
+ LOG.log(Level.INFO, "Disconnected with success.");
+ } else {
+ LOG.log(Level.INFO, "Unable to disconnect. No active connection.");
+ }
+ }
+ public void cleanup() {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+
+ if (out != null) {
+ out.close();
+ }
+
+ try {
+ if (clientSocket != null) {
+ clientSocket.close();
+ }
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ }
+
+ public static void main(String[] args) {
+ Client client = new Client();
+ client.connect();
+
+ try {
+ System.out.print("4 * 4 = ");
+ System.out.println(client.calculate(4, '*', 4));
+ } catch (Exception ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ System.out.println(ex.getMessage());
+ }
+
+ client.disconnect();
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/company/Main.java b/src/com/company/Main.java
new file mode 100644
index 0000000..d9d1a8b
--- /dev/null
+++ b/src/com/company/Main.java
@@ -0,0 +1,8 @@
+package com.company;
+
+public class Main {
+
+ public static void main(String[] args) {
+ // write your code here
+ }
+}
diff --git a/src/com/company/Protocol.java b/src/com/company/Protocol.java
new file mode 100644
index 0000000..c05593e
--- /dev/null
+++ b/src/com/company/Protocol.java
@@ -0,0 +1,9 @@
+package com.company;
+
+public class Protocol {
+ public static final int DEFAULT_PORT = 25566;
+ public static final char OP_ADD = '+';
+ public static final char OP_SUB = '-';
+ public static final char OP_MUL = '*';
+ public static final char OP_DIV = '/';
+}
diff --git a/src/com/company/Server.java b/src/com/company/Server.java
new file mode 100644
index 0000000..030eae5
--- /dev/null
+++ b/src/com/company/Server.java
@@ -0,0 +1,193 @@
+package com.company;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class Server implements Runnable {
+
+ final static Logger LOG = Logger.getLogger(Server.class.getName());
+
+ boolean shouldRun;
+ ServerSocket serverSocket;
+ final List connectedWorkers;
+
+ public Server() {
+ this.shouldRun = true;
+ this.connectedWorkers = Collections.synchronizedList(new LinkedList());
+ }
+
+ private void registerWorker(Worker worker) {
+
+ connectedWorkers.add(worker);
+ }
+
+ private void unregisterWorker(Worker worker) {
+
+ connectedWorkers.remove(worker);
+ }
+
+ private void notifyConnectedWorkers(String message) {
+
+ synchronized (connectedWorkers) {
+ LOG.info("Notifying workers");
+ for(Worker worker : connectedWorkers){
+ worker.sendNotification(message);
+ }
+ }
+ LOG.info("Workers notified");
+
+ }
+
+ @Override
+ public void run() {
+
+ try {
+ serverSocket = new ServerSocket(Protocol.DEFAULT_PORT);
+
+ while (this.shouldRun) {
+
+ Socket clientSocket = serverSocket.accept();
+
+ Server.this.notifyConnectedWorkers("Someone has arrived...");
+
+ Worker newWorker = new Worker(clientSocket);
+ registerWorker(newWorker);
+
+ new Thread(newWorker).start();
+ }
+
+ serverSocket.close();
+
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ System.exit(-1);
+ }
+ }
+
+ class Worker implements Runnable {
+
+ Socket clientSocket;
+ BufferedReader in;
+ PrintWriter out;
+ boolean connected;
+
+
+ public Worker(Socket clientSocket) {
+
+ this.clientSocket = clientSocket;
+
+ try {
+
+ in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+ out = new PrintWriter(clientSocket.getOutputStream());
+ connected = true;
+
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+
+ }
+
+ @Override
+ public void run() {
+
+ String calcul;
+ double result = 0;
+ Server.this.notifyConnectedWorkers("Welcome !");
+ sendNotification("Send an operation: [op1] [+,-,*,/] [op2]");
+
+
+ try {
+
+ while (connected && ((calcul = in.readLine()) != null)) {
+
+ String[] strOp = calcul.split(" ");
+
+ double op1 = Double.parseDouble(strOp[0]);
+ double op2 = Double.parseDouble(strOp[2]);
+
+ switch (strOp[1].toCharArray()[0]) {
+
+ case (Protocol.OP_ADD):
+ sendNotification("RES " + (op1 + op2));
+ break;
+ case (Protocol.OP_SUB):
+ sendNotification("RES " + (op1 - op2));
+ break;
+ case (Protocol.OP_MUL):
+ sendNotification("RES " + (op1 * op2));
+ break;
+ case (Protocol.OP_DIV):
+
+ if(op2 != 0){
+
+ sendNotification("RES " + (op1 / op2));
+ } else {
+
+ sendNotification("ERR cannot divide by 0");
+ }
+
+ break;
+ default:
+ sendNotification("ERR unknown : " + strOp[1] + ", use only : [+, -, *, /]");
+ }
+
+
+ }
+
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ } finally {
+ unregisterWorker(this);
+ Server.this.notifyConnectedWorkers("Someone left...");
+ cleanup();
+ }
+ }
+
+ private void cleanup() {
+
+ LOG.log(Level.INFO, "Cleaning up worker");
+
+ LOG.log(Level.INFO, "Closing clientSocked");
+ try {
+ clientSocket.close();
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+
+ LOG.log(Level.INFO, "Closing in");
+ try {
+ in.close();
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+
+ LOG.log(Level.INFO, "Closing out");
+ if(out != null){
+ out.close();
+ }
+
+ LOG.log(Level.INFO, "Clean up done");
+ }
+
+ public void sendNotification(String message) {
+ out.println(message);
+ out.flush();
+ }
+
+ private void disconnect() {
+ LOG.log(Level.INFO , "Disconnecting worker");
+ connected = false;
+ cleanup();
+ }
+ }
+}