<commit_before>/*
 * $Id: Deadline.java,v 1.12 2002-12-13 02:21:29 tal Exp $
 */

/*

Copyright (c) 2000-2002 Board of Trustees of Leland Stanford Jr. University,
all rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
STANFORD UNIVERSITY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of Stanford University shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Stanford University.

*/

package org.lockss.util;
import java.util.*;
import java.text.*;

/** Deadline represents a time (at which some operation must complete).
 */
public class Deadline implements Comparable {
  /** A long time from now (but not really never). */
  public static final Deadline NEVER = new Deadline(Long.MAX_VALUE);

  protected static Logger log = Logger.getLogger("Deadline");

  private static LockssRandom random = null;
  protected Date expiration;
  protected long duration;		// only for testing
  private List subscribers;		// those who wish to be notified
					// if/when this Deadline's duration
					// changes
  
  /** Create a Deadline that expires at the specified Date, with the
   * specified duration.  Done this way so factory methods don't risk a
   * timer tick between getting the current time, and the constructor
   * computing the duration, which would then be different from what was
   * specified.
   */
  private Deadline(Date at, long duration) {
    expiration = at;
    this.duration = duration;
  }
  
  /** Create a Deadline that expires at the specified Date. */
  private Deadline(Date at) {
    duration = at.getTime() - nowMs();
    expiration = at;
  }
  
  /** Create a Deadline that expires at the specified date. */
  private Deadline(long at) {
    this(new Date(at));
  }
  
  /** Create a Deadline that expires in <code>duration</code> milliseconds. */
  public static Deadline in(long duration) {
    return new Deadline(new Date(nowMs() + duration), duration);
  }

  /** Create a Deadline representing the specified Date.
   * @param at
   */
  public static Deadline at(Date at) {
    return new Deadline(at);
  }
  
  /** Create a Deadline representing the specified date/time.
   * @param at date/time in milliseconds from the epoch.
   */
  public static Deadline at(long at) {
    return new Deadline(at);
  }
  
  /** Create a Deadline representing a random time between
   * <code>earliest</code> (inclusive) and <code>latest</code> (exclusive).
   * The random time is uniformly distributed between the endpoints.
   * @param earliest The earliest possible time
   * @param latest The latest possible time
   */
  public static Deadline atRandomRange(long earliest, long latest) {
    return new Deadline(earliest + getRandom().nextLong(latest - earliest));
  }

  /** Create a Deadline representing a random time between now (inclusive)
   * and <code>before</code> (exclusive).  The random time is uniformly
   * distributed.
   * @param before The time before which the deadline should expire
   */
  public static Deadline atRandomBefore(long before) {
    return atRandomRange(nowMs(), before);
  }

  /** Create a Deadline representing a random time between
   * <code>earliest</code> (inclusive) and <code>latest</code> (exclusive).
   * The random time is uniformly distributed between the endpoints.
   * @param earliest The earliest possible time
   * @param latest The latest possible time
   */
  public static Deadline atRandomRange(Deadline earliest, Deadline latest) {
    return atRandomRange(earliest.getExpirationTime(),
			 latest.getExpirationTime());
  }

  /** Create a Deadline representing a random time between now (inclusive)
   * and <code>before</code> (exclusive).  The random time is uniformly
   * distributed.
   * @param before The time before which the deadline should expire
   */
  public static Deadline atRandomBefore(Deadline before) {
    return atRandomRange(nowMs(), before.getExpirationTime());
  }

  /** Create a Deadline representing a random time between
   * <code>minDuration</code> (inclusive) and <code>maxDuration</code>
   * (exclusive) milliseconds from now.  The random time is uniformly
   * distributed between the endpoints.
   * @param minDuration The minimum duration, in milliseconds.
   * @param maxDuration The maximum duration, in milliseconds.
   */
  public static Deadline inRandomRange(long minDuration, long maxDuration) {
    return atRandomRange(nowMs() + minDuration, nowMs() + maxDuration);
  }

  /** Create a Deadline representing a random time between now (inclusive)
   * and <code>maxDuration</code> (exclusive) milliseconds from now.  The
   * random time is uniformly distributed.
   * @param maxDuration The maximum duration, in milliseconds.
   */
  public static Deadline inRandomBefore(long maxDuration) {
    return inRandomRange(0, maxDuration);
  }

//   /** Return a timer whose duration is a random, normally distrubuted value
//    * whose mean is <code>meanDuration</code> and standard deviation
//    * <code>stddev</code>.  */
//   public Deadline withinOf(double stddev, long meanDuration) {
//     super(meanDuration + (long)(stddev * getRandom().nextGaussian()));
//   }

  /** Return the absolute expiration time, in milliseconds */
  public long getExpirationTime() {
    return expiration.getTime();
  }

  /** Return the expiration time as a Date */
  public Date getExpiration() {
    return expiration;
  }

  /** Return the time remaining until expiration, in milliseconds.
   * This method should not be used to obtain a duration to sleep; use
   * {@link #getSleepTime()} for that.
   */
  public synchronized long getRemainingTime() {
    return (expired() ? 0 : expiration.getTime() - nowMs());
  }

