diff --git a/Client/Client.jar b/Client/Client.jar
new file mode 100644
index 0000000..c206af5
Binary files /dev/null and b/Client/Client.jar differ
diff --git a/Client/pom.xml b/Client/pom.xml
new file mode 100644
index 0000000..c05549b
--- /dev/null
+++ b/Client/pom.xml
@@ -0,0 +1,27 @@
+
+
+ 4.0.0
+
+ org.example
+ mvn
+ 1.0-SNAPSHOT
+
+
+ org.apache.commons
+ commons-lang3
+ 3.5
+
+
+ org.jsoup
+ jsoup
+ 1.13.1
+
+
+ org.json
+ json
+ 20200518
+
+
+
\ No newline at end of file
diff --git a/Client/src/main/java/META-INF/MANIFEST.MF b/Client/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..440fa71
--- /dev/null
+++ b/Client/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: sample.Main
+
diff --git a/Client/src/main/java/sample/Controller.java b/Client/src/main/java/sample/Controller.java
new file mode 100644
index 0000000..3ec0072
--- /dev/null
+++ b/Client/src/main/java/sample/Controller.java
@@ -0,0 +1,247 @@
+package sample;
+
+import com.sun.jdi.event.ExceptionEvent;
+import javafx.application.Platform;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.Button;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+import org.apache.commons.lang3.SerializationUtils;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+
+import java.io.*;
+import java.net.Socket;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.*;
+
+public class Controller implements Initializable {
+ @FXML
+ Pane pane;
+ @FXML
+ Button buttonLoad;
+ @FXML
+ Label labelInfo;
+ @FXML
+ TextField textFieldServerIp;
+ @FXML
+ ComboBox comboBoxMode;
+ String[] modes;
+ //Label labelClientId;
+ //TextField textFieldClientId;
+ HBox hBoxBottom;
+ JSONObject jsonObjectRates;
+ public void getDateFromServer() {
+ try {
+ Socket socket = new Socket(getServerIpString(), 5000);
+ Calendar calendar = ((Calendar) getObjectFromServer(socket));
+ labelInfo.setText(" Seconds : " + calendar.get(Calendar.SECOND) + " Minutes : "
+ + calendar.get(Calendar.MINUTE) + " Hours : " + calendar.get(Calendar.HOUR)
+ + " Day : " + calendar.get(Calendar.DAY_OF_MONTH) + " Month : " + calendar.get(Calendar.MONTH)
+ + " Year : " + calendar.get(Calendar.YEAR));
+ socket.close();
+ } catch (Exception ex) {
+ labelInfo.setText("Error. Couldn't load data from server." + ex.getMessage());
+ }
+ }
+
+ public void getAphorismFromServer() {
+ try {
+ Socket socket = new Socket(getServerIpString(), 6000);
+ String aphorism = (String) getObjectFromServer(socket);
+ labelInfo.setText(aphorism);
+ socket.close();
+ } catch (Exception ex) {
+ labelInfo.setText("Error. Couldn't load data from server." + ex.getMessage());
+ }
+ }
+
+ private Object getObjectFromServer(Socket socket) throws Exception {
+ DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
+ int packetSize = dataInputStream.readInt();
+ byte[] bytes = new byte[packetSize];
+ dataInputStream.read(bytes);
+ return SerializationUtils.deserialize(bytes);
+ }
+
+ private String getServerIpString() {
+ String serverIp;
+ if (textFieldServerIp.getText() == "")
+ serverIp = "localhost";
+ else
+ serverIp = textFieldServerIp.getText();
+ return serverIp;
+ }
+
+ private void listenToServerEvents() {
+
+ try {
+ labelInfo.setText("");
+ Socket socket = new Socket(getServerIpString(), 7000);
+ Thread readingThread = new Thread() {
+ public void run() {
+ try {
+ while (true) {
+ TextField textFieldId = (TextField) hBoxBottom.getChildren().get(1);
+ sendData(socket, Integer.parseInt(textFieldId.getText()));
+ String serverMessage = (String) getObjectFromServer(socket);
+ if (!serverMessage.equals(""))
+ Platform.runLater(() -> labelInfo.setText(labelInfo.getText() + "\n" + serverMessage));
+ }
+ } catch (Exception ex) {
+
+ }
+ }
+ };
+ readingThread.start();
+ } catch (Exception ex) {
+ labelInfo.setText(labelInfo.getText() + "\n" + ex.getMessage());
+ }
+ }
+
+ private void sendData(Socket socket, Object object) throws Exception {
+ DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
+ byte[] bytes = SerializationUtils.serialize((Serializable) object);
+ dataOutputStream.writeInt(bytes.length);
+ dataOutputStream.write(bytes);
+ dataOutputStream.flush();
+ }
+
+ public void setButtonEvent() {
+
+ switch ((String) comboBoxMode.getSelectionModel().getSelectedItem()) {
+ case "Date":
+ deleteBottomLine();
+ buttonLoad.setOnAction((e) -> getDateFromServer());
+ break;
+ case "Aphorism":
+ deleteBottomLine();
+ buttonLoad.setOnAction((e) -> getAphorismFromServer());
+ break;
+ case "Events log": {
+ deleteBottomLine();
+ createClientIdLine();
+ buttonLoad.setOnAction((e) -> listenToServerEvents());
+ break;
+ }
+ case "Currency": {
+ deleteBottomLine();
+ createCurrencyLine();
+ buttonLoad.setOnAction((e) -> showCurrencyRelation());
+ break;
+ }
+ }
+ }
+ private void showCurrencyRelation()
+ {
+ try {
+ double leftPrice = 1.0 / getCurrencyValue(getCurrencyCombobox(0).getSelectionModel().getSelectedItem());
+ double rightPrice = 1.0 / getCurrencyValue(getCurrencyCombobox(1).getSelectionModel().getSelectedItem());
+ labelInfo.setText("1 = " + rightPrice / leftPrice);
+ }
+ catch (Exception ex)
+ {
+ labelInfo.setText("Please set values properly. "+ex.getMessage());
+ }
+ }
+ private void createClientIdLine() {
+ if (hBoxBottom == null) {
+ hBoxBottom = new HBox();
+ Label labelClientId = new Label();
+ labelClientId.setText("Client id");
+ TextField textFieldClientId = new TextField();
+ hBoxBottom.getChildren().addAll(labelClientId, textFieldClientId);
+ VBox vBox = (VBox) pane.getChildren().get(0);
+ vBox.getChildren().add(hBoxBottom);
+ }
+ }
+ private double getCurrencyValue(String currency)
+ {
+ return jsonObjectRates.getDouble(currency);
+ }
+ private void createCurrencyLine() {
+ if (hBoxBottom == null) {
+ hBoxBottom = new HBox();
+ ComboBox comboBoxLeftValue = new ComboBox();
+ comboBoxLeftValue.setMinSize(pane.getWidth() / 2, comboBoxLeftValue.getHeight());
+ ComboBox comboBoxRightValue = new ComboBox();
+ comboBoxRightValue.setMinSize(pane.getWidth() / 2, comboBoxLeftValue.getHeight());
+ hBoxBottom.getChildren().addAll(comboBoxLeftValue, comboBoxRightValue);
+ VBox vBox = (VBox) pane.getChildren().get(0);
+ vBox.getChildren().add(hBoxBottom);
+ ArrayList values=getCurrecniesListFromSite();
+ ComboBox comboBoxLeft=getCurrencyCombobox(0);
+ ComboBox comboBoxRight=getCurrencyCombobox(1);
+ comboBoxLeft.getItems().addAll(values);
+ comboBoxRight.getItems().addAll(values);
+ }
+ }
+
+ private void deleteBottomLine() {
+ if (hBoxBottom != null) {
+ VBox vBox = (VBox) pane.getChildren().get(0);
+ vBox.getChildren().remove(hBoxBottom);
+ hBoxBottom = null;
+ }
+ }
+ private ComboBox getCurrencyCombobox(int index)
+ {
+ return (ComboBox) hBoxBottom.getChildren().get(index);
+ }
+ @Override
+ public void initialize(URL location, ResourceBundle resources) {
+ labelInfo.setWrapText(true);
+ modes = new String[]{"Date", "Aphorism", "Events log", "Currency"};
+ comboBoxMode.getItems().addAll(modes);
+ }
+
+ private ArrayList getCurrecniesListFromSite() {
+ try {
+ jsonObjectRates = getJsonObjectRates();
+ Iterator iterator = jsonObjectRates.keys();
+ ArrayList names = new ArrayList();
+ while (iterator.hasNext()) {
+ names.add( (String) iterator.next());
+ }
+ return names;
+ } catch (Exception ex) {
+ }
+ return null;
+ }
+ private JSONObject getJsonObjectRates() throws Exception
+ {
+ JSONObject jsonObject = readJsonFromUrl("https://openexchangerates.org/api/latest.json?app_id=5a11aa4d56564bbdb101289a6fa338d7");
+ JSONObject jsonRates = jsonObject.getJSONObject("rates");
+ return jsonRates;
+ }
+ //Copied code
+ private static String readAll(Reader rd) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ int cp;
+ while ((cp = rd.read()) != -1) {
+ sb.append((char) cp);
+ }
+ return sb.toString();
+ }
+
+ public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
+ InputStream is = new URL(url).openStream();
+ try {
+ BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
+ String jsonText = readAll(rd);
+ JSONObject json = new JSONObject(jsonText);
+ return json;
+ } finally {
+ is.close();
+ }
+ }
+}
diff --git a/Client/src/main/java/sample/Main.java b/Client/src/main/java/sample/Main.java
new file mode 100644
index 0000000..41cc34e
--- /dev/null
+++ b/Client/src/main/java/sample/Main.java
@@ -0,0 +1,50 @@
+package sample;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class Main extends Application {
+
+ @Override
+ public void start(Stage primaryStage) throws Exception{
+ Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
+ primaryStage.setTitle("Hello World");
+ primaryStage.setScene(new Scene(root));
+ primaryStage.show();
+ }
+ public File getResourceAsFile() {
+ try {
+ InputStream inStream = ClassLoader.getSystemClassLoader().getResourceAsStream("/sample.fml");
+ if (inStream == null) {
+ return null;
+ }
+ File tempFile = File.createTempFile(String.valueOf(inStream.hashCode()), ".tmp");
+ tempFile.deleteOnExit();
+
+ try (FileOutputStream outStream = new FileOutputStream(tempFile)) {
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = inStream.read(buffer)) != -1) {
+ outStream.write(buffer, 0, bytesRead);
+ }
+ }
+ return tempFile;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+
+ public static void main(String[] args) {
+ launch(args);
+ }
+}
diff --git a/Client/src/main/resources/META-INF/MANIFEST.MF b/Client/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..440fa71
--- /dev/null
+++ b/Client/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: sample.Main
+
diff --git a/Client/src/main/resources/sample.fxml b/Client/src/main/resources/sample.fxml
new file mode 100644
index 0000000..2db5c29
--- /dev/null
+++ b/Client/src/main/resources/sample.fxml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Server/Aphorisms.txt b/Server/Aphorisms.txt
new file mode 100644
index 0000000..e62bd39
--- /dev/null
+++ b/Server/Aphorisms.txt
@@ -0,0 +1,6 @@
+Actions speak louder than words
+All for one and one for all
+Don't fire until you see the whites of their eyes
+Early to bed, early to rise, makes a man healthy, wealthy, and wise
+Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime
+Give him an inch and he'll take a mile
\ No newline at end of file
diff --git a/Server/NetCLockServer.jar b/Server/NetCLockServer.jar
new file mode 100644
index 0000000..5c076ef
Binary files /dev/null and b/Server/NetCLockServer.jar differ
diff --git a/Server/pom.xml b/Server/pom.xml
new file mode 100644
index 0000000..2752e89
--- /dev/null
+++ b/Server/pom.xml
@@ -0,0 +1,18 @@
+
+
+ 4.0.0
+
+ org.example
+ mvn
+ 1.0-SNAPSHOT
+
+
+ org.apache.commons
+ commons-lang3
+ 3.5
+
+
+
+
\ No newline at end of file
diff --git a/Server/src/main/java/Aphorisms.txt b/Server/src/main/java/Aphorisms.txt
new file mode 100644
index 0000000..e62bd39
--- /dev/null
+++ b/Server/src/main/java/Aphorisms.txt
@@ -0,0 +1,6 @@
+Actions speak louder than words
+All for one and one for all
+Don't fire until you see the whites of their eyes
+Early to bed, early to rise, makes a man healthy, wealthy, and wise
+Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime
+Give him an inch and he'll take a mile
\ No newline at end of file
diff --git a/Server/src/main/java/META-INF/MANIFEST.MF b/Server/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..4f3348f
--- /dev/null
+++ b/Server/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: Main
diff --git a/Server/src/main/java/Main.java b/Server/src/main/java/Main.java
new file mode 100644
index 0000000..5febb31
--- /dev/null
+++ b/Server/src/main/java/Main.java
@@ -0,0 +1,174 @@
+import org.apache.commons.lang3.SerializationUtils;
+
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Scanner;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class Main {
+ private static int threadNumberDate = 0;
+ private static ArrayList aphorisms;
+ private static ArrayList clients;
+
+ private static void loadAphorismsFromFile() throws Exception {
+ aphorisms = new ArrayList<>();
+ File jarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());
+ File file = new File(jarFile.getParentFile(), "Aphorisms.txt");
+ BufferedReader br =new BufferedReader(new FileReader(file));
+ String line;
+ while ((line = br.readLine()) != null) {
+ aphorisms.add(line);
+ }
+ }
+
+
+ public static void main(String[] args) throws Exception {
+ clients = new ArrayList<>();
+ loadAphorismsFromFile();
+ startDateThread();
+ startAphorismThread();
+ startEventsThread();
+ }
+
+ private static void startEventsThread() throws Exception {
+ ServerSocket serverSocket = new ServerSocket(7000);
+ String threadName = "Events thread ";
+ Scanner scanner = new Scanner(System.in);
+ Thread threadAddingClients = new Thread(() -> {
+ while (true) {
+ try {
+ System.out.println(threadName + "Waiting for signal");
+ Socket socket = serverSocket.accept();
+ clients.add(socket);
+ threadNumberDate++;
+ } catch (Exception ex) {
+ break;
+ }
+ }
+ });
+ threadAddingClients.start();
+ Thread threadSendingToClients = new Thread() {
+ public void run() {
+ System.out.println(threadName + "> New thread " + threadNumberDate);
+ while (true) {
+ int enteredId=scanner.nextInt();
+ String message = scanner.nextLine();
+ if (message.equals("") || message.equals("\n"))
+ break;
+ else {
+ for (int i = 0; i < clients.size(); i++) {
+ int id;
+ try {
+ id = (Integer)getObjectFromServer(clients.get(i));
+ }
+ catch (Exception ex)
+ {
+ id=-1;
+ }
+ if(id==-1 || id==enteredId||enteredId==-1)
+ sendData(clients.get(i), message);
+ else
+ sendData(clients.get(i),"");
+ }
+ }
+ }
+ }
+ };
+ threadSendingToClients.start();
+ }
+
+ private static void startDateThread() throws Exception {
+ ServerSocket serverSocket = new ServerSocket(5000);
+ String threadName = "Date thread ";
+ Thread thread = new Thread(() -> {
+ while (true) {
+ try {
+ System.out.println(threadName + "Waiting for signal");
+ Socket socket = serverSocket.accept();
+ Thread threadProcessing = new Thread() {
+ public void run() {
+ System.out.println(threadName + "> New thread " + threadNumberDate);
+ Calendar calendar = Calendar.getInstance();
+ sendData(socket, calendar);
+ try {
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ System.out.println(threadName + " " + threadNumberDate + " > Data sent.Closing connection");
+ }
+ };
+ threadProcessing.start();
+ threadNumberDate++;
+
+ } catch (Exception ex) {
+ break;
+ }
+ }
+ });
+ thread.start();
+ }
+
+ private static void startAphorismThread() throws Exception {
+ ServerSocket serverSocket = new ServerSocket(6000);
+ String threadName = "Aphorism thread ";
+ Thread thread = new Thread(() -> {
+ while (true) {
+ try {
+ System.out.println(threadName + "Waiting for signal");
+ Socket socket = serverSocket.accept();
+ Thread threadProcessing = new Thread() {
+ public void run() {
+ System.out.println(threadName + "> New thread " + threadNumberDate);
+ String aphorism = getRandomAphorism();
+ sendData(socket, aphorism);
+ try {
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ System.out.println(threadName + " " + threadNumberDate + " > Data sent.Closing connection");
+ }
+ };
+ threadProcessing.start();
+ threadNumberDate++;
+
+ } catch (Exception ex) {
+ break;
+ }
+ }
+ });
+ thread.start();
+ }
+
+ private static void sendData(Socket socket, Object object) {
+ try {
+ DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
+ objectOutputStream.writeObject(object);
+ objectOutputStream.flush();
+ byte[] bytes = byteArrayOutputStream.toByteArray();
+ dataOutputStream.writeInt(bytes.length);
+ dataOutputStream.write(bytes);
+ dataOutputStream.flush();
+ } catch (Exception ex) {
+ System.out.println(ex.getMessage());
+ }
+ }
+ private static Object getObjectFromServer(Socket socket) throws Exception {
+ DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
+ int packetSize = dataInputStream.readInt();
+ byte[] bytes = new byte[packetSize];
+ dataInputStream.read(bytes);
+ return SerializationUtils.deserialize(bytes);
+ }
+
+ private static String getRandomAphorism() {
+ return aphorisms.get(ThreadLocalRandom.current().nextInt(0, aphorisms.size()));
+ }
+}
diff --git a/Server/src/main/resources/META-INF/MANIFEST.MF b/Server/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5ee19cb
--- /dev/null
+++ b/Server/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: Main
+