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/03.FTP/pom.xml b/03.FTP/pom.xml
new file mode 100644
index 0000000..7a4bf75
--- /dev/null
+++ b/03.FTP/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+
+ 03
+ FTP
+ 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/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Client.java b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Client.java
new file mode 100644
index 0000000..3322a31
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Client.java
@@ -0,0 +1,93 @@
+package ru.spbau.mit.alyokhina;
+
+import javafx.stage.Stage;
+import javafx.util.Pair;
+
+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;
+ private Stage stage;
+ /**
+ * 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(Request.LIST_REQUEST.ordinal());
+ 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(Request.GET_REQUEST.ordinal());
+ 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(Request.IS_EXISTS_REQUEST.ordinal());
+ dataOutputStream.writeUTF(path);
+ dataOutputStream.flush();
+ return dataInputStream.readBoolean();
+ }
+
+}
diff --git a/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Main.java b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Main.java
new file mode 100644
index 0000000..def3386
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Main.java
@@ -0,0 +1,77 @@
+package ru.spbau.mit.alyokhina;
+
+
+import javafx.util.Pair;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Scanner;
+
+/** Console UI (list files on server and download files) */
+public class Main {
+ public static void main(String[] args) {
+ int type;
+ Scanner in = new Scanner(System.in);
+ do {
+ System.out.println("1 - запустить сервер");
+ System.out.println("2 - запустить клиента");
+ System.out.println("3 - выйти");
+ type = in.nextInt();
+ if (type == 1) {
+ System.out.println("Введите порт");
+ int port = in.nextInt();
+ try {
+ final Server server = new Server(port);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ System.out.println("Сервер создан");
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+ if (type == 2) {
+ try {
+ System.out.println("Введите порт");
+ int port = in.nextInt();
+ Client client = new Client("localhost", port);
+ int typeRequest = 0;
+ do {
+ System.out.println("1 - list");
+ System.out.println("2 - get");
+ System.out.println("3 - назад");
+ typeRequest = in.nextInt();
+ if (typeRequest == 1) {
+ System.out.println("Введите путь к директории");
+ String path = in.next();
+ List> files = client.list(path);
+ for (Pair file : files) {
+ System.out.print(file.getKey());
+ if (file.getValue()) {
+ System.out.println(" is directory");
+ } else {
+ System.out.println(" is file");
+ }
+ }
+ }
+ if (typeRequest == 2) {
+ System.out.println("Введите путь к файлу");
+ String path = in.next();
+ System.out.println("Введите путь для сохранения");
+ String fileName = in.next();
+ File file = client.get(path, fileName);
+ System.out.print("Размер файла = ");
+ System.out.println(file.length());
+ }
+ } while (typeRequest != 3);
+
+
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+ } while (type != 3);
+ System.exit(0);
+ }
+}
+
diff --git a/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Request.java b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Request.java
new file mode 100644
index 0000000..a010235
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Request.java
@@ -0,0 +1,7 @@
+package ru.spbau.mit.alyokhina;
+
+public enum Request {
+ LIST_REQUEST,
+ GET_REQUEST,
+ IS_EXISTS_REQUEST
+}
diff --git a/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Server.java b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Server.java
new file mode 100644
index 0000000..5c21baf
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Server.java
@@ -0,0 +1,120 @@
+package ru.spbau.mit.alyokhina;
+
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * A server that processes two list requests and receives
+ */
+public class Server {
+ /**
+ * 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 == Request.LIST_REQUEST.ordinal()) {
+ list(path, dataOutputStream);
+ } else if (requestType == Request.GET_REQUEST.ordinal()) {
+ get(path, dataOutputStream);
+ } else if (requestType == Request.IS_EXISTS_REQUEST.ordinal()) {
+ 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/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/ClientUI.java b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/ClientUI.java
new file mode 100644
index 0000000..fa59a65
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/ClientUI.java
@@ -0,0 +1,186 @@
+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.stage.FileChooser;
+import javafx.stage.Stage;
+import javafx.util.Pair;
+import ru.spbau.mit.alyokhina.Client;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+
+
+/**
+ * UI for Client
+ */
+public class ClientUI {
+ private Stage stage;
+
+ /**
+ * Constructor
+ *
+ * @param gridPane on which objects will be placed
+ */
+ public ClientUI(GridPane gridPane, Stage stage) {
+ this.stage = stage;
+ gridPane.getChildren().clear();
+ NewElementsCreator.createLabel(gridPane, 50, 300, 0, 0, "Введите порт");
+ TextField textFieldForPort = NewElementsCreator.createTextField(gridPane, 50, 300, 0, 1);
+ NewElementsCreator.createLabel(gridPane, 50, 300, 0, 2, "Введите хост");
+ TextField textFieldForHost = NewElementsCreator.createTextField(gridPane, 50, 300, 0, 3);
+ NewElementsCreator.createLabel(gridPane, 50, 300, 0, 4, "Введите путь");
+ TextField textFieldForPath = NewElementsCreator.createTextField(gridPane, 50, 300, 0, 5);
+
+ NewElementsCreator.addActionToButton(
+ NewElementsCreator.createButton(gridPane, 50, 100, 1, 6, "OK"),
+ actionEvent -> startClient(gridPane, textFieldForPort.getText(), textFieldForHost.getText(), textFieldForPath.getText()));
+
+ NewElementsCreator.addActionToButton(
+ NewElementsCreator.createButton(gridPane, 50, 100, 1, 0, "Назад"),
+ actionEvent -> NewElementsCreator.createMainActivity(gridPane, stage));
+ }
+
+ /**
+ * 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)) {
+ NewElementsCreator.createLabel(gridPane, 50, 100, 0, 6, "Такого пути не существует");
+ } else {
+ gridPane.getChildren().clear();
+ NewElementsCreator.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 = NewElementsCreator.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) {
+ NewElementsCreator.createLabel(gridPane, 50, 100, 0, 6, e.getMessage(), "#ff0000");
+ }
+ NewElementsCreator.createBackButton(gridPane, 100, 100, 1, 0, "Назад", path, client, this, stage);
+
+ NewElementsCreator.addActionToButton(
+ NewElementsCreator.createButton(gridPane, 100, 150, 2, 0, "В главное меню"),
+ actionEvent -> NewElementsCreator.createMainActivity(gridPane, stage));
+ }
+
+ /**
+ * Get an agreement to download a file
+ *
+ * @param gridPane on which objects will be placed
+ * @param client to communicate with the server
+ * @param dir directory of the file, that would be download
+ * @param fileName name of the file, that would be download
+ */
+ private void agreement(GridPane gridPane, Client client, String dir, String fileName) {
+ gridPane.getChildren().clear();
+ NewElementsCreator.createLabel(gridPane, 50, 200, 1, 0, "Вы уверены, что хотите скачать?");
+ NewElementsCreator.addActionToButton(
+ NewElementsCreator.createButton(gridPane, 50, 50, 0, 1, "Да"),
+ actionEvent -> download(gridPane, client, dir, fileName)
+ );
+
+ NewElementsCreator.createBackButton(gridPane, 50, 50, 2, 1, "Нет", dir + '/' + fileName, client, this, stage);
+ }
+
+ /**
+ * Download file from server
+ *
+ * @param gridPane on which objects will be placed
+ * @param client to communicate with the server
+ * @param dir directory of the file, that would be download
+ * @param fileName name of the file, that would be download
+ */
+ private void download(GridPane gridPane, Client client, String dir, String fileName) {
+ FileChooser fileChooser = new FileChooser();
+ File dirFile = new File(dir);
+ fileChooser.setInitialDirectory(dirFile);
+ fileChooser.setInitialFileName(fileName);
+ File selectedFile = fileChooser.showSaveDialog(stage);
+ try {
+ client.get(dir + '/' + fileName, selectedFile.getAbsolutePath());
+ afterDownload(gridPane, client, dir + '/' + fileName);
+ } catch (IOException e) {
+ if (gridPane.getChildren().size() > 4) {
+ for (int i = 4; i < gridPane.getChildren().size(); i++) {
+ gridPane.getChildren().remove(i);
+ }
+ }
+ NewElementsCreator.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();
+ NewElementsCreator.createBackButton(gridPane, 100, 200, 0, 0, "Продолжить", path, client, this, stage);
+ NewElementsCreator.addActionToButton(
+ NewElementsCreator.createButton(gridPane, 100, 200, 0, 1, "В главное меню"),
+ actionEvent -> NewElementsCreator.createMainActivity(gridPane, stage)
+ );
+ NewElementsCreator.addActionToButton(
+ NewElementsCreator.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) {
+ NewElementsCreator.createLabel(gridPane, 50, 300, 0, 6, "Неккоректный порт. \nПопробуйте еще раз", "#ff0000");
+ return;
+ }
+ try {
+ Client client = new Client(host, port);
+ printFiles(gridPane, client, path);
+ } catch (IOException e) {
+ NewElementsCreator.createLabel(gridPane, 50, 300, 0, 6, e.getMessage(), "#ff0000");
+ }
+ }
+}
diff --git a/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/Main.java b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/Main.java
new file mode 100644
index 0000000..f01bbc7
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/Main.java
@@ -0,0 +1,25 @@
+package ru.spbau.mit.alyokhina.ui;
+
+import javafx.application.Application;
+import javafx.geometry.Pos;
+import javafx.scene.Scene;
+import javafx.scene.layout.GridPane;
+import javafx.stage.Stage;
+
+public class Main extends Application {
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ primaryStage.setTitle("FTP_GUI");
+ GridPane gridPane = new GridPane();
+ gridPane.setAlignment(Pos.CENTER);
+ primaryStage.setScene(new Scene(gridPane, 600, 400));
+ primaryStage.show();
+ NewElementsCreator.createMainActivity(gridPane, primaryStage);
+
+ }
+
+ public static void main(String[] args) {
+ launch(args);
+ }
+}
\ No newline at end of file
diff --git a/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/NewElementsCreator.java b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/NewElementsCreator.java
new file mode 100644
index 0000000..e1ef566
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/NewElementsCreator.java
@@ -0,0 +1,218 @@
+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.stage.Stage;
+import javafx.util.Pair;
+import ru.spbau.mit.alyokhina.Client;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.util.HashSet;
+import java.util.List;
+
+public class NewElementsCreator {
+
+ /**
+ * 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, Stage stage) {
+ gridPane.getChildren().clear();
+ addActionToButton(
+ createButton(gridPane, 50, 200, 0, 0, "Создать сервер"),
+ actionEvent -> new ServerUI(gridPane, stage)
+ );
+ addActionToButton(
+ createButton(gridPane, 50, 200, 0, 1, "Новый клиент"),
+ actionEvent -> new ClientUI(gridPane, stage)
+ );
+ 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, Stage stage) {
+
+ addActionToButton(
+ createButton(gridPane, height, width, x, y, text),
+ actionEvent -> {
+ if (path.equals("/")) {
+ createMainActivity(gridPane, stage);
+ } 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/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/ServerUI.java b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/ServerUI.java
new file mode 100644
index 0000000..3255b70
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/ui/ServerUI.java
@@ -0,0 +1,69 @@
+package ru.spbau.mit.alyokhina.ui;
+
+import javafx.scene.control.TextField;
+import javafx.scene.layout.GridPane;
+import javafx.stage.Stage;
+import ru.spbau.mit.alyokhina.Server;
+
+import java.io.IOException;
+
+public class ServerUI {
+ private Stage stage;
+
+ public ServerUI(GridPane gridPane, Stage stage) {
+ this.stage = stage;
+ gridPane.getChildren().clear();
+ NewElementsCreator.createLabel(gridPane, 50, 400, 0, 0, "Введите порт");
+ TextField port = NewElementsCreator.createTextField(gridPane, 100, 200, 0, 2);
+ NewElementsCreator.addActionToButton(
+ NewElementsCreator.createButton(gridPane, 50, 100, 1, 3, "OK"),
+ actionEvent -> {
+ createServer(gridPane, port.getText());
+ }
+ );
+ NewElementsCreator.addActionToButton(
+ NewElementsCreator.createButton(gridPane, 50, 100, 1, 0, "Назад"),
+ actionEvent -> {
+ NewElementsCreator.createMainActivity(gridPane, stage);
+ }
+ );
+ }
+
+ private void result(GridPane gridPane) {
+ gridPane.getChildren().clear();
+ NewElementsCreator.createLabel(gridPane, 100, 200, 0, 0, "Сервер создан");
+ NewElementsCreator.addActionToButton(
+ NewElementsCreator.createButton(gridPane, 50, 200, 0, 1, "Назад"),
+ actionEvent -> {
+ NewElementsCreator.createMainActivity(gridPane, stage);
+ }
+ );
+ }
+
+
+ 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) {
+ NewElementsCreator.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) {
+ NewElementsCreator.createLabel(gridPane, 50, 400, 0, 3, e.getMessage(), "#ff0000");
+ }
+
+ }
+}
diff --git a/03.FTP/src/main/resources/directory.png b/03.FTP/src/main/resources/directory.png
new file mode 100644
index 0000000..ada21cb
Binary files /dev/null and b/03.FTP/src/main/resources/directory.png differ
diff --git a/03.FTP/src/main/resources/file.png b/03.FTP/src/main/resources/file.png
new file mode 100644
index 0000000..7c0209a
Binary files /dev/null and b/03.FTP/src/main/resources/file.png differ
diff --git a/03.FTP/src/main/resources/lec6.ps b/03.FTP/src/main/resources/lec6.ps
new file mode 100644
index 0000000..c9aa3b1
Binary files /dev/null and b/03.FTP/src/main/resources/lec6.ps differ
diff --git a/03.FTP/src/test/java/ru/spbau/mit/alyokhina/ClientTest.java b/03.FTP/src/test/java/ru/spbau/mit/alyokhina/ClientTest.java
new file mode 100644
index 0000000..7f81a8e
--- /dev/null
+++ b/03.FTP/src/test/java/ru/spbau/mit/alyokhina/ClientTest.java
@@ -0,0 +1,290 @@
+package ru.spbau.mit.alyokhina;
+
+import javafx.util.Pair;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+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;
+ private static File dirTestList1;
+ private static File dirTestList2;
+ private static File dirTestGet;
+ private static File file1ForTestGet;
+ private static File file2ForTestGet;
+ private static File copyFile1ForTestGet;
+ private static File copyFile2ForTestGet;
+
+ @ClassRule
+ public static TemporaryFolder folderForTest = new TemporaryFolder();
+
+ @BeforeClass
+ public static void createFiles() throws IOException {
+ dirTestList1 = folderForTest.newFolder("testList1");
+ folderForTest.newFolder("testList1", "dir1");
+ folderForTest.newFolder("testList1", "dir2");
+ folderForTest.newFile("testList1/file1");
+ folderForTest.newFile("testList1/file2");
+ folderForTest.newFile("testList1/file3");
+
+ dirTestList2 = folderForTest.newFolder("testList2");
+ folderForTest.newFolder("testList2", "dir1");
+ folderForTest.newFolder("testList2", "dir2");
+ folderForTest.newFolder("testList2", "dir3");
+ folderForTest.newFolder("testList2", "dir4");
+ folderForTest.newFolder("testList2", "dir5");
+ folderForTest.newFile("testList2/file1");
+ folderForTest.newFile("testList2/file2");
+
+ dirTestGet = folderForTest.newFolder("testGet1");
+ file1ForTestGet = folderForTest.newFile("testGet1/file1");
+ file2ForTestGet = folderForTest.newFile("testGet1/file2");
+
+ copyFile1ForTestGet = folderForTest.newFile("testGet1/copyFile1");
+ copyFile2ForTestGet = folderForTest.newFile("testGet1/copyFile2");
+
+ FileOutputStream fout = new FileOutputStream(file1ForTestGet);
+ String str = "Я вас любил: любовь еще, быть может,\n" +
+ "В душе моей угасла не совсем;\n" +
+ "Но пусть она вас больше не тревожит;\n" +
+ "Я не хочу печалить вас ничем.\n" +
+ "Я вас любил безмолвно, безнадежно,\n" +
+ "То робостью, то ревностью томим;\n" +
+ "Я вас любил так искренно, так нежно,\n" +
+ "Как дай вам бог любимой быть другим.";
+ fout.write(str.getBytes());
+
+ fout = new FileOutputStream(file2ForTestGet);
+ str = "Я выжила… Отчаянно, ознобно,\n" +
+ "Легко. Светает. Снег сошёл на нет.\n" +
+ "Не слышен плач, не ослепляет свет.\n" +
+ "Глаза пусты, глаза беззлобны.\n" +
+ "\n" +
+ "Недостающий воздух – чушь, пустяк,\n" +
+ "Совпал с полночным и привычным зноем.\n" +
+ "А если будет что-нибудь не так…\n" +
+ "Ты мне поможешь? Нас пока что двое?";
+ fout.write(str.getBytes());
+ }
+
+ @Test
+ public void testCreateClientAndServer() {
+ try {
+ if (!isCreateServer) {
+ final Server server = new Server(1408);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ isCreateServer = true;
+ }
+ 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(dirTestList1.getAbsolutePath());
+ 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(dirTestList1.getAbsolutePath());
+ List> files2 = client2.list(dirTestList2.getAbsolutePath());
+ 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(dirTestList1.getAbsolutePath() + "/test3");
+ 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);
+ client.get(file1ForTestGet.getAbsolutePath(), copyFile1ForTestGet.getAbsolutePath());
+ assertEquals(true, equalFiles(file1ForTestGet, copyFile1ForTestGet));
+
+ } 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);
+ client1.get(file1ForTestGet.getAbsolutePath(), copyFile1ForTestGet.getAbsolutePath());
+ assertEquals(true, equalFiles(file1ForTestGet, copyFile1ForTestGet));
+
+ Client client2 = new Client("localhost", 1408);
+ client2.get(file2ForTestGet.getAbsolutePath(), copyFile2ForTestGet.getAbsolutePath());
+ assertEquals(true, equalFiles(file2ForTestGet, copyFile2ForTestGet));
+
+ } 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(dirTestGet.getAbsolutePath() + "/file3", dirTestGet.getAbsolutePath() + "/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
+