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 package org.apache.hc.core5.util;
29
30 import java.text.ParseException;
31 import java.time.Instant;
32 import java.time.ZoneOffset;
33 import java.time.format.DateTimeFormatter;
34 import java.time.format.DateTimeFormatterBuilder;
35 import java.util.concurrent.TimeUnit;
36
37
38
39
40
41
42
43 public class Deadline {
44
45
46
47
48 public static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
49
50
51
52
53 private static final long INTERNAL_MAX_VALUE = Long.MAX_VALUE;
54
55
56
57
58 private static final long INTERNAL_MIN_VALUE = 0;
59
60
61
62
63 public static Deadline MAX_VALUE = new Deadline(INTERNAL_MAX_VALUE);
64
65
66
67
68 public static Deadline MIN_VALUE = new Deadline(INTERNAL_MIN_VALUE);
69
70 private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
71 .parseLenient()
72 .parseCaseInsensitive()
73 .appendPattern(DATE_FORMAT)
74 .toFormatter();
75
76
77
78
79
80
81
82
83
84 public static Deadline calculate(final long timeMillis, final TimeValue timeValue) {
85 if (TimeValue.isPositive(timeValue)) {
86
87 final long deadline = timeMillis + timeValue.toMilliseconds();
88 return deadline < 0 ? Deadline.MAX_VALUE : Deadline.fromUnixMilliseconds(deadline);
89 }
90 return Deadline.MAX_VALUE;
91 }
92
93
94
95
96
97
98
99
100 public static Deadline calculate(final TimeValue timeValue) {
101 return calculate(System.currentTimeMillis(), timeValue);
102 }
103
104
105
106
107
108
109
110 public static Deadline fromUnixMilliseconds(final long value) {
111 if (value == INTERNAL_MAX_VALUE) {
112 return MAX_VALUE;
113 }
114 if (value == INTERNAL_MIN_VALUE) {
115 return MIN_VALUE;
116 }
117 return new Deadline(value);
118 }
119
120
121
122
123
124
125
126
127 public static Deadline parse(final String source) throws ParseException {
128 if (source == null) {
129 return null;
130 }
131 final Instant instant = Instant.from(DATE_TIME_FORMATTER.parse(source));
132 return fromUnixMilliseconds(instant.toEpochMilli());
133 }
134
135 private volatile boolean frozen;
136
137 private volatile long lastCheck;
138
139
140
141
142 private final long value;
143
144
145
146
147
148
149 private Deadline(final long deadlineMillis) {
150 super();
151 this.value = deadlineMillis;
152 setLastCheck();
153 }
154
155 @Override
156 public boolean equals(final Object obj) {
157
158 if (this == obj) {
159 return true;
160 }
161 if (obj == null) {
162 return false;
163 }
164 if (getClass() != obj.getClass()) {
165 return false;
166 }
167 final Deadline other = (Deadline) obj;
168 return value == other.value;
169 }
170
171 @Override
172 public int hashCode() {
173
174 return Long.hashCode(value);
175 }
176
177
178
179
180
181
182
183 public String format(final TimeUnit overdueTimeUnit) {
184 if (value == MAX_VALUE.value) {
185 return "No deadline (infinite)";
186 }
187 return String.format("Deadline: %s, %s overdue", formatTarget(), TimeValue.of(remaining(), overdueTimeUnit));
188 }
189
190
191
192
193
194
195 public String formatTarget() {
196 if (value == MAX_VALUE.value) {
197 return "(infinite)";
198 }
199 return DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(value).atOffset(ZoneOffset.UTC));
200 }
201
202 public Deadline freeze() {
203 frozen = true;
204 return this;
205 }
206
207
208
209
210
211
212 long getLastCheck() {
213 return lastCheck;
214 }
215
216
217
218
219
220
221 public long getValue() {
222 return value;
223 }
224
225
226
227
228
229
230
231 public boolean isBefore(final long millis) {
232 return value < millis;
233 }
234
235
236
237
238
239
240 public boolean isExpired() {
241 setLastCheck();
242 return value < this.lastCheck;
243 }
244
245
246
247
248
249
250 public boolean isMax() {
251 return value == INTERNAL_MAX_VALUE;
252 }
253
254
255
256
257
258
259 public boolean isMin() {
260 return value == INTERNAL_MIN_VALUE;
261 }
262
263
264
265
266
267
268 public boolean isNotExpired() {
269 setLastCheck();
270 return value >= this.lastCheck;
271 }
272
273
274
275
276
277
278
279 public Deadline min(final Deadline other) {
280 return value <= other.value ? this : other;
281 }
282
283
284
285
286
287
288 public long remaining() {
289 setLastCheck();
290 return value - lastCheck;
291 }
292
293
294
295
296
297
298 public TimeValue remainingTimeValue() {
299 return TimeValue.of(remaining(), TimeUnit.MILLISECONDS);
300 }
301
302 private void setLastCheck() {
303 if (!frozen) {
304 this.lastCheck = System.currentTimeMillis();
305 }}
306
307 @Override
308 public String toString() {
309 return formatTarget();
310 }
311
312 }