/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.configuration;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Parses and saves the RCE console line arguments.
*
* TODO useful to add a unit test?
*
* @author Sascha Zur
* @author Robert Mischke
*/
public final class CommandLineArguments {
/**
* The token to activate the headless run mode.
*/
public static final String HEADLESS_MODE_TOKEN = "--headless";
/**
* The token for the "execute these commands" option.
*/
public static final String EXEC_OPTION_TOKEN = "--exec";
/**
* The token for the "disable components" option.
*/
public static final String DISABLE_COMPONENTS_TOKEN = "--disable-components";
/**
* The token for the "execute these commands in headless mode and terminate" option.
*/
public static final String BATCH_OPTION_TOKEN = "--batch";
/**
* The token to activate the configuration shell mode.
*/
public static final String CONFIGURATION_SHELL_TOKEN = "--configure";
/**
* Standard parameters (followed by a value) that this class should ignore.
*/
public static final String[] PARAMETER_TOKENS_TO_IGNORE = new String[] { "-launcher", "-name", "-application", "-data",
"-configuration", "-dev", "-os", "-ws", "-arch", "-nl", "-startup", "-vm", "-exitdata", "-showsplash", "--launcher.XXMaxPermSize",
"--launcher.library", "--launcher.overrideVmargs" };
/**
* Standard flags (without a value) that this class should ignore.
*/
public static final String[] FLAG_TOKENS_TO_IGNORE = new String[] { "-consoleLog", "-console", "-clean", "-nosplash", "-noSplash" };
// this is null until configuration is complete; this serves as a safeguard against accessing undefined settings
private static volatile CommandLineArguments configuration;
private boolean showAdvancedTab;
private boolean headlessModeRequested;
private boolean batchModeRequested;
private boolean configurationShellRequested;
/**
* @see #getExecCommandTokens()
*/
private String[] execCommandTokens;
private boolean doNotStartComponentsRequested;
private boolean doNotStartNetworkRequested;
private boolean isValid;
/**
* A simple buffer to read command line arguments from. The purpose of turning this into a class is to avoid scattered
* "has another argument" checks. With this class, the "getNext()" operation can throw a meaningful exception when another argument is
* required, but the end of the command line is reached instead.
*
* @author Robert Mischke
*/
private static class CommandStack {
private String[] args;
private int next = 0;
CommandStack(String[] args) {
this.args = args;
}
public boolean hasNext() {
return next < args.length;
}
public String getNext() {
if (!hasNext()) {
if (args.length == 0) {
throw new IllegalStateException("Expected at least one command-line argument");
} else {
throw new IllegalStateException("Expected another command-line segment after " + args[next - 1]);
}
}
return args[next++];
}
public int lastPos() {
return next - 1;
}
public void setLastPos() {
next--;
}
}
private CommandLineArguments(String[] input) {
final List<String> parametersToIgnore = Arrays.asList(PARAMETER_TOKENS_TO_IGNORE);
final List<String> flagsToIgnore = Arrays.asList(FLAG_TOKENS_TO_IGNORE);
CommandStack args = new CommandStack(input);
while (args.hasNext()) {
String option = args.getNext();
if (option.equals(HEADLESS_MODE_TOKEN)) {
setHeadlessModeRequested(true);
} else if (option.equals(CONFIGURATION_SHELL_TOKEN)) {
setConfigurationShellRequested(true);
} else if (option.equals("--wf-run")) {
assertNoExecCommandYet();
String wfFile = args.getNext();
// delegate by creating an equivalent --exec command string
parseExecCommandTokens("wf run " + wfFile + " ; stop");
} else if (option.equals(DISABLE_COMPONENTS_TOKEN)) {
setDoNotStartComponentsRequested(true);
} else if (option.equals(EXEC_OPTION_TOKEN)) {
assertNoExecCommandYet();
String cmdString = args.getNext();
parseExecCommandTokens(cmdString);
} else if (option.equals(BATCH_OPTION_TOKEN)) {
assertNoExecCommandYet();
String cmdString = args.getNext();
parseExecCommandTokens(cmdString);
setBatchModeRequested(true);
} else if (option.equals("--showAdvancedTab")) {
setShowAdvancedTab(true);
} else if (option.equals("-p") || option.equals("--profile")) {
// parameter is already handled by LaunchParameters class; ignore here
if (args.hasNext()) { // there should be a following token
args.getNext(); // yes -> discard
} else {
getTemporaryLogger().warn("Missing expected parameter after -p/--profile option");
}
} else if (parametersToIgnore.contains(option)) {
// these parameters are passed in, but are irrelevant, so ignore them and their value
String next = args.getNext();
// ensure that the next argument is not a parameter to avoid parser confusion on missing values
if (next.startsWith("-")) {
args.setLastPos();
continue;
}
} else if (!flagsToIgnore.contains(option)) {
// if the token is ALSO not a flag (zero-parameter option) to be ignored, log a warning
getTemporaryLogger().warn(
"Ignoring unrecognized command-line argument '" + option + "' at position " + args.lastPos());
}
}
isValid = true;
}
/**
* Parses and saves the RCE console line arguments. If an error is detected, a {@link IllegalArgumentException} is thrown.
*
* @param input the program arguments
*/
public static void initialize(String[] input) {
configuration = new CommandLineArguments(input);
getTemporaryLogger().debug("Parsed command-line options");
}
public static boolean isHeadlessModeRequested() {
return getConfiguration().headlessModeRequested;
}
public static boolean isBatchModeRequested() {
return getConfiguration().batchModeRequested;
}
public static boolean isConfigurationShellRequested() {
return getConfiguration().configurationShellRequested;
}
/**
* Method for various (background) services to check whether they should start running. Currently only disabled when running in text UI
* configuration mode.
*
* @return true if standard background services (e.g. network, monitoring) should start
*/
public static boolean isNormalOperationRequested() {
return !getConfiguration().configurationShellRequested;
}
public static boolean isDoNotStartComponentsRequested() {
return getConfiguration().doNotStartComponentsRequested || getConfiguration().configurationShellRequested;
}
public static boolean isDoNotStartNetworkRequested() {
return getConfiguration().doNotStartNetworkRequested || getConfiguration().configurationShellRequested;
}
private static CommandLineArguments getConfiguration() {
if (configuration == null) {
throw new IllegalStateException("A configuration value was accessed before the configuration was parsed");
}
return configuration;
}
/**
* @return the boolean value whether the advanced tab should be shown or not
*/
public static boolean isShowAdvancedTab() {
return getConfiguration().showAdvancedTab;
}
/**
* If --exec "<cmdString>" was used, this method returns the individual tokens of "cmdString"; otherwise, this method returns
* null.
*
* @return the array of tokens, or null if unused
*/
public static String[] getExecCommandTokens() {
return getConfiguration().execCommandTokens;
}
/**
* @return true if there was a consistency error in the provided command-line arguments
*/
public static boolean hasConfigurationErrors() {
return !getConfiguration().isValid;
}
private void setHeadlessModeRequested(boolean value) {
headlessModeRequested = value;
}
private void setConfigurationShellRequested(boolean value) {
configurationShellRequested = value;
// set implied other settings
setHeadlessModeRequested(true);
setDoNotStartComponentsRequested(true);
setDoNotStartNetworkRequested(true);
}
private void setDoNotStartNetworkRequested(boolean value) {
doNotStartNetworkRequested = value;
}
private void setDoNotStartComponentsRequested(boolean value) {
doNotStartComponentsRequested = value;
}
private void setBatchModeRequested(boolean value) {
batchModeRequested = value;
// set implied other settings
setHeadlessModeRequested(true);
}
private void setShowAdvancedTab(boolean value) {
showAdvancedTab = value;
}
private void assertNoExecCommandYet() {
if (execCommandTokens != null) {
throw new IllegalArgumentException("Only one of \"--exec\", \"--batch\" or \"--wf-run\" can be used at the same time");
}
}
private void parseExecCommandTokens(String cmdString) {
execCommandTokens = cmdString.trim().split("\\s+");
}
private static Log getTemporaryLogger() {
return LogFactory.getLog(CommandLineArguments.class);
}
}