/*
* Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved.
*
* The Sun Project JXTA(TM) Software License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by Sun Microsystems, Inc. for JXTA(TM) technology."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
* not be used to endorse or promote products derived from this software
* without prior written permission. For written permission, please contact
* Project JXTA at http://www.jxta.org.
*
* 5. Products derived from this software may not be called "JXTA", nor may
* "JXTA" appear in their name, without prior written permission of Sun.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
* MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JXTA is a registered trademark of Sun Microsystems, Inc. in the United
* States and other countries.
*
* Please see the license information page at :
* <http://www.jxta.org/project/www/license.html> for instructions on use of
* the license in source files.
*
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of Project JXTA. For more information on Project JXTA, please see
* http://www.jxta.org.
*
* This license is based on the BSD license adopted by the Apache Foundation.
*/
package net.jxta.impl.util;
/**
* Utilities for manipulating absolute and relative times and for accelerating
* and decelerating time for testing purposes.
* <p/>
* The "time warp" functionality is useful for debugging and is scoped to
* the class loader in which the TimeUtils class is loaded.
* <p/>
* Additionally, an alternative {@link SystemClock} implementation can be provided
* to decouple your tests from the real system clock. This is particularly useful
* for precise control over time for time-dependent behaviour tests, without
* needing to use Thread.sleep() or a busy-wait loop.
*/
public final class TimeUtils {
/**
* Zero milliseconds (yes its redundant).
*/
public static final long ZEROMILLISECONDS = 0L;
/**
* The number of milliseconds in a millisecond. (yes its redundant).
*/
public static final long AMILLISECOND = 1L;
/**
* The number of milliseconds in a hundredth of a second.
*/
public static final long AHUNDREDTHOFASECOND = 10 * AMILLISECOND;
/**
* The number of milliseconds in a tenth of a second.
*/
public static final long ATENTHOFASECOND = 100 * AMILLISECOND;
/**
* The number of milliseconds in a second.
*/
public static final long ASECOND = 1000 * AMILLISECOND;
/**
* The number of milliseconds in a minute.
*/
public static final long AMINUTE = 60 * ASECOND;
/**
* The number of milliseconds in an hour.
*/
public static final long ANHOUR = 60 * AMINUTE;
/**
* The number of milliseconds in a day.
*/
public static final long ADAY = 24 * ANHOUR;
/**
* The number of milliseconds in a week.
*/
public static final long AWEEK = 7 * ADAY;
/**
* The number of milliseconds in a fortnight (two weeks).
*/
public static final long AFORTNIGHT = 14 * ADAY;
/**
* The number of milliseconds in the month of January.
*/
public static final long AJANUARY = 31 * ADAY;
/**
* The number of milliseconds in the month of February in a non-leap year.
*/
public static final long AFEBRUARY = 28 * ADAY;
/**
* The number of milliseconds in the month of February in a leap year.
*/
public static final long ALEAPFEBRUARY = 29 * ADAY;
/**
* The number of milliseconds in the month of March.
*/
public static final long AMARCH = 31 * ADAY;
/**
* The number of milliseconds in the month of April.
*/
public static final long ANAPRIL = 30 * ADAY;
/**
* The number of milliseconds in the month of May.
*/
public static final long AMAY = 31 * ADAY;
/**
* The number of milliseconds in the month of June.
*/
public static final long AJUNE = 30 * ADAY;
/**
* The number of milliseconds in the month of July.
*/
public static final long AJULY = 31 * ADAY;
/**
* The number of milliseconds in the month of August.
*/
public static final long ANAUGUST = 31 * ADAY;
/**
* The number of milliseconds in the month of September.
*/
public static final long ASEPTEMBER = 30 * ADAY;
/**
* The number of milliseconds in the month of October.
*/
public static final long ANOCTOBER = 31 * ADAY;
/**
* The number of milliseconds in the month of November.
*/
public static final long ANOVEMBER = 30 * ADAY;
/**
* The number of milliseconds in the month of December.
*/
public static final long ADECEMBER = 31 * ADAY;
/**
* The number of milliseconds in a non-leap year.
*/
public static final long AYEAR = AJANUARY + AFEBRUARY + AMARCH + ANAPRIL + AMAY + AJUNE + AJULY + ANAUGUST + ASEPTEMBER
+ ANOCTOBER + ANOVEMBER + ADECEMBER;
/**
* The number of milliseconds in a leap year.
*/
public static final long ALEAPYEAR = AJANUARY + ALEAPFEBRUARY + AMARCH + ANAPRIL + AMAY + AJUNE + AJULY + ANAUGUST
+ ASEPTEMBER + ANOCTOBER + ANOVEMBER + ADECEMBER;
/**
* This odd little guy is for use in testing. it is applied anywhere the
* current time is used and allows modules which use timeutils to be tested
* through long (simulated) periods of time passing.
*/
static volatile long TIMEWARP = 0;
/**
* Absolute time in millis at which we began timewarping.
*/
static long WARPBEGAN = 0;
/**
* The rate at which time is warped using the auto-warper.
*/
static double WARPFACTOR = 1.0;
/**
* Don't let anyone instantiate this class.
*/
private TimeUtils() {
}
private static SystemClock clock = new JavaSystemClock();
public static void setClock(SystemClock sc) {
clock = sc;
}
public static void resetClock() {
clock = new JavaSystemClock();
}
/**
* @return The current time which has been possibly adjusted for testing purposes
*/
public static long timeNow() {
long now = clock.getCurrentTime();
if (WARPFACTOR != 1.0) {
long elapsed = now - WARPBEGAN;
long dialation = (long) (elapsed * WARPFACTOR);
TIMEWARP += (dialation - elapsed);
}
return now + TIMEWARP;
}
/**
* Convert a duration into a duration expressed in milliseconds to absolute
* time realtive to the current real time. Special handling for the maximum
* and minimum durations converts them to the maximum and minimum absolute
* times.
*
* @param duration a time duration expressed in milliseconds.
* @return an absolute time in milliseconds based on the duration's
* relation to the current real time.
*/
public static long toAbsoluteTimeMillis(long duration) {
return toAbsoluteTimeMillis(duration, timeNow());
}
/**
* Convert a duration into a duration expressed in milliseconds to absolute
* time realtive to the provided absolute time. Special handling for the
* maximum and minimum durations converts them to the maximum and minimum
* absolute times.
*
* @param duration a time duration expressed in milliseconds.
* @param fromWhen an absolute time expressed in milliseconds.
* @return an absolute time in milliseconds based on the duration's
* relation to the provided absolute time.
*/
public static long toAbsoluteTimeMillis(long duration, long fromWhen) {
// Special cases for the boundaries.
if (Long.MAX_VALUE == duration) {
return Long.MAX_VALUE;
}
if (Long.MIN_VALUE == duration) {
return Long.MIN_VALUE;
}
long whence = fromWhen + duration;
if (duration > 0) {
// check for overflow
if (whence < fromWhen) {
whence = Long.MAX_VALUE;
}
} else {
// check for underflow
if (whence > fromWhen) {
whence = Long.MIN_VALUE;
}
}
return whence;
}
/**
* Convert an absolute real time in milliseconds to a duration relative
* to the current real time. Special handling for the maximum and minimum
* absolute times converts them to the maximum and minimum durations.
*
* @param whence an absolute real time expressed in milliseconds.
* @return a duration expressed in milliseconds relative to the current
* real time.
*/
public static long toRelativeTimeMillis(long whence) {
return toRelativeTimeMillis(whence, timeNow());
}
/**
* Convert an absolute real time in milliseconds to a duration relative
* to the specified absolute real time. Special handling for the maximum
* and minimum absolute times converts them to the maximum and minimum
* durations.
*
* @param whence An absolute real time expressed in milliseconds.
* @param fromWhen The base time in absolute real time expressed in
* milliseconds from which the relative time will be calculated.
* @return a duration expressed in milliseconds relative to the provided
* absolute time.
*/
public static long toRelativeTimeMillis(long whence, long fromWhen) {
// Special cases for the boundaries.
if (Long.MAX_VALUE == whence) {
return Long.MAX_VALUE;
}
if (Long.MIN_VALUE == whence) {
return Long.MIN_VALUE;
}
return whence - fromWhen;
}
/**
* Multiplies a duration in relative milliseconds by a multiplier while
* accounting for overflow and underflow of the magnitude value.
*
* @param duration a time duration expressed in milliseconds.
* @param multiplier a non-negative value which will be multiplied against
* the duration.
* @return a time duration expressed in milliseconds.
*/
public static long multiplyRelativeTimeMillis(long duration, long multiplier) {
if (multiplier < 0) {
throw new IllegalArgumentException("Only non-negative multipliers are allowed.");
}
long result_mag = (Long.MIN_VALUE != duration)
? Long.highestOneBit(Math.abs(duration)) + Long.highestOneBit(multiplier)
: Long.SIZE + Long.highestOneBit(multiplier);
long result = duration * multiplier;
if (result_mag > (Long.SIZE - 1)) {
// over or underflowed
result = (duration < 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
}
return result;
}
/**
* A utility for advancing the timewarp by the number of milliseconds
* specified. May not be used if you are also using {@link #autoWarp(double)}.
*
* @param advanceby Advance the timewarp by the number of milliseconds
* specified.
*/
public static void timeWarp(long advanceby) {
if (0 != WARPBEGAN) {
throw new IllegalStateException("auto time warping already initialized at warp factor " + WARPFACTOR);
}
TIMEWARP += advanceby;
}
/**
* A utility for automagically adjusting the time dialation of the
* time warp.
*
* @param warpfactor a decimal ratio at which artifical time will pass.
* <p/>
* <ul>
* <li>To have time pass at the rate of an hour every minute, initialize
* with: <tt>(double)(TimeUtils.ANHOUR / TimeUtils.AMINUTE)</tt>.</li>
* <li>To have time pass at five times normal rate, initialize
* with: <tt>5.0</tt>.</li>
* <li>etc.</li>
* </ul>
*/
public static void autoWarp(double warpfactor) {
if (0 != WARPBEGAN) {
throw new IllegalStateException("Auto time warping already initialized at warp factor " + WARPFACTOR);
}
if (warpfactor <= 0.0) {
throw new IllegalArgumentException("Time should not stand still or run backwards. It's unnatural.");
}
if (warpfactor != 1.0) {
WARPFACTOR = warpfactor;
WARPBEGAN = System.currentTimeMillis();
}
}
/**
* Return a relative time adjusted by the current warping factor.
* Needed for external methods which do not use {@link #timeNow()} such
* as {@link Object#wait(long)} and
* {@link java.net.Socket#setSoTimeout(int)}.
*
* @param initial The initial time value to "warp".
* @return The provided initial time adjusted by the current warping factor.
*/
public static long warpedRelativeTime(long initial) {
if (0 == initial) {
return 0;
}
long adjusted = (long) (initial * WARPFACTOR);
// Handle overflow and underflow
if (initial < 0) {
if (adjusted >= 0) {
adjusted = Long.MIN_VALUE;
}
} else {
if (adjusted < 0) {
adjusted = Long.MAX_VALUE;
}
}
// since 0 is usually a special "wait forever" value we don't allow time
// to be reduced to zero because that would cause a change of behaviour
// in many cases.
return (0 != adjusted) ? adjusted : 1;
}
}