Skip to content
Snippets Groups Projects
ReHost.java 5.37 KiB
Newer Older
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;

/**
 * This is a utility class, that manages the integration of content into hosts
 * This class copies the jar-file this is in and either:
 * - adds content to the currently hosted content
 * - replaces the currently hosted content
 * - removes the currently hosted content
 * "Currently hosted" content refers to the content in this jar file.
 * The modified content will then be inside a new copy of this server,
 * as I have not found a way to modify a currently executed jar file.
 */
public final class ReHost {
    private ReHost() {
        throw new IllegalArgumentException("Utility class");
    }

    /**
     * Creates a new copy of this jar file with its hosted content
     * replaced by the content of the directory {@code contentToHost}.
     * @param contentToHost The content the newly created server should host.
     * @param targetFile The File location where the newly created Server should be placed.
     * @param ui The User interface used to ask the user things,
     *           like "do you want to overwrite XY", if {@code targetFile} exists
     * @throws IllegalArgumentException <ul><li>if either parameter is null,</li>
     *                                  <li>{@code contentToHost} does not exist</li>
     *                                  <li>{@code targetFile} exists and is a directory</li></ul>
     */
    public static void host(Path contentToHost, Path targetFile, UI ui) {
        unhost(targetFile, ui, false);
        addHostedContent(contentToHost, targetFile, ui);
    }

    public static void unhost(Path targetFile, UI ui) {
        unhost(targetFile, ui, true);
    }

    private static void unhost(Path targetFile, UI ignored, boolean createContentDir) {
        Either<Path, IOException> temp = copySelf(targetFile);
        switch  (temp) {
            case Either.Left<Path, IOException> left -> {
                Path tempFile = left.unwrap();
                clearContents(tempFile, createContentDir);
                try {
                    Files.move(tempFile, targetFile, StandardCopyOption.REPLACE_EXISTING);
                    System.out.println("Successfully copied " + tempFile + " to " + targetFile);
                } catch (IOException e) {
                    e.printStackTrace(System.out);
                }
            }
            case Either.Right<Path, IOException> right -> {
                Exception e = right.right();
                e.printStackTrace(System.out);
            }
        }
    }

    public static void addHostedContent(Path additionalContentToHost, Path targetFile, UI ignored) {
        copySelf(targetFile);
        copyContents(targetFile, additionalContentToHost);
    }

    /*
     * UTILITY METHODS:
     */
    private static Either<Path, URISyntaxException> jarLocation() {
        return Either.of(() -> {
            try {
                return new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toPath();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }


    private static Either<Path, IOException> copySelf(Path target) {
        Either<Path, URISyntaxException> jarLocation = jarLocation();

        return Either.of(() -> {
            try {
                return Files.copy(jarLocation.unwrap(), target, StandardCopyOption.REPLACE_EXISTING);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    private static void clearContents(Path targetFile) {
        clearContents(targetFile, true);
    }

    private static void clearContents(Path targetFile, boolean createContentDir) {
        Map<String, String> env = new HashMap<>();
        env.put("create", "false");

        try (FileSystem fs = FileSystems.newFileSystem(targetFile, env)) {
            Path target = fs.getPath("/content");

            purgeDirectory(target);

            if (createContentDir) Files.createDirectory(target);
        } catch (Exception e) {
            e.printStackTrace(System.out);
            System.exit(4);
        }
    }

    private static void purgeDirectory(Path dirPath) {
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dirPath)){
            for (Path path : stream) {
                if (Files.isDirectory(path)) {
                    purgeDirectory(path);
                }
                Files.delete(path);
            }
            Files.delete(dirPath);
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }
    }

    private static void copyContents(Path targetFile, Path contentDir) {
        Map<String, String> env = new HashMap<>();
        env.put("create", "false");
        try (FileSystem fs = FileSystems.newFileSystem(targetFile, env)) {
            Path target = fs.getPath("/content");

            try (DirectoryStream<Path> stream = Files.newDirectoryStream(contentDir)) {
                for (Path path : stream) {
                    Path name = path.getFileName();
                    Path target2 = target.resolve(name.toString());
                    Files.copy(path, target2, StandardCopyOption.REPLACE_EXISTING);
                }
            }

        } catch (Exception e) {
            e.printStackTrace(System.out);
            System.exit(4);
        }
    }
}