1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tradefed.util;
18 
19 import com.google.common.math.LongMath;
20 
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23 
24 /**
25  * This is a sentinel type which wraps a {@code Long}. It exists solely as a hint to the options
26  * parsing machinery that a particular value should be parsed as if it were a string representing a
27  * time value.
28  *
29  * @deprecated use {@link java.time.Duration} instead.
30  */
31 @SuppressWarnings("serial")
32 @Deprecated
33 public class TimeVal extends Number implements Comparable<Long> {
34     private static final Pattern TIME_PATTERN =
35             Pattern.compile("(?i)" +  // case insensitive
36                     "(?:(?<d>\\d+)d)?" +  // a number followed by "d"
37                     "(?:(?<h>\\d+)h)?" +
38                     "(?:(?<m>\\d+)m)?" +
39                     "(?:(?<s>\\d+)s)?" +
40                     "(?:(?<ms>\\d+)(?:ms)?)?");  // a number followed by "ms"
41 
42     private Long mValue = null;
43 
44     /**
45      * Constructs a newly allocated TimeVal object that represents the specified Long argument
46      */
TimeVal(Long value)47     public TimeVal(Long value) {
48         mValue = value;
49     }
50 
51     /**
52      * Constructs a newly allocated TimeVal object that represents the <emph>timestamp</emph>
53      * indicated by the String parameter.  The string is converted to a TimeVal in exactly the
54      * manner used by the {@link #fromString(String)} method.
55      */
TimeVal(String value)56     public TimeVal(String value) throws NumberFormatException {
57         mValue = fromString(value);
58     }
59 
60     /**
61      * @return the wrapped {@code Long} value.
62      */
asLong()63     public Long asLong() {
64         return mValue;
65     }
66 
67     /**
68      * Parses the string as a hierarchical time value
69      * <p />
70      * The default unit is millis.  The parser will accept {@code s} for seconds (1000 millis),
71      * {@code m} for minutes (60 seconds), {@code h} for hours (60 minutes), or {@code d} for days
72      * (24 hours).
73      * <p />
74      * Units may be mixed and matched, so long as each unit appears at most once, and so long as
75      * all units which do appear are listed in decreasing order of scale.  So, for instance,
76      * {@code h} may only appear before {@code m}, and may only appear after {@code d}.  As a
77      * specific example, "1d2h3m4s5ms" would be a valid time value, as would "4" or "4ms".  All
78      * embedded whitespace is discarded.
79      * <p />
80      * Do note that this method rejects overflows.  So the output number is guaranteed to be
81      * non-negative, and to fit within the {@code long} type.
82      */
fromString(String value)83     public static long fromString(String value) throws NumberFormatException {
84         if (value == null) throw new NumberFormatException("value is null");
85 
86         try {
87             value = value.replaceAll("\\s+", "");
88             Matcher m = TIME_PATTERN.matcher(value);
89             if (m.matches()) {
90                 // This works by, essentially, modifying the units of timeValue, from the
91                 // largest supported unit, until we've dropped down to millis.
92                 long timeValue = 0;
93                 timeValue = val(m.group("d"));
94 
95                 // 1 day == 24 hours
96                 timeValue = LongMath.checkedMultiply(timeValue, 24);
97                 timeValue = LongMath.checkedAdd(timeValue, val(m.group("h")));
98 
99                 // 1 hour == 60 minutes
100                 timeValue = LongMath.checkedMultiply(timeValue, 60);
101                 timeValue = LongMath.checkedAdd(timeValue, val(m.group("m")));
102 
103                 // 1 hour == 60 seconds
104                 timeValue = LongMath.checkedMultiply(timeValue, 60);
105                 timeValue = LongMath.checkedAdd(timeValue, val(m.group("s")));
106 
107                 // 1 second == 1000 millis
108                 timeValue = LongMath.checkedMultiply(timeValue, 1000);
109                 timeValue = LongMath.checkedAdd(timeValue, val(m.group("ms")));
110 
111                 return timeValue;
112             }
113         } catch (ArithmeticException e) {
114             throw new NumberFormatException(String.format(
115                     "Failed to parse value %s as a time value: %s", value, e.getMessage()));
116         }
117 
118         throw new NumberFormatException(
119                 String.format("Failed to parse value %s as a time value", value));
120     }
121 
val(String str)122     static long val(String str) throws NumberFormatException {
123         if (str == null) return 0;
124 
125         Long value = Long.parseLong(str);
126         return value;
127     }
128 
129 
130     // implementing interfaces
131     /**
132      * {@inheritDoc}
133      */
134     @Override
doubleValue()135     public double doubleValue() {
136         return mValue.doubleValue();
137     }
138 
139     /**
140      * {@inheritDoc}
141      */
142     @Override
floatValue()143     public float floatValue() {
144         return mValue.floatValue();
145     }
146 
147     /**
148      * {@inheritDoc}
149      */
150     @Override
intValue()151     public int intValue() {
152         return mValue.intValue();
153     }
154 
155     /**
156      * {@inheritDoc}
157      */
158     @Override
longValue()159     public long longValue() {
160         return mValue.longValue();
161     }
162 
163     /**
164      * {@inheritDoc}
165      */
166     @Override
compareTo(Long other)167     public int compareTo(Long other) {
168         return mValue.compareTo(other);
169     }
170 }
171