/*
* $Id$
* This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc
*
* Copyright (c) 2000-2012 Stephane GALLAND.
* Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
* Universite de Technologie de Belfort-Montbeliard.
* Copyright (c) 2013-2016 The original authors, and other authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arakhne.afc.vmutil;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import org.eclipse.xtext.xbase.lib.Inline;
import org.eclipse.xtext.xbase.lib.Pure;
import org.arakhne.afc.vmutil.locale.Locale;
/**
* This utility class permits to get the java command line for the current VM.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
public class VMCommandLine {
private static String classnameToLaunch;
private static boolean analyzed;
private static SortedMap<String, List<Object>> commandLineOptions;
private static String[] commandLineParameters;
/**
* Create a interface to the command line options.
*
* @param classToLaunch is the class which contains a <code>main</code>.
* @param parameters is the parameters to pass to the <code>main</code>.
* @see #saveVMParametersIfNotSet(Class, String[])
*/
public VMCommandLine(Class<?> classToLaunch, String... parameters) {
saveVMParametersIfNotSet(classToLaunch, parameters);
}
/**
* Create a interface to the command line options.
*
* @param classToLaunch is the class which contains a <code>main</code>.
* @param parameters is the parameters to pass to the <code>main</code>.
* @since 6.2
* @see #saveVMParametersIfNotSet(String, String[])
*/
public VMCommandLine(String classToLaunch, String... parameters) {
saveVMParametersIfNotSet(classToLaunch, parameters);
}
/**
* Create a interface to the command line options.
*
* @param classToLaunch is the class which contains a <code>main</code>.
* @param optionDefinitions is the list of definitions of the available command line options.
* @param parameters is the parameters to pass to the <code>main</code>.
* @see #saveVMParametersIfNotSet(Class, String[])
* @see #splitOptionsAndParameters(String[])
*/
public VMCommandLine(Class<?> classToLaunch, String[] optionDefinitions, String... parameters) {
saveVMParametersIfNotSet(classToLaunch, parameters);
splitOptionsAndParameters(optionDefinitions);
}
/**
* Create a interface to the command line options.
*
* @param classToLaunch is the class which contains a <code>main</code>.
* @param optionDefinitions is the list of definitions of the available command line options.
* @param parameters is the parameters to pass to the <code>main</code>.
* @since 6.2
* @see #saveVMParametersIfNotSet(String, String[])
* @see #splitOptionsAndParameters(String[])
*/
public VMCommandLine(String classToLaunch, String[] optionDefinitions, String... parameters) {
saveVMParametersIfNotSet(classToLaunch, parameters);
splitOptionsAndParameters(optionDefinitions);
}
/**
* Create a interface to the command line options.
*
* @see #VMCommandLine(Class, String[], String[])
* @see #VMCommandLine(Class, String[])
*/
public VMCommandLine() {
if (classnameToLaunch == null) {
throw new IllegalArgumentException(Locale.getString("E1")); //$NON-NLS-1$
}
}
/** Replies a binary executable filename depending of the current platform.
*
* @param name is the name which must be converted into a binary executable filename.
* @return the binary executable filename.
*/
@Pure
public static String getExecutableFilename(String name) {
if (OperatingSystem.WIN.isCurrentOS()) {
return name + ".exe"; //$NON-NLS-1$
}
return name;
}
/** Replies the current java VM binary.
*
* @return the binary executable filename that was used to launch the virtual machine.
*/
@Pure
public static String getVMBinary() {
final String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
final File binDir = new File(new File(javaHome), "bin"); //$NON-NLS-1$
if (binDir.isDirectory()) {
File exec = new File(binDir, getExecutableFilename("javaw")); //$NON-NLS-1$
if (exec.isFile()) {
return exec.getAbsolutePath();
}
exec = new File(binDir, getExecutableFilename("java")); //$NON-NLS-1$
if (exec.isFile()) {
return exec.getAbsolutePath();
}
}
return null;
}
/** Run a new VM with the given class path.
*
* @param classToLaunch is the class to launch.
* @param classpath is the class path to use.
* @param additionalParams is the list of additional parameters
* @return the process that is running the new virtual machine, neither <code>null</code>
* @throws IOException when a IO error occurs.
* @since 6.2
*/
@Inline(value = "VMCommandLine.launchVMWithClassPath(($1).getCanonicalName(), ($2), ($3))",
imported = {VMCommandLine.class}, statementExpression = true)
public static Process launchVMWithClassPath(Class<?> classToLaunch, String classpath,
String... additionalParams) throws IOException {
return launchVMWithClassPath(classToLaunch.getCanonicalName(), classpath, additionalParams);
}
/** Run a new VM with the given class path.
*
* @param classToLaunch is the class to launch.
* @param classpath is the class path to use.
* @param additionalParams is the list of additional parameters
* @return the process that is running the new virtual machine, neither <code>null</code>
* @throws IOException when a IO error occurs.
* @since 6.2
*/
@SuppressWarnings({"checkstyle:magicnumber"})
public static Process launchVMWithClassPath(String classToLaunch, String classpath,
String... additionalParams) throws IOException {
final String javaBin = getVMBinary();
if (javaBin == null) {
throw new FileNotFoundException("java"); //$NON-NLS-1$
}
final long totalMemory = Runtime.getRuntime().maxMemory() / 1024;
final String userDir = FileSystem.getUserHomeDirectoryName();
final String[] params;
final int nParams;
if (classpath != null && !"".equals(classpath)) { //$NON-NLS-1$
nParams = 5;
params = new String[additionalParams.length + nParams];
params[0] = javaBin;
params[1] = "-Xmx" + totalMemory + "k"; //$NON-NLS-1$ //$NON-NLS-2$
params[2] = "-classpath"; //$NON-NLS-1$
params[3] = classpath;
params[4] = classToLaunch;
} else {
nParams = 3;
params = new String[additionalParams.length + nParams];
params[0] = javaBin;
params[1] = "-Xmx" + totalMemory + "k"; //$NON-NLS-1$ //$NON-NLS-2$
params[2] = classToLaunch;
}
System.arraycopy(additionalParams, 0, params, nParams, additionalParams.length);
return Runtime.getRuntime().exec(params, null, new File(userDir));
}
/** Run a new VM with the given class path.
*
* @param classToLaunch is the class to launch.
* @param classpath is the class path to use.
* @param additionalParams is the list of additional parameters
* @return the process that is running the new virtual machine, neither <code>null</code>
* @throws IOException when a IO error occurs.
* @since 6.2
*/
@Inline(value = "VMCommandLine.launchVMWithClassPath(($1).getCanonicalName(), ($2), ($3))",
imported = {VMCommandLine.class}, statementExpression = true)
public static Process launchVMWithClassPath(Class<?> classToLaunch, File[] classpath,
String... additionalParams) throws IOException {
return launchVMWithClassPath(classToLaunch.getCanonicalName(), classpath, additionalParams);
}
/** Run a new VM with the given class path.
*
* @param classToLaunch is the class to launch.
* @param classpath is the class path to use.
* @param additionalParams is the list of additional parameters
* @return the process that is running the new virtual machine, neither <code>null</code>
* @throws IOException when a IO error occurs.
* @since 6.2
*/
public static Process launchVMWithClassPath(String classToLaunch, File[] classpath,
String... additionalParams) throws IOException {
final StringBuilder b = new StringBuilder();
for (final File f : classpath) {
if (b.length() > 0) {
b.append(File.pathSeparator);
}
b.append(f.getAbsolutePath());
}
return launchVMWithClassPath(classToLaunch, b.toString(), additionalParams);
}
/** Run a jar file inside a new VM.
*
* @param jarFile is the jar file to launch.
* @param additionalParams is the list of additional parameters
* @return the process that is running the new virtual machine, neither <code>null</code>
* @throws IOException when a IO error occurs.
* @since 6.2
*/
@SuppressWarnings("checkstyle:magicnumber")
public static Process launchVMWithJar(File jarFile, String... additionalParams) throws IOException {
final String javaBin = getVMBinary();
if (javaBin == null) {
throw new FileNotFoundException("java"); //$NON-NLS-1$
}
final long totalMemory = Runtime.getRuntime().maxMemory() / 1024;
final String userDir = FileSystem.getUserHomeDirectoryName();
final int nParams = 4;
final String[] params = new String[additionalParams.length + nParams];
params[0] = javaBin;
params[1] = "-Xmx" + totalMemory + "k"; //$NON-NLS-1$ //$NON-NLS-2$
params[2] = "-jar"; //$NON-NLS-1$
params[3] = jarFile.getAbsolutePath();
System.arraycopy(additionalParams, 0, params, nParams, additionalParams.length);
return Runtime.getRuntime().exec(params, null, new File(userDir));
}
/** Run a new VM with the class path of the current VM.
*
* @param classToLaunch is the class to launch.
* @param additionalParams is the list of additional parameters
* @return the process that is running the new virtual machine, neither <code>null</code>
* @throws IOException when a IO error occurs.
*/
@Inline(value = "VMCommandLine.launchVM(($1).getCanonicalName(), ($2))", imported = {VMCommandLine.class},
statementExpression = true)
public static Process launchVM(Class<?> classToLaunch, String... additionalParams) throws IOException {
return launchVM(classToLaunch.getCanonicalName(), additionalParams);
}
/** Run a new VM with the class path of the current VM.
*
* @param classToLaunch is the class to launch.
* @param additionalParams is the list of additional parameters
* @return the process that is running the new virtual machine, neither <code>null</code>
* @throws IOException when a IO error occurs.
* @since 6.2
*/
@Inline(value = "VMCommandLine.launchVMWithClassPath(($1), System.getProperty(\"java.class.path\"), ($2))",
imported = {VMCommandLine.class}, statementExpression = true)
public static Process launchVM(String classToLaunch, String... additionalParams) throws IOException {
return launchVMWithClassPath(
classToLaunch,
System.getProperty("java.class.path"), //$NON-NLS-1$
additionalParams);
}
/** Save parameters that permit to relaunch a VM with
* {@link #relaunchVM()}.
*
* @param classToLaunch is the class which contains a <code>main</code>.
* @param parameters is the parameters to pass to the <code>main</code>.
*/
@Inline(value = "VMCommandLine.saveVMParameters((($1) != null) ? ($1).getCanonicalName() : null, ($2))",
imported = {VMCommandLine.class}, statementExpression = true)
public static void saveVMParameters(Class<?> classToLaunch, String... parameters) {
saveVMParameters(
(classToLaunch != null)
? classToLaunch.getCanonicalName()
: null, parameters);
}
/** Save parameters that permit to relaunch a VM with
* {@link #relaunchVM()}.
*
* @param classToLaunch is the class which contains a <code>main</code>.
* @param parameters is the parameters to pass to the <code>main</code>.
* @since 6.2
*/
public static void saveVMParameters(String classToLaunch, String... parameters) {
classnameToLaunch = classToLaunch;
commandLineParameters = parameters;
if (commandLineOptions != null) {
commandLineOptions.clear();
}
commandLineOptions = null;
analyzed = false;
}
/** Save parameters that permit to relaunch a VM with
* {@link #relaunchVM()}.
*
* @param classToLaunch is the class which contains a <code>main</code>.
* @param parameters is the parameters to pass to the <code>main</code>.
*/
@Inline(value = "VMCommandLine.saveVMParametersIfNotSet(($1).getCanonicalName(), ($2))",
imported = {VMCommandLine.class}, statementExpression = true)
public static void saveVMParametersIfNotSet(Class<?> classToLaunch, String... parameters) {
saveVMParametersIfNotSet(classToLaunch.getCanonicalName(), parameters);
}
/** Save parameters that permit to relaunch a VM with
* {@link #relaunchVM()}.
*
* @param classToLaunch is the class which contains a <code>main</code>.
* @param parameters is the parameters to pass to the <code>main</code>.
* @since 6.2
*/
public static void saveVMParametersIfNotSet(String classToLaunch, String... parameters) {
if (classnameToLaunch == null || "".equals(classnameToLaunch)) { //$NON-NLS-1$
saveVMParameters(classToLaunch, parameters);
}
}
/** Launch a VM with the same parameters as ones saved by
* {@link #saveVMParameters(Class, String[])}.
*
* @return the process that is running the new virtual machine, neither <code>null</code>
* @throws IOException when a IO error occurs.
*/
public static Process relaunchVM() throws IOException {
if (classnameToLaunch == null) {
return null;
}
return launchVM(classnameToLaunch, getAllCommandLineParameters());
}
/** Replies the command line including the options and the standard parameters.
*
* @return the command line.
*/
@Pure
@SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity"})
public static String[] getAllCommandLineParameters() {
final int osize = commandLineOptions == null ? 0 : commandLineOptions.size();
final int psize = commandLineParameters == null ? 0 : commandLineParameters.length;
final int tsize = (osize > 0 && psize > 0) ? 1 : 0;
final List<String> params = new ArrayList<>(osize + tsize);
if (osize > 0) {
List<Object> values;
String name;
String prefix;
String v;
for (final Entry<String, List<Object>> entry : commandLineOptions.entrySet()) {
name = entry.getKey();
prefix = (name.length() > 1) ? "--" : "-"; //$NON-NLS-1$ //$NON-NLS-2$
values = entry.getValue();
if (values == null || values.isEmpty()) {
params.add(prefix + name);
} else {
for (final Object value : values) {
if (value != null) {
v = value.toString();
if (v != null && v.length() > 0) {
params.add(prefix + name + "=" + v); //$NON-NLS-1$
} else {
params.add(prefix + name);
}
}
}
}
}
}
if (tsize > 0) {
params.add("--"); //$NON-NLS-1$
}
final String[] tab = new String[params.size() + psize];
params.toArray(tab);
params.clear();
if (psize > 0) {
System.arraycopy(commandLineParameters, 0, tab, osize + tsize, psize);
}
return tab;
}
/** Replies the command line parameters.
*
* @return the list of the parameters on the command line
*/
@Pure
public static String[] getCommandLineParameters() {
return commandLineParameters == null ? new String[0] : commandLineParameters;
}
/** Shift the command line parameters by one on the left.
* The first parameter is removed from the list.
*
* @return the removed element or <code>null</code>
*/
public static String shiftCommandLineParameters() {
String removed = null;
if (commandLineParameters != null) {
if (commandLineParameters.length == 0) {
commandLineParameters = null;
} else if (commandLineParameters.length == 1) {
removed = commandLineParameters[0];
commandLineParameters = null;
} else {
removed = commandLineParameters[0];
final String[] newTab = new String[commandLineParameters.length - 1];
System.arraycopy(commandLineParameters, 1, newTab, 0, commandLineParameters.length - 1);
commandLineParameters = newTab;
}
}
return removed;
}
/** Replies the command line options.
*
* @return the list of options passed on the command line
*/
@Pure
public static Map<String, List<Object>> getCommandLineOptions() {
if (commandLineOptions != null) {
return Collections.unmodifiableSortedMap(commandLineOptions);
}
return Collections.emptyMap();
}
/** Replies one command option.
*
* @param name is the name of the option
* @return the option value or <code>null</code> if the option is not on the command line.
*/
@Pure
public static List<Object> getCommandLineOption(String name) {
if (commandLineOptions != null && commandLineOptions.containsKey(name)) {
final List<Object> value = commandLineOptions.get(name);
return value == null ? Collections.emptyList() : value;
}
return Collections.emptyList();
}
/** Replies if an option was specified on the command line.
*
* @param name is the name of the option
* @return <code>true</code> if the option was found on the command line, otherwise <code>false</code>.
*/
@Pure
public static boolean hasCommandLineOption(String name) {
return commandLineOptions != null && commandLineOptions.containsKey(name);
}
@SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity"})
private static boolean registerOptionValue(SortedMap<String, List<Object>> options, String name, Object value,
OptionType type) {
boolean success = true;
Object optValue = value;
List<Object> values = options.get(name);
if (values == null) {
values = new ArrayList<>();
options.put(name, values);
}
switch (type) {
case AUTO_INCREMENTED:
final long v;
if (values.isEmpty()) {
v = -1;
} else {
optValue = values.get(0);
if (optValue == null) {
v = 0;
} else if (!(optValue instanceof Number)) {
v = Long.parseLong(optValue.toString());
} else {
v = ((Number) optValue).longValue();
}
}
if (values.isEmpty()) {
values.add(Long.valueOf(v + 1));
} else {
values.set(0, Long.valueOf(v + 1));
}
break;
case FLAG:
if (optValue == null) {
if (values.isEmpty()) {
optValue = Boolean.TRUE;
} else {
optValue = values.get(0);
}
} else if (!(optValue instanceof Boolean)) {
optValue = Boolean.parseBoolean(optValue.toString());
}
if (values.isEmpty()) {
values.add(optValue);
} else {
values.set(0, optValue);
}
break;
case MANDATORY_BOOLEAN:
case OPTIONAL_BOOLEAN:
if (optValue == null) {
optValue = Boolean.TRUE;
} else if (!(optValue instanceof Boolean)) {
optValue = Boolean.parseBoolean(optValue.toString());
}
values.add(optValue);
break;
case MANDATORY_FLOAT:
case OPTIONAL_FLOAT:
try {
if (optValue == null) {
optValue = Double.valueOf(0.);
} else if (!(optValue instanceof Number)) {
optValue = Double.parseDouble(optValue.toString());
} else {
optValue = Double.valueOf(((Number) optValue).doubleValue());
}
} catch (NumberFormatException e) {
if (type.isOptional()) {
success = false;
optValue = Double.valueOf(0.);
} else {
throw e;
}
}
values.add(optValue);
break;
case MANDATORY_INTEGER:
case OPTIONAL_INTEGER:
try {
if (optValue == null) {
optValue = Long.valueOf(0);
} else if (!(optValue instanceof Number)) {
optValue = Long.parseLong(optValue.toString());
} else {
optValue = Long.valueOf(((Number) optValue).longValue());
}
} catch (NumberFormatException e) {
if (type.isOptional()) {
success = false;
optValue = Long.valueOf(0);
} else {
throw e;
}
}
values.add(optValue);
break;
case MANDATORY_STRING:
case OPTIONAL_STRING:
values.add(optValue == null ? "" : optValue.toString()); //$NON-NLS-1$
break;
case SIMPLE:
values.add(optValue);
break;
default:
}
return success;
}
/** Analyse the command line to extract the options.
*
* <p>The options will be recognized thanks to the {@code optionDefinitions}.
* Each entry of {@code optionDefinitions} describes an option. They must
* have one of the following formats:
* <ul>
* <li>{@code name}: a simple option without value or flag,</li>
* <li>{@code name=s}: an option with a mandatory string value,</li>
* <li>{@code name:s}: an option with an optional string value,</li>
* <li>{@code name=i}: an option with a mandatory integer value,</li>
* <li>{@code name:i}: an option with an optional integer value,</li>
* <li>{@code name=f}: an option with a mandatory floating-point value,</li>
* <li>{@code name:f}: an option with an optional floating-point value,</li>
* <li>{@code name=b}: an option with a mandatory boolean value,</li>
* <li>{@code name:b}: an option with an optional boolean value,</li>
* <li>{@code name+}: an option with an autoincremented integer value,</li>
* <li>{@code name!}: an option which could be flaged or not: {@code --name} or {@code --noname}.</li>
* </ul>
*
* @param optionDefinitions is the list of definitions of the available command line options.
*/
@SuppressWarnings({"checkstyle:cyclomaticcomplexity", "npathcomplexity"})
public static void splitOptionsAndParameters(String... optionDefinitions) {
if (analyzed) {
return;
}
final List<String> params = new ArrayList<>();
final SortedMap<String, List<Object>> options = new TreeMap<>();
String opt;
// Analyze definitions
final Map<String, OptionType> defs = new TreeMap<>();
for (final String def : optionDefinitions) {
if (def.endsWith("!")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 1);
defs.put(opt, OptionType.FLAG);
registerOptionValue(options, opt, Boolean.FALSE, OptionType.FLAG);
} else if (def.endsWith("+")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 1);
defs.put(opt, OptionType.AUTO_INCREMENTED);
registerOptionValue(options, opt, Long.valueOf(0), OptionType.AUTO_INCREMENTED);
} else if (def.endsWith("=b")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 2);
defs.put(opt, OptionType.MANDATORY_BOOLEAN);
} else if (def.endsWith(":b")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 2);
defs.put(opt, OptionType.OPTIONAL_BOOLEAN);
} else if (def.endsWith("=f")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 2);
defs.put(opt, OptionType.MANDATORY_FLOAT);
} else if (def.endsWith(":f")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 2);
defs.put(opt, OptionType.OPTIONAL_FLOAT);
} else if (def.endsWith("=i")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 2);
defs.put(opt, OptionType.MANDATORY_INTEGER);
} else if (def.endsWith(":i")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 2);
defs.put(opt, OptionType.OPTIONAL_INTEGER);
} else if (def.endsWith("=s")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 2);
defs.put(opt, OptionType.MANDATORY_STRING);
} else if (def.endsWith(":s")) { //$NON-NLS-1$
opt = def.substring(0, def.length() - 2);
defs.put(opt, OptionType.OPTIONAL_STRING);
} else {
defs.put(def, OptionType.SIMPLE);
}
}
int idx;
String base;
String nbase;
String val;
OptionType type;
OptionType waitingValue = null;
String valueOptionName = null;
boolean allParameters = false;
boolean success;
for (final String param : commandLineParameters) {
if (allParameters) {
params.add(param);
continue;
}
if (waitingValue != null && waitingValue.isMandatory()) {
// Expect a value as the next parameter
success = registerOptionValue(options, valueOptionName, param, waitingValue);
waitingValue = null;
valueOptionName = null;
if (success) {
continue;
}
}
if ("--".equals(param)) { //$NON-NLS-1$
if (waitingValue != null) {
registerOptionValue(options, valueOptionName, null, waitingValue);
waitingValue = null;
valueOptionName = null;
}
allParameters = true;
continue;
} else if ((File.separatorChar != '/') && (param.startsWith("/"))) { //$NON-NLS-1$
opt = param.substring(1);
} else if (param.startsWith("--")) { //$NON-NLS-1$
opt = param.substring(2);
} else if (param.startsWith("-")) { //$NON-NLS-1$
opt = param.substring(1);
} else if (waitingValue != null) {
success = registerOptionValue(options, valueOptionName, param, waitingValue);
waitingValue = null;
valueOptionName = null;
if (!success) {
params.add(param);
}
continue;
} else {
params.add(param);
continue;
}
if (waitingValue != null) {
success = registerOptionValue(options, valueOptionName, param, waitingValue);
waitingValue = null;
valueOptionName = null;
if (success) {
continue;
}
}
idx = opt.indexOf('=');
if (idx > 0) {
base = opt.substring(0, idx);
val = opt.substring(idx + 1);
} else {
base = opt;
val = null;
}
nbase = null;
type = defs.get(base);
if (type == null && base.toLowerCase().startsWith("no")) { //$NON-NLS-1$
nbase = base.substring(2);
type = defs.get(nbase);
}
if (type != null) {
switch (type) {
case FLAG:
if (nbase == null) {
registerOptionValue(options, base, Boolean.TRUE, type);
} else {
registerOptionValue(options, nbase, Boolean.FALSE, type);
}
break;
case MANDATORY_FLOAT:
case MANDATORY_BOOLEAN:
case MANDATORY_INTEGER:
case MANDATORY_STRING:
case OPTIONAL_FLOAT:
case OPTIONAL_BOOLEAN:
case OPTIONAL_INTEGER:
case OPTIONAL_STRING:
if (val != null) {
registerOptionValue(options, base, val, type);
} else {
waitingValue = type;
valueOptionName = base;
}
break;
case AUTO_INCREMENTED:
case SIMPLE:
default:
registerOptionValue(options, base, val, type);
}
} else {
// Not a recognized option, assuming simple
registerOptionValue(options, base, val, OptionType.SIMPLE);
}
}
if (waitingValue != null && waitingValue.isMandatory()) {
throw new IllegalStateException(Locale.getString("E2", valueOptionName)); //$NON-NLS-1$
}
commandLineParameters = new String[params.size()];
params.toArray(commandLineParameters);
params.clear();
commandLineOptions = options;
analyzed = true;
}
/** Replies if the given option is present on the command line.
*
* @param optionLabel is the name of the option
* @return <code>true</code> if the option is present, otherwise <code>false</code>
*/
@Pure
@SuppressWarnings("static-method")
public boolean hasOption(String optionLabel) {
return hasCommandLineOption(optionLabel);
}
/** Replies the first value of the option.
*
* @param optionLabel is the name of the option
* @return the option value or <code>null</code> if the option is not present or has no value.
*/
@Pure
@SuppressWarnings("static-method")
public Object getFirstOptionValue(String optionLabel) {
final List<Object> options = getCommandLineOption(optionLabel);
if (options == null || options.isEmpty()) {
return null;
}
return options.get(0);
}
/** Replies the values of the option.
*
* @param optionLabel is the name of the option
* @return the option values or <code>null</code> if the option is not present.
*/
@Pure
@SuppressWarnings("static-method")
public List<Object> getOptionValues(String optionLabel) {
final List<Object> options = getCommandLineOption(optionLabel);
if (options == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(options);
}
/** Replies the parameters on the command line that are not options.
*
* @return the parameters.
*/
@Pure
@SuppressWarnings("static-method")
public String[] getParameters() {
return getCommandLineParameters();
}
/** Shift the command line parameters by one on the left.
* The first parameter is removed from the list.
*
* @return the removed element or <code>null</code>
*/
@SuppressWarnings("static-method")
public String shiftParameters() {
return shiftCommandLineParameters();
}
/** Replies the count of parameters on the command line that are not options.
*
* @return the count of parameters
*/
@Pure
@SuppressWarnings("static-method")
public int getParameterCount() {
return getCommandLineParameters().length;
}
/** Replies the parameter at the specified index.
*
* @param index position of the parameter to reply.
* @return the value of the parameter.
* @throws IndexOutOfBoundsException if the given index is out of bounds.
*/
@Pure
@SuppressWarnings("static-method")
public String getParameterAt(int index) {
return getCommandLineParameters()[index];
}
/** Replies if the given index corresponds to a command line parameter.
*
* @param index position of the parameter to test.
* @return <code>true</code> if the given index corresponds to a parameter,
* otherwise <code>false</code>
* @throws IndexOutOfBoundsException if the given index is out of bounds.
*/
@Pure
@SuppressWarnings("static-method")
public boolean isParameterExists(int index) {
final String[] params = getCommandLineParameters();
return index >= 0 && index < params.length && params[index] != null;
}
/** Type of command line option.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
private enum OptionType {
/**
* A simple option without value or flag.
*/
SIMPLE,
/** An option with a mandatory string value.
*/
MANDATORY_STRING,
/** An option with an optional string value.
*/
OPTIONAL_STRING,
/** An option with a mandatory integer value.
*/
MANDATORY_INTEGER,
/** An option with an optional integer value.
*/
OPTIONAL_INTEGER,
/** An option with a mandatory floating-point value.
*/
MANDATORY_FLOAT,
/** An option with an optional floating-point value.
*/
OPTIONAL_FLOAT,
/** An option with a mandatory boolean value.
*/
MANDATORY_BOOLEAN,
/** An option with an optional boolean value.
*/
OPTIONAL_BOOLEAN,
/** An option with an auto-incremented integer value.
*/
AUTO_INCREMENTED,
/** An option which could be flaged or not: {@code --name} or {@code --noname}.
*/
FLAG;
/** Replies if the value is mandatory.
*
* @return <code>true</code> if the value is mandatory, otherwise <code>false</code>
*/
@Pure
public boolean isMandatory() {
return this == MANDATORY_BOOLEAN
|| this == MANDATORY_FLOAT
|| this == MANDATORY_STRING
|| this == MANDATORY_INTEGER;
}
/** Replies if the value is optional.
*
* @return <code>true</code> if the value is not mandatory, otherwise <code>false</code>
*/
@Pure
public boolean isOptional() {
return this == OPTIONAL_BOOLEAN
|| this == OPTIONAL_FLOAT
|| this == OPTIONAL_STRING
|| this == OPTIONAL_INTEGER;
}
}
}