  /** Return the time to sleep, in milliseconds.
   * This method should be used instead of {@link #getRemainingTime()} to
   * determine how long to sleep.  When operating with the real time base
   * it returns the same value as getRemainingTime().  When using a fake
   * time base for debugging, it returns a small number so that any sleeps
   * will complete quickly, as it is impossible to predict when the fake
   * time base will be advanced to the deadline.
  */
  public synchronized long getSleepTime() {
    if (TimeBase.isSimulated()) {
      return expired() ? 0 : 5;
    } else {
      return getRemainingTime();
    }
  }

  /** Return true iff the timer has expired */
  public synchronized boolean expired() {
    return (!now().before(expiration));
  }

  /** Return true iff this deadline expires before <code>other</code>. */
  public boolean before(Deadline other) {
    return expiration.before(other.expiration);
  }

  /** Cause the deadline to expire immediately */
  public synchronized void expire() {
    expiration.setTime(0);
    changed();
  }

  /** Change expiration time to n milliseconds from now. */
  public synchronized void expireIn(long millis) {
    expiration.setTime(millis);
    changed();
  }

  /** Add <code>delta</code> milliseconds to the deadline. */
  public synchronized void later(long delta) {
    expireIn(expiration.getTime() + delta);
  }

  /** Subtract <code>delta</code> from the deadline. */
  public synchronized void sooner(long delta) {
    expireIn(expiration.getTime() - delta);
  }

  /** Register a callback that will be called if/when the Deadline's
   * duration changes (by a call to expire(), sooner(), etc.)
   */
  public synchronized void registerCallback(Callback callback) {
    if (subscribers == null) {
      subscribers = new LinkedList();
    }
    subscribers.add(callback);
  }

  /** Unregister a change callback */
  public synchronized void unregisterCallback(Callback callback) {
    subscribers.remove(callback);
  }

  /** Call dedlineChanged() method of all sunbscribers   */
  protected synchronized void changed() {
    if (subscribers != null) {
      for (Iterator iter = subscribers.iterator(); iter.hasNext(); ) {
	// tk - run these in a separate thread
	try {
	  Callback cb = (Callback)iter.next();
	  cb.changed(this);
	} catch (Exception e) {
	  log.error("Callback threw", e);<commit_msg>Fixed expireIn(), added expireAt()<commit_after>/*
 * $Id: Deadline.java,v 1.13 2002-12-13 23:07:29 tal Exp $
 */

/*

Copyright (c) 2000-2002 Board of Trustees of Leland Stanford Jr. University,
all rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
STANFORD UNIVERSITY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of Stanford University shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Stanford University.

*/

package org.lockss.util;
import java.util.*;
import java.text.*;

/** Deadline represents a time (at which some operation must complete).
 */
public class Deadline implements Comparable {
  /** A long time from now (but not really never). */
  public static final Deadline NEVER = new Deadline(Long.MAX_VALUE);

  protected static Logger log = Logger.getLogger("Deadline");

  private static LockssRandom random = null;
  protected Date expiration;
  protected long duration;		// only for testing
  private List subscribers;		// those who wish to be notified
					// if/when this Deadline's duration
					// changes
  
  /** Create a Deadline that expires at the specified Date, with the
   * specified duration.  Done this way so factory methods don't risk a
   * timer tick between getting the current time, and the constructor
   * computing the duration, which would then be different from what was
   * specified.
   */
  private Deadline(Date at, long duration) {
    expiration = at;
    this.duration = duration;
  }
  
  /** Create a Deadline that expires at the specified Date. */
  private Deadline(Date at) {
    duration = at.getTime() - nowMs();
    expiration = at;
  }
  
  /** Create a Deadline that expires at the specified date. */
  private Deadline(long at) {
    this(new Date(at));
  }
  
  /** Create a Deadline that expires in <code>duration</code> milliseconds. */
  public static Deadline in(long duration) {
    return new Deadline(new Date(nowMs() + duration), duration);
  }

  /** Create a Deadline representing the specified Date.
   * @param at
   */
  public static Deadline at(Date at) {
    return new Deadline(at);
  }
  
  /** Create a Deadline representing the specified date/time.
   * @param at date/time in milliseconds from the epoch.
   */
  public static Deadline at(long at) {
    return new Deadline(at);
  }
  
  /** Create a Deadline representing a random time between
   * <code>earliest</code> (inclusive) and <code>latest</code> (exclusive).
   * The random time is uniformly distributed between the endpoints.
   * @param earliest The earliest possible time
   * @param latest The latest possible time
   */
  public static Deadline atRandomRange(long earliest, long latest) {
    return new Deadline(earliest + getRandom().nextLong(latest - earliest));
  }

  /** Create a Deadline representing a random time between now (inclusive)
   * and <code>before</code> (exclusive).  The random time is uniformly
   * distributed.
   * @param before The time before which the deadline should expire
   */
  public static Deadline atRandomBefore(long before) {
    return atRandomRange(nowMs(), before);
  }

  /** Create a Deadline representing a random time between
   * <code>earliest</code> (inclusive) and <code>latest</code> (exclusive).
   * The random time is uniformly distributed between the endpoints.
   * @param earliest The earliest possible time
   * @param latest The latest possible time
   */
  public static Deadline atRandomRange(Deadline earliest, Deadline latest) {
    return atRandomRange(earliest.getExpirationTime(),
			 latest.getExpirationTime());
  }

  /** Create a Deadline representing a random time between now (inclusive)
   * and <code>before</code> (exclusive).  The random time is uniformly
   * distributed.
   * @param before The time before which the deadline should expire
   */
  public static Deadline atRandomBefore(Deadline before) {
    return atRandomRange(nowMs(), before.getExpirationTime());
  }

  /** Create a Deadline representing a random time between
   * <code>minDuration</code> (inclusive) and <code>maxDuration</code>
   * (exclusive) milliseconds from now.  The random time is uniformly
   * distributed between the endpoints.
   * @param minDuration The minimum duration, in milliseconds.
   * @param maxDuration The maximum duration, in milliseconds.
   */
  public static Deadline inRandomRange(long minDuration, long maxDuration) {
    return atRandomRange(nowMs() + minDuration, nowMs() + maxDuration);
  }

  /** Create a Deadline representing a random time between now (inclusive)
   * and <code>maxDuration</code> (exclusive) milliseconds from now.  The
   * random time is uniformly distributed.
   * @param maxDuration The maximum duration, in milliseconds.
   */
  public static Deadline inRandomBefore(long maxDuration) {
    return inRandomRange(0, maxDuration);
  }

//   /** Return a timer whose duration is a random, normally distrubuted value
//    * whose mean is <code>meanDuration</code> and standard deviation
//    * <code>stddev</code>.  */
//   public Deadline withinOf(double stddev, long meanDuration) {
//     super(meanDuration + (long)(stddev * getRandom().nextGaussian()));
//   }

  /** Return the absolute expiration time, in milliseconds */
  public long getExpirationTime() {
    return expiration.getTime();
  }

  /** Return the expiration time as a Date */
  public Date getExpiration() {
    return expiration;
  }

  /** Return the time remaining until expiration, in milliseconds.
   * This method should not be used to obtain a duration to sleep; use
   * {@link #getSleepTime()} for that.
   */
  public synchronized long getRemainingTime() {
    return (expired() ? 0 : expiration.getTime() - nowMs());
  }

  /** Return the time to sleep, in milliseconds.
   * This method should be used instead of {@link #getRemainingTime()} to
   * determine how long to sleep.  When operating with the real time base
   * it returns the same value as getRemainingTime().  When using a fake
   * time base for debugging, it returns a small number so that any sleeps
   * will complete quickly, as it is impossible to predict when the fake
   * time base will be advanced to the deadline.
  */
  public synchronized long getSleepTime() {
    if (TimeBase.isSimulated()) {
      return expired() ? 0 : 5;
    } else {
      return getRemainingTime();
    }
  }

  /** Return true iff the timer has expired */
  public synchronized boolean expired() {
    return (!now().before(expiration));
  }

  /** Return true iff this deadline expires before <code>other</code>. */
  public boolean before(Deadline other) {
    return expiration.before(other.expiration);
  }

  /** Cause the deadline to expire immediately */
  public synchronized void expire() {
    expiration.setTime(0);
    changed();
  }

  /** Change expiration time to time n. */
  public synchronized void expireAt(long millis) {
    expiration.setTime(millis);
    changed();
  }

  /** Change expiration time to n milliseconds from now. */
  public synchronized void expireIn(long millis) {
    expiration.setTime(nowMs() + millis);
    changed();
  }

  /** Add <code>delta</code> milliseconds to the deadline. */
  public synchronized void later(long delta) {
    expireAt(expiration.getTime() + delta);
  }

  /** Subtract <code>delta</code> from the deadline. */
  public synchronized void sooner(long delta) {
    expireAt(expiration.getTime() - delta);
  }

  /** Register a callback that will be called if/when the Deadline's
   * duration changes (by a call to expire(), sooner(), etc.)
   */
  public synchronized void registerCallback(Callback callback) {
    if (subscribers == null) {
      subscribers = new LinkedList();
    }
    subscribers.add(callback);
  }

  /** Unregister a change callback */
  public synchronized void unregisterCallback(Callback callback) {
    subscribers.remove(callback);
  }

  /** Call dedlineChanged() method of all sunbscribers   */
  protected synchronized void changed() {
    if (subscribers != null) {
      for (Iterator iter = subscribers.iterator(); iter.hasNext(); ) {
	// tk - run these in a separate thread
	try {
	  Callback cb = (Callback)iter.next();
	  cb.changed(this);
	} catch (Exception e) {
	  log.error("Callback threw", e);
{'fraction_non_alphanumeric': 0.09194963754292255, 'fraction_numerical': 0.0032702894206137244, 'mean_word_length': 3.605421686746988, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4803295', 'n_tokens_mistral': 5087, 'n_tokens_neox': 4815, 'n_words': 2038}