/* * Copyright 2010 UnboundID Corp. * All Rights Reserved. */ /* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.common; /** * This class provides a utility that may be used to parse string * representations of durations. A duration string may be an integer, in which * case it will be interpreted as seconds. Otherwise, it may be specified as a * sequence of integers followed by units, delimited by spaces or commas. * Supported units include: * <UL> * <LI>s, sec, secs, second, seconds -- Indicates that the preceding integer * value represents a number of seconds.</LI> * <LI>m, min, mins, minute, minutes -- Indicates that the preceding integer * value represents a number of minutes.</LI> * <LI>h, hr, hrs, hour, hours -- Indicates that the preceding integer value * represents a number of hours.</LI> * <LI>d, day, days -- Indicates that the preceding integer value represents a * number of days.</LI> * </UL> * <BR> * The following are examples of valid ways to specify a duration of "123456" * seconds: * <UL> * <LI>123456</LI> * <LI>123456s</LI> * <LI>123456 seconds</LI> * <LI>1d 10h 17m 36s</LI> * <LI>1d 10h 17m 36s</LI> * <LI>1 day 10 hours 17 minutes 36 seconds</LI> * <LI>1 day, 10 hours, 17 minutes, 36 seconds</LI> * </UL> */ public final class DurationParser { /** * Parses the provided string as a duration. * * @param s The string to be parsed. * * @return The number of seconds represented by the provided duration. * * @throws SLAMDException If the provided string cannot be parsed as a * valid duration. */ public static int parse(final String s) throws SLAMDException { if (s == null) { throw new SLAMDException("Unable to parse a duration value because the " + "provided string is null."); } final StringBuilder b = new StringBuilder(s.trim().toLowerCase()); if (b.length() == 0) { throw new SLAMDException("Unable to parse a duration value because the " + "provided string is empty."); } int numSeconds = 0; while (b.length() > 0) { final int constantValue = extractNumeric(s, b); if (b.length() == 0) { numSeconds += constantValue; } else { final int unitValue = extractUnit(s, b); numSeconds += (constantValue * unitValue); } } return numSeconds; } /** * Extracts a numeric value from the provided buffer, removing digits as they * are encountered. * * @param s The original string value that was provided. * @param b The buffer to be processed. * * @return The numeric value that has been extracted. * * @throws SLAMDException If a problem is encountered. */ private static int extractNumeric(final String s, final StringBuilder b) throws SLAMDException { int value = 0; boolean digitFound = false; while (b.length() > 0) { final char c = b.charAt(0); switch (c) { case '0': value *= 10L; b.deleteCharAt(0); digitFound = true; break; case '1': value = (value * 10) + 1; b.deleteCharAt(0); digitFound = true; break; case '2': value = (value * 10) + 2; b.deleteCharAt(0); digitFound = true; break; case '3': value = (value * 10) + 3; b.deleteCharAt(0); digitFound = true; break; case '4': value = (value * 10) + 4; b.deleteCharAt(0); digitFound = true; break; case '5': value = (value * 10) + 5; b.deleteCharAt(0); digitFound = true; break; case '6': value = (value * 10) + 6; b.deleteCharAt(0); digitFound = true; break; case '7': value = (value * 10) + 7; b.deleteCharAt(0); digitFound = true; break; case '8': value = (value * 10) + 8; b.deleteCharAt(0); digitFound = true; break; case '9': value = (value * 10) + 9; b.deleteCharAt(0); digitFound = true; break; case ' ': case ',': b.deleteCharAt(0); break; default: if (! digitFound) { throw new SLAMDException("Unable to parse the provided string '" + s + "' as a duration because it was missing a numeric " + "element where one was expected."); } return value; } } return value; } /** * Extracts a unit from the provided buffer, removing the associated * characters as they are processed. * * @param s The original string that was provided. * @param b The buffer to be processed. * * @return The numeric value representing the number of seconds in that unit. * * @throws SLAMDException If a problem is encountered. */ private static int extractUnit(final String s, final StringBuilder b) throws SLAMDException { final StringBuilder unitBuffer = new StringBuilder(); while (b.length() > 0) { final char c = b.charAt(0); if (Character.isDigit(c)) { break; } if ((c == ' ') || (c == ',')) { b.deleteCharAt(0); break; } unitBuffer.append(c); b.deleteCharAt(0); } final String unit = unitBuffer.toString(); if (unit.equals("s") || unit.equals("sec") || unit.equals("secs") || unit.equals("second") || unit.equals("seconds")) { return 1; } else if (unit.equals("m") || unit.equals("min") || unit.equals("mins") || unit.equals("minute") || unit.equals("minutes")) { return 60; } else if (unit.equals("h") || unit.equals("hr") || unit.equals("hrs") || unit.equals("hour") || unit.equals("hours")) { return 3600; } else if (unit.equals("d") || unit.equals("day") || unit.equals("days")) { return 86400; } else { throw new SLAMDException("Unable to parse the provided string '" + s + "' as a duration because '" + unit + "' is not a supported unit."); } } /** * Provides a number of test cases for the duration parser. * * @param args The command-line arguments. */ public static void main(final String[] args) throws Exception { final String[] values = { "123456", "123456s", "123456sec", "123456secs", "123456second", "123456seconds", " 123456 s ", " 123456 sec ", " 123456 secs ", " 123456 second ", " 123456 seconds ", " 1 2 3 4 5 6 ", " 123,456 ", " 123,456 seconds ", " 1d37056s", " 1 d, 37056s", " 1 d , 37056s", "1 d 10 h 1056s", "1d10h17m36s", "1 d 10 h 17 m 36 s", "1 day 10 h 17 m 36 s", "1 days 10 h 17 m 36 s", "1 d 10 hr 17 m 36 s", "1 d 10 hrs 17 m 36 s", "1 d 10 hour 17 m 36 s", "1 d 10 hours 17 m 36 s", "1 d 10 h 17 min 36 s", "1 d 10 h 17 mins 36 s", "1 d 10 h 17 minute 36 s", "1 d 10 h 17 minutes 36 s", "1 d 10 h 17 m 36 sec", "1 d 10 h 17 m 36 secs", "1 d 10 h 17 m 36 second", "1 d 10 h 17 m 36 seconds", "1 day, 10 hours, 17 minutes, 36 seconds" }; for (final String s : values) { final int numSeconds = parse(s); if (numSeconds != 123456) { System.err.println("ERROR: String '" + s + "' was parsed as " + numSeconds); } else { System.out.println("String '" + s + "' was correctly parsed as " + numSeconds); } } } }