All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.util.args.DurationArgument Maven / Gradle / Ivy

Go to download

The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use Java API for communicating with LDAP directory servers and performing related tasks like reading and writing LDIF, encoding and decoding data using base64 and ASN.1 BER, and performing secure communication. This package contains the Standard Edition of the LDAP SDK, which is a complete, general-purpose library for communicating with LDAPv3 directory servers.

There is a newer version: 7.0.1
Show newest version
/*
 * Copyright 2010-2018 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright (C) 2010-2018 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.util.args;



import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.unboundid.util.Debug;
import com.unboundid.util.LDAPSDKUsageException;
import com.unboundid.util.Mutable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;

import static com.unboundid.util.args.ArgsMessages.*;



/**
 * Creates a new argument that is intended to represent a duration.  Duration
 * values contain an integer portion and a unit portion which represents the
 * time unit.  The unit must be one of the following:
 * 
    *
  • Nanoseconds -- ns, nano, nanos, nanosecond, nanoseconds
  • *
  • Microseconds -- us, micro, micros, microsecond, microseconds
  • *
  • Milliseconds -- ms, milli, millis, millisecond, milliseconds
  • *
  • Seconds -- s, sec, secs, second, seconds
  • *
  • Minutes -- m, min, mins, minute, minutes
  • *
  • Hours -- h, hr, hrs, hour, hours
  • *
  • Days -- d, day, days
  • *
  • Weeks -- w, week, weeks
  • *
* * There may be zero or more spaces between the integer portion and the unit * portion. However, if spaces are used in the command-line argument, then the * value must be enquoted or the spaces must be escaped so that the duration * is not seen as multiple arguments. */ @Mutable() @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) public final class DurationArgument extends Argument { /** * The serial version UID for this serializable class. */ private static final long serialVersionUID = -8824262632728709264L; // The argument value validators that have been registered for this argument. private final List validators; // The default value for this argument, in nanoseconds. private final Long defaultValueNanos; // The maximum allowed value for this argument, in nanoseconds. private final long maxValueNanos; // The minimum allowed value for this argument, in nanoseconds. private final long minValueNanos; // The provided value for this argument, in nanoseconds. private Long valueNanos; // The string representation of the lower bound, using the user-supplied // value. private final String lowerBoundStr; // The string representation of the upper bound, using the user-supplied // value. private final String upperBoundStr; /** * Creates a new duration argument that will not be required, will use a * default placeholder, and will have no default value and no bounds on the * set of allowed values. * * @param shortIdentifier The short identifier for this argument. It may * not be {@code null} if the long identifier is * {@code null}. * @param longIdentifier The long identifier for this argument. It may * not be {@code null} if the short identifier is * {@code null}. * @param description A human-readable description for this argument. * It must not be {@code null}. * * @throws ArgumentException If there is a problem with the definition of * this argument. */ public DurationArgument(final Character shortIdentifier, final String longIdentifier, final String description) throws ArgumentException { this(shortIdentifier, longIdentifier, false, null, description); } /** * Creates a new duration argument with no default value and no bounds on the * set of allowed values. * * @param shortIdentifier The short identifier for this argument. It may * not be {@code null} if the long identifier is * {@code null}. * @param longIdentifier The long identifier for this argument. It may * not be {@code null} if the short identifier is * {@code null}. * @param isRequired Indicates whether this argument is required to * be provided. * @param valuePlaceholder A placeholder to display in usage information to * indicate that a value must be provided. It may * be {@code null} if a default placeholder should * be used. * @param description A human-readable description for this argument. * It must not be {@code null}. * * @throws ArgumentException If there is a problem with the definition of * this argument. */ public DurationArgument(final Character shortIdentifier, final String longIdentifier, final boolean isRequired, final String valuePlaceholder, final String description) throws ArgumentException { this(shortIdentifier, longIdentifier, isRequired, valuePlaceholder, description, null, null, null, null, null, null); } /** * Creates a new duration argument with the provided information. * * @param shortIdentifier The short identifier for this argument. It may * not be {@code null} if the long identifier is * {@code null}. * @param longIdentifier The long identifier for this argument. It may * not be {@code null} if the short identifier is * {@code null}. * @param isRequired Indicates whether this argument is required to * be provided. * @param valuePlaceholder A placeholder to display in usage information to * indicate that a value must be provided. It may * be {@code null} if a default placeholder should * be used. * @param description A human-readable description for this argument. * It must not be {@code null}. * @param defaultValue The default value that will be used for this * argument if none is provided. It may be * {@code null} if there should not be a default * value. * @param defaultValueUnit The time unit for the default value. It may be * {@code null} only if the default value is also * {@code null}. * @param lowerBound The value for the minimum duration that may be * represented using this argument, in conjunction * with the {@code lowerBoundUnit} parameter to * specify the unit for this value. If this is * {@code null}, then a lower bound of 0 nanoseconds * will be used. * @param lowerBoundUnit The time unit for the lower bound value. It may * be {@code null} only if the lower bound is also * {@code null}. * @param upperBound The value for the maximum duration that may be * represented using this argument, in conjunction * with the {@code upperBoundUnit} parameter to * specify the unit for this value. If this is * {@code null}, then an upper bound of * {@code Long.MAX_VALUE} nanoseconds will be used. * @param upperBoundUnit The time unit for the upper bound value. It may * be {@code null} only if the upper bound is also * {@code null}. * * @throws ArgumentException If there is a problem with the definition of * this argument. */ public DurationArgument(final Character shortIdentifier, final String longIdentifier, final boolean isRequired, final String valuePlaceholder, final String description, final Long defaultValue, final TimeUnit defaultValueUnit, final Long lowerBound, final TimeUnit lowerBoundUnit, final Long upperBound, final TimeUnit upperBoundUnit) throws ArgumentException { super(shortIdentifier, longIdentifier, isRequired, 1, (valuePlaceholder == null) ? INFO_PLACEHOLDER_DURATION.get() : valuePlaceholder, description); if (defaultValue == null) { defaultValueNanos = null; } else { if (defaultValueUnit == null) { throw new ArgumentException(ERR_DURATION_DEFAULT_REQUIRES_UNIT.get( getIdentifierString())); } defaultValueNanos = defaultValueUnit.toNanos(defaultValue); } if (lowerBound == null) { minValueNanos = 0L; lowerBoundStr = "0ns"; } else { if (lowerBoundUnit == null) { throw new ArgumentException(ERR_DURATION_LOWER_REQUIRES_UNIT.get( getIdentifierString())); } minValueNanos = lowerBoundUnit.toNanos(lowerBound); switch (lowerBoundUnit) { case NANOSECONDS: lowerBoundStr = minValueNanos + "ns"; break; case MICROSECONDS: lowerBoundStr = lowerBound + "us"; break; case MILLISECONDS: lowerBoundStr = lowerBound + "ms"; break; case SECONDS: lowerBoundStr = lowerBound + "s"; break; case MINUTES: lowerBoundStr = lowerBound + "m"; break; case HOURS: lowerBoundStr = lowerBound + "h"; break; case DAYS: lowerBoundStr = lowerBound + "d"; break; default: throw new LDAPSDKUsageException( ERR_DURATION_UNSUPPORTED_LOWER_BOUND_UNIT.get( lowerBoundUnit.name())); } } if (upperBound == null) { maxValueNanos = Long.MAX_VALUE; upperBoundStr = Long.MAX_VALUE + "ns"; } else { if (upperBoundUnit == null) { throw new ArgumentException(ERR_DURATION_UPPER_REQUIRES_UNIT.get( getIdentifierString())); } maxValueNanos = upperBoundUnit.toNanos(upperBound); switch (upperBoundUnit) { case NANOSECONDS: upperBoundStr = minValueNanos + "ns"; break; case MICROSECONDS: upperBoundStr = upperBound + "us"; break; case MILLISECONDS: upperBoundStr = upperBound + "ms"; break; case SECONDS: upperBoundStr = upperBound + "s"; break; case MINUTES: upperBoundStr = upperBound + "m"; break; case HOURS: upperBoundStr = upperBound + "h"; break; case DAYS: upperBoundStr = upperBound + "d"; break; default: throw new LDAPSDKUsageException( ERR_DURATION_UNSUPPORTED_UPPER_BOUND_UNIT.get( upperBoundUnit.name())); } } if (minValueNanos > maxValueNanos) { throw new ArgumentException(ERR_DURATION_LOWER_GT_UPPER.get( getIdentifierString(), lowerBoundStr, upperBoundStr)); } valueNanos = null; validators = new ArrayList<>(5); } /** * Creates a new duration argument that is a "clean" copy of the provided * source argument. * * @param source The source argument to use for this argument. */ private DurationArgument(final DurationArgument source) { super(source); defaultValueNanos = source.defaultValueNanos; maxValueNanos = source.maxValueNanos; minValueNanos = source.minValueNanos; lowerBoundStr = source.lowerBoundStr; upperBoundStr = source.upperBoundStr; validators = new ArrayList<>(source.validators); valueNanos = null; } /** * Retrieves the lower bound for this argument using the specified time unit. * * @param unit The time unit in which the lower bound value may be * expressed. * * @return The lower bound for this argument using the specified time unit. */ public long getLowerBound(final TimeUnit unit) { return unit.convert(minValueNanos, TimeUnit.NANOSECONDS); } /** * Retrieves the upper bound for this argument using the specified time unit. * * @param unit The time unit in which the upper bound value may be * expressed. * * @return The upper bound for this argument using the specified time unit. */ public long getUpperBound(final TimeUnit unit) { return unit.convert(maxValueNanos, TimeUnit.NANOSECONDS); } /** * {@inheritDoc} */ @Override() public List getValueStringRepresentations(final boolean useDefault) { final long v; if (valueNanos != null) { v = valueNanos; } else if (useDefault && (defaultValueNanos != null)) { v = defaultValueNanos; } else { return Collections.emptyList(); } return Collections.singletonList(nanosToDuration(v)); } /** * {@inheritDoc} */ @Override() protected boolean hasDefaultValue() { return (defaultValueNanos != null); } /** * Retrieves the default value for this argument using the specified time * unit, if defined. * * @param unit The time unit in which the default value should be expressed. * * @return The default value for this argument using the specified time unit, * or {@code null} if none is defined. */ public Long getDefaultValue(final TimeUnit unit) { if (defaultValueNanos == null) { return null; } return unit.convert(defaultValueNanos, TimeUnit.NANOSECONDS); } /** * Retrieves the value for this argument using the specified time unit, if one * was provided. * * @param unit The time unit in which to express the value for this * argument. * * @return The value for this argument using the specified time unit. If no * value was provided but a default value was defined, then the * default value will be returned. If no value was provided and no * default value was defined, then {@code null} will be returned. */ public Long getValue(final TimeUnit unit) { if (valueNanos == null) { if (defaultValueNanos == null) { return null; } return unit.convert(defaultValueNanos, TimeUnit.NANOSECONDS); } else { return unit.convert(valueNanos, TimeUnit.NANOSECONDS); } } /** * Updates this argument to ensure that the provided validator will be invoked * for any values provided to this argument. This validator will be invoked * after all other validation has been performed for this argument. * * @param validator The argument value validator to be invoked. It must not * be {@code null}. */ public void addValueValidator(final ArgumentValueValidator validator) { validators.add(validator); } /** * {@inheritDoc} */ @Override() protected void addValue(final String valueString) throws ArgumentException { if (valueNanos != null) { throw new ArgumentException( ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get(getIdentifierString())); } final long proposedValueNanos; try { proposedValueNanos = parseDuration(valueString, TimeUnit.NANOSECONDS); } catch (final ArgumentException ae) { Debug.debugException(ae); throw new ArgumentException( ERR_DURATION_MALFORMED_VALUE.get(valueString, getIdentifierString(), ae.getMessage()), ae); } if (proposedValueNanos < minValueNanos) { throw new ArgumentException(ERR_DURATION_BELOW_LOWER_BOUND.get( getIdentifierString(), lowerBoundStr)); } else if (proposedValueNanos > maxValueNanos) { throw new ArgumentException(ERR_DURATION_ABOVE_UPPER_BOUND.get( getIdentifierString(), upperBoundStr)); } else { for (final ArgumentValueValidator v : validators) { v.validateArgumentValue(this, valueString); } valueNanos = proposedValueNanos; } } /** * Parses the provided string representation of a duration to a corresponding * numeric representation. * * @param durationString The string representation of the duration to be * parsed. * @param timeUnit The time unit to use for the return value. * * @return The parsed duration as a count in the specified time unit. * * @throws ArgumentException If the provided string cannot be parsed as a * valid duration. */ public static long parseDuration(final String durationString, final TimeUnit timeUnit) throws ArgumentException { // The string must not be empty. final String lowerStr = StaticUtils.toLowerCase(durationString); if (lowerStr.isEmpty()) { throw new ArgumentException(ERR_DURATION_EMPTY_VALUE.get()); } // Find the position of the first non-digit character. boolean digitFound = false; boolean nonDigitFound = false; int nonDigitPos = -1; for (int i=0; i < lowerStr.length(); i++) { final char c = lowerStr.charAt(i); if (Character.isDigit(c)) { digitFound = true; } else { nonDigitFound = true; nonDigitPos = i; if (! digitFound) { throw new ArgumentException(ERR_DURATION_NO_DIGIT.get()); } break; } } if (! nonDigitFound) { throw new ArgumentException(ERR_DURATION_NO_UNIT.get()); } // Separate the integer portion from the unit. long integerPortion = Long.parseLong(lowerStr.substring(0, nonDigitPos)); final String unitStr = lowerStr.substring(nonDigitPos).trim(); // Parse the time unit. final TimeUnit unitFromString; if (unitStr.equals("ns") || unitStr.equals("nano") || unitStr.equals("nanos") || unitStr.equals("nanosecond") || unitStr.equals("nanoseconds")) { unitFromString = TimeUnit.NANOSECONDS; } else if (unitStr.equals("us") || unitStr.equals("micro") || unitStr.equals("micros") || unitStr.equals("microsecond") || unitStr.equals("microseconds")) { unitFromString = TimeUnit.MICROSECONDS; } else if (unitStr.equals("ms") || unitStr.equals("milli") || unitStr.equals("millis") || unitStr.equals("millisecond") || unitStr.equals("milliseconds")) { unitFromString = TimeUnit.MILLISECONDS; } else if (unitStr.equals("s") || unitStr.equals("sec") || unitStr.equals("secs") || unitStr.equals("second") || unitStr.equals("seconds")) { unitFromString = TimeUnit.SECONDS; } else if (unitStr.equals("m") || unitStr.equals("min") || unitStr.equals("mins") || unitStr.equals("minute") || unitStr.equals("minutes")) { integerPortion *= 60L; unitFromString = TimeUnit.SECONDS; } else if (unitStr.equals("h") || unitStr.equals("hr") || unitStr.equals("hrs") || unitStr.equals("hour") || unitStr.equals("hours")) { integerPortion *= 3600L; unitFromString = TimeUnit.SECONDS; } else if (unitStr.equals("d") || unitStr.equals("day") || unitStr.equals("days")) { integerPortion *= 86_400L; unitFromString = TimeUnit.SECONDS; } else if (unitStr.equals("w") || unitStr.equals("week") || unitStr.equals("weeks")) { integerPortion *= 604_800; unitFromString = TimeUnit.SECONDS; } else { throw new ArgumentException(ERR_DURATION_UNRECOGNIZED_UNIT.get(unitStr)); } return timeUnit.convert(integerPortion, unitFromString); } /** * {@inheritDoc} */ @Override() public String getDataTypeName() { return INFO_DURATION_TYPE_NAME.get(); } /** * {@inheritDoc} */ @Override() public String getValueConstraints() { final StringBuilder buffer = new StringBuilder(); buffer.append(INFO_DURATION_CONSTRAINTS_FORMAT.get()); if (lowerBoundStr != null) { if (upperBoundStr == null) { buffer.append(" "); buffer.append(INFO_DURATION_CONSTRAINTS_LOWER_BOUND.get(lowerBoundStr)); } else { buffer.append(" "); buffer.append(INFO_DURATION_CONSTRAINTS_LOWER_AND_UPPER_BOUND.get( lowerBoundStr, upperBoundStr)); } } else { if (upperBoundStr != null) { buffer.append(" "); buffer.append(INFO_DURATION_CONSTRAINTS_UPPER_BOUND.get(upperBoundStr)); } } return buffer.toString(); } /** * {@inheritDoc} */ @Override() protected void reset() { super.reset(); valueNanos = null; } /** * {@inheritDoc} */ @Override() public DurationArgument getCleanCopy() { return new DurationArgument(this); } /** * Converts the specified number of nanoseconds into a duration string using * the largest possible whole unit (e.g., if the value represents a whole * number of seconds, then the returned string will be expressed in seconds). * * @param nanos The number of nanoseconds to convert to a duration string. * * @return The duration string for the specified number of nanoseconds. */ public static String nanosToDuration(final long nanos) { if (nanos == 0) { return "0 nanoseconds"; } if (nanos == 604_800_000_000_000L) { return "1 week"; } else if ((nanos % 604_800_000_000_000L) == 0L) { return (nanos / 604_800_000_000_000L) + " weeks"; } else if (nanos == 86_400_000_000_000L) { return "1 day"; } else if ((nanos % 86_400_000_000_000L) == 0L) { return (nanos / 86_400_000_000_000L) + " days"; } else if (nanos == 3_600_000_000_000L) { return "1 hour"; } else if ((nanos % 3_600_000_000_000L) == 0L) { return (nanos / 3_600_000_000_000L) + " hours"; } else if (nanos == 60_000_000_000L) { return "1 minute"; } else if ((nanos % 60_000_000_000L) == 0L) { return (nanos / 60_000_000_000L) + " minutes"; } else if (nanos == 1_000_000_000L) { return "1 second"; } else if ((nanos % 1_000_000_000L) == 0L) { return (nanos / 1_000_000_000L) + " seconds"; } else if (nanos == 1_000_000L) { return "1 millisecond"; } else if ((nanos % 1_000_000L) == 0L) { return (nanos / 1_000_000L) + " milliseconds"; } else if (nanos == 1000L) { return "1 microsecond"; } else if ((nanos % 1000L) == 0L) { return (nanos / 1000L) + " microseconds"; } else if (nanos == 1L) { return "1 nanosecond"; } else { return nanos + " nanoseconds"; } } /** * {@inheritDoc} */ @Override() protected void addToCommandLine(final List argStrings) { if (valueNanos != null) { argStrings.add(getIdentifierString()); if (isSensitive()) { argStrings.add("***REDACTED***"); } else { argStrings.add(nanosToDuration(valueNanos)); } } } /** * {@inheritDoc} */ @Override() public void toString(final StringBuilder buffer) { buffer.append("DurationArgument("); appendBasicToStringInfo(buffer); if (lowerBoundStr != null) { buffer.append(", lowerBound='"); buffer.append(lowerBoundStr); buffer.append('\''); } if (upperBoundStr != null) { buffer.append(", upperBound='"); buffer.append(upperBoundStr); buffer.append('\''); } if (defaultValueNanos != null) { buffer.append(", defaultValueNanos="); buffer.append(defaultValueNanos); } buffer.append(')'); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy