001package org.cache2k.impl.threading;
002
003/*
004 * #%L
005 * cache2k core package
006 * %%
007 * Copyright (C) 2000 - 2015 headissue GmbH, Munich
008 * %%
009 * This program is free software: you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as
011 * published by the Free Software Foundation, either version 3 of the 
012 * License, or (at your option) any later version.
013 * 
014 * This program is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 * 
019 * You should have received a copy of the GNU General Public 
020 * License along with this program.  If not, see
021 * <http://www.gnu.org/licenses/gpl-3.0.html>.
022 * #L%
023 */
024
025import java.util.Iterator;
026import java.util.LinkedList;
027import java.util.List;
028import java.util.concurrent.ExecutionException;
029import java.util.concurrent.Future;
030import java.util.concurrent.TimeUnit;
031import java.util.concurrent.TimeoutException;
032
033/**
034 * @author Jens Wilke; created: 2014-06-03
035 */
036public class Futures {
037
038  /**
039   * A container for futures which waits for all futures to finish.
040   * Futures to wait for can be added with {@link #add(java.util.concurrent.Future)}
041   * or the constructor. Waiting for all futures to finish is done
042   * via {@link #get()}.
043   *
044   * <p/>The get method call will throw Exceptions from the added futures.
045   */
046  public static class WaitForAllFuture<V> implements Future<V> {
047
048    List<Future<V>> futureList = new LinkedList<Future<V>>();
049
050    public WaitForAllFuture(Future<V> _top) {
051      add(_top);
052    }
053
054    @SafeVarargs
055    public WaitForAllFuture(final Future<V>... _top) {
056      for (Future<V> f : _top) { add(f); }
057    }
058
059    /**
060     * Add a new future to the list for Futures we should wait for.
061     */
062    public synchronized void add(Future<V> f) {
063      if (f == null) { return; }
064      futureList.add(f);
065    }
066
067    /**
068     * Send cancel to all futures that are not yet cancelled. Returns
069     * true if every future is in cancelled state.
070     */
071    @Override
072    public synchronized boolean cancel(boolean mayInterruptIfRunning) {
073      if (futureList.size() == 0) {
074        return false;
075      }
076      boolean _flag = true;
077      for (Future<V> f : futureList) {
078        if (!f.isCancelled()) {
079          f.cancel(mayInterruptIfRunning);
080          _flag &= f.isCancelled();
081        }
082      }
083      return _flag;
084    }
085
086    /**
087     * Unsupported, it is not possible to implement useful semantics.
088     */
089    @Override
090    public boolean isCancelled() {
091      throw new UnsupportedOperationException();
092    }
093
094    /**
095     * True, if every future is done or no future is contained.
096     *
097     * <p/>The list of futures is not touched, since an exception
098     * may be thrown via get.
099     */
100    @Override
101    public synchronized boolean isDone() {
102      boolean _flag = true;
103      for (Future<V> f : futureList) {
104        _flag &= f.isDone();
105      }
106      return _flag;
107    }
108
109    /**
110     * Wait until everything is finished. It may happen that a new future during
111     * this method waits for finishing another one. If this happens, we wait
112     * for that task also.
113     *
114     * <p/>All get methods of the futures are executed to probe for possible
115     * exceptions. Futures completed without exceptions, will be removed
116     * for the list.
117     *
118     * <p/>Implementation is a bit tricky. We need to call a potential stalling
119     * get outside the synchronized block, since new futures may come in in parallel.
120     */
121    @Override
122    public V get() throws InterruptedException, ExecutionException {
123      for (;;) {
124        Future<V> _needsGet = null;
125        synchronized (this) {
126          Iterator<Future<V>> it = futureList.iterator();
127          while (it.hasNext()){
128            Future<V> f = it.next();
129            if (!f.isDone()) {
130              _needsGet = f;
131              break;
132            }
133            f.get();
134            it.remove();
135          }
136        }
137        if (_needsGet != null) {
138          _needsGet.get();
139          continue;
140        }
141        return null;
142      }
143    }
144
145    @Override
146    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
147      long _maxTime = System.currentTimeMillis() + unit.toMillis(timeout);
148      if (_maxTime < 0) {
149        return get();
150      }
151      for (;;) {
152        Future<V> _needsGet = null;
153        synchronized (this) {
154          Iterator<Future<V>> it = futureList.iterator();
155          while (it.hasNext()){
156            Future<V> f = it.next();
157            if (!f.isDone()) {
158              _needsGet = f;
159              break;
160            }
161            f.get();
162            it.remove();
163          }
164        }
165        if (_needsGet != null) {
166          long now = System.currentTimeMillis();
167          long _waitTime = _maxTime - now;
168          if (_waitTime <= 0) {
169            throw new TimeoutException();
170          }
171          _needsGet.get(_maxTime - now, TimeUnit.MILLISECONDS);
172          continue;
173        }
174        return null;
175      }
176    }
177
178  }
179
180  public static class FinishedFuture<V> implements Future<V> {
181
182    V result;
183
184    public FinishedFuture() {
185    }
186
187    public FinishedFuture(V result) {
188      this.result = result;
189    }
190
191    @Override
192    public boolean cancel(boolean mayInterruptIfRunning) {
193      return false;
194    }
195
196    @Override
197    public boolean isCancelled() {
198      return false;
199    }
200
201    @Override
202    public boolean isDone() {
203      return true;
204    }
205
206    @Override
207    public V get() {
208      return result;
209    }
210
211    @Override
212    public V get(long timeout, TimeUnit unit)  {
213      return result;
214    }
215  }
216
217  public static class ExceptionFuture<V> implements Future<V> {
218
219    private Throwable exception;
220
221    public ExceptionFuture(Throwable exception) {
222      this.exception = exception;
223    }
224
225    @Override
226    public boolean cancel(boolean mayInterruptIfRunning) {
227      return false;
228    }
229
230    @Override
231    public boolean isCancelled() {
232      return false;
233    }
234
235    @Override
236    public boolean isDone() {
237      return true;
238    }
239
240    @Override
241    public V get() throws ExecutionException {
242      throw new ExecutionException(exception);
243    }
244
245    @Override
246    public V get(long timeout, TimeUnit unit) throws ExecutionException {
247      throw new ExecutionException(exception);
248    }
249
250  }
251
252  public static abstract class BusyWaitFuture<V> implements Future<V> {
253
254    private int spinMillis = 123;
255    private V result = null;
256
257    protected BusyWaitFuture() { }
258
259    protected BusyWaitFuture(V _defaultResult) {
260      this.result = _defaultResult;
261    }
262
263    protected BusyWaitFuture(int spinMillis, V _defaultResult) {
264      this.spinMillis = spinMillis;
265      this.result = _defaultResult;
266    }
267
268    protected V getResult() { return result; }
269
270    @Override
271    public boolean cancel(boolean mayInterruptIfRunning) { return false; }
272
273    @Override
274    public boolean isCancelled() { return false; }
275
276    @Override
277    public abstract boolean isDone();
278
279    /** Just busy wait for running fetches. We have no notification for this. */
280    @Override
281    public V get() throws InterruptedException, ExecutionException {
282      while (!isDone()) { Thread.sleep(spinMillis); }
283      return getResult();
284    }
285
286    @Override
287    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
288      long _maxMillis = unit.toMillis(timeout) + System.currentTimeMillis();
289      if (_maxMillis < 0) { return get(); }
290      while (!isDone() && System.currentTimeMillis() < _maxMillis) { Thread.sleep(spinMillis); }
291      if (!isDone()) { throw new TimeoutException(); }
292      return getResult();
293    }
294
295  }
296
297}