| | |
| | | * |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011 ForgeRock AS |
| | | * Portions Copyright 2011-2013 ForgeRock AS |
| | | */ |
| | | package org.opends.server.util.args; |
| | | import org.opends.messages.Message; |
| | | |
| | | |
| | | |
| | | import java.io.File; |
| | | import java.io.FileInputStream; |
| | | import java.io.IOException; |
| | | import java.io.OutputStream; |
| | | import java.util.ArrayList; |
| | | import java.util.Enumeration; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedList; |
| | | import java.util.Properties; |
| | | import java.util.TreeSet; |
| | | import java.util.Set; |
| | | import java.util.*; |
| | | |
| | | import org.opends.messages.Message; |
| | | import org.opends.messages.MessageBuilder; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.util.SetupUtils; |
| | | |
| | | import static org.opends.messages.ToolMessages.*; |
| | | import static org.opends.messages.UtilityMessages.*; |
| | | import static org.opends.server.tools.ToolConstants.*; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | import static org.opends.server.tools.ToolConstants.*; |
| | | import static org.opends.messages.ToolMessages.*; |
| | | |
| | | import org.opends.messages.MessageBuilder; |
| | | |
| | | |
| | | /** |
| | | * This class defines a utility that can be used to deal with command-line |
| | |
| | | */ |
| | | private BooleanArgument noPropertiesFileArgument; |
| | | |
| | | // The argument that will be used to trigger the display of usage information. |
| | | /** |
| | | * The argument that will be used to trigger the display of usage information. |
| | | */ |
| | | private Argument usageArgument; |
| | | |
| | | // The argument that will be used to trigger the display of the OpenDS |
| | | // version. |
| | | /** |
| | | * The argument that will be used to trigger the display of the OpenDJ |
| | | * version. |
| | | */ |
| | | private Argument versionArgument; |
| | | |
| | | // The set of unnamed trailing arguments that were provided for this parser. |
| | | /** The set of unnamed trailing arguments that were provided for this parser. |
| | | */ |
| | | private ArrayList<String> trailingArguments; |
| | | |
| | | // Indicates whether this parser will allow additional unnamed arguments at |
| | | // the end of the list. |
| | | /** |
| | | * Indicates whether this parser will allow additional unnamed arguments at |
| | | * the end of the list. |
| | | */ |
| | | private boolean allowsTrailingArguments; |
| | | |
| | | // Indicates whether long arguments should be treated in a case-sensitive |
| | | // manner. |
| | | /** |
| | | * Indicates whether long arguments should be treated in a case-sensitive |
| | | * manner. |
| | | */ |
| | | private boolean longArgumentsCaseSensitive; |
| | | |
| | | // Indicates whether the usage or version information has been displayed. |
| | | /** Indicates whether the usage or version information has been displayed. */ |
| | | private boolean usageOrVersionDisplayed; |
| | | |
| | | // Indicates whether the version argument was provided. |
| | | /** Indicates whether the version argument was provided. */ |
| | | private boolean versionPresent; |
| | | |
| | | // The set of arguments defined for this parser, referenced by short ID. |
| | | private HashMap<Character,Argument> shortIDMap; |
| | | /** The set of arguments defined for this parser, referenced by short ID. */ |
| | | private Map<Character,Argument> shortIDMap; |
| | | |
| | | // The set of arguments defined for this parser, referenced by argument name. |
| | | private HashMap<String,Argument> argumentMap; |
| | | /** |
| | | * The set of arguments defined for this parser, referenced by argument name. |
| | | */ |
| | | private Map<String,Argument> argumentMap; |
| | | |
| | | // The set of arguments defined for this parser, referenced by long ID. |
| | | private HashMap<String,Argument> longIDMap; |
| | | /** The set of arguments defined for this parser, referenced by long ID. */ |
| | | private Map<String,Argument> longIDMap; |
| | | |
| | | // The maximum number of unnamed trailing arguments that may be provided. |
| | | /** The maximum number of unnamed trailing arguments that may be provided. */ |
| | | private int maxTrailingArguments; |
| | | |
| | | // The minimum number of unnamed trailing arguments that may be provided. |
| | | /** The minimum number of unnamed trailing arguments that may be provided. */ |
| | | private int minTrailingArguments; |
| | | |
| | | // The total set of arguments defined for this parser. |
| | | /** The total set of arguments defined for this parser. */ |
| | | private LinkedList<Argument> argumentList; |
| | | |
| | | // The output stream to which usage information should be printed. |
| | | /** The output stream to which usage information should be printed. */ |
| | | private OutputStream usageOutputStream; |
| | | |
| | | // The fully-qualified name of the Java class that should be invoked to launch |
| | | // the program with which this argument parser is associated. |
| | | /** |
| | | * The fully-qualified name of the Java class that should be invoked to launch |
| | | * the program with which this argument parser is associated. |
| | | */ |
| | | private String mainClassName; |
| | | |
| | | // A human-readable description for the tool, which will be included when |
| | | // displaying usage information. |
| | | /** |
| | | * A human-readable description for the tool, which will be included when |
| | | * displaying usage information. |
| | | */ |
| | | private Message toolDescription; |
| | | |
| | | // The display name that will be used for the trailing arguments in the usage |
| | | // information. |
| | | /** |
| | | * The display name that will be used for the trailing arguments in the usage |
| | | * information. |
| | | */ |
| | | private String trailingArgsDisplayName; |
| | | |
| | | // The raw set of command-line arguments that were provided. |
| | | /** The raw set of command-line arguments that were provided. */ |
| | | private String[] rawArguments; |
| | | |
| | | /** Set of argument groups. */ |
| | |
| | | INFO_DESCRIPTION_GENERAL_ARGS.get(), Integer.MIN_VALUE); |
| | | |
| | | |
| | | private final static String INDENT = " "; |
| | | private final static int MAX_LENGTH = SetupUtils.isWindows() ? 79 : 80; |
| | | private static final String INDENT = " "; |
| | | private static final int MAX_LENGTH = SetupUtils.isWindows() ? 79 : 80; |
| | | |
| | | /** |
| | | * Creates a new instance of this argument parser with no arguments. |
| | |
| | | * @return The set of arguments mapped by the short identifier that may be |
| | | * used to reference them. |
| | | */ |
| | | public HashMap<Character,Argument> getArgumentsByShortID() |
| | | public Map<Character, Argument> getArgumentsByShortID() |
| | | { |
| | | return shortIDMap; |
| | | } |
| | |
| | | * @return The set of arguments mapped by the long identifier that may be |
| | | * used to reference them. |
| | | */ |
| | | public HashMap<String,Argument> getArgumentsByLongID() |
| | | public Map<String, Argument> getArgumentsByLongID() |
| | | { |
| | | return longIDMap; |
| | | } |
| | |
| | | { |
| | | |
| | | Character shortID = argument.getShortIdentifier(); |
| | | if ((shortID != null) && shortIDMap.containsKey(shortID)) |
| | | if (shortID != null && shortIDMap.containsKey(shortID)) |
| | | { |
| | | String conflictingName = shortIDMap.get(shortID).getName(); |
| | | |
| | |
| | | throw new ArgumentException(message); |
| | | } |
| | | |
| | | if ((versionArgument != null) && (shortID != null)) |
| | | if (versionArgument != null |
| | | && shortID != null |
| | | && shortID.equals(versionArgument.getShortIdentifier())) |
| | | { |
| | | if (shortID.equals(versionArgument.getShortIdentifier())) |
| | | // Update the version argument to not display its short identifier. |
| | | try |
| | | { |
| | | // Update the version argument to not display its short identifier. |
| | | try { |
| | | versionArgument = new BooleanArgument( |
| | | OPTION_LONG_PRODUCT_VERSION, |
| | | null, |
| | | OPTION_LONG_PRODUCT_VERSION, |
| | | INFO_DESCRIPTION_PRODUCT_VERSION.get()); |
| | | this.generalArgGroup.addArgument(versionArgument); |
| | | } catch (ArgumentException e) { |
| | | // ignore |
| | | } |
| | | versionArgument = new BooleanArgument( |
| | | OPTION_LONG_PRODUCT_VERSION, |
| | | null, |
| | | OPTION_LONG_PRODUCT_VERSION, |
| | | INFO_DESCRIPTION_PRODUCT_VERSION.get()); |
| | | this.generalArgGroup.addArgument(versionArgument); |
| | | } |
| | | catch (ArgumentException e) { |
| | | // ignore |
| | | } |
| | | } |
| | | |
| | |
| | | if (inTrailingArgs) |
| | | { |
| | | trailingArguments.add(arg); |
| | | if ((maxTrailingArguments > 0) && |
| | | (trailingArguments.size() > maxTrailingArguments)) |
| | | if (maxTrailingArguments > 0 && |
| | | trailingArguments.size() > maxTrailingArguments) |
| | | { |
| | | Message message = |
| | | ERR_ARGPARSER_TOO_MANY_TRAILING_ARGS.get(maxTrailingArguments); |
| | |
| | | { |
| | | // "--help" will always be interpreted as requesting usage |
| | | // information. |
| | | try |
| | | { |
| | | getUsage(usageOutputStream); |
| | | } catch (Exception e) {} |
| | | |
| | | getUsage(usageOutputStream); |
| | | return; |
| | | } |
| | | else |
| | |
| | | // information. |
| | | usageOrVersionDisplayed = true; |
| | | versionPresent = true; |
| | | try |
| | | { |
| | | DirectoryServer.printVersion(usageOutputStream); |
| | | } catch (Exception e) {} |
| | | |
| | | printVersion(); |
| | | return; |
| | | } |
| | | else |
| | |
| | | |
| | | // If this is the usage argument, then immediately stop and print |
| | | // usage information. |
| | | if ((usageArgument != null) && |
| | | if (usageArgument != null && |
| | | usageArgument.getName().equals(a.getName())) |
| | | { |
| | | try |
| | | { |
| | | getUsage(usageOutputStream); |
| | | } catch (Exception e) {} |
| | | |
| | | getUsage(usageOutputStream); |
| | | return; |
| | | } |
| | | } |
| | |
| | | |
| | | // If the argument already has a value, then make sure it is |
| | | // acceptable to have more than one. |
| | | if (a.hasValue() && (! a.isMultiValued())) |
| | | if (a.hasValue() && !a.isMultiValued()) |
| | | { |
| | | Message message = |
| | | ERR_ARGPARSER_NOT_MULTIVALUED_FOR_LONG_ID.get(origArgName); |
| | |
| | | if (argCharacter == '?') |
| | | { |
| | | // "-?" will always be interpreted as requesting usage information. |
| | | try |
| | | { |
| | | getUsage(usageOutputStream); |
| | | } catch (Exception e) {} |
| | | |
| | | getUsage(usageOutputStream); |
| | | return; |
| | | } |
| | | else |
| | | if ( (argCharacter == OPTION_SHORT_PRODUCT_VERSION) |
| | | && |
| | | ( ! shortIDMap.containsKey(OPTION_SHORT_PRODUCT_VERSION))) |
| | | if (argCharacter == OPTION_SHORT_PRODUCT_VERSION |
| | | && !shortIDMap.containsKey(OPTION_SHORT_PRODUCT_VERSION)) |
| | | { |
| | | // "-V" will always be interpreted as requesting |
| | | // version information except if it's already defined (e.g in |
| | | // ldap tools). |
| | | usageOrVersionDisplayed = true ; |
| | | versionPresent = true; |
| | | try |
| | | { |
| | | DirectoryServer.printVersion(usageOutputStream); |
| | | } catch (Exception e) {} |
| | | printVersion(); |
| | | return; |
| | | } |
| | | else |
| | |
| | | |
| | | // If this is the usage argument, then immediately stop and print |
| | | // usage information. |
| | | if ((usageArgument != null) && |
| | | if (usageArgument != null && |
| | | usageArgument.getName().equals(a.getName())) |
| | | { |
| | | try |
| | | { |
| | | getUsage(usageOutputStream); |
| | | } catch (Exception e) {} |
| | | |
| | | getUsage(usageOutputStream); |
| | | return; |
| | | } |
| | | } |
| | |
| | | |
| | | // If the argument already has a value, then make sure it is |
| | | // acceptable to have more than one. |
| | | if (a.hasValue() && (! a.isMultiValued())) |
| | | if (a.hasValue() && !a.isMultiValued()) |
| | | { |
| | | Message message = ERR_ARGPARSER_NOT_MULTIVALUED_FOR_SHORT_ID.get( |
| | | String.valueOf(argCharacter)); |
| | |
| | | |
| | | // If this is the usage argument, then immediately stop and |
| | | // print usage information. |
| | | if ((usageArgument != null) && |
| | | if (usageArgument != null && |
| | | usageArgument.getName().equals(b.getName())) |
| | | { |
| | | try |
| | | { |
| | | getUsage(usageOutputStream); |
| | | } catch (Exception e) {} |
| | | |
| | | getUsage(usageOutputStream); |
| | | return; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | |
| | | // If we allow trailing arguments and there is a minimum number, then make |
| | | // sure at least that many were provided. |
| | | if (allowsTrailingArguments && (minTrailingArguments > 0)) |
| | | if (allowsTrailingArguments |
| | | && minTrailingArguments > 0 |
| | | && trailingArguments.size() < minTrailingArguments) |
| | | { |
| | | if (trailingArguments.size() < minTrailingArguments) |
| | | { |
| | | Message message = |
| | | ERR_ARGPARSER_TOO_FEW_TRAILING_ARGUMENTS.get(minTrailingArguments); |
| | | throw new ArgumentException(message); |
| | | } |
| | | Message message = |
| | | ERR_ARGPARSER_TOO_FEW_TRAILING_ARGUMENTS.get(minTrailingArguments); |
| | | throw new ArgumentException(message); |
| | | } |
| | | |
| | | // If we don't have the argumentProperties, try to load a properties file. |
| | |
| | | // For cases where there is not, see that argument is required. |
| | | for (Argument a : argumentList) |
| | | { |
| | | if (! a.isPresent()) |
| | | if (!a.isPresent() |
| | | // See if there is a value in the properties that can be used |
| | | && argumentProperties != null |
| | | && a.getPropertyName() != null) |
| | | { |
| | | // See if there is a value in the properties that can be used |
| | | if ((argumentProperties != null) && (a.getPropertyName() != null)) |
| | | String value = |
| | | argumentProperties.getProperty(a.getPropertyName().toLowerCase()); |
| | | MessageBuilder invalidReason = new MessageBuilder(); |
| | | if (value != null) |
| | | { |
| | | String value = argumentProperties.getProperty(a.getPropertyName() |
| | | .toLowerCase()); |
| | | MessageBuilder invalidReason = new MessageBuilder(); |
| | | if (value != null) |
| | | Boolean addValue = true; |
| | | if (!(a instanceof BooleanArgument)) |
| | | { |
| | | Boolean addValue = true; |
| | | if (!( a instanceof BooleanArgument)) |
| | | addValue = a.valueIsAcceptable(value, invalidReason); |
| | | } |
| | | if (addValue) |
| | | { |
| | | a.addValue(value); |
| | | if (a.needsValue()) |
| | | { |
| | | addValue = a.valueIsAcceptable(value, invalidReason); |
| | | a.setPresent(true); |
| | | } |
| | | if (addValue) |
| | | { |
| | | a.addValue(value); |
| | | if (a.needsValue()) |
| | | { |
| | | a.setPresent(true); |
| | | } |
| | | a.setValueSetByProperty(true); |
| | | } |
| | | a.setValueSetByProperty(true); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | if ((! a.isPresent()) && a.needsValue()) |
| | | if (!a.isPresent() && a.needsValue()) |
| | | { |
| | | // See if the argument defines a default. |
| | | if (a.getDefaultValue() != null) |
| | |
| | | |
| | | // If there is still no value and the argument is required, then that's |
| | | // a problem. |
| | | if ((! a.hasValue()) && a.isRequired()) |
| | | if (!a.hasValue() && a.isRequired()) |
| | | { |
| | | Message message = |
| | | ERR_ARGPARSER_NO_VALUE_FOR_REQUIRED_ARG.get(a.getName()); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | private void printVersion() |
| | | { |
| | | try |
| | | { |
| | | DirectoryServer.printVersion(usageOutputStream); |
| | | } catch (Exception e) {} |
| | | } |
| | | |
| | | /** |
| | | * Check if we have a properties file. |
| | |
| | | throws ArgumentException |
| | | { |
| | | // We don't look for properties file. |
| | | if ((noPropertiesFileArgument != null) |
| | | && (noPropertiesFileArgument.isPresent())) |
| | | if (noPropertiesFileArgument != null |
| | | && noPropertiesFileArgument.isPresent()) |
| | | { |
| | | return null; |
| | | } |
| | |
| | | public void getUsage(StringBuilder buffer) |
| | | { |
| | | usageOrVersionDisplayed = true; |
| | | if ((toolDescription != null) && (toolDescription.length() > 0)) |
| | | if (toolDescription != null && toolDescription.length() > 0) |
| | | { |
| | | buffer.append(wrapText(toolDescription.toString(), MAX_LENGTH - 1)); |
| | | buffer.append(EOL); |
| | |
| | | } |
| | | |
| | | String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME); |
| | | if ((scriptName == null) || (scriptName.length() == 0)) |
| | | if (scriptName == null || scriptName.length() == 0) |
| | | { |
| | | buffer.append(INFO_ARGPARSER_USAGE_JAVA_CLASSNAME.get(mainClassName)); |
| | | } |
| | |
| | | } |
| | | |
| | | // Help argument should be printed at the end |
| | | if ((usageArgument != null) && |
| | | usageArgument.getName().equals(a.getName())) |
| | | if (usageArgument != null |
| | | && usageArgument.getName().equals(a.getName())) |
| | | { |
| | | helpArgument = a ; |
| | | continue ; |
| | |
| | | * |
| | | * @param outputStream The output stream to which the usage information |
| | | * should be written. |
| | | * |
| | | * @throws IOException If a problem occurs while attempting to write the |
| | | * usage information to the provided output stream. |
| | | */ |
| | | public void getUsage(OutputStream outputStream) |
| | | throws IOException |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | getUsage(buffer); |
| | | |
| | | outputStream.write(buffer.toString().getBytes()); |
| | | try |
| | | { |
| | | outputStream.write(buffer.toString().getBytes()); |
| | | } |
| | | catch (Exception e) {} |
| | | } |
| | | |
| | | |
| | |
| | | if (lineLength > MAX_LENGTH) |
| | | { |
| | | buffer.append(EOL); |
| | | buffer.append(newBuffer.toString()); |
| | | } |
| | | else |
| | | { |
| | | buffer.append(newBuffer.toString()); |
| | | } |
| | | buffer.append(newBuffer.toString()); |
| | | } |
| | | |
| | | buffer.append(EOL); |
| | |
| | | } |
| | | } |
| | | |
| | | if (a.needsValue() && (a.getDefaultValue() != null) && |
| | | (a.getDefaultValue().length() > 0)) |
| | | if (a.needsValue() |
| | | && a.getDefaultValue() != null |
| | | && a.getDefaultValue().length() > 0) |
| | | { |
| | | buffer.append(INDENT); |
| | | buffer.append(INFO_ARGPARSER_USAGE_DEFAULT_VALUE.get( |