TimeService.java
/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2015-2016 ForgeRock AS.
*/
package org.forgerock.util.time;
/**
* Provides time related methods for computing durations, for providing the now
* instant and other use cases.
* <p>
* Why using a service interface instead of JVM provided time methods?
* <p>
* Simply because you gain better control over the time understood by the
* application. For example, if you would have to code an expiration time logic,
* you would check periodically if the computed expiration timestamp is greater
* than the now timestamp. So far, so good.
* <p>
* When it comes to testing, things gets worst: you typically have to use
* {@link Thread#sleep(long)} to wait for a given amount of time so that your
* expiration date is reached. That makes tests much longer to execute and
* somehow brittle when you're testing short timeouts.
* <p>
* Using a {@link TimeService} helps you to keep your code readable and provides
* a way to better control how the time is flowing for your application
* (especially useful in the tests).
* <p>
* For example, {@link #now()} is used in place of
* {@link System#currentTimeMillis()}. in your code and you can easily mock it
* and make it return controlled values. Here is an example with <a
* href="https://code.google.com/p/mockito/">Mockito</a>:
*
* <pre>
* @Mock
* private TimeService time;
*
* @BeforeMethod
* public void setUp() throws Exception {
* MockitoAnnotations.initMocks(this);
* }
*
* @Test
* public shouldAdvanceInTime() throws Exception {
* // Mimics steps in the future at each call
* when(time.now()).thenReturn(0L, 1000L, 10000L);
*
* assertThat(time.now()).isEqualTo(0L);
* assertThat(time.now()).isEqualTo(1000L);
* assertThat(time.now()).isEqualTo(10000L);
* }
* </pre>
*
* TimeService provides a {@linkplain #SYSTEM default service implementation}
* using the System provided time methods for ease of use.
*
* @see System#currentTimeMillis()
* @since 1.3.4
*/
public interface TimeService {
/**
* {@link TimeService} implementation based on {@link System}.
*
* @see System#currentTimeMillis()
* @since 1.3.4
*/
TimeService SYSTEM = new TimeService() {
@Override
public long now() {
return System.currentTimeMillis();
}
@Override
public long since(final long past) {
return now() - past;
}
};
/**
* Returns a value that represents "now" since the epoch.
*
* @return a value that represents "now" since the epoch.
* @since 1.3.4
*/
long now();
/**
* Computes the elapsed time between {@linkplain #now() now} and {@code past}.
*
* @param past
* time value to compare to now.
* @return the elapsed time
* @since 1.3.4
*/
long since(long past);
}