at.nonblocking.cliwix.cli.CliwixCliClient.java Source code

Java tutorial

Introduction

Here is the source code for at.nonblocking.cliwix.cli.CliwixCliClient.java

Source

/*
 * Copyright (c) 2014-2016
 * nonblocking.at gmbh [http://www.nonblocking.at]
 *
 * This file is part of Cliwix.
 *
 * Cliwix is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package at.nonblocking.cliwix.cli;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import java.io.*;
import java.nio.file.Files;
import java.util.Date;
import java.util.concurrent.ExecutionException;

public class CliwixCliClient {

    private static final int EXIT_STATUS_FAIL = 1;

    static boolean debug = false;
    static Console console = new ConsoleDefaultImpl();
    static HttpGetHandler getHandler = new HttpGetHandlerDefaultImpl();
    static HttpPostHandler postHandler = new HttpPostHandlerDefaultImpl();
    static HttpDeleteHandler deleteHandler = new HttpDeleteHandlerDefaultImpl();

    static CookieManager cookieManager = new CookieManagerImpl();

    public static void main(String[] args) throws Exception {
        Options options = null;

        try {
            options = Options.parseArgs(args);
        } catch (CliwixCliClientArgumentException e) {
            if (debug)
                console.printStacktrace(e);
            console.printlnError("Error: Invalid arguments: " + e.getMessage());
            Options.printUsage();
            console.exit(EXIT_STATUS_FAIL);
            return;
        }

        if (options == null || Options.COMMAND_HELP.equals(options.getCommand())) {
            Options.printUsage();
            console.exit(0);
            return;
        }

        if (Options.COMMAND_CREATE_CONFIG.equals(options.getCommand())) {
            if (args.length < 2) {
                console.printlnError("Error: No config file location given!");
                console.exit(EXIT_STATUS_FAIL);
                return;
            }
            File configFile = new File(args[1]);
            options.copyDefaultPropertiesTo(configFile);
            console.println("Configuration saved under: " + configFile.getAbsolutePath());
            console.exit(0);
            return;
        }

        debug = options.isDebug();

        String cliwixServerUrl = options.getServerCliwixUrl();
        String username = options.getServerUsername();
        String password = options.getServerPassword();

        if (cliwixServerUrl == null) {
            console.printlnError("Error: Property server.cliwix.url is required!");
            console.exit(EXIT_STATUS_FAIL);
            return;
        }

        cookieManager.clear();

        //Login
        if (username != null && password != null) {
            JSONObject loginData = new JSONObject();
            loginData.put("username", username);
            loginData.put("password", password);
            JSONObject result = postJson(cliwixServerUrl, "/services/login", loginData);
            JSONObject loginResult = (JSONObject) result.get("loginResult");

            if (loginResult.get("succeeded") == Boolean.TRUE) {
                console.println("Login successful");
            } else {
                console.printlnError("Error: Login failed! Reason: " + loginData.get("errorMessage"));
                console.exit(EXIT_STATUS_FAIL);
                return;
            }

        } else if (username != null) {
            console.printlnError("Error: If -user is set -pass is required!");
            console.exit(EXIT_STATUS_FAIL);
            return;
        } else if (password != null) {
            console.printlnError("Error: If -pass is set -user is required!");
            console.exit(EXIT_STATUS_FAIL);
            return;
        }

        switch (options.getCommand()) {
        case Options.COMMAND_INFO:
            doInfo(cliwixServerUrl, options);
            break;
        case Options.COMMAND_EXPORT:
            doExport(cliwixServerUrl, options);
            break;
        case Options.COMMAND_IMPORT:
            doImport(cliwixServerUrl, options);
            break;
        default:
        case Options.COMMAND_HELP:
            Options.printUsage();
        }
    }

    private static boolean serverTest(String serverUrl) {
        JSONObject json = getJson(serverUrl, "/services/info/status");
        String state = (String) ((JSONObject) json.get("infoStatus")).get("status");

        switch (state) {
        case "LIFERAY_NOT_FOUND":
            console.printlnError("Error: No Liferay server found!");
            console.exit(EXIT_STATUS_FAIL);
        case "LIFERAY_VERSION_NOT_SUPPORTED":
            console.printlnError("Error: Liferay version not supported!");
            console.exit(EXIT_STATUS_FAIL);
        case "NOT_READY":
            return false;
        default:
        case "READY":
            console.println("Server is ready.");
            return true;
        }
    }

    private static void waitForServerReady(String serverUrl, Options options) {
        long startTime = System.currentTimeMillis();
        boolean ready = false;

        while (!ready && (System.currentTimeMillis() - startTime) < options.getTimeoutServerReadySec() * 1000) {
            ready = serverTest(serverUrl);
            if (!ready) {
                console.println("Server not ready. Waiting...");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                }
            }
        }
    }

    private static void doInfo(String cliwixServerUrl, Options options) {
        waitForServerReady(cliwixServerUrl, options);

        JSONObject json = getJson(cliwixServerUrl, "/services/info");
        JSONObject info = (JSONObject) json.get("info");

        console.println("Server info:");
        console.println("  Cliwix Version: " + info.get("cliwixVersion"));
        console.println("  Cliwix Workspace Directory: " + info.get("cliwixWorkspaceDirectory"));
        console.println("  Liferay Release: " + info.get("liferayRelease"));
    }

    private static void doExport(String cliwixServerUrl, Options options) {
        waitForServerReady(cliwixServerUrl, options);

        String exportFolder = options.getExportFolder();
        if (exportFolder == null) {
            console.printlnError("Error: Property export.folder is required.");
            console.exit(EXIT_STATUS_FAIL);
            return;
        }

        File outputDir = null;
        try {
            outputDir = new File(exportFolder);
            outputDir.mkdirs();
        } catch (Exception e) {
            console.printlnError("Error: Invalid export folder: " + exportFolder);
            console.exit(EXIT_STATUS_FAIL);
            return;
        }

        JSONObject exportSettings = options.getExportSettings();

        JSONObject json = postJson(cliwixServerUrl, "/services/exports", exportSettings);
        JSONObject exportResult = (JSONObject) json.get("exportResult");
        String exportId = (String) exportResult.get("exportId");

        console.println("Export started. Id: " + exportId);

        boolean success = waitForImportExport(true, exportId, cliwixServerUrl, options);

        if (success) {
            console.println("Export succeeded.");

            String path = "/services/exports/" + exportId + "/zip";
            if (debug)
                console.println("Sending GET request: " + path);
            Response zipResponse = getHandler.get(cliwixServerUrl, path, cookieManager);
            handleError(zipResponse);

            File tempFile = null;
            try {
                tempFile = File.createTempFile("export", ".zip");
            } catch (IOException e) {
                if (debug)
                    console.printStacktrace(e);
                console.printlnError("Error: Unable to create temporary zip file");
                console.exit(EXIT_STATUS_FAIL);
                return;
            }
            long fileLength = zipResponse.getContentLength();
            ProgressCallback progressCallback = new ProgressCallbackConsoleImpl(console);

            try (InputStream inputStream = zipResponse.getResponseStream();
                    OutputStream outputStream = new FileOutputStream(tempFile)) {

                byte[] buffer = new byte[BaseHttpHandler.CHUNK_SIZE];
                long transferred = 0;
                int len = -1;
                while ((len = inputStream.read(buffer)) > 0) {
                    outputStream.write(buffer, 0, len);
                    transferred = transferred + len;
                    progressCallback.bytesTransferred(transferred, fileLength);
                }

                progressCallback.bytesTransferred(fileLength, fileLength);

            } catch (IOException e) {
                if (debug)
                    console.printStacktrace(e);
                console.printlnError("Error: " + e.getMessage());
                console.exit(EXIT_STATUS_FAIL);
            } finally {
                zipResponse.disconnect();
            }

            if (options.isExtractZip()) {
                try {
                    ZipFile zip = new ZipFile(tempFile);
                    zip.extractAll(outputDir.getAbsolutePath());
                } catch (ZipException e) {
                    if (debug)
                        console.printStacktrace(e);
                    console.printlnError("Error: Corrupt ZIP file");
                    console.exit(EXIT_STATUS_FAIL);
                } finally {
                    tempFile.delete();
                }
            } else {
                File targetFile = new File(outputDir, "export_" + exportId + ".zip");
                try (FileInputStream fis = new FileInputStream(tempFile)) {
                    Files.copy(fis, targetFile.toPath());
                } catch (IOException e) {
                    if (debug)
                        console.printStacktrace(e);
                    console.printlnError("Error: " + e.getMessage());
                    console.exit(EXIT_STATUS_FAIL);
                } finally {
                    tempFile.delete();
                }
            }

            console.println("Export data written to: " + outputDir.getAbsolutePath());

        } else {
            console.printlnError("Export failed!");

            String path = "/services/exports/" + exportId + "/report";
            if (debug)
                console.println("Sending GET request: " + path);
            Response reportResponse = getHandler.get(cliwixServerUrl, path, cookieManager);
            handleError(reportResponse);

            File reportFile = new File(outputDir, "export-report.html");

            try (OutputStream outputStream = new FileOutputStream(reportFile)) {
                outputStream.write(reportResponse.getResponseAsString().getBytes("UTF-8"));
                console.println("Error report written to: " + reportFile.getAbsolutePath());

            } catch (IOException e) {
                if (debug)
                    console.printStacktrace(e);
                console.printlnError("Error: No report found");
            } finally {
                reportResponse.disconnect();
            }
        }

        if (options.isExportDeleteOnServerAfterTransfer()) {
            Response deleteResponse = deleteHandler.delete(cliwixServerUrl, "/services/exports/" + exportId,
                    cookieManager);
            if (deleteResponse.getStatusCode() == 200) {
                console.println("Successfully deleted export folder on server.");
            } else {
                console.printlnError("Failed to delete export folder on server!");
            }
        }

        if (!success) {
            console.exit(EXIT_STATUS_FAIL);
        }
    }

    private static void doImport(String cliwixServerUrl, Options options) {
        waitForServerReady(cliwixServerUrl, options);

        String importReportFolder = options.getImportReportFolder();
        if (importReportFolder == null) {
            importReportFolder = ".";
        }
        File outputDir = null;
        try {
            outputDir = new File(importReportFolder);
            outputDir.mkdirs();
        } catch (Exception e) {
            console.printlnError("Error: Invalid import report folder: " + importReportFolder);
            console.exit(EXIT_STATUS_FAIL);
            return;
        }

        String input = options.getImportInput();
        if (input == null) {
            console.printlnError("Error: Property import.input is required.");
            console.exit(EXIT_STATUS_FAIL);
            return;
        }

        File inputFile = new File(input);
        if (!inputFile.exists()) {
            console.printlnError("Error: Input does not exist: " + inputFile.getAbsolutePath());
            console.exit(EXIT_STATUS_FAIL);
        }

        if (inputFile.isDirectory()) {
            try {
                File tempFile = File.createTempFile("import", ".zip");
                tempFile.delete(); //Must not exist
                ZipFile zipFile = new ZipFile(tempFile);
                ZipParameters zipParams = new ZipParameters();
                zipParams.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
                zipParams.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_FASTEST);
                zipParams.setIncludeRootFolder(false);
                zipFile.addFolder(inputFile, zipParams);
                inputFile = tempFile;
            } catch (IOException | ZipException e) {
                if (debug)
                    console.printStacktrace(e);
                console.printlnError("Error: Unable to create zip file");
                console.exit(EXIT_STATUS_FAIL);
                return;
            }

        } else if (!inputFile.getName().endsWith(".xml") && !inputFile.getName().endsWith(".zip")) {
            console.printlnError("Error: Invalid input (must be a folder or a XML file or a ZIP archive): "
                    + inputFile.getAbsolutePath());
            console.exit(EXIT_STATUS_FAIL);
            return;
        }

        JSONObject uploadResult = uploadFile(cliwixServerUrl, "/services/uploads", inputFile);
        String tmpFileName = (String) ((JSONObject) uploadResult.get("uploadResult")).get("tmpFileName");

        JSONObject importSettings = options.getImportSettings(tmpFileName);

        JSONObject importResult = postJson(cliwixServerUrl, "/services/imports", importSettings);

        String importId = (String) ((JSONObject) importResult.get("importResult")).get("importId");
        console.println("Import started. Id: " + importId);

        boolean success = waitForImportExport(false, importId, cliwixServerUrl, options);

        if (success) {
            console.println("Import succeeded.");
        } else {
            console.printlnError("Error: Import failed!");
        }

        String path = "/services/imports/" + importId + "/report";
        if (debug)
            console.println("Sending GET request: " + path);
        Response reportResponse = getHandler.get(cliwixServerUrl, path, cookieManager);
        handleError(reportResponse);

        File reportFile = new File(outputDir, "import-report.html");

        try (OutputStream outputStream = new FileOutputStream(reportFile)) {
            outputStream.write(reportResponse.getResponseAsString().getBytes("UTF-8"));
            console.println("Import report written to: " + reportFile.getAbsolutePath());

        } catch (IOException e) {
            if (debug)
                console.printStacktrace(e);
            console.printlnError("Error: No import report found");
            success = false;
        } finally {
            reportResponse.disconnect();
        }

        if (options.isImportDeleteOnServerAfterTransfer()) {
            Response deleteResponse = deleteHandler.delete(cliwixServerUrl, "/services/imports/" + importId,
                    cookieManager);
            if (deleteResponse.getStatusCode() == 200) {
                console.println("Successfully deleted import folder on server.");
            } else {
                console.printlnError("Failed to delete import folder on server!");
            }
        }

        if (!success) {
            console.exit(EXIT_STATUS_FAIL);
        }
    }

    private static boolean waitForImportExport(boolean export, String id, String serverUrl, Options options) {
        String path;
        if (export)
            path = "/services/exports/" + id + "/status";
        else
            path = "/services/imports/" + id + "/status";

        long startTime = System.currentTimeMillis();
        long timeout = export ? options.getTimeoutExportSec() * 1000 : options.getTimeoutImportSec() * 1000;

        while (System.currentTimeMillis() - startTime < timeout) {
            JSONObject json = getJson(serverUrl, path);
            String state = (String) ((JSONObject) json.get(export ? "exportStatus" : "importStatus")).get("status");

            switch (state) {
            case "success":
                return true;
            case "processing":
                console.println("Waiting for " + (export ? "export" : "import") + " to complete...");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                }
                break;
            default:
            case "fail":
                return false;
            }
        }

        return false;
    }

    private static void handleError(Response response) {
        if (response.getStatusCode() != 200) {
            String message = response.getStatusCode() + ": " + response.getStatusMessage();

            try {
                if (response.getContentType().contains("json")) {
                    String jsonString = response.getResponseAsString();
                    JSONObject json = (JSONObject) JSONValue.parse(jsonString);
                    message = (String) ((JSONObject) json.get("error")).get("message");
                }
            } catch (Exception e) {
                if (debug)
                    console.printStacktrace(e);
            }

            console.printlnError("Error: " + message);
            console.exit(EXIT_STATUS_FAIL);
        }
    }

    private static JSONObject getJson(String serverUrl, String path) {
        if (debug)
            console.println("Sending GET request: " + path);
        Response response = getHandler.get(serverUrl, path, cookieManager);
        handleError(response);

        JSONObject obj = null;
        try {
            String infoResponseJson = response.getResponseAsString();
            if (debug)
                console.println("Received: " + infoResponseJson);
            return (JSONObject) JSONValue.parse(infoResponseJson);
        } catch (IOException e) {
            if (debug)
                console.printStacktrace(e);
            console.printlnError("Error: " + e.getMessage());
            console.exit(EXIT_STATUS_FAIL);
        } finally {
            response.disconnect();
        }

        return null;
    }

    private static JSONObject postJson(String serverUrl, String path, JSONObject request) {
        String requestString = JSONValue.toJSONString(request);

        if (debug)
            console.println("Sending: " + requestString);
        Response response = postHandler.post(serverUrl, path, new ByteArrayInputStream(requestString.getBytes()),
                requestString.length(), CONTENT_TYPE.JSON, null, null, cookieManager);
        handleError(response);

        JSONObject obj = null;
        try {
            String exportResult = response.getResponseAsString();
            if (debug)
                console.println("Received: " + exportResult);
            return (JSONObject) JSONValue.parse(exportResult);
        } catch (IOException e) {
            if (debug)
                console.printStacktrace(e);
            console.printlnError("Error: " + e.getMessage());
            console.exit(EXIT_STATUS_FAIL);
        } finally {
            response.disconnect();
        }

        return null;
    }

    private static JSONObject uploadFile(String serverUrl, String path, File file) {
        if (debug)
            console.println("Uploading file to: " + path);

        Response response = null;
        try {
            response = postHandler.post(serverUrl, path, new FileInputStream(file), file.length(),
                    CONTENT_TYPE.UPLOAD, file.getName(), new ProgressCallbackConsoleImpl(console), cookieManager);
        } catch (IOException e) {
            if (debug)
                console.printStacktrace(e);
            console.printlnError("Error: File not found. " + file.getAbsolutePath());
            console.exit(EXIT_STATUS_FAIL);
            return null;
        }

        handleError(response);

        JSONObject obj = null;
        try {
            String exportResult = response.getResponseAsString();
            if (debug)
                console.println("Received: " + exportResult);
            return (JSONObject) JSONValue.parse(exportResult);
        } catch (IOException e) {
            if (debug)
                console.printStacktrace(e);
            console.printlnError("Error: " + e.getMessage());
            console.exit(EXIT_STATUS_FAIL);
        } finally {
            response.disconnect();
        }

        return null;
    }

}