/*
|
* The contents of this file are subject to the terms of the Common Development and
|
* Distribution License (the License). You may not use this file except in compliance with the
|
* License.
|
*
|
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
|
* specific language governing permission and limitations under the License.
|
*
|
* When distributing Covered Software, include this CDDL Header Notice in each file and include
|
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
|
* Header, with the fields enclosed by brackets [] replaced by your own identifying
|
* information: "Portions Copyright [year] [name of copyright owner]".
|
*
|
* Copyright 2008 Sun Microsystems, Inc.
|
* Portions Copyright 2015 ForgeRock AS.
|
*/
|
package org.forgerock.opendj.config;
|
|
import java.util.HashMap;
|
import java.util.Map;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
/**
|
* This enumeration defines various duration units.
|
*/
|
public enum DurationUnit {
|
|
/** A day unit. */
|
DAYS(24 * 60 * 60 * 1000, "d", "days"),
|
|
/** An hour unit. */
|
HOURS(60 * 60 * 1000, "h", "hours"),
|
|
/** A millisecond unit. */
|
MILLI_SECONDS(1L, "ms", "milliseconds"),
|
|
/** A minute unit. */
|
MINUTES(60 * 1000, "m", "minutes"),
|
|
/** A second unit. */
|
SECONDS(1000L, "s", "seconds"),
|
|
/** A week unit. */
|
WEEKS(7 * 24 * 60 * 60 * 1000, "w", "weeks");
|
|
/** A lookup table for resolving a unit from its name. */
|
private static final Map<String, DurationUnit> NAME_TO_UNIT = new HashMap<>();
|
static {
|
|
for (DurationUnit unit : DurationUnit.values()) {
|
NAME_TO_UNIT.put(unit.shortName, unit);
|
NAME_TO_UNIT.put(unit.longName, unit);
|
}
|
}
|
|
/**
|
* Get the unit corresponding to the provided unit name.
|
*
|
* @param s
|
* The name of the unit. Can be the abbreviated or long name and
|
* can contain white space and mixed case characters.
|
* @return Returns the unit corresponding to the provided unit name.
|
* @throws IllegalArgumentException
|
* If the provided name did not correspond to a known duration
|
* unit.
|
*/
|
public static DurationUnit getUnit(String s) {
|
DurationUnit unit = NAME_TO_UNIT.get(s.trim().toLowerCase());
|
if (unit == null) {
|
throw new IllegalArgumentException("Illegal duration unit \"" + s + "\"");
|
}
|
return unit;
|
}
|
|
/**
|
* Parse the provided duration string and return its equivalent duration in
|
* milliseconds. The duration string must specify the unit e.g. "10s". This
|
* method will parse duration string representations produced from the
|
* {@link #toString(long)} method. Therefore, a duration can comprise of
|
* multiple duration specifiers, for example <code>1d15m25s</code>.
|
*
|
* @param s
|
* The duration string to be parsed.
|
* @return Returns the parsed duration in milliseconds.
|
* @throws NumberFormatException
|
* If the provided duration string could not be parsed.
|
* @see #toString(long)
|
*/
|
public static long parseValue(String s) {
|
return parseValue(s, null);
|
}
|
|
/**
|
* Parse the provided duration string and return its equivalent duration in
|
* milliseconds. This method will parse duration string representations
|
* produced from the {@link #toString(long)} method. Therefore, a duration
|
* can comprise of multiple duration specifiers, for example
|
* <code>1d15m25s</code>.
|
*
|
* @param s
|
* The duration string to be parsed.
|
* @param defaultUnit
|
* The default unit to use if there is no unit specified in the
|
* duration string, or <code>null</code> if the string must
|
* always contain a unit.
|
* @return Returns the parsed duration in milliseconds.
|
* @throws NumberFormatException
|
* If the provided duration string could not be parsed.
|
* @see #toString(long)
|
*/
|
public static long parseValue(String s, DurationUnit defaultUnit) {
|
String ns = s.trim();
|
if (ns.length() == 0) {
|
throw new NumberFormatException("Empty duration value \"" + s + "\"");
|
}
|
|
Pattern p1 =
|
Pattern.compile("^\\s*((\\d+)\\s*w)?" + "\\s*((\\d+)\\s*d)?" + "\\s*((\\d+)\\s*h)?"
|
+ "\\s*((\\d+)\\s*m)?" + "\\s*((\\d+)\\s*s)?" + "\\s*((\\d+)\\s*ms)?\\s*$", Pattern.CASE_INSENSITIVE);
|
Matcher m1 = p1.matcher(ns);
|
if (m1.matches()) {
|
// Value must be of the form produced by toString(long).
|
String weeks = m1.group(2);
|
String days = m1.group(4);
|
String hours = m1.group(6);
|
String minutes = m1.group(8);
|
String seconds = m1.group(10);
|
String ms = m1.group(12);
|
|
long duration = 0;
|
|
try {
|
if (weeks != null) {
|
duration += Long.valueOf(weeks) * WEEKS.getDuration();
|
}
|
|
if (days != null) {
|
duration += Long.valueOf(days) * DAYS.getDuration();
|
}
|
|
if (hours != null) {
|
duration += Long.valueOf(hours) * HOURS.getDuration();
|
}
|
|
if (minutes != null) {
|
duration += Long.valueOf(minutes) * MINUTES.getDuration();
|
}
|
|
if (seconds != null) {
|
duration += Long.valueOf(seconds) * SECONDS.getDuration();
|
}
|
|
if (ms != null) {
|
duration += Long.valueOf(ms) * MILLI_SECONDS.getDuration();
|
}
|
} catch (NumberFormatException e) {
|
throw new NumberFormatException("Invalid duration value \"" + s + "\"");
|
}
|
|
return duration;
|
} else {
|
// Value must be a floating point number followed by a unit.
|
Pattern p2 = Pattern.compile("^\\s*(\\d+(\\.\\d+)?)\\s*(\\w+)?\\s*$");
|
Matcher m2 = p2.matcher(ns);
|
|
if (!m2.matches()) {
|
throw new NumberFormatException("Invalid duration value \"" + s + "\"");
|
}
|
|
// Group 1 is the float.
|
double d;
|
try {
|
d = Double.valueOf(m2.group(1));
|
} catch (NumberFormatException e) {
|
throw new NumberFormatException("Invalid duration value \"" + s + "\"");
|
}
|
|
// Group 3 is the unit.
|
String unitString = m2.group(3);
|
DurationUnit unit;
|
if (unitString == null) {
|
if (defaultUnit == null) {
|
throw new NumberFormatException("Invalid duration value \"" + s + "\"");
|
} else {
|
unit = defaultUnit;
|
}
|
} else {
|
try {
|
unit = getUnit(unitString);
|
} catch (IllegalArgumentException e) {
|
throw new NumberFormatException("Invalid duration value \"" + s + "\"");
|
}
|
}
|
|
return unit.toMilliSeconds(d);
|
}
|
}
|
|
/**
|
* Returns a string representation of the provided duration. The string
|
* representation can be parsed using the {@link #parseValue(String)}
|
* method. The string representation is comprised of one or more of the
|
* number of weeks, days, hours, minutes, seconds, and milliseconds. Here
|
* are some examples:
|
*
|
* <pre>
|
* toString(0) // 0 ms
|
* toString(999) // 999 ms
|
* toString(1000) // 1 s
|
* toString(1500) // 1 s 500 ms
|
* toString(3650000) // 1 h 50 s
|
* toString(3700000) // 1 h 1 m 40 s
|
* </pre>
|
*
|
* @param duration
|
* The duration in milliseconds.
|
* @return Returns a string representation of the provided duration.
|
* @throws IllegalArgumentException
|
* If the provided duration is negative.
|
* @see #parseValue(String)
|
* @see #parseValue(String, DurationUnit)
|
*/
|
public static String toString(long duration) {
|
if (duration < 0) {
|
throw new IllegalArgumentException("Negative duration " + duration);
|
}
|
|
if (duration == 0) {
|
return "0 ms";
|
}
|
|
DurationUnit[] units = new DurationUnit[] { WEEKS, DAYS, HOURS, MINUTES, SECONDS, MILLI_SECONDS };
|
long remainder = duration;
|
StringBuilder builder = new StringBuilder();
|
boolean isFirst = true;
|
for (DurationUnit unit : units) {
|
long count = remainder / unit.getDuration();
|
if (count > 0) {
|
if (!isFirst) {
|
builder.append(' ');
|
}
|
builder.append(count);
|
builder.append(' ');
|
builder.append(unit.getShortName());
|
remainder = remainder - (count * unit.getDuration());
|
isFirst = false;
|
}
|
}
|
return builder.toString();
|
}
|
|
/** The long name of the unit. */
|
private final String longName;
|
|
/** The abbreviation of the unit. */
|
private final String shortName;
|
|
/** The size of the unit in milliseconds. */
|
private final long sz;
|
|
/** Private constructor. */
|
private DurationUnit(long sz, String shortName, String longName) {
|
this.sz = sz;
|
this.shortName = shortName;
|
this.longName = longName;
|
}
|
|
/**
|
* Converts the specified duration in milliseconds to this unit.
|
*
|
* @param duration
|
* The duration in milliseconds.
|
* @return Returns milliseconds in this unit.
|
*/
|
public double fromMilliSeconds(long duration) {
|
return (double) duration / sz;
|
}
|
|
/**
|
* Get the number of milliseconds that this unit represents.
|
*
|
* @return Returns the number of milliseconds that this unit represents.
|
*/
|
public long getDuration() {
|
return sz;
|
}
|
|
/**
|
* Get the long name of this unit.
|
*
|
* @return Returns the long name of this unit.
|
*/
|
public String getLongName() {
|
return longName;
|
}
|
|
/**
|
* Get the abbreviated name of this unit.
|
*
|
* @return Returns the abbreviated name of this unit.
|
*/
|
public String getShortName() {
|
return shortName;
|
}
|
|
/**
|
* Converts the specified duration in this unit to milliseconds.
|
*
|
* @param duration
|
* The duration as a quantity of this unit.
|
* @return Returns the number of milliseconds that the duration represents.
|
*/
|
public long toMilliSeconds(double duration) {
|
return (long) (sz * duration);
|
}
|
|
/**
|
* {@inheritDoc}
|
* <p>
|
* This implementation returns the abbreviated name of this duration unit.
|
*/
|
@Override
|
public String toString() {
|
return shortName;
|
}
|
}
|