/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. * Portions copyright 2013 ForgeRock AS */ package org.opends.server.util.args; import java.util.Iterator; import java.util.LinkedList; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import static org.opends.messages.UtilityMessages.*; import static org.opends.server.util.StaticUtils.*; /** * This class defines a generic argument that may be used in the argument list * for an application. This is an abstract class that must be subclassed in * order to provide specific functionality. */ public abstract class Argument { /** * Indicates whether this argument should be hidden in the usage information. */ private boolean isHidden; /** * Indicates whether this argument may be specified more than once for * multiple values. */ private boolean isMultiValued; /** * Indicates whether this argument was provided in the set of command-line * arguments. */ private boolean isPresent; /** Indicates whether this argument is required to have a value. */ private boolean isRequired; /** Indicates whether this argument requires a value. */ private boolean needsValue; /** The single-character identifier for this argument. */ private Character shortIdentifier; /** The unique ID of the description for this argument. */ private Message description; /** The set of provided values for this argument. */ private LinkedList values; /** The default value for the argument if none other is provided. */ private String defaultValue; /** The long identifier for this argument. */ private String longIdentifier; /** The generic name that will be used to refer to this argument. */ private String name; /** The name of the property that can be used to set the default value. */ private String propertyName; /** * The value placeholder for this argument, which will be used in usage * information. It describes the format that must be used to specify the * values for this argument. */ private Message valuePlaceholder; /** * Indicates whether this argument was provided in the set of properties found * is a properties file. */ private boolean isValueSetByProperty; /** * Creates a new argument with the provided information. * * @param name The generic name that should be used to refer to * this argument. * @param shortIdentifier The single-character identifier for this * argument, or null if there is none. * @param longIdentifier The long identifier for this argument, or * null if there is none. * @param isRequired Indicates whether this argument must be specified * on the command line. * @param isMultiValued Indicates whether this argument may be specified * more than once to provide multiple values. * @param needsValue Indicates whether this argument requires a value. * @param valuePlaceholder The placeholder for the argument value that will * be displayed in usage information, or * null if this argument does not * require a value. * @param defaultValue The default value that should be used for this * argument if none is provided in a properties file * or on the command line. This may be * null if there is no generic default. * @param propertyName The name of the property in a property file that * may be used to override the default value but * will be overridden by a command-line argument. * @param description Message for the description of this * argument. * * @throws ArgumentException If there is a problem with any of the * parameters used to create this argument. */ protected Argument(String name, Character shortIdentifier, String longIdentifier, boolean isRequired, boolean isMultiValued, boolean needsValue, Message valuePlaceholder, String defaultValue, String propertyName, Message description) throws ArgumentException { this.name = name; this.shortIdentifier = shortIdentifier; this.longIdentifier = longIdentifier; this.isRequired = isRequired; this.isMultiValued = isMultiValued; this.needsValue = needsValue; this.valuePlaceholder = valuePlaceholder; this.defaultValue = defaultValue; this.propertyName = propertyName; this.description = description; this.isValueSetByProperty = false ; if (shortIdentifier == null && longIdentifier == null) { Message message = ERR_ARG_NO_IDENTIFIER.get(name); throw new ArgumentException(message); } if (needsValue && valuePlaceholder == null) { Message message = ERR_ARG_NO_VALUE_PLACEHOLDER.get(name); throw new ArgumentException(message); } values = new LinkedList(); isPresent = false; isHidden = false; } /** * Retrieves the generic name that will be used to refer to this argument. * * @return The generic name that will be used to refer to this argument. */ public String getName() { return name; } /** * Retrieves the single-character identifier that may be used to specify the * value of this argument. * * @return The single-character identifier that may be used to specify the * value of this argument, or null if there is none. */ public Character getShortIdentifier() { return shortIdentifier; } /** * Retrieves the long (multi-character) identifier that may be used to specify * the value of this argument. * * @return The long (multi-character) identifier that may be used to specify * the value of this argument. */ public String getLongIdentifier() { return longIdentifier; } /** * Indicates whether this argument is required to have at least one value. * * @return true if this argument is required to have at least * one value, or false if it does not need to have a * value. */ public boolean isRequired() { return isRequired; } /** * Specifies whether this argument is required to have at least one value. * * @param isRequired Indicates whether this argument is required to have at * least one value. */ public void setRequired(boolean isRequired) { this.isRequired = isRequired; } /** * Indicates whether this argument is present in the parsed set of * command-line arguments. * * @return true if this argument is present in the parsed set of * command-line arguments, or false if not. */ public boolean isPresent() { return isPresent; } /** * Specifies whether this argument is present in the parsed set of * command-line arguments. * * @param isPresent Indicates whether this argument is present in the set of * command-line arguments. */ public void setPresent(boolean isPresent) { this.isPresent = isPresent; } /** * Indicates whether this argument should be hidden from the usage * information. * * @return true if this argument should be hidden from the usage * information, or false if not. */ public boolean isHidden() { return isHidden; } /** * Specifies whether this argument should be hidden from the usage * information. * * @param isHidden Indicates whether this argument should be hidden from the * usage information. */ public void setHidden(boolean isHidden) { this.isHidden = isHidden; } /** * Indicates whether this argument may be provided more than once on the * command line to specify multiple values. * * @return true if this argument may be provided more than once * on the command line to specify multiple values, or * false if it may have at most one value. */ public boolean isMultiValued() { return isMultiValued; } /** * Specifies whether this argument may be provided more than once on the * command line to specify multiple values. * * @param isMultiValued Indicates whether this argument may be provided more * than once on the command line to specify multiple * values. */ public void setMultiValued(boolean isMultiValued) { this.isMultiValued = isMultiValued; } /** * Indicates whether a value must be provided with this argument if it is * present. * * @return true if a value must be provided with the argument if * it is present, or false if the argument does not take * a value and the presence of the argument identifier itself is * sufficient to convey the necessary information. */ public boolean needsValue() { return needsValue; } /** * Specifies whether a value must be provided with this argument if it is * present. If this is changed from false to true, * then a value placeholder must also be provided. * * @param needsValue Indicates whether a value must be provided with this * argument if it is present. */ public void setNeedsValue(boolean needsValue) { this.needsValue = needsValue; } /** * Retrieves the value placeholder that will be displayed for this argument in * the generated usage information. * * @return The value placeholder that will be displayed for this argument in * the generated usage information, or null if there is * none. */ public Message getValuePlaceholder() { return valuePlaceholder; } /** * Specifies the value placeholder that will be displayed for this argument in * the generated usage information. It may be null only if * needsValue() returns false. * * @param valuePlaceholder The value placeholder that will be displayed for * this argument in the generated usage information. */ public void setValuePlaceholder(Message valuePlaceholder) { this.valuePlaceholder = valuePlaceholder; } /** * Retrieves the default value that will be used for this argument if it is * not specified on the command line and it is not set from a properties file. * * @return The default value that will be used for this argument if it is not * specified on the command line and it is not set from a properties * file, or null if there is no default value. */ public String getDefaultValue() { return defaultValue; } /** * Specifies the default value that will be used for this argument if it is * not specified on the command line and it is not set from a properties file. * * @param defaultValue The default value that will be used for this argument * if it is not specified on the command line and it is * not set from a properties file. */ public void setDefaultValue(String defaultValue) { this.defaultValue = defaultValue; } /** * Retrieves the name of a property in a properties file that may be used to * set the default value for this argument if it is present. A value read * from a properties file will override the default value returned from the * getDefaultValue, but the properties file value will be * overridden by a value supplied on the command line. * * @return The name of a property in a properties file that may be used to * set the default value for this argument if it is present. */ public String getPropertyName() { return propertyName; } /** * Specifies the name of a property in a properties file that may be used to * set the default value for this argument if it is present. * * @param propertyName The name of a property in a properties file that may * be used to set the default value for this argument if * it is present. */ public void setPropertyName(String propertyName) { this.propertyName = propertyName; } /** * Indicates whether this argument was provided in the set of * properties found is a properties file. * * @return true if this argument was provided in the * set of properties found is a properties file, or * false if not. */ public boolean isValueSetByProperty() { return isValueSetByProperty; } /** * Specifies whether this argument was provided in the set of * properties found is a properties file. * * @param isValueSetByProperty * Specify whether this argument was provided in the set * of properties found is a properties file. */ public void setValueSetByProperty(boolean isValueSetByProperty) { this.isValueSetByProperty = isValueSetByProperty; } /** * Retrieves the human-readable description for this argument. * * @return The human-readable description for this argument. */ public Message getDescription() { return description != null ? description : Message.EMPTY; } /** * Indicates whether this argument has at least one value. * * @return true if this argument has at least one value, or * false if it does not have any values. */ public boolean hasValue() { return !values.isEmpty(); } /** * Retrieves the string value for this argument. If it has multiple values, * then the first will be returned. If it does not have any values, then the * default value will be returned. * * @return The string value for this argument, or null if there * are no values and no default value has been given. */ public String getValue() { if (values.isEmpty()) { return defaultValue; } return values.getFirst(); } /** * Retrieves the set of string values for this argument. * * @return The set of string values for this argument. */ public LinkedList getValues() { return values; } /** * Retrieves the value of this argument as an integer. * * @return The value of this argument as an integer. * * @throws ArgumentException If there are multiple values, or the value * cannot be parsed as an integer. */ public int getIntValue() throws ArgumentException { if (values.isEmpty()) { Message message = ERR_ARG_NO_INT_VALUE.get(name); throw new ArgumentException(message); } Iterator iterator = values.iterator(); String valueString = iterator.next(); int intValue; try { intValue = Integer.parseInt(valueString); } catch (Exception e) { Message message = ERR_ARG_CANNOT_DECODE_AS_INT.get(valueString, name); throw new ArgumentException(message, e); } if (iterator.hasNext()) { Message message = ERR_ARG_INT_MULTIPLE_VALUES.get(name); throw new ArgumentException(message); } return intValue; } /** * Retrieves the set of values for this argument as a list of integers. * * @return A list of the integer representations of the values for this * argument. * * @throws ArgumentException If any of the values cannot be parsed as an * integer. */ public LinkedList getIntValues() throws ArgumentException { LinkedList intList = new LinkedList(); for (String valueString : values) { try { intList.add(Integer.valueOf(valueString)); } catch (Exception e) { Message message = ERR_ARG_CANNOT_DECODE_AS_INT.get(valueString, name); throw new ArgumentException(message, e); } } return intList; } /** * Retrieves the value of this argument as a Boolean. * * @return The value of this argument as a Boolean. * * @throws ArgumentException If this argument cannot be interpreted as a * Boolean value. */ public boolean getBooleanValue() throws ArgumentException { if (values.isEmpty()) { Message message = ERR_ARG_NO_BOOLEAN_VALUE.get(name); throw new ArgumentException(message); } Iterator iterator = values.iterator(); String valueString = toLowerCase(iterator.next()); boolean booleanValue; if ("true".equals(valueString) || "yes".equals(valueString) || "on".equals(valueString) || "1".equals(valueString)) { booleanValue = true; } else if ("false".equals(valueString) || "no".equals(valueString) || "off".equals(valueString) || "0".equals(valueString)) { booleanValue = false; } else { Message message = ERR_ARG_CANNOT_DECODE_AS_BOOLEAN.get(valueString, name); throw new ArgumentException(message); } if (iterator.hasNext()) { Message message = ERR_ARG_BOOLEAN_MULTIPLE_VALUES.get(name); throw new ArgumentException(message); } return booleanValue; } /** * Indicates whether the provided value is acceptable for use in this * argument. * * @param valueString The value for which to make the determination. * @param invalidReason A buffer into which the invalid reason may be * written if the value is not acceptable. * * @return true if the value is acceptable, or * false if it is not. */ public abstract boolean valueIsAcceptable(String valueString, MessageBuilder invalidReason); /** * Adds a value to the set of values for this argument. This should only be * called if the value is allowed by the valueIsAcceptable * method. * * @param valueString The string representation of the value to add to this * argument. */ public void addValue(String valueString) { values.add(valueString); } /** * Clears the set of values assigned to this argument. */ public void clearValues() { values.clear(); } /** {@inheritDoc} */ @Override public String toString() { final StringBuilder sb = new StringBuilder(getClass().getSimpleName()); sb.append("[name=\"").append(this.name).append("\""); if (shortIdentifier != null || longIdentifier != null) { sb.append(", options="); if (shortIdentifier != null) { sb.append("-").append(shortIdentifier); } if (longIdentifier != null) { if (shortIdentifier != null) { sb.append(" "); } sb.append("--").append(longIdentifier); } } sb.append(", ").append(isRequired ? "required" : "optional"); sb.append(", ").append(isMultiValued ? "multiValued" : "singleValued"); sb.append(", defaultValue=\"").append(defaultValue) .append("\", valueFormat=\"").append(valuePlaceholder) .append("\", providedValues=\"").append(values) .append("\", description=\"").append(description) .append("\"]"); return sb.toString(); } }