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 +