![JAR search and dependency download from the Maven repository](/logo.png)
org.ow2.petals.cli.AbstractMain Maven / Gradle / Ivy
/**
* Copyright (c) 2010-2012 EBM WebSourcing, 2012-2016 Linagora
*
* This program/library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or (at your
* option) any later version.
*
* This program/library 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program/library; If not, see http://www.gnu.org/licenses/
* for the GNU Lesser General Public License version 2.1.
*/
package org.ow2.petals.cli;
import static org.ow2.petals.cli.shell.ShellFactory.DEBUG_LONG_OPTION;
import static org.ow2.petals.cli.shell.ShellFactory.DEBUG_SHORT_OPTION;
import static org.ow2.petals.cli.shell.ShellFactory.YESFLAG_LONG_OPTION;
import static org.ow2.petals.cli.shell.ShellFactory.YESFLAG_SHORT_OPTION;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.logging.LogManager;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.ow2.petals.cli.api.command.ConnectionCommand;
import org.ow2.petals.cli.api.command.exception.CommandInvalidException;
import org.ow2.petals.cli.api.connection.ConnectionParameters;
import org.ow2.petals.cli.api.pref.PreferenceFileException;
import org.ow2.petals.cli.api.pref.Preferences;
import org.ow2.petals.cli.api.pref.exception.MissingDefaultPreferenceFileException;
import org.ow2.petals.cli.api.pref.exception.PreferenceFileNotFoundException;
import org.ow2.petals.cli.api.shell.ShellExtension;
import org.ow2.petals.cli.api.shell.exception.DuplicatedCommandException;
import org.ow2.petals.cli.exception.InitLoggingException;
import org.ow2.petals.cli.shell.AbstractShell;
import org.ow2.petals.cli.shell.ShellFactory;
import org.ow2.petals.cli.shell.exception.ShellCreationException;
/**
* Abract class used as abtract main class for all Petals CLI
*
* @author Christophe DENEUX - Linagaora
*/
public abstract class AbstractMain {
/**
* Footer part of the usage message
*/
public static final String USAGE_FOOTER = String.format("%n%s%n",
"Which evolution would you like on Petals? Share it! http://www.petalslink.com/feedback");
/**
* The short name of the option printing help on command line
*/
private static final String HELP_SHORT_OPTION = "H";
/**
* The long name of the option printing help on command line
*/
private static final String HELP_LONG_OPTION = "help";
/**
* The short name of the option printing the version of Petals CLI
*/
protected static final String VERSION_SHORT_OPTION = "V";
/**
* The long name of the option printing the version of Petals CLI
*/
private static final String VERSION_LONG_OPTION = "version";
/**
* The connection command, or null
if no connection command is available.
*/
private final ConnectionCommand connectionCommand;
/**
* @param connectionCommand
* The connection command, or null
if no connection command is available.
*/
public AbstractMain(final ConnectionCommand connectionCommand) {
this.connectionCommand = connectionCommand;
}
/**
* Print version informations
*/
private void printVersion() {
final StringBuilder sb = new StringBuilder();
sb.append(
String.format("%s %s%n", this.getUsageHeader(),
this.getClass().getPackage().getImplementationVersion()));
sb.append(String.format("%s %s %s%n", System.getProperty("java.runtime.name"),
System.getProperty("java.runtime.version"), System.getProperty("java.vm.vendor")));
sb.append(String.format("%s %s %s%n", System.getProperty("os.name"), System.getProperty("os.version"),
System.getProperty("os.arch")));
System.out.print(sb.toString());
}
/**
* Print the usage message
*/
private void printUsage() {
final StringBuilder usage = new StringBuilder().append("[-").append(DEBUG_SHORT_OPTION)
.append("] ");
usage.append("[-").append(YESFLAG_SHORT_OPTION).append("] ");
if (this.connectionCommand != null) {
// We add arguments of the connection command. We don't add the Yes flag of the connection command
final HelpFormatter helpFormatter = new HelpFormatter();
final StringWriter sw = new StringWriter();
helpFormatter.printUsage(new PrintWriter(sw), HelpFormatter.DEFAULT_WIDTH, "",
this.connectionCommand.getOptions());
usage.append(sw.toString());
}
usage.append("[-").append(HELP_SHORT_OPTION).append(" | -").append(VERSION_SHORT_OPTION)
.append(" | ").append(ShellFactory.getUsage()).toString();
final HelpFormatter formatter = new HelpFormatter();
formatter.setWidth(USAGE_FOOTER.length());
formatter.printHelp(String.format("%s%n", this.getUsageHeader()), usage.toString(), this.createOptions(),
USAGE_FOOTER);
}
/**
* By default, the logging system is initialized from the JAR-embedded
* configuration file 'petals-cli-logging.properties
'. At
* runtime, it is possible to change this configuration using the system
* property 'java.util.logging.config.file
'.
*/
private final void initLogging() throws InitLoggingException {
try {
final String configurationPath = System.getProperty("java.util.logging.config.file");
if (configurationPath == null) {
final InputStream is = this.getClass().getResourceAsStream(
"/petals-cli-logging.properties");
if (is == null) {
LogManager.getLogManager().readConfiguration();
} else {
LogManager.getLogManager().readConfiguration(is);
}
} else {
LogManager.getLogManager().readConfiguration();
}
} catch (final Exception e) {
throw new InitLoggingException(e);
}
}
/**
* Parse options and command line arguments
*
* @param args
* Arguments from the command line
* @param preferences
* The preferences
* @param shellExtensions
* A list of shell extension, or null
if no shell extension is available
* @return system return code
*/
public int run(final String[] args, final Preferences preferences, final ShellExtension[] shellExtensions) {
int exitCode = 0;
try {
this.initLogging();
if (preferences != null) {
preferences.intializePreferenceParameters();
}
final CommandLineParser parser = new DefaultParser();
try {
// We can't use a static attribute for options because an error will occurs in unit tests: an instance
// of options can be parsed once.
final CommandLine cmd = parser.parse(this.createOptions(), args);
try {
if (cmd.hasOption(VERSION_SHORT_OPTION)) {
printVersion();
} else if (cmd.hasOption(HELP_SHORT_OPTION)) {
this.printUsage();
} else {
exitCode = createAndRunPetalsCLIShell(cmd, args, preferences,
shellExtensions, this.getPromptBase());
}
} catch (final ShellCreationException e) {
System.err.println("ERROR creating the shell: " + e.getMessage());
e.printStackTrace();
exitCode = 1;
} catch (final DuplicatedCommandException e) {
// A command has been registered twice. This has not to occur otherwise it's a bug
System.err.println("BUG : **** Command registered twice: " + e.getCommandName() + " ****");
exitCode = 1;
}
} catch (final ParseException e) {
System.err.println("ERROR: " + e.getMessage() + "\n");
printUsage();
exitCode = 1;
}
} catch (final InitLoggingException e) {
System.err.println("ERROR: " + e.getMessage() + "\n");
exitCode = 1;
} catch (final MissingDefaultPreferenceFileException e) {
System.err.println("ERROR: " + e.getMessage() + "\n");
exitCode = 1;
} catch (final PreferenceFileNotFoundException e) {
System.err.println("ERROR: " + e.getMessage() + "\n");
exitCode = 1;
} catch (final PreferenceFileException e) {
System.err.println("ERROR: " + e.getMessage() + "\n");
exitCode = 1;
}
return exitCode;
}
/**
* Create the right Petals CLI shell according to arguments of the command line and run it.
*
* @param cmdLine
* The command line parsed
* @param args
* Initial arguments of the command line
* @param preferences
* Preferences
* @param shellExtensions
* A list of shell extension, or null
if no shell extension is available
* @param basePrompt
* The base prompt
* @return The exit code associated to the shell execution (and its commands executed)
* @throws DuplicatedCommandException
* A command has been registered twice when creating the shell. As it's a hard coded registration, it's
* a BIG bug.
* @throws ParseException
* An error occurs creating the shell about provided options or arguments.
* @throws ShellCreationException
* Another error occurs creating the shell
*/
private int createAndRunPetalsCLIShell(final CommandLine cmdLine, final String[] args,
final Preferences preferences,
final ShellExtension[] shellExtensions, final String basePrompt)
throws DuplicatedCommandException, ShellCreationException, ParseException {
int exitCode = 0;
final AbstractShell shell = ShellFactory.getInstance().newShell(cmdLine, args, preferences, shellExtensions,
this.getPromptBase());
if (shell != null) {
shell.setDefaultPrompt();
if (this.connectionCommand != null) {
this.connectionCommand.setShell(shell);
}
// We add a shutdown hook to disconnect Petals CLI if needed
final Runtime runtime = Runtime.getRuntime();
runtime.addShutdownHook(new Thread("Disconnection hook") {
@Override
public void run() {
shell.disconnectIfNeeded();
}
});
try {
if (this.connectionCommand != null) {
final ConnectionParameters connectionParameters = this.connectionCommand
.parseConnectionParameters(cmdLine, true);
shell.setConnectionParameters(connectionParameters);
}
shell.run();
exitCode = shell.getExitStatus();
} catch (final CommandInvalidException e) {
final String msg = e.getMessage() != null ? e.getMessage()
: "An unexpected error occurred. Use the -" + DEBUG_SHORT_OPTION
+ " option for more information.";
System.err.println("ERROR: " + msg + "\n");
printUsage();
exitCode = 1;
} catch (final Exception e) {
final String msg = e.getMessage() != null ? e.getMessage()
: "An unexpected error occurred. Use the -" + DEBUG_SHORT_OPTION
+ " option for more information.";
System.err.println("ERROR: " + msg + "\n");
if (cmdLine.hasOption(DEBUG_SHORT_OPTION)) {
e.printStackTrace();
}
exitCode = 1;
}
// Disconnect if needed to prevent resource consumption if the command 'disconnect' was not used
shell.disconnectIfNeeded();
} else {
System.err.println("ERROR: Unable to determine the execution mode: console, command, file or inlined\n");
printUsage();
exitCode = 1;
}
return exitCode;
}
/**
* Create the general options of the CLI, composed of:
*
* - shell options,
* - connection options.
*
*
* @return The general options of the CLI
*/
private Options createOptions() {
final Options options = new Options();
options.addOption(DEBUG_SHORT_OPTION, DEBUG_LONG_OPTION, false, "Print stack trace and debugging informations");
options.addOption(YESFLAG_SHORT_OPTION, YESFLAG_LONG_OPTION, false,
"Enable automatic confirmation ('yes' flag)");
if (this.connectionCommand != null) {
final Iterator
© 2015 - 2025 Weber Informatics LLC | Privacy Policy