org.ow2.proactive_grid_cloud_portal.cli.EntryPoint.java Source code

Java tutorial

Introduction

Here is the source code for org.ow2.proactive_grid_cloud_portal.cli.EntryPoint.java

Source

/*
 * ProActive Parallel Suite(TM):
 * The Open Source library for parallel and distributed
 * Workflows & Scheduling, Orchestration, Cloud Automation
 * and Big Data Analysis on Enterprise Grids & Clouds.
 *
 * Copyright (c) 2007 - 2017 ActiveEon
 * Contact: contact@activeeon.com
 *
 * This library 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: version 3 of
 * the License.
 *
 * 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/>.
 *
 * If needed, contact us to obtain a release under GPL Version 2 or 3
 * or a different license than the AGPL.
 */
package org.ow2.proactive_grid_cloud_portal.cli;

import static com.google.common.base.Throwables.getStackTraceAsString;
import static org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES;
import static org.ow2.proactive_grid_cloud_portal.cli.CLIException.REASON_UNAUTHORIZED_ACCESS;
import static org.ow2.proactive_grid_cloud_portal.cli.RestConstants.DFLT_REST_SCHEDULER_URL;
import static org.ow2.proactive_grid_cloud_portal.cli.cmd.AbstractCommand.writeDebugModeUsageWithBreakEndLine;
import static org.ow2.proactive_grid_cloud_portal.cli.cmd.AbstractLoginCommand.PROP_PERSISTED_SESSION;
import static org.ow2.proactive_grid_cloud_portal.cli.cmd.AbstractLoginCommand.PROP_RENEW_SESSION;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.codehaus.jackson.map.ObjectMapper;
import org.ow2.proactive_grid_cloud_portal.cli.cmd.AbstractLoginCommand;
import org.ow2.proactive_grid_cloud_portal.cli.cmd.Command;
import org.ow2.proactive_grid_cloud_portal.cli.console.AbstractDevice;
import org.ow2.proactive_grid_cloud_portal.cli.console.JLineDevice;

import com.google.common.collect.ObjectArrays;

public abstract class EntryPoint {

    protected abstract String resourceType();

    protected int run(String... args) {

        CommandFactory commandFactory = null;
        CommandLine cli = null;
        AbstractDevice console;

        ApplicationContext currentContext = new ApplicationContextImpl().currentContext();

        // Cannot rely on AbstractCommand#isDebugModeEnabled
        // because at this step SetDebugModeCommand#execute has not yet been executed
        // Consequently, SetDebugModeCommand.PROP_DEBUG_MODE is not set even if debug mode is enabled.
        boolean isDebugModeEnabled = isDebugModeEnabled(args);

        try {
            commandFactory = getCommandFactory(currentContext);
            Options options = commandFactory.supportedOptions();

            cli = parseArgs(options, args);
        } catch (IOException ioe) {
            System.err.println("An error occurred.");
            ioe.printStackTrace(System.err);
            return 1;
        } catch (ParseException pe) {
            writeError(currentContext, pe.getMessage(), pe, isDebugModeEnabled);
            // print usage
            Command help = commandFactory.commandForOption(new Option("h", null));
            if (help != null) {
                help.execute(currentContext);
            }
            return 1;
        }

        currentContext.setObjectMapper(new ObjectMapper().configure(FAIL_ON_UNKNOWN_PROPERTIES, false));
        currentContext.setRestServerUrl(DFLT_REST_SCHEDULER_URL);
        currentContext.setResourceType(resourceType());

        // retrieve the (ordered) command list corresponding to command-line
        // arguments
        List<Command> commands;
        try {
            commands = commandFactory.getCommandList(cli, currentContext);
        } catch (CLIException e) {
            writeError(currentContext, "An error occurred.", e, isDebugModeEnabled);
            return 1;
        }

        boolean retryLogin = false;

        try {
            executeCommandList(commands, currentContext);
        } catch (CLIException error) {
            if (REASON_UNAUTHORIZED_ACCESS == error.reason() && hasLoginCommand(commands)) {
                retryLogin = true;
            } else {
                writeError(currentContext, "An error occurred.", error, isDebugModeEnabled);
                return 1;
            }
        } catch (Throwable e) {
            writeError(currentContext, "An error occurred.", e, isDebugModeEnabled);
            return 1;
        }

        /*
         * in case of an existing session-id, the REST CLI reuses it without
         * obtaining a new session-id even if a login with credentials
         * specified. However if the REST server responds with an authorization
         * error (e.g. due to session timeout), it re-executes the commands list
         * with AbstractLoginCommand.PROP_RENEW_SESSION property set to 'true'.
         * This will effectively re-execute the user command with a new
         * session-id from server.
         */
        if (retryLogin && currentContext.getProperty(PROP_PERSISTED_SESSION, Boolean.TYPE, false)) {
            try {
                currentContext.setProperty(PROP_RENEW_SESSION, true);
                executeCommandList(commands, currentContext);
            } catch (Throwable error) {
                writeError(currentContext, "An error occurred while execution.", error, isDebugModeEnabled);
                return 1;
            }
        }
        return 0;
    }

    protected static CommandFactory getCommandFactory(ApplicationContext currentContext) throws IOException {
        CommandFactory commandFactory;
        AbstractDevice console;
        commandFactory = getCommandFactory();
        console = AbstractDevice.getConsole(AbstractDevice.JLINE);
        ((JLineDevice) console).setCommands(ObjectArrays.concat(commandFactory.supportedCommandEntries(),
                CommandSet.INTERACTIVE_COMMANDS, CommandSet.Entry.class));
        currentContext.setDevice(console);
        return commandFactory;
    }

    private static CommandFactory getCommandFactory() {
        return CommandFactory.getCommandFactory(CommandFactory.Type.ALL);
    }

    protected static CommandLine parseArgs(Options options, String[] args) throws ParseException {
        return new DefaultParser().parse(options, args);
    }

    /*
     * The arguments are parsed manually because in case of
     * parsing error (i.e. ParseException is raised), CommandLine object will be null.
     * However, it is required in that case to know whether debug mode is enabled or not.
     */
    private boolean isDebugModeEnabled(String[] args) {
        String shortOption = "-" + CommandSet.DEBUG.opt();
        String longOption = "--" + CommandSet.DEBUG.longOpt();

        for (String arg : args) {
            if (arg.equals(shortOption) || arg.equals(longOption)) {
                return true;
            }
        }

        return false;
    }

    private void executeCommandList(List<Command> commandList, ApplicationContext currentContext)
            throws CLIException {
        for (Command command : commandList) {
            command.execute(currentContext);
        }
    }

    private void writeError(ApplicationContext currentContext, String errorMsg, Throwable cause,
            boolean isDebugModeEnabled) {
        PrintWriter writer = new PrintWriter(currentContext.getDevice().getWriter(), true);
        writer.printf("%s", errorMsg);

        if (cause != null) {
            if (cause.getMessage() != null) {
                writer.printf("%n%nError message: %s%n", cause.getMessage());
            }

            if (isDebugModeEnabled) {
                if (cause instanceof CLIException && ((CLIException) cause).stackTrace() != null) {
                    writer.printf("%nStack trace: %s%n", ((CLIException) cause).stackTrace());
                } else {
                    writer.printf("%nStack trace: %s%n", getStackTraceAsString(cause));
                }
            } else {
                writeDebugModeUsageWithBreakEndLine(currentContext);
            }
        }
    }

    private boolean hasLoginCommand(List<Command> commandList) {
        for (Command c : commandList) {
            if (c instanceof AbstractLoginCommand) {
                return true;
            }
        }
        return false;
    }
}