diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..6b8dde0
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,7 @@
+language: java
+jdk:
+ - oraclejdk8
+os:
+ - linux
+script:
+ - chmod +x buildscript.sh && ./buildscript.sh
diff --git a/04.FTP_GUI/pom.xml b/04.FTP_GUI/pom.xml
new file mode 100644
index 0000000..59da308
--- /dev/null
+++ b/04.FTP_GUI/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+
+ 04
+ FTP_GUI
+ 1.0-SNAPSHOT
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
+
+ junit
+ junit
+ 4.12
+
+
+
+
+
\ No newline at end of file
diff --git a/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/Main.java b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/Main.java
new file mode 100644
index 0000000..335ebac
--- /dev/null
+++ b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/Main.java
@@ -0,0 +1,26 @@
+package ru.spbau.mit.alyokhina;
+
+import javafx.application.Application;
+import javafx.geometry.Pos;
+import javafx.scene.Scene;
+import javafx.scene.layout.GridPane;
+import javafx.stage.Stage;
+import ru.spbau.mit.alyokhina.ui.*;
+
+public class Main extends Application {
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ primaryStage.setTitle("Крестики - Нолики");
+ GridPane gridPane = new GridPane();
+ gridPane.setAlignment(Pos.CENTER);
+ CreateNewElements.createMainActivity(gridPane);
+ primaryStage.setScene(new Scene(gridPane, 600, 400));
+ primaryStage.show();
+
+ }
+
+ public static void main(String[] args) {
+ launch(args);
+ }
+}
\ No newline at end of file
diff --git a/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/client/Client.java b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/client/Client.java
new file mode 100644
index 0000000..8dbfc96
--- /dev/null
+++ b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/client/Client.java
@@ -0,0 +1,99 @@
+package ru.spbau.mit.alyokhina.client;
+
+import javafx.util.Pair;
+import ru.spbau.mit.alyokhina.server.Server;
+
+
+import java.io.*;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Client, which allows you to execute the requests list and get
+ */
+public class Client {
+ /**
+ * OutputStream from Socket
+ */
+ private DataOutputStream dataOutputStream;
+ /**
+ * InputStream from Socket
+ */
+ private DataInputStream dataInputStream;
+
+ /**
+ * Constructor
+ *
+ * @throws IOException if Socket or Stream can't be created
+ */
+ public Client(String host, int port) throws IOException {
+ Socket clientSocket = new Socket(host, port);
+ dataInputStream = new DataInputStream(clientSocket.getInputStream());
+ dataOutputStream = new DataOutputStream(clientSocket.getOutputStream());
+
+ }
+
+
+ /**
+ * Listing files in the directory on the server
+ *
+ * @param path directory path
+ * @return list of Pair. Fist value - name of file. Second value - type of file ( if file is directory - true, else false)
+ * Count files in directory = length of list
+ * @throws IOException if we can't read/write in InputStream/OutputStream
+ */
+ public List> list(String path) throws IOException {
+ List> listFiles = new ArrayList<>();
+ dataOutputStream.writeInt(Server.LIST_REQUEST);
+ dataOutputStream.writeUTF(path);
+ dataOutputStream.flush();
+ int count = dataInputStream.readInt();
+ for (int i = 0; i < count; i++) {
+ String fileName = dataInputStream.readUTF();
+ Boolean isDirectory = dataInputStream.readBoolean();
+ listFiles.add(new Pair<>(fileName, isDirectory));
+ }
+ return listFiles;
+ }
+
+ /**
+ * Сopy the file from the server to the file
+ *
+ * @param path path of the file from server
+ * @param nameFileForSave the name of the file into which the content will be copied
+ * @return file into which the content will be copied
+ * @throws IOException if we can't read/write in InputStream/OutputStream
+ */
+ public File get(String path, String nameFileForSave) throws IOException {
+ dataOutputStream.writeInt(Server.GET_REQUEST);
+ dataOutputStream.writeUTF(path);
+ dataOutputStream.flush();
+ File fileForSave = new File(nameFileForSave);
+ int count = dataInputStream.readInt();
+ if (count != 0) {
+ byte[] bytes = new byte[count];
+ int countReadBytes = dataInputStream.read(bytes);
+ if (countReadBytes != count) {
+ throw new IOException("Impossible to read all data");
+ }
+ DataOutputStream dataOutputStreamForSave = new DataOutputStream(new FileOutputStream(fileForSave));
+ dataOutputStreamForSave.write(bytes);
+ }
+ return fileForSave;
+ }
+
+ /**
+ * check file in server for existence
+ *
+ * @param path path of the file, that we want to check
+ * @return true - is exists, false - else
+ * @throws IOException if we can't write in dataOutputStream
+ */
+ public boolean isExists(String path) throws IOException {
+ dataOutputStream.writeInt(Server.IS_EXISTS_REQUEST);
+ dataOutputStream.writeUTF(path);
+ dataOutputStream.flush();
+ return dataInputStream.readBoolean();
+ }
+}
\ No newline at end of file
diff --git a/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/server/Server.java b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/server/Server.java
new file mode 100644
index 0000000..0fbcfb1
--- /dev/null
+++ b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/server/Server.java
@@ -0,0 +1,131 @@
+package ru.spbau.mit.alyokhina.server;
+
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * A server that processes two list requests and receives
+ */
+public class Server {
+ /**
+ * Value for request list
+ */
+ public static int LIST_REQUEST = 1;
+ /**
+ * Value for request get
+ */
+ public static int GET_REQUEST = 2;
+ /**
+ * Value for request is exist file
+ */
+ public static int IS_EXISTS_REQUEST = 3;
+ /**
+ * Socket for connection with this server
+ */
+ private ServerSocket serverSocket;
+
+ /**
+ * Constructor
+ *
+ * @param port port of connection
+ * @throws IOException if Socket can't be created
+ */
+ public Server(int port) throws IOException {
+ serverSocket = new ServerSocket(port);
+
+ }
+
+ /**
+ * Start of the server
+ */
+ public void start() {
+ while (true) {
+ try {
+ final Socket socket = serverSocket.accept();
+ Thread thread = new Thread(() -> {
+ try (DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
+ DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream())) {
+ while (!Thread.interrupted()) {
+ int requestType = dataInputStream.readInt();
+ String path = dataInputStream.readUTF();
+ if (requestType == LIST_REQUEST) {
+ list(path, dataOutputStream);
+ } else if (requestType == GET_REQUEST) {
+ get(path, dataOutputStream);
+ } else if (requestType == IS_EXISTS_REQUEST) {
+ isExist(path, dataOutputStream);
+ }
+ }
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ });
+ thread.start();
+ } catch (IOException ignored) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Write count files, names of files and their types from input directory to dataOutputStream
+ *
+ * @param path directory path
+ * @param dataOutputStream stream for write result
+ * @throws IOException if it is impossible to write in dataOutputStream
+ */
+ private void list(String path, DataOutputStream dataOutputStream) throws IOException {
+ File directory = new File(path);
+ File[] files = directory.listFiles();
+ dataOutputStream.writeInt(files == null ? 0 : files.length);
+ if (files != null) {
+ for (File file : files) {
+ dataOutputStream.writeUTF(file.getName());
+ dataOutputStream.writeBoolean(file.isDirectory());
+ }
+ }
+ dataOutputStream.flush();
+ }
+
+ /**
+ * Write file contents in dataOutputStream
+ *
+ * @param path name of file
+ * @param dataOutputStream OutputStream for write result
+ * @throws IOException if it is impossible to write in dataOutputStream
+ */
+ private void get(String path, DataOutputStream dataOutputStream) throws IOException {
+ File file = new File(path);
+ int length = (int) file.length();
+ if (length != 0) {
+ DataInputStream dataInputStreamForRequest = new DataInputStream(new FileInputStream(file));
+ byte[] bytes = new byte[length];
+
+ if (dataInputStreamForRequest.read(bytes) == length) {
+ dataOutputStream.writeInt(length);
+ dataOutputStream.write(bytes);
+ } else {
+ throw new IOException("Impossible to read all data");
+ }
+ dataInputStreamForRequest.close();
+ } else {
+ dataOutputStream.writeInt(length);
+ }
+ }
+
+ /**
+ * check file for existence
+ *
+ * @param path path of the file, that we want to check
+ * @throws IOException if we can't write in dataOutputStream or create
+ */
+ private void isExist(String path, DataOutputStream dataOutputStream) throws IOException {
+ File file = new File(path);
+ dataOutputStream.writeBoolean(file.exists());
+ }
+}
+
+
+
+
diff --git a/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/ui/ClientUI.java b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/ui/ClientUI.java
new file mode 100644
index 0000000..b9af4ad
--- /dev/null
+++ b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/ui/ClientUI.java
@@ -0,0 +1,183 @@
+package ru.spbau.mit.alyokhina.ui;
+
+import javafx.application.Platform;
+import javafx.scene.control.ListView;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.GridPane;
+import javafx.util.Pair;
+import ru.spbau.mit.alyokhina.client.Client;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+
+
+/**
+ * UI for Client
+ */
+public class ClientUI {
+ /**
+ * Constructor
+ *
+ * @param gridPane on which objects will be placed
+ */
+ public ClientUI(GridPane gridPane) {
+ gridPane.getChildren().clear();
+ CreateNewElements.createLabel(gridPane, 50, 300, 0, 0, "Введите порт");
+ TextField textFieldForPort = CreateNewElements.createTextField(gridPane, 50, 300, 0, 1);
+ CreateNewElements.createLabel(gridPane, 50, 300, 0, 2, "Введите хост");
+ TextField textFieldForHost = CreateNewElements.createTextField(gridPane, 50, 300, 0, 3);
+ CreateNewElements.createLabel(gridPane, 50, 300, 0, 4, "Введите путь");
+ TextField textFieldForPath = CreateNewElements.createTextField(gridPane, 50, 300, 0, 5);
+
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 50, 100, 1, 6, "OK"),
+ actionEvent -> startClient(gridPane, textFieldForPort.getText(), textFieldForHost.getText(), textFieldForPath.getText()));
+
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 50, 100, 1, 0, "Назад"),
+ actionEvent -> CreateNewElements.createMainActivity(gridPane));
+ }
+
+ /**
+ * Print files from the server on this path
+ *
+ * @param gridPane on which objects will be placed
+ * @param client to communicate with the server
+ * @param path on which we want to get the files
+ */
+ public void printFiles(GridPane gridPane, Client client, String path) {
+
+ try {
+ if (!client.isExists(path)) {
+ CreateNewElements.createLabel(gridPane, 50, 100, 0, 6, "Такого пути не существует");
+ } else {
+ gridPane.getChildren().clear();
+ CreateNewElements.createLabel(gridPane, 50, 100, 0, 0, path);
+ List> files = client.list(path);
+ HashSet dir = new HashSet<>();
+ for (Pair file : files) {
+ if (file.getValue()) {
+ dir.add(file.getKey());
+ }
+ }
+ ListView listView = CreateNewElements.createListView(gridPane, files, dir);
+ listView.setOnMouseClicked(event -> {
+ if (dir.contains(listView.getSelectionModel().getSelectedItem())) {
+ printFiles(gridPane, client, path + '/' + listView.getSelectionModel().getSelectedItem());
+ } else {
+ agreement(gridPane, client, path + '/' + listView.getSelectionModel().getSelectedItem());
+ }
+ });
+
+ }
+ } catch (IOException e) {
+ CreateNewElements.createLabel(gridPane, 50, 100, 0, 6, e.getMessage(), "#ff0000");
+ }
+ CreateNewElements.createBackButton(gridPane, 100, 100, 1, 0, "Назад", path, client, this);
+
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 100, 150, 2, 0, "В главное меню"),
+ actionEvent -> CreateNewElements.createMainActivity(gridPane));
+ }
+
+ /**
+ * Get an agreement to download a file
+ *
+ * @param gridPane on which objects will be placed
+ * @param client to communicate with the server
+ * @param path path of the file, that we want to download
+ */
+ private void agreement(GridPane gridPane, Client client, String path) {
+ gridPane.getChildren().clear();
+ CreateNewElements.createLabel(gridPane, 50, 200, 1, 0, "Вы уверены, что хотите скачать?");
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 50, 50, 0, 1, "Да"),
+ actionEvent -> download(gridPane, client, path)
+ );
+
+ CreateNewElements.createBackButton(gridPane, 50, 50, 2, 1, "Нет", path, client, this);
+ }
+
+ /**
+ * Download file from server
+ *
+ * @param gridPane on which objects will be placed
+ * @param client to communicate with the server
+ * @param path path of the file, that would be download
+ */
+ private void download(GridPane gridPane, Client client, String path) {
+ gridPane.getChildren().clear();
+ CreateNewElements.createLabel(gridPane, 50, 300, 0, 0, "Введите путь для сохранения");
+ TextField textFieldForDowloadPath = CreateNewElements.createTextField(gridPane, 50, 300, 0, 1);
+ CreateNewElements.createBackButton(gridPane, 50, 100, 1, 0, "Назад", path, client, this);
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 50, 100, 1, 2, "OK"),
+ actionEvent -> {
+ try {
+ client.get(path, textFieldForDowloadPath.getText());
+ afterDownload(gridPane, client, path);
+ } catch (IOException e) {
+ if (gridPane.getChildren().size() > 4) {
+ for (int i = 4; i < gridPane.getChildren().size(); i++) {
+ gridPane.getChildren().remove(i);
+ }
+ }
+ CreateNewElements.createLabel(gridPane, 50, 300, 0, 2, e.getMessage(), "#ff0000");
+ }
+ });
+
+
+ }
+
+
+ /**
+ * Selecting the transition after downloading the file
+ *
+ * @param gridPane on which objects will be placed
+ * @param client to communicate with the server
+ * @param path of the file, that was downloaded
+ */
+ private void afterDownload(GridPane gridPane, Client client, String path) {
+ gridPane.getChildren().clear();
+ CreateNewElements.createBackButton(gridPane, 100, 200, 0, 0, "Продолжить", path, client, this);
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 100, 200, 0, 1, "В главное меню"),
+ actionEvent -> CreateNewElements.createMainActivity(gridPane)
+ );
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 100, 200, 0, 2, "Выход"),
+ actionEvent -> Platform.exit()
+ );
+
+ }
+
+ /**
+ * Start client work
+ *
+ * @param gridPane on which objects will be placed
+ * @param namePort for create client
+ * @param host gor create client
+ * @param path of the current directory
+ */
+ private void startClient(GridPane gridPane, String namePort, String host, String path) {
+ if (gridPane.getChildren().size() > 8) {
+ for (int i = 8; i < gridPane.getChildren().size(); i++) {
+ gridPane.getChildren().remove(i);
+ }
+ }
+ Integer port;
+ try {
+ port = Integer.parseInt(namePort);
+ } catch (NumberFormatException e) {
+ CreateNewElements.createLabel(gridPane, 50, 300, 0, 6, "Неккоректный порт. \nПопробуйте еще раз", "#ff0000");
+ return;
+ }
+ try {
+ Client client = new Client(host, port);
+ printFiles(gridPane, client, path);
+ } catch (IOException e) {
+ CreateNewElements.createLabel(gridPane, 50, 300, 0, 6, e.getMessage(), "#ff0000");
+ }
+ }
+}
diff --git a/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/ui/CreateNewElements.java b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/ui/CreateNewElements.java
new file mode 100644
index 0000000..7c3630d
--- /dev/null
+++ b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/ui/CreateNewElements.java
@@ -0,0 +1,215 @@
+package ru.spbau.mit.alyokhina.ui;
+
+import javafx.application.Platform;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.event.ActionEvent;
+import javafx.geometry.Pos;
+import javafx.scene.control.*;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.GridPane;
+import javafx.scene.paint.Color;
+
+import javafx.event.EventHandler;
+import javafx.util.Pair;
+import ru.spbau.mit.alyokhina.client.Client;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.util.HashSet;
+import java.util.List;
+
+public class CreateNewElements {
+
+ /**
+ * Create button
+ *
+ * @param height height of the button
+ * @param width width of the button
+ * @param x abscissa coordinate
+ * @param y ordinate coordinate
+ * @param text this text will be on the button
+ * @return new button
+ */
+ public static Button createButton(GridPane gridPane, double height, double width, int x, int y, String text) {
+ Button button = new Button();
+ gridPane.add(button, x, y);
+ button.setText(text);
+ button.setPrefHeight(height);
+ button.setPrefWidth(width);
+ button.setLayoutX(x);
+ button.setLayoutY(y);
+ return button;
+ }
+
+ /**
+ * Create label
+ *
+ * @param height height of the label
+ * @param width width of the label
+ * @param x abscissa coordinate
+ * @param y ordinate coordinate
+ * @param text this text will be on the label
+ * @return new label
+ */
+ public static Label createLabel(GridPane gridPane, double height, double width, int x, int y, String text) {
+ Label label = new Label();
+ gridPane.add(label, x, y);
+ label.setText(text);
+ label.setPrefHeight(height);
+ label.setPrefWidth(width);
+ label.setAlignment(Pos.CENTER);
+ label.setWrapText(true);
+ return label;
+ }
+
+ /**
+ * Create label
+ *
+ * @param height height of the label
+ * @param width width of the label
+ * @param x abscissa coordinate
+ * @param y ordinate coordinate
+ * @param text this text will be on the label
+ * @param color color of the text
+ */
+ public static void createLabel(GridPane gridPane, double height, double width, int x, int y, String text, String color) {
+ Label label = createLabel(gridPane, height, width, x, y, text);
+ label.setTextFill(Color.web(color));
+ }
+
+ /**
+ * Create TextField
+ *
+ * @param height height of the textField
+ * @param width width of the textField
+ * @param x abscissa coordinate
+ * @param y ordinate coordinate
+ * @return new textField
+ */
+ public static TextField createTextField(GridPane gridPane, double height, double width, int x, int y) {
+ TextField textField = new TextField();
+ textField.setPrefHeight(height);
+ textField.setPrefWidth(width);
+ gridPane.add(textField, x, y);
+ return textField;
+ }
+
+
+ /**
+ * Add an action to click a button
+ * @param button add action to this button
+ * @param actionEvent this action will be after click
+ */
+ public static void addActionToButton(Button button, EventHandler actionEvent) {
+ button.setOnAction(actionEvent);
+ }
+
+
+ /**
+ * Create ListView
+ * @param gridPane on which objects will be placed
+ * @param files list all files will be printed. First parameter is files name, second - true, if directory, else - false
+ * @param dir set of name of files, which is directory
+ * @return ListView
+ */
+ public static ListView createListView(GridPane gridPane, List> files, HashSet dir) {
+ ListView listView = new ListView<>();
+ ObservableList items = FXCollections.observableArrayList();
+ for (Pair file : files) {
+ items.add(file.getKey());
+ }
+ listView.setItems(items);
+
+ listView.setCellFactory(param -> new ListCell() {
+ private ImageView imageView = new ImageView();
+
+ @Override
+ public void updateItem(String name, boolean empty) {
+ super.updateItem(name, empty);
+ if (empty) {
+ setText(null);
+ setGraphic(null);
+ } else {
+ try {
+ if (dir.contains(name)) {
+ imageView.setImage(new Image(new File("src/main/resources/directory.png").toURI().toURL().toExternalForm()));
+ } else {
+ imageView.setImage(new Image(new File("src/main/resources/file.png").toURI().toURL().toExternalForm()));
+ }
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ setText(name);
+ imageView.setFitHeight(25);
+ imageView.setFitWidth(25);
+ setGraphic(imageView);
+ }
+ }
+ });
+ gridPane.add(listView, 0, 1);
+ return listView;
+ }
+
+
+ /**
+ * Create Main Activity. 3 buttons : create server, create client, exit
+ * @param gridPane on which objects will be placed
+ */
+ public static void createMainActivity(GridPane gridPane) {
+ gridPane.getChildren().clear();
+ addActionToButton(
+ createButton(gridPane, 50, 200, 0, 0, "Создать сервер"),
+ actionEvent -> new ServerUI(gridPane)
+ );
+ addActionToButton(
+ createButton(gridPane, 50, 200, 0, 1, "Новый клиент"),
+ actionEvent -> new ClientUI(gridPane)
+ );
+ addActionToButton(
+ createButton(gridPane, 50, 200, 0, 2, "Выход"),
+ actionEvent -> Platform.exit()
+ );
+ }
+
+
+ /**
+ * Create button for back
+ * @param gridPane on which objects will be placed
+ * @param height height of the button
+ * @param width width of the button
+ * @param x abscissa coordinate
+ * @param y ordinate coordinate
+ * @param text this text will be on the button
+ * @param path path for back from the current directory
+ * @param client to communicate with the server
+ * @param clientUI for print result
+ */
+ public static void createBackButton(GridPane gridPane, double height, double width, int x, int y, String text, String path, Client client, ClientUI clientUI) {
+ addActionToButton(
+ createButton(gridPane, height, width, x, y, text),
+ actionEvent -> {
+ if (path.equals("/")) {
+ createMainActivity(gridPane);
+ } else {
+ int end = 0;
+ for (int i = path.length() - 1; i >= 0; i--) {
+ if (path.charAt(i) == '/') {
+ end = i;
+ break;
+ }
+ }
+ if (end == 0) {
+ clientUI.printFiles(gridPane, client, "/");
+ } else {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < end; i++) {
+ stringBuilder.append(path.charAt(i));
+ }
+ clientUI.printFiles(gridPane, client, stringBuilder.toString());
+ }
+ }
+ });
+ }
+}
diff --git a/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/ui/ServerUI.java b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/ui/ServerUI.java
new file mode 100644
index 0000000..fde6667
--- /dev/null
+++ b/04.FTP_GUI/src/main/java/ru/spbau/mit/alyokhina/ui/ServerUI.java
@@ -0,0 +1,66 @@
+package ru.spbau.mit.alyokhina.ui;
+
+import javafx.scene.control.TextField;
+import javafx.scene.layout.GridPane;
+import ru.spbau.mit.alyokhina.server.Server;
+
+import java.io.IOException;
+
+public class ServerUI {
+
+ public ServerUI(GridPane gridPane) {
+ gridPane.getChildren().clear();
+ CreateNewElements.createLabel(gridPane, 50, 400, 0, 0, "Введите порт");
+ TextField port = CreateNewElements.createTextField(gridPane, 100, 200, 0, 2);
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 50, 100, 1, 3, "OK"),
+ actionEvent -> {
+ createServer(gridPane, port.getText());
+ }
+ );
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 50, 100, 1, 0, "Назад"),
+ actionEvent -> {
+ CreateNewElements.createMainActivity(gridPane);
+ }
+ );
+ }
+
+ private void result(GridPane gridPane) {
+ gridPane.getChildren().clear();
+ CreateNewElements.createLabel(gridPane, 100, 200, 0, 0, "Сервер создан");
+ CreateNewElements.addActionToButton(
+ CreateNewElements.createButton(gridPane, 50, 200, 0, 1, "Назад"),
+ actionEvent -> {
+ CreateNewElements.createMainActivity(gridPane);
+ }
+ );
+ }
+
+
+ private void createServer(GridPane gridPane, String namePort) {
+ if (gridPane.getChildren().size() > 4) {
+ for (int i = 4; i < gridPane.getChildren().size();i++) {
+ gridPane.getChildren().remove(i);
+ }
+ }
+ Integer port;
+ try{
+ port = Integer.parseInt(namePort);
+ }
+ catch (NumberFormatException e) {
+ CreateNewElements.createLabel(gridPane, 50, 400, 0, 3, "Неккоректный порт. \nПопробуйте еще раз", "#ff0000");
+ return;
+ }
+ try {
+ Server server = new Server(port);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ result(gridPane);
+ }
+ catch (IOException | IllegalArgumentException e) {
+ CreateNewElements.createLabel(gridPane, 50, 400, 0, 3, e.getMessage(), "#ff0000");
+ }
+
+ }
+}
diff --git a/04.FTP_GUI/src/main/resources/directory.png b/04.FTP_GUI/src/main/resources/directory.png
new file mode 100644
index 0000000..ada21cb
Binary files /dev/null and b/04.FTP_GUI/src/main/resources/directory.png differ
diff --git a/04.FTP_GUI/src/main/resources/file.png b/04.FTP_GUI/src/main/resources/file.png
new file mode 100644
index 0000000..7c0209a
Binary files /dev/null and b/04.FTP_GUI/src/main/resources/file.png differ
diff --git a/04.FTP_GUI/src/resources/testGet1/copyFile1 b/04.FTP_GUI/src/resources/testGet1/copyFile1
new file mode 100644
index 0000000..4d20f7a
--- /dev/null
+++ b/04.FTP_GUI/src/resources/testGet1/copyFile1
@@ -0,0 +1,8 @@
+Я вас любил: любовь еще, быть может,
+В душе моей угасла не совсем;
+Но пусть она вас больше не тревожит;
+Я не хочу печалить вас ничем.
+Я вас любил безмолвно, безнадежно,
+То робостью, то ревностью томим;
+Я вас любил так искренно, так нежно,
+Как дай вам бог любимой быть другим.
\ No newline at end of file
diff --git a/04.FTP_GUI/src/resources/testGet1/copyFile2 b/04.FTP_GUI/src/resources/testGet1/copyFile2
new file mode 100644
index 0000000..9d57e16
--- /dev/null
+++ b/04.FTP_GUI/src/resources/testGet1/copyFile2
@@ -0,0 +1,9 @@
+Я выжила… Отчаянно, ознобно,
+Легко. Светает. Снег сошёл на нет.
+Не слышен плач, не ослепляет свет.
+Глаза пусты, глаза беззлобны.
+
+Недостающий воздух – чушь, пустяк,
+Совпал с полночным и привычным зноем.
+А если будет что-нибудь не так…
+Ты мне поможешь? Нас пока что двое?
\ No newline at end of file
diff --git a/04.FTP_GUI/src/resources/testGet1/file1 b/04.FTP_GUI/src/resources/testGet1/file1
new file mode 100644
index 0000000..4d20f7a
--- /dev/null
+++ b/04.FTP_GUI/src/resources/testGet1/file1
@@ -0,0 +1,8 @@
+Я вас любил: любовь еще, быть может,
+В душе моей угасла не совсем;
+Но пусть она вас больше не тревожит;
+Я не хочу печалить вас ничем.
+Я вас любил безмолвно, безнадежно,
+То робостью, то ревностью томим;
+Я вас любил так искренно, так нежно,
+Как дай вам бог любимой быть другим.
\ No newline at end of file
diff --git a/04.FTP_GUI/src/resources/testGet1/file2 b/04.FTP_GUI/src/resources/testGet1/file2
new file mode 100644
index 0000000..9d57e16
--- /dev/null
+++ b/04.FTP_GUI/src/resources/testGet1/file2
@@ -0,0 +1,9 @@
+Я выжила… Отчаянно, ознобно,
+Легко. Светает. Снег сошёл на нет.
+Не слышен плач, не ослепляет свет.
+Глаза пусты, глаза беззлобны.
+
+Недостающий воздух – чушь, пустяк,
+Совпал с полночным и привычным зноем.
+А если будет что-нибудь не так…
+Ты мне поможешь? Нас пока что двое?
\ No newline at end of file
diff --git a/04.FTP_GUI/src/resources/testList1/dir1/1 b/04.FTP_GUI/src/resources/testList1/dir1/1
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList1/dir2/1 b/04.FTP_GUI/src/resources/testList1/dir2/1
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList1/file1 b/04.FTP_GUI/src/resources/testList1/file1
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList1/file2 b/04.FTP_GUI/src/resources/testList1/file2
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList1/file3 b/04.FTP_GUI/src/resources/testList1/file3
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList2/dir1/1 b/04.FTP_GUI/src/resources/testList2/dir1/1
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList2/dir2/1 b/04.FTP_GUI/src/resources/testList2/dir2/1
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList2/dir3/1 b/04.FTP_GUI/src/resources/testList2/dir3/1
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList2/dir4/1 b/04.FTP_GUI/src/resources/testList2/dir4/1
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList2/dir5/1 b/04.FTP_GUI/src/resources/testList2/dir5/1
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList2/file1 b/04.FTP_GUI/src/resources/testList2/file1
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/resources/testList2/file2 b/04.FTP_GUI/src/resources/testList2/file2
new file mode 100644
index 0000000..e69de29
diff --git a/04.FTP_GUI/src/test/java/ru/spbau/mit/alyokhina/client/ClientTest.java b/04.FTP_GUI/src/test/java/ru/spbau/mit/alyokhina/client/ClientTest.java
new file mode 100644
index 0000000..f7128cb
--- /dev/null
+++ b/04.FTP_GUI/src/test/java/ru/spbau/mit/alyokhina/client/ClientTest.java
@@ -0,0 +1,231 @@
+package ru.spbau.mit.alyokhina.client;
+
+import javafx.util.Pair;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import ru.spbau.mit.alyokhina.server.Server;
+
+import static org.junit.Assert.assertEquals;
+
+
+/**
+ * Test for client-server connection
+ */
+public class ClientTest {
+ /**
+ * If a server was created, this flag will be true
+ */
+ private static boolean isCreateServer = false;
+
+
+ @Test
+ public void testCreateClientAndServer() {
+ try {
+ if (!isCreateServer) {
+ final Server server = new Server(1408);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ isCreateServer = true;
+ }
+ Client client = new Client("localhost", 1408);
+
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testListWithOneClient() {
+ try {
+ if (!isCreateServer) {
+ final Server server = new Server(1408);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ isCreateServer = true;
+ }
+ Client client = new Client("localhost", 1408);
+ List> files = client.list("src/resources/testList1");
+ List> rightAnswer = new ArrayList<>();
+ rightAnswer.add(new Pair<>("dir1", true));
+ rightAnswer.add(new Pair<>("dir2", true));
+ rightAnswer.add(new Pair<>("file3", false));
+ rightAnswer.add(new Pair<>("file1", false));
+ rightAnswer.add(new Pair<>("file2", false));
+ assertEquals(rightAnswer.size(), equalLists(rightAnswer, files));
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+
+ @Test
+ public void testListWithTwoClients() {
+ try {
+ if (!isCreateServer) {
+ final Server server = new Server(1408);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ isCreateServer = true;
+ }
+ Client client1 = new Client("localhost", 1408);
+ Client client2 = new Client("localhost", 1408);
+ List> files1 = client1.list("src/resources/testList1");
+ List> files2 = client2.list("src/resources/testList2");
+ List> rightAnswer1 = new ArrayList<>();
+ rightAnswer1.add(new Pair<>("dir1", true));
+ rightAnswer1.add(new Pair<>("dir2", true));
+ rightAnswer1.add(new Pair<>("file3", false));
+ rightAnswer1.add(new Pair<>("file1", false));
+ rightAnswer1.add(new Pair<>("file2", false));
+ assertEquals(rightAnswer1.size(), equalLists(rightAnswer1, files1));
+
+ List> rightAnswer2 = new ArrayList<>();
+ rightAnswer2.add(new Pair<>("dir1", true));
+ rightAnswer2.add(new Pair<>("dir2", true));
+ rightAnswer2.add(new Pair<>("dir3", true));
+ rightAnswer2.add(new Pair<>("dir4", true));
+ rightAnswer2.add(new Pair<>("dir5", true));
+ rightAnswer2.add(new Pair<>("file1", false));
+ rightAnswer2.add(new Pair<>("file2", false));
+ assertEquals(rightAnswer2.size(), equalLists(files2, rightAnswer2));
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCreateWithNonexistentDirectory() {
+ try {
+ if (!isCreateServer) {
+ final Server server = new Server(1408);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ isCreateServer = true;
+ }
+ Client client = new Client("localhost", 1408);
+ List> files = client.list("src/resources/testList3");
+ assertEquals(0, files.size());
+
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+
+ @Test
+ public void testGetWithOneClient() {
+ try {
+ if (!isCreateServer) {
+ final Server server = new Server(1408);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ isCreateServer = true;
+ }
+ Client client = new Client("localhost", 1408);
+ File copyFile = client.get("src/resources/testGet1/file1", "src/resources/testGet1/copyFile1");
+ File file = new File("src/resources/testGet1/file1");
+ assertEquals(true, equalFiles(file, copyFile));
+
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+
+ @Test
+ public void testGetWithTwoClients() {
+ try {
+ if (!isCreateServer) {
+ final Server server = new Server(1408);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ isCreateServer = true;
+ }
+ Client client1 = new Client("localhost", 1408);
+ File copyFile1 = client1.get("src/resources/testGet1/file1", "src/resources/testGet1/copyFile1");
+ File file1 = new File("src/resources/testGet1/file1");
+ assertEquals(true, equalFiles(file1, copyFile1));
+
+ Client client2 = new Client("localhost", 1408);
+ File copyFile2 = client2.get("src/resources/testGet1/file2", "src/resources/testGet1/copyFile2");
+ File file2 = new File("src/resources/testGet1/file2");
+ assertEquals(true, equalFiles(file2, copyFile2));
+
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testGetWithNonexistentFiles() {
+ try {
+ if (!isCreateServer) {
+ final Server server = new Server(1408);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ isCreateServer = true;
+ }
+ Client client = new Client("localhost", 1408);
+ File file = client.get("src/resources/testGet1/file3", "src/resources/testGet1/copyFile3");
+ assertEquals(0, file.length());
+
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+
+ /**
+ * Compare two List>
+ */
+ private static int equalLists(List> a, List> b) {
+ if (a.size() != b.size()) {
+ return -1;
+ }
+ int i = 0;
+ for (Pair elem1 : a) {
+ boolean flag = false;
+ for (Pair elem2 : b) {
+ if (elem1.getKey().equals(elem2.getKey()) && elem1.getValue() == elem2.getValue()) {
+ flag = true;
+ }
+ }
+ if (!flag) {
+ return i;
+ }
+ i++;
+ }
+ return a.size();
+ }
+
+ /**
+ * Compare files
+ */
+ private static boolean equalFiles(File file, File copyFile) throws IOException {
+ if (file.length() != copyFile.length()) {
+ return false;
+ }
+ byte[] data1 = new byte[(int) file.length()];
+ byte[] data2 = new byte[(int) file.length()];
+ FileInputStream fisForFile = new FileInputStream(file);
+ FileInputStream fisForCopyFile = new FileInputStream(copyFile);
+ if (fisForFile.read(data1) != file.length()) {
+ throw new IOException("Can't read file");
+ }
+ if (fisForCopyFile.read(data2) != copyFile.length()) {
+ throw new IOException("Can't read file");
+ }
+ for (int i = 0; i < data1.length; i++) {
+ if (data1[i] != data2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/buildscript.sh b/buildscript.sh
new file mode 100755
index 0000000..1cc07e7
--- /dev/null
+++ b/buildscript.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+files=$(find . -maxdepth 1 -type d | grep "./0.*")
+for file in $files
+do
+ cd $file
+ mvn test -B
+ cd ../
+done
+