level31.lesson15.big01 Задание 15 - баг

Добрый день!
Само задание:
Задание 15.

Пора попробовать что-нибудь распаковать. Для этого добавим публичный метод void extractAll(Path
outputFolder) throws Exception в класс ZipFileManager. Path outputFolder  - это путь, куда мы будем
распаковывать наш архив. У тебя уже большой опыт работы с элементами архива и потоками. Так что, я
дам только подсказки по реализации этого метода, а тебе придется хорошенько подумать, как это все
сделать:
1.	Проверь, есть ли zip файл вообще
2.	Если директория outputFolder не существует, то ее нужно создать, как и все папки, внутри которых
она лежит.
3.	Внутри архива некоторые файлы могут лежат внутри папок, тогда метод getName() элемента
архива ZipEntry, вернет не совсем имя, как может показаться из названия, а относительный путь
внутри архива. Этот относительный путь должен сохраниться и после распаковки, но уже
относительно той директории, куда мы распаковали архив
4.	Реализуй метод execute() класса ZipExtractCommand, по аналогии с таким же методом класса
ZipCreateCommand, сделай такой же блок try-catch, только поменяй сообщения выводимые
пользователю, чтобы он понял, что сейчас мы будем распаковывать архив, и что нужно ввести
полное имя архива и директорию, куда будем распаковывать. Не забудь вызвать метод extractAll
класса ZipFileManager, а не createZip, как это было в ZipCreateCommand
5.	Запускай программу и наслаждайся результатом распаковки

Столкнулся с таким багом — рабочий код, а именно
public void extractAll(Path outputFolder) throws Exception {
        if (Files.notExists(zipFile))
            throw new WrongZipFileException();
        if (Files.notExists(outputFolder)){
            Files.createDirectories(outputFolder);
        }

        ZipFile zip = new ZipFile(zipFile.toString());
        Enumeration entries = zip.entries();

        while (entries.hasMoreElements()) {
            ZipEntry zipEntry = (ZipEntry) entries.nextElement();
            Path fullPath = outputFolder.resolve(zipEntry.getName());

            if (zipEntry.isDirectory()) {
                Files.createDirectories(fullPath);
            } else {
                OutputStream output = Files.newOutputStream(fullPath);
                copyData(zip.getInputStream(zipEntry), output);
                output.close();
            }
        }
        zip.close();
    }

валидатор не принял, а принял, когда я, по совету форумчан, исправил его на некорректный (не извлекает архив при наличии в нем папок), вот так —
public void extractAll(Path outputFolder) throws Exception {
        if (Files.notExists(zipFile))
            throw new WrongZipFileException();
        if (Files.notExists(outputFolder)){
            Files.createDirectories(outputFolder);
        }

        ZipFile zip = new ZipFile(zipFile.toString());
        Enumeration entries = zip.entries();

        while (entries.hasMoreElements()) {
            ZipEntry zipEntry = (ZipEntry) entries.nextElement();
            Path fullPath = outputFolder.resolve(zipEntry.getName());

                Files.createDirectories(fullPath.getParent());

                OutputStream output = Files.newOutputStream(fullPath);
                copyData(zip.getInputStream(zipEntry), output);
                output.close();
        }
        zip.close();
    }

Почему нерабочий код не проходит, а рабочий — нет?
Мало того, когда я сдал задание, на месте моего метода появился вот такой:
public void extractAll(Path outputFolder) throws Exception {
        // Проверяем существует ли zip файл
        if (!Files.isRegularFile(zipFile)) {
            throw new WrongZipFileException();
        }

        try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(zipFile))) {
            // Создаем директорию вывода, если она не существует
            if (Files.notExists(outputFolder))
                Files.createDirectories(outputFolder);

            // Проходимся по содержимому zip потока (файла)
            ZipEntry zipEntry = zipInputStream.getNextEntry();

            while (zipEntry != null) {
                String fileName = zipEntry.getName();
                Path fileFullName = outputFolder.resolve(fileName);

                // Создаем необходимые директории
                Path parent = fileFullName.getParent();
                if (Files.notExists(parent))
                    Files.createDirectories(parent);

                try (OutputStream outputStream = Files.newOutputStream(fileFullName)) {
                    copyData(zipInputStream, outputStream);
                }
                zipEntry = zipInputStream.getNextEntry();
            }
        }
    }

— который, в отличие от моего первоначального кода, тоже не может извлечь архив, если в нем есть папки — создает файл с нулевым размером вместо директории.
Задаче уже порядочно времени, неужели нельзя исправить? Или может я чего-то не понял?

level31.lesson15.big01 Задание 5

Если кто то как и я испытавает некоторые трудности при решении этого задания, то возможно Вам пригодится совет: обратите особое внимание на слово «константное» в пункте 3. Добавь в класс приватное статическое константное хранилище команд Map<Operation, Command>
allKnownCommandsMap. Константное это не просто final. Нужно сделать так чтобы мэпа была немодифицируема.
  • ,

Неизвестная ошибка при работе с сервером (level31.lesson15.big01 Задание 5)

После получения этого задания плагин выдаёт сообщение «Неизвестная ошибка при работе с сервером».

Задание 5.

Разделим команды на два типа: те, которые работают непосредственно с архивом и вспомогательные
(например EXIT). Все команды первого типа, будут иметь общий функционал, его удобно вынести в какой-
то их общий базовый класс. Назовем этот класс ZipCommand. Он, как и все классы команд, должен
реализовывать интерфейс Command. Все команды, которые работают с архивом, должны быть
унаследованы от класса ZipCommand. Мы не будем создавать объекты класса ZipCommand, поэтому
сделаем его абстрактным.
1. Создай абстрактный класс ZipCommand, реализующий интерфейс Command
2. Создай по одному классу для каждой команды. Все перечисленные команды должны быть
унаследованы от ZipCommand и содержать пустую реализацию метода execute(), его реализацию
мы будем писать для каждой команды отдельно по мере реализации нашего архиватора.
2.1. Команда создания архива (упаковки файлов в архив) – class ZipCreateCommand
2.2. Команда просмотра содержимого архива – class ZipContentCommand
2.3. Команда распаковки архива – class ZipExtractCommand
2.4. Команда добавления файла в архив – class ZipAddCommand
2.5. Команда удаления файла из архива – class ZipRemoveCommand

Даже если удалить все файлы задачи — ошибка та же (вместо, например, «Программа не прошла тестирование» или «Программа не компилируется на сервере»).

level31.lesson15.big01 Задание 16

Работает все как нужно, но не принимает сервер

Задание:
Задание 16.

Пришло время что-нибудь удалить из архива. Архив очень хитрая штука, нельзя вот так просто взять и
удалить какой-то элемент внутри него.
Почему? Представь, что мы решили сами придумать свой алгоритм сжатия текста. Посмотрев исходный
текст, мы видим, что в нем часто встречается фраза "быть программистом круто". Мы можем в месте, где
второй, третий, N-ый раз встречается наша фраза сделать пометку, что тут была фраза, как в строке S
начиная с символа номер K и длиной N, а саму фразу удалить. Когда мы заменим много повторяющихся
фраз, текс заметно сократится, но станет нечитаемым для тех, кто не знаком с нашим алгоритмом сжатия.
Мы же этот текст сможем восстановить (разархивировать). А теперь представь, что нам нужно удалить
часть текста, на которую ссылались сжатые фрагменты. В такой ситуации, весь наш архив перестанет
иметь смысл. Вот почему нельзя просто так удалить часть архива. Это очень примерное описание
варианта архивации, в реальности все намного сложнее.
Поэтому, чтобы что-то удалить из архива, нужно создать новый архив, переписать в него все, кроме
удаляемых файлов, а потом заменить старый архив вновь созданным.
1.	Добавь публичный метод для удаления файлов из архива void removeFiles(List<Path> pathList)
throws Exception в класс ZipFileManager. В pathList будет передаваться список относительных путей на
файлы внутри архива. Он должен:
	1.1. Бросать исключение WrongZipFileException, если файл архива не существует
	1.2. Создать временный файл архива с помощью метода createTempFile() класса Files
	1.3. Пройтись по всем файлам оригинального архива, проверить, есть ли текущий файл в списке
на удаление.
	- Если файл есть в списке, вывести сообщение, что мы удалили файл с таким-то именем и
	перейти к следующему файлу.
	- Если файла нет в списке на удаление, переписать его в новый архив
	1.4. Заменить оригинальный файл архива временным, в который мы записали нужные файлы.
Это нужно сделать с помощью метода move() класса Files
2.	Добавь публичный метод void removeFile(Path path) throws Exception в класс ZipFileManager,
который будет вызывать метод removeFiles, создавая список из одного элемента. Это можно сделать с помощью
метода singletonList() класса Collections. Посмотри, как он работает.
3.	Реализуй метод execute() класса ZipRemoveCommand, создав объект класса ZipFileManager,
спросив пользователя из какого архива и какой файл будем удалять, и вызвав метод removeFile().
Все остальное, как и в других командах. Исключение PathIsNotFoundException можно не ловить, т.к. метод
removeFile() не должен его кидать.
4.	Запусти программу и проверить, что удаление файла из архива работает.


Код:
ZipFileManager

public void removeFiles(List<Path> pathList) throws Exception {
        if (!Files.isRegularFile(zipFile)) {
            throw new WrongZipFileException();
        }

        Path tmpFile = Files.createTempFile("tmp", ".zip");

        try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(zipFile));
             ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(tmpFile))) {

            ZipEntry zipEntry = zipInputStream.getNextEntry();

            while (zipEntry != null) {
                String fileName = zipEntry.getName();
                Path fileFullName = Paths.get(fileName);

                if(zipEntry.isDirectory()) {
                    zipOutputStream.putNextEntry(new ZipEntry(fileName));
                    zipEntry = zipInputStream.getNextEntry();
                    continue;
                }
                for(Path deleteFile : pathList) {
                    if((fileFullName.getFileName()).equals(deleteFile)) {
                        ConsoleHelper.writeMessage("Файл " + fileFullName.getFileName() + " удалён");
                    } else {
                        zipOutputStream.putNextEntry(new ZipEntry(fileFullName.toString()));
                        copyData(zipInputStream, zipOutputStream);
                        zipOutputStream.closeEntry();
                    }
                }

                zipEntry = zipInputStream.getNextEntry();
            }
        }

        Files.move(tmpFile, zipFile, StandardCopyOption.REPLACE_EXISTING);
    }

    public void removeFile(Path path) throws Exception {
        removeFiles(Collections.singletonList(path));
    }


ZipRemoveCommand
public class ZipRemoveCommand extends ZipCommand {
    @Override
    public void execute() throws Exception {
        ConsoleHelper.writeMessage("Удаление файла");
        ZipFileManager zfm = getZipFileManager();


        ConsoleHelper.writeMessage("Введите имя файла для удаления");
        Path deleteFilePath = Paths.get(ConsoleHelper.readString());
        zfm.removeFile(deleteFilePath);

        ConsoleHelper.writeMessage("Удаление из архива завершено.");
    }
}