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..96350e5
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Client.java
@@ -0,0 +1,78 @@
+package ru.spbau.mit.alyokhina;
+
+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;
+
+ /**
+ * 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;
+ }
+
+}
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..95e5340
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Request.java
@@ -0,0 +1,6 @@
+package ru.spbau.mit.alyokhina;
+
+public enum Request {
+ LIST_REQUEST,
+ GET_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..e6a6ca8
--- /dev/null
+++ b/03.FTP/src/main/java/ru/spbau/mit/alyokhina/Server.java
@@ -0,0 +1,100 @@
+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);
+ }
+ }
+ } 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);
+ }
+ }
+}
+
+
+
+
+
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..39acb8f
--- /dev/null
+++ b/03.FTP/src/test/java/ru/spbau/mit/alyokhina/ClientTest.java
@@ -0,0 +1,276 @@
+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() throws IOException {
+
+ if (!isCreateServer) {
+ final Server server = new Server(1408);
+ Thread thread = new Thread(server::start);
+ thread.start();
+ isCreateServer = true;
+ }
+ new Client("localhost", 1408);
+
+
+ }
+
+
+ @Test
+ public void testListWithOneClient() throws IOException {
+
+ 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));
+
+ }
+
+
+ @Test
+ public void testListWithTwoClients() throws IOException {
+
+ 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));
+
+ }
+
+ @Test
+ public void testCreateWithNonexistentDirectory() throws IOException {
+
+ 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());
+
+
+ }
+
+
+ @Test
+ public void testGetWithOneClient() throws IOException {
+
+ 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));
+
+
+ }
+
+
+ @Test
+ public void testGetWithTwoClients() throws IOException {
+
+ 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));
+
+
+ }
+
+ @Test
+ public void testGetWithNonexistentFiles() throws IOException {
+
+ 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());
+
+
+ }
+
+
+ /**
+ * 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
+