Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2007 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.base;
     18 
     19 import com.google.common.annotations.VisibleForTesting;
     20 
     21 import java.io.Serializable;
     22 import java.util.concurrent.TimeUnit;
     23 
     24 import javax.annotation.Nullable;
     25 
     26 /**
     27  * Useful suppliers.
     28  *
     29  * <p>All methods return serializable suppliers as long as they're given
     30  * serializable parameters.
     31  *
     32  * @author Laurence Gonsalves
     33  * @author Harry Heymann
     34  * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
     35  */
     36 public final class Suppliers {
     37   private Suppliers() {}
     38 
     39   /**
     40    * Returns a new supplier which is the composition of the provided function
     41    * and supplier. In other words, the new supplier's value will be computed by
     42    * retrieving the value from {@code first}, and then applying
     43    * {@code function} to that value. Note that the resulting supplier will not
     44    * call {@code first} or invoke {@code function} until it is called.
     45    */
     46   public static <F, T> Supplier<T> compose(
     47       Function<? super F, T> function, Supplier<F> first) {
     48     Preconditions.checkNotNull(function);
     49     Preconditions.checkNotNull(first);
     50     return new SupplierComposition<F, T>(function, first);
     51   }
     52 
     53   private static class SupplierComposition<F, T>
     54       implements Supplier<T>, Serializable {
     55     final Function<? super F, ? extends T> function;
     56     final Supplier<? extends F> first;
     57 
     58     SupplierComposition(Function<? super F, ? extends T> function,
     59         Supplier<? extends F> first) {
     60       this.function = function;
     61       this.first = first;
     62     }
     63     public T get() {
     64       return function.apply(first.get());
     65     }
     66     private static final long serialVersionUID = 0;
     67   }
     68 
     69   /**
     70    * Returns a supplier which caches the instance retrieved during the first
     71    * call to {@code get()} and returns that value on subsequent calls to
     72    * {@code get()}. See:
     73    * <a href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
     74    *
     75    * <p>The returned supplier is thread-safe. The supplier's serialized form
     76    * does not contain the cached value, which will be recalculated when {@code
     77    * get()} is called on the reserialized instance.
     78    */
     79   public static <T> Supplier<T> memoize(Supplier<T> delegate) {
     80     return new MemoizingSupplier<T>(Preconditions.checkNotNull(delegate));
     81   }
     82 
     83   @VisibleForTesting static class MemoizingSupplier<T>
     84       implements Supplier<T>, Serializable {
     85     final Supplier<T> delegate;
     86     transient boolean initialized;
     87     transient T value;
     88 
     89     MemoizingSupplier(Supplier<T> delegate) {
     90       this.delegate = delegate;
     91     }
     92 
     93     public synchronized T get() {
     94       if (!initialized) {
     95         value = delegate.get();
     96         initialized = true;
     97       }
     98       return value;
     99     }
    100 
    101     private static final long serialVersionUID = 0;
    102   }
    103 
    104   /**
    105    * Returns a supplier that caches the instance supplied by the delegate and
    106    * removes the cached value after the specified time has passed. Subsequent
    107    * calls to {@code get()} return the cached value if the expiration time has
    108    * not passed. After the expiration time, a new value is retrieved, cached,
    109    * and returned. See:
    110    * <a href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
    111    *
    112    * <p>The returned supplier is thread-safe. The supplier's serialized form
    113    * does not contain the cached value, which will be recalculated when {@code
    114    * get()} is called on the reserialized instance.
    115    *
    116    * @param duration the length of time after a value is created that it
    117    *     should stop being returned by subsequent {@code get()} calls
    118    * @param unit the unit that {@code duration} is expressed in
    119    * @throws IllegalArgumentException if {@code duration} is not positive
    120    * @since 2010.01.04 <b>tentative</b>
    121    */
    122   public static <T> Supplier<T> memoizeWithExpiration(
    123       Supplier<T> delegate, long duration, TimeUnit unit) {
    124     return new ExpiringMemoizingSupplier<T>(delegate, duration, unit);
    125   }
    126 
    127   @VisibleForTesting static class ExpiringMemoizingSupplier<T>
    128       implements Supplier<T>, Serializable {
    129     final Supplier<T> delegate;
    130     final long durationNanos;
    131     transient boolean initialized;
    132     transient T value;
    133     transient long expirationNanos;
    134 
    135     ExpiringMemoizingSupplier(
    136         Supplier<T> delegate, long duration, TimeUnit unit) {
    137       this.delegate = Preconditions.checkNotNull(delegate);
    138       this.durationNanos = unit.toNanos(duration);
    139       Preconditions.checkArgument(duration > 0);
    140     }
    141 
    142     public synchronized T get() {
    143       if (!initialized || System.nanoTime() - expirationNanos >= 0) {
    144         value = delegate.get();
    145         initialized = true;
    146         expirationNanos = System.nanoTime() + durationNanos;
    147       }
    148       return value;
    149     }
    150 
    151     private static final long serialVersionUID = 0;
    152   }
    153 
    154   /**
    155    * Returns a supplier that always supplies {@code instance}.
    156    */
    157   public static <T> Supplier<T> ofInstance(@Nullable T instance) {
    158     return new SupplierOfInstance<T>(instance);
    159   }
    160 
    161   private static class SupplierOfInstance<T>
    162       implements Supplier<T>, Serializable {
    163     final T instance;
    164 
    165     SupplierOfInstance(T instance) {
    166       this.instance = instance;
    167     }
    168     public T get() {
    169       return instance;
    170     }
    171     private static final long serialVersionUID = 0;
    172   }
    173 
    174   /**
    175    * Returns a supplier whose {@code get()} method synchronizes on
    176    * {@code delegate} before calling it, making it thread-safe.
    177    */
    178   public static <T> Supplier<T> synchronizedSupplier(Supplier<T> delegate) {
    179     return new ThreadSafeSupplier<T>(Preconditions.checkNotNull(delegate));
    180   }
    181 
    182   private static class ThreadSafeSupplier<T>
    183       implements Supplier<T>, Serializable {
    184     final Supplier<T> delegate;
    185 
    186     ThreadSafeSupplier(Supplier<T> delegate) {
    187       this.delegate = delegate;
    188     }
    189     public T get() {
    190       synchronized (delegate) {
    191         return delegate.get();
    192       }
    193     }
    194     private static final long serialVersionUID = 0;
    195   }
    196 }
    197