View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.core5.util;
29  
30  import java.text.ParseException;
31  import java.text.SimpleDateFormat;
32  import java.util.Objects;
33  import java.util.concurrent.TimeUnit;
34  
35  /**
36   * A deadline based on a UNIX time, the elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January
37   * 1970.
38   *
39   * @since 5.0
40   */
41  public class Deadline {
42  
43      /**
44       * The format used for parsing and formatting dates.
45       */
46      public static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
47  
48      /**
49       * A special internal value that marks a deadline as the longest possible.
50       */
51      private static final long INTERNAL_MAX_VALUE = Long.MAX_VALUE;
52  
53      /**
54       * A special internal value that marks a deadline as the shortest possible.
55       */
56      private static final long INTERNAL_MIN_VALUE = 0;
57  
58      /**
59       * The maximum (longest-lived) deadline.
60       */
61      public static Deadlineine.html#Deadline">Deadline MAX_VALUE = new Deadline(INTERNAL_MAX_VALUE);
62  
63      /**
64       * The minimum (shortest-lived) deadline.
65       */
66      public static Deadlineine.html#Deadline">Deadline MIN_VALUE = new Deadline(INTERNAL_MIN_VALUE);
67  
68      private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT);
69  
70      /**
71       * Calculates a deadline with a given time in milliseconds plus a given time value. Non-positive time values
72       * represent an indefinite timeout without a deadline.
73       *
74       * @param timeMillis A time in UNIX milliseconds, usually the current time.
75       * @param timeValue time value to add to {@code timeMillis}.
76       * @return a deadline representing the current time plus the given time value.
77       */
78      public static Deadline calculate(final long timeMillis, final TimeValue timeValue) {
79          if (TimeValue.isPositive(timeValue)) {
80              // TODO handle unlikely overflow
81              final long deadline = timeMillis + timeValue.toMilliseconds();
82              return deadline < 0 ? Deadline.MAX_VALUE : Deadline.fromUnixMilliseconds(deadline);
83          }
84          return Deadline.MAX_VALUE;
85      }
86  
87      /**
88       * Calculates a deadline from now plus a given time value. Non-positive time values
89       * represent an indefinite timeout without a deadline.
90       *
91       * @param timeValue time value to add to {@code timeMillis}.
92       * @return a deadline representing the current time plus the given time value.
93       */
94      public static Deadline calculate(final TimeValue timeValue) {
95          return calculate(System.currentTimeMillis(), timeValue);
96      }
97  
98      /**
99       * Creates a deadline from a UNIX time in milliseconds.
100      *
101      * @param value a UNIX time in milliseconds.
102      * @return a new deadline.
103      */
104     public static Deadline fromUnixMilliseconds(final long value) {
105         if (value == INTERNAL_MAX_VALUE) {
106             return MAX_VALUE;
107         }
108         if (value == INTERNAL_MIN_VALUE) {
109             return MIN_VALUE;
110         }
111         return new Deadline(value);
112     }
113 
114     /**
115      * Creates a deadline from a string in the format {@value #DATE_FORMAT}.
116      *
117      * @param source a string in the format {@value #DATE_FORMAT}.
118      * @return a deadline from a string in the format {@value #DATE_FORMAT}.
119      * @throws ParseException if the specified source string cannot be parsed.
120      */
121     public static Deadline parse(final String source) throws ParseException {
122         return fromUnixMilliseconds(simpleDateFormat.parse(source).getTime());
123     }
124 
125     private volatile boolean frozen;
126 
127     private volatile long lastCheck;
128 
129     /*
130      * Internal representation is a UNIX time.
131      */
132     private final long value;
133 
134     /**
135      * Constructs a new instance with the given UNIX time in milliseconds.
136      *
137      * @param deadlineMillis UNIX time in milliseconds.
138      */
139     private Deadline(final long deadlineMillis) {
140         super();
141         this.value = deadlineMillis;
142         setLastCheck();
143     }
144 
145     @Override
146     public boolean equals(final Object obj) {
147         // Only take into account the deadline value.
148         if (this == obj) {
149             return true;
150         }
151         if (obj == null) {
152             return false;
153         }
154         if (getClass() != obj.getClass()) {
155             return false;
156         }
157         final Deadline./../../../../org/apache/hc/core5/util/Deadline.html#Deadline">Deadline other = (Deadline) obj;
158         return value == other.value;
159     }
160 
161     /**
162      * Formats this deadline.
163      *
164      * @param overdueTimeUnit the time unit to show how much over the deadline we are.
165      * @return a formatted string.
166      */
167     public String format(final TimeUnit overdueTimeUnit) {
168         return String.format("Deadline: %s, %s overdue", formatTarget(), remainingTimeValue());
169     }
170 
171     /**
172      * Formats the deadline value as a string in the format {@value #DATE_FORMAT}.
173      *
174      * @return a formatted string in the format {@value #DATE_FORMAT}.
175      */
176     public String formatTarget() {
177         return simpleDateFormat.format(value);
178     }
179 
180     public Deadline freeze() {
181         frozen = true;
182         return this;
183     }
184 
185     /**
186      * Package private for testing.
187      *
188      * @return the last time we checked the current time.
189      */
190     long getLastCheck() {
191         return lastCheck;
192     }
193 
194     /**
195      * Gets the UNIX time deadline value.
196      *
197      * @return the UNIX time deadline value.
198      */
199     public long getValue() {
200         return value;
201     }
202 
203     @Override
204     public int hashCode() {
205         // Only take into account the deadline value.
206         return Objects.hash(value);
207     }
208 
209     /**
210      * Returns whether this deadline occurs before the given time in milliseconds.
211      *
212      * @param millis the time to compare.
213      * @return whether this deadline occurs before the given time in milliseconds.
214      */
215     public boolean isBefore(final long millis) {
216         return value < millis;
217     }
218 
219     /**
220      * Returns whether the deadline has expired.
221      *
222      * @return whether the deadline has expired.
223      */
224     public boolean isExpired() {
225         setLastCheck();
226         return value < this.lastCheck;
227     }
228 
229     /**
230      * Returns whether this deadline is the maximum deadline.
231      *
232      * @return whether this deadline is the maximum deadline.
233      */
234     public boolean isMax() {
235         return value == INTERNAL_MAX_VALUE;
236     }
237 
238     /**
239      * Returns whether this deadline is the minimum deadline.
240      *
241      * @return whether this deadline is the minimum deadline.
242      */
243     public boolean isMin() {
244         return value == INTERNAL_MIN_VALUE;
245     }
246 
247     /**
248      * Returns whether this deadline has not expired.
249      *
250      * @return whether this deadline has not expired.
251      */
252     public boolean isNotExpired() {
253         setLastCheck();
254         return value >= this.lastCheck;
255     }
256 
257     /**
258      * Returns the smaller of this and another {@code Deadline}.
259      *
260      * @param other another deadline.
261      * @return the smaller of {@code this} and {@code other}.
262      */
263     public Deadline/Deadline.html#Deadline">Deadline min(final Deadline other) {
264         return value <= other.value ? this : other;
265     }
266 
267     /**
268      * Returns the difference in milliseconds between the deadline and now.
269      *
270      * @return the different in milliseconds between the deadline and now.
271      */
272     public long remaining() {
273         setLastCheck();
274         return value - lastCheck;
275     }
276 
277     /**
278      * Returns the difference as a TimeValue between the deadline and now.
279      *
280      * @return Returns the different as a TimeValue between the deadline and now.
281      */
282     public TimeValue remainingTimeValue() {
283         return TimeValue.of(remaining(), TimeUnit.MILLISECONDS);
284     }
285 
286     private void setLastCheck() {
287         if (!frozen) {
288             this.lastCheck = System.currentTimeMillis();
289         }}
290 
291     @Override
292     public String toString() {
293         return formatTarget();
294     }
295 
296 }