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 } else {
187 return String.format("Deadline: %s, %s overdue", formatTarget(), TimeValue.of(remaining(), overdueTimeUnit));
188 }
189 }
190
191
192
193
194
195
196 public String formatTarget() {
197 if (value == MAX_VALUE.value) {
198 return "(infinite)";
199 } else {
200 return DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(value).atOffset(ZoneOffset.UTC));
201 }
202 }
203
204 public Deadline freeze() {
205 frozen = true;
206 return this;
207 }
208
209
210
211
212
213
214 long getLastCheck() {
215 return lastCheck;
216 }
217
218
219
220
221
222
223 public long getValue() {
224 return value;
225 }
226
227
228
229
230
231
232
233 public boolean isBefore(final long millis) {
234 return value < millis;
235 }
236
237
238
239
240
241
242 public boolean isExpired() {
243 setLastCheck();
244 return value < this.lastCheck;
245 }
246
247
248
249
250
251
252 public boolean isMax() {
253 return value == INTERNAL_MAX_VALUE;
254 }
255
256
257
258
259
260
261 public boolean isMin() {
262 return value == INTERNAL_MIN_VALUE;
263 }
264
265
266
267
268
269
270 public boolean isNotExpired() {
271 setLastCheck();
272 return value >= this.lastCheck;
273 }
274
275
276
277
278
279
280
281 public Deadline min(final Deadline other) {
282 return value <= other.value ? this : other;
283 }
284
285
286
287
288
289
290 public long remaining() {
291 setLastCheck();
292 return value - lastCheck;
293 }
294
295
296
297
298
299
300 public TimeValue remainingTimeValue() {
301 return TimeValue.of(remaining(), TimeUnit.MILLISECONDS);
302 }
303
304 private void setLastCheck() {
305 if (!frozen) {
306 this.lastCheck = System.currentTimeMillis();
307 }}
308
309 @Override
310 public String toString() {
311 return formatTarget();
312 }
313
314 }