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 +