aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/query/ParameterParser.java
blob: a27e1bfde551dd40d3312bf85b6aa427f7212620 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.query;

import static com.yahoo.container.util.Util.quote;

/**
 * Wrapper class to avoid code duplication of common parsing requirements.
 *
 * @author <a href="steinar@yahoo-inc.com">Steinar Knutsen</a>
 */
public class ParameterParser {

    /**
     * Tries to return the given object as a Long. If it is a Number, treat it
     * as a number of seconds, i.e. get a Long representation and multiply by
     * 1000. If it has a String representation, try to parse this as a floating
     * point number, followed by by an optional unit (seconds and an SI prefix,
     * a couple of valid examples are "s" and "ms". Only a very small subset of
     * SI prefixes are supported). If no unit is given, seconds are assumed.
     *
     * @param value
     *                some representation of a number of seconds
     * @param defaultValue
     *                returned if value is null
     * @return value as a number of milliseconds
     * @throws NumberFormatException
     *                 if value is not a Number instance and its String
     *                 representation cannot be parsed as a number followed
     *                 optionally by time unit
     */
    public static Long asMilliSeconds(Object value, Long defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        if (value instanceof Number) {
            Number n = (Number) value;
            return Long.valueOf(n.longValue() * 1000L);
        }
        return parseTime(value.toString());
    }

    private static Long parseTime(String time) throws NumberFormatException {

        time = time.trim();
        try {
            int unitOffset = findUnitOffset(time);
            double measure = Double.valueOf(time.substring(0, unitOffset));
            double multiplier = parseUnit(time.substring(unitOffset));
            return Long.valueOf((long) (measure * multiplier));
        } catch (RuntimeException e) {
            throw new IllegalArgumentException("Error parsing " + quote(time), e);
        }
    }

    private static int findUnitOffset(String time) {
        int unitOffset = 0;
        while (unitOffset < time.length()) {
            char c = time.charAt(unitOffset);
            if (c == '.' || (c >= '0' && c <= '9')) {
                unitOffset += 1;
            } else {
                break;
            }
        }
        if (unitOffset == 0) {
            throw new NumberFormatException("Invalid number " + quote(time));
        }
        return unitOffset;
    }

    private static double parseUnit(String unit) {
        unit = unit.trim();
        final double multiplier;
        if ("ks".equals(unit)) {
            multiplier = 1e6d;
        } else if ("s".equals(unit)) {
            multiplier = 1000.0d;
        } else if ("ms".equals(unit)) {
            multiplier = 1.0d;
        } else if ("\u00B5s".equals(unit)) {
            // microseconds
            multiplier = 1e-3d;
        } else {
            multiplier = 1000.0d;
        }
        return multiplier;
    }
}