package play.libs; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Iterator; import java.util.ListIterator; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicLong; import play.exceptions.UnexpectedException; public class F { public static class Promise<V> implements Future<V>, F.Action<V> { final CountDownLatch taskLock = new CountDownLatch(1); boolean cancelled = false; public boolean cancel(boolean mayInterruptIfRunning) { return false; } public boolean isCancelled() { return false; } public boolean isDone() { return invoked; } public V getOrNull() { return result; } public V get() throws InterruptedException, ExecutionException { taskLock.await(); if (exception != null) { // The result of the promise is an exception - throw it throw new ExecutionException(exception); } return result; } public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { taskLock.await(timeout, unit); if (exception != null) { // The result of the promise is an exception - throw it throw new ExecutionException(exception); } return result; } List<F.Action<Promise<V>>> callbacks = new ArrayList<F.Action<Promise<V>>>(); boolean invoked = false; V result = null; Throwable exception = null; public void invoke(V result) { invokeWithResultOrException(result, null); } public void invokeWithException(Throwable t) { invokeWithResultOrException(null, t); } protected void invokeWithResultOrException(V result, Throwable t) { synchronized (this) { if (!invoked) { invoked = true; this.result = result; this.exception = t; taskLock.countDown(); } else { return; } } for (F.Action<Promise<V>> callback : callbacks) { callback.invoke(this); } } public void onRedeem(F.Action<Promise<V>> callback) { synchronized (this) { if (!invoked) { callbacks.add(callback); } } if (invoked) { callback.invoke(this); } } public static <T> Promise<List<T>> waitAll(final Promise<T>... promises) { return waitAll(Arrays.asList(promises)); } public static <T> Promise<List<T>> waitAll(final Collection<Promise<T>> promises) { final CountDownLatch waitAllLock = new CountDownLatch(promises.size()); final Promise<List<T>> result = new Promise<List<T>>() { @Override public boolean cancel(boolean mayInterruptIfRunning) { boolean r = true; for (Promise<T> f : promises) { r = r & f.cancel(mayInterruptIfRunning); } return r; } @Override public boolean isCancelled() { boolean r = true; for (Promise<T> f : promises) { r = r & f.isCancelled(); } return r; } @Override public boolean isDone() { boolean r = true; for (Promise<T> f : promises) { r = r & f.isDone(); } return r; } @Override public List<T> get() throws InterruptedException, ExecutionException { waitAllLock.await(); List<T> r = new ArrayList<T>(); for (Promise<T> f : promises) { r.add(f.get()); } return r; } @Override public List<T> get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { waitAllLock.await(timeout, unit); return get(); } }; final F.Action<Promise<T>> action = new F.Action<Promise<T>>() { public void invoke(Promise<T> completed) { waitAllLock.countDown(); if (waitAllLock.getCount() == 0) { try { result.invoke(result.get()); } catch (Exception e) { throw new UnexpectedException(e); } } } }; for (Promise<T> f : promises) { f.onRedeem(action); } return result; } public static <A, B> Promise<F.Tuple<A, B>> wait2(Promise<A> tA, Promise<B> tB) { final Promise<F.Tuple<A, B>> result = new Promise<F.Tuple<A, B>>(); final Promise<List<Object>> t = waitAll(new Promise[]{tA, tB}); t.onRedeem(new F.Action<Promise<List<Object>>>() { public void invoke(Promise<List<Object>> completed) { List<Object> values = completed.getOrNull(); result.invoke(new F.Tuple((A) values.get(0), (B) values.get(1))); } }); return result; } public static <A, B, C> Promise<F.T3<A, B, C>> wait3(Promise<A> tA, Promise<B> tB, Promise<C> tC) { final Promise<F.T3<A, B, C>> result = new Promise<F.T3<A, B, C>>(); final Promise<List<Object>> t = waitAll(new Promise[]{tA, tB, tC}); t.onRedeem(new F.Action<Promise<List<Object>>>() { public void invoke(Promise<List<Object>> completed) { List<Object> values = completed.getOrNull(); result.invoke(new F.T3((A) values.get(0), (B) values.get(1), (C) values.get(2))); } }); return result; } public static <A, B, C, D> Promise<F.T4<A, B, C, D>> wait4(Promise<A> tA, Promise<B> tB, Promise<C> tC, Promise<D> tD) { final Promise<F.T4<A, B, C, D>> result = new Promise<F.T4<A, B, C, D>>(); final Promise<List<Object>> t = waitAll(new Promise[]{tA, tB, tC, tD}); t.onRedeem(new F.Action<Promise<List<Object>>>() { public void invoke(Promise<List<Object>> completed) { List<Object> values = completed.getOrNull(); result.invoke(new F.T4((A) values.get(0), (B) values.get(1), (C) values.get(2), (D) values.get(3))); } }); return result; } public static <A, B, C, D, E> Promise<F.T5<A, B, C, D, E>> wait5(Promise<A> tA, Promise<B> tB, Promise<C> tC, Promise<D> tD, Promise<E> tE) { final Promise<F.T5<A, B, C, D, E>> result = new Promise<F.T5<A, B, C, D, E>>(); final Promise<List<Object>> t = waitAll(new Promise[]{tA, tB, tC, tD, tE}); t.onRedeem(new F.Action<Promise<List<Object>>>() { public void invoke(Promise<List<Object>> completed) { List<Object> values = completed.getOrNull(); result.invoke(new F.T5((A) values.get(0), (B) values.get(1), (C) values.get(2), (D) values.get(3), (E) values.get(4))); } }); return result; } private static Promise<F.Tuple<Integer, Promise<Object>>> waitEitherInternal(final Promise<?>... futures) { final Promise<F.Tuple<Integer, Promise<Object>>> result = new Promise<F.Tuple<Integer, Promise<Object>>>(); for (int i = 0; i < futures.length; i++) { final int index = i + 1; ((Promise<Object>) futures[i]).onRedeem(new F.Action<Promise<Object>>() { public void invoke(Promise<Object> completed) { result.invoke(new F.Tuple(index, completed)); } }); } return result; } public static <A, B> Promise<F.Either<A, B>> waitEither(final Promise<A> tA, final Promise<B> tB) { final Promise<F.Either<A, B>> result = new Promise<F.Either<A, B>>(); final Promise<F.Tuple<Integer, Promise<Object>>> t = waitEitherInternal(tA, tB); t.onRedeem(new F.Action<Promise<F.Tuple<Integer, Promise<Object>>>>() { public void invoke(Promise<F.Tuple<Integer, Promise<Object>>> completed) { F.Tuple<Integer, Promise<Object>> value = completed.getOrNull(); switch (value._1) { case 1: result.invoke(F.Either.<A, B>_1((A) value._2.getOrNull())); break; case 2: result.invoke(F.Either.<A, B>_2((B) value._2.getOrNull())); break; } } }); return result; } public static <A, B, C> Promise<F.E3<A, B, C>> waitEither(final Promise<A> tA, final Promise<B> tB, final Promise<C> tC) { final Promise<F.E3<A, B, C>> result = new Promise<F.E3<A, B, C>>(); final Promise<F.Tuple<Integer, Promise<Object>>> t = waitEitherInternal(tA, tB, tC); t.onRedeem(new F.Action<Promise<F.Tuple<Integer, Promise<Object>>>>() { public void invoke(Promise<F.Tuple<Integer, Promise<Object>>> completed) { F.Tuple<Integer, Promise<Object>> value = completed.getOrNull(); switch (value._1) { case 1: result.invoke(F.E3.<A, B, C>_1((A) value._2.getOrNull())); break; case 2: result.invoke(F.E3.<A, B, C>_2((B) value._2.getOrNull())); break; case 3: result.invoke(F.E3.<A, B, C>_3((C) value._2.getOrNull())); break; } } }); return result; } public static <A, B, C, D> Promise<F.E4<A, B, C, D>> waitEither(final Promise<A> tA, final Promise<B> tB, final Promise<C> tC, final Promise<D> tD) { final Promise<F.E4<A, B, C, D>> result = new Promise<F.E4<A, B, C, D>>(); final Promise<F.Tuple<Integer, Promise<Object>>> t = waitEitherInternal(tA, tB, tC, tD); t.onRedeem(new F.Action<Promise<F.Tuple<Integer, Promise<Object>>>>() { public void invoke(Promise<F.Tuple<Integer, Promise<Object>>> completed) { F.Tuple<Integer, Promise<Object>> value = completed.getOrNull(); switch (value._1) { case 1: result.invoke(F.E4.<A, B, C, D>_1((A) value._2.getOrNull())); break; case 2: result.invoke(F.E4.<A, B, C, D>_2((B) value._2.getOrNull())); break; case 3: result.invoke(F.E4.<A, B, C, D>_3((C) value._2.getOrNull())); break; case 4: result.invoke(F.E4.<A, B, C, D>_4((D) value._2.getOrNull())); break; } } }); return result; } public static <A, B, C, D, E> Promise<F.E5<A, B, C, D, E>> waitEither(final Promise<A> tA, final Promise<B> tB, final Promise<C> tC, final Promise<D> tD, final Promise<E> tE) { final Promise<F.E5<A, B, C, D, E>> result = new Promise<F.E5<A, B, C, D, E>>(); final Promise<F.Tuple<Integer, Promise<Object>>> t = waitEitherInternal(tA, tB, tC, tD, tE); t.onRedeem(new F.Action<Promise<F.Tuple<Integer, Promise<Object>>>>() { public void invoke(Promise<F.Tuple<Integer, Promise<Object>>> completed) { F.Tuple<Integer, Promise<Object>> value = completed.getOrNull(); switch (value._1) { case 1: result.invoke(F.E5.<A, B, C, D, E>_1((A) value._2.getOrNull())); break; case 2: result.invoke(F.E5.<A, B, C, D, E>_2((B) value._2.getOrNull())); break; case 3: result.invoke(F.E5.<A, B, C, D, E>_3((C) value._2.getOrNull())); break; case 4: result.invoke(F.E5.<A, B, C, D, E>_4((D) value._2.getOrNull())); break; case 5: result.invoke(F.E5.<A, B, C, D, E>_5((E) value._2.getOrNull())); break; } } }); return result; } public static <T> Promise<T> waitAny(final Promise<T>... futures) { final Promise<T> result = new Promise<T>(); final F.Action<Promise<T>> action = new F.Action<Promise<T>>() { public void invoke(Promise<T> completed) { synchronized (this) { if (result.isDone()) { return; } } result.invoke(completed.getOrNull()); } }; for (Promise<T> f : futures) { f.onRedeem(action); } return result; } } public static class Timeout extends Promise<Timeout> { static Timer timer = new Timer("F.Timeout", true); final public String token; final public long delay; public Timeout(String delay) { this(Time.parseDuration(delay) * 1000); } public Timeout(String token, String delay) { this(token, Time.parseDuration(delay) * 1000); } public Timeout(long delay) { this("timeout", delay); } public Timeout(String token, long delay) { this.delay = delay; this.token = token; final Timeout timeout = this; timer.schedule(new TimerTask() { @Override public void run() { timeout.invoke(timeout); } }, delay); } @Override public String toString() { return "Timeout(" + delay + ")"; } } public static Timeout Timeout(String delay) { return new Timeout(delay); } public static Timeout Timeout(String token, String delay) { return new Timeout(token, delay); } public static Timeout Timeout(long delay) { return new Timeout(delay); } public static Timeout Timeout(String token, long delay) { return new Timeout(token, delay); } public static class EventStream<T> { final int bufferSize; final ConcurrentLinkedQueue<T> events = new ConcurrentLinkedQueue<T>(); final List<Promise<T>> waiting = Collections.synchronizedList(new ArrayList<Promise<T>>()); public EventStream() { this.bufferSize = 100; } public EventStream(int maxBufferSize) { this.bufferSize = maxBufferSize; } public synchronized Promise<T> nextEvent() { if (events.isEmpty()) { LazyTask task = new LazyTask(); waiting.add(task); return task; } return new LazyTask(events.peek()); } public synchronized void publish(T event) { if (events.size() > bufferSize) { events.poll(); } events.offer(event); notifyNewEvent(); } void notifyNewEvent() { T value = events.peek(); for (Promise<T> task : waiting) { task.invoke(value); } waiting.clear(); } class LazyTask extends Promise<T> { public LazyTask() { } public LazyTask(T value) { invoke(value); } @Override public T get() throws InterruptedException, ExecutionException { T value = super.get(); markAsRead(value); return value; } @Override public T getOrNull() { T value = super.getOrNull(); markAsRead(value); return value; } private void markAsRead(T value) { if (value != null) { events.remove(value); } } } } public static class IndexedEvent<M> { private static final AtomicLong idGenerator = new AtomicLong(1); final public M data; final public Long id; public IndexedEvent(M data) { this.data = data; this.id = idGenerator.getAndIncrement(); } @Override public String toString() { return "Event(id: " + id + ", " + data + ")"; } public static void resetIdGenerator() { idGenerator.set(1); } } public static class ArchivedEventStream<T> { final int archiveSize; final ConcurrentLinkedQueue<IndexedEvent<T>> events = new ConcurrentLinkedQueue<IndexedEvent<T>>(); final List<FilterTask<T>> waiting = Collections.synchronizedList(new ArrayList<FilterTask<T>>()); final List<EventStream<T>> pipedStreams = new ArrayList<EventStream<T>>(); public ArchivedEventStream(int archiveSize) { this.archiveSize = archiveSize; } public synchronized EventStream<T> eventStream() { final EventStream<T> stream = new EventStream<T>(archiveSize); for (IndexedEvent<T> event : events) { stream.publish(event.data); } pipedStreams.add(stream); return stream; } public synchronized Promise<List<IndexedEvent<T>>> nextEvents(long lastEventSeen) { FilterTask<T> filter = new FilterTask<T>(lastEventSeen); waiting.add(filter); notifyNewEvent(); return filter; } public synchronized List<IndexedEvent> availableEvents(long lastEventSeen) { List<IndexedEvent> result = new ArrayList<IndexedEvent>(); for (IndexedEvent event : events) { if (event.id > lastEventSeen) { result.add(event); } } return result; } public List<T> archive() { List<T> result = new ArrayList<T>(); for (IndexedEvent<T> event : events) { result.add(event.data); } return result; } public synchronized void publish(T event) { if (events.size() >= archiveSize) { events.poll(); } events.offer(new IndexedEvent(event)); notifyNewEvent(); for (EventStream<T> eventStream : pipedStreams) { eventStream.publish(event); } } void notifyNewEvent() { for (ListIterator<FilterTask<T>> it = waiting.listIterator(); it.hasNext();) { FilterTask<T> filter = it.next(); for (IndexedEvent<T> event : events) { filter.propose(event); } if (filter.trigger()) { it.remove(); } } } static class FilterTask<K> extends Promise<List<IndexedEvent<K>>> { final Long lastEventSeen; final List<IndexedEvent<K>> newEvents = new ArrayList<IndexedEvent<K>>(); public FilterTask(Long lastEventSeen) { this.lastEventSeen = lastEventSeen; } public void propose(IndexedEvent<K> event) { if (event.id > lastEventSeen) { newEvents.add(event); } } public boolean trigger() { if (newEvents.isEmpty()) { return false; } invoke(newEvents); return true; } } } public static interface Action0 { void invoke(); } public static interface Action<T> { void invoke(T result); } public static abstract class Option<T> implements Iterable<T> { public abstract boolean isDefined(); public abstract T get(); public static <T> None<T> None() { return (None<T>) (Object) None; } public static <T> Some<T> Some(T value) { return new Some<T>(value); } } public static <A> Some<A> Some(A a) { return new Some(a); } public static class None<T> extends Option<T> { @Override public boolean isDefined() { return false; } @Override public T get() { throw new IllegalStateException("No value"); } public Iterator<T> iterator() { return Collections.<T>emptyList().iterator(); } @Override public String toString() { return "None"; } } public static None<Object> None = new None<Object>(); public static class Some<T> extends Option<T> { final T value; public Some(T value) { this.value = value; } @Override public boolean isDefined() { return true; } @Override public T get() { return value; } public Iterator<T> iterator() { return Collections.singletonList(value).iterator(); } @Override public String toString() { return "Some(" + value + ")"; } } public static class Either<A, B> { final public Option<A> _1; final public Option<B> _2; private Either(Option<A> _1, Option<B> _2) { this._1 = _1; this._2 = _2; } public static <A, B> Either<A, B> _1(A value) { return new Either(Some(value), None); } public static <A, B> Either<A, B> _2(B value) { return new Either(None, Some(value)); } @Override public String toString() { return "E2(_1: " + _1 + ", _2: " + _2 + ")"; } } public static class E2<A, B> extends Either<A, B> { private E2(Option<A> _1, Option<B> _2) { super(_1, _2); } } public static class E3<A, B, C> { final public Option<A> _1; final public Option<B> _2; final public Option<C> _3; private E3(Option<A> _1, Option<B> _2, Option<C> _3) { this._1 = _1; this._2 = _2; this._3 = _3; } public static <A, B, C> E3<A, B, C> _1(A value) { return new E3(Some(value), None, None); } public static <A, B, C> E3<A, B, C> _2(B value) { return new E3(None, Some(value), None); } public static <A, B, C> E3<A, B, C> _3(C value) { return new E3(None, None, Some(value)); } @Override public String toString() { return "E3(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ")"; } } public static class E4<A, B, C, D> { final public Option<A> _1; final public Option<B> _2; final public Option<C> _3; final public Option<D> _4; private E4(Option<A> _1, Option<B> _2, Option<C> _3, Option<D> _4) { this._1 = _1; this._2 = _2; this._3 = _3; this._4 = _4; } public static <A, B, C, D> E4<A, B, C, D> _1(A value) { return new E4(Option.Some(value), None, None, None); } public static <A, B, C, D> E4<A, B, C, D> _2(B value) { return new E4(None, Some(value), None, None); } public static <A, B, C, D> E4<A, B, C, D> _3(C value) { return new E4(None, None, Some(value), None); } public static <A, B, C, D> E4<A, B, C, D> _4(D value) { return new E4(None, None, None, Some(value)); } @Override public String toString() { return "E4(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ", _4:" + _4 + ")"; } } public static class E5<A, B, C, D, E> { final public Option<A> _1; final public Option<B> _2; final public Option<C> _3; final public Option<D> _4; final public Option<E> _5; private E5(Option<A> _1, Option<B> _2, Option<C> _3, Option<D> _4, Option<E> _5) { this._1 = _1; this._2 = _2; this._3 = _3; this._4 = _4; this._5 = _5; } public static <A, B, C, D, E> E5<A, B, C, D, E> _1(A value) { return new E5(Option.Some(value), None, None, None, None); } public static <A, B, C, D, E> E5<A, B, C, D, E> _2(B value) { return new E5(None, Option.Some(value), None, None, None); } public static <A, B, C, D, E> E5<A, B, C, D, E> _3(C value) { return new E5(None, None, Option.Some(value), None, None); } public static <A, B, C, D, E> E5<A, B, C, D, E> _4(D value) { return new E5(None, None, None, Option.Some(value), None); } public static <A, B, C, D, E> E5<A, B, C, D, E> _5(E value) { return new E5(None, None, None, None, Option.Some(value)); } @Override public String toString() { return "E5(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ", _4:" + _4 + ", _5:" + _5 + ")"; } } public static class Tuple<A, B> { final public A _1; final public B _2; public Tuple(A _1, B _2) { this._1 = _1; this._2 = _2; } @Override public String toString() { return "T2(_1: " + _1 + ", _2: " + _2 + ")"; } } public static <A, B> Tuple<A, B> Tuple(A a, B b) { return new Tuple(a, b); } public static class T2<A, B> extends Tuple<A, B> { public T2(A _1, B _2) { super(_1, _2); } } public static <A, B> T2<A, B> T2(A a, B b) { return new T2(a, b); } public static class T3<A, B, C> { final public A _1; final public B _2; final public C _3; public T3(A _1, B _2, C _3) { this._1 = _1; this._2 = _2; this._3 = _3; } @Override public String toString() { return "T3(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ")"; } } public static <A, B, C> T3<A, B, C> T3(A a, B b, C c) { return new T3(a, b, c); } public static class T4<A, B, C, D> { final public A _1; final public B _2; final public C _3; final public D _4; public T4(A _1, B _2, C _3, D _4) { this._1 = _1; this._2 = _2; this._3 = _3; this._4 = _4; } @Override public String toString() { return "T4(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ", _4:" + _4 + ")"; } } public static <A, B, C, D> T4<A, B, C, D> T4(A a, B b, C c, D d) { return new T4<A, B, C, D>(a, b, c, d); } public static class T5<A, B, C, D, E> { final public A _1; final public B _2; final public C _3; final public D _4; final public E _5; public T5(A _1, B _2, C _3, D _4, E _5) { this._1 = _1; this._2 = _2; this._3 = _3; this._4 = _4; this._5 = _5; } @Override public String toString() { return "T5(_1: " + _1 + ", _2: " + _2 + ", _3:" + _3 + ", _4:" + _4 + ", _5:" + _5 + ")"; } } public static <A, B, C, D, E> T5<A, B, C, D, E> T5(A a, B b, C c, D d, E e) { return new T5<A, B, C, D, E>(a, b, c, d, e); } public static abstract class Matcher<T, R> { public abstract Option<R> match(T o); public Option<R> match(Option<T> o) { if (o.isDefined()) { return match(o.get()); } return Option.None(); } public <NR> Matcher<T, NR> and(final Matcher<R, NR> nextMatcher) { final Matcher<T, R> firstMatcher = this; return new Matcher<T, NR>() { @Override public Option<NR> match(T o) { for (R r : firstMatcher.match(o)) { return nextMatcher.match(r); } return Option.None(); } }; } public static Matcher<Object, String> String = new Matcher<Object, String>() { @Override public Option<String> match(Object o) { if (o instanceof String) { return Option.Some((String) o); } return Option.None(); } }; public static <K> Matcher<Object, K> ClassOf(final Class<K> clazz) { return new Matcher<Object, K>() { @Override public Option<K> match(Object o) { if (o instanceof Option && ((Option) o).isDefined()) { o = ((Option) o).get(); } if (clazz.isInstance(o)) { return Option.Some((K) o); } return Option.None(); } }; } public static Matcher<String, String> StartsWith(final String prefix) { return new Matcher<String, String>() { @Override public Option<String> match(String o) { if (o.startsWith(prefix)) { return Option.Some(o); } return Option.None(); } }; } public static Matcher<String, String> Re(final String pattern) { return new Matcher<String, String>() { @Override public Option<String> match(String o) { if (o.matches(pattern)) { return Option.Some(o); } return Option.None(); } }; } public static <X> Matcher<X, X> Equals(final X other) { return new Matcher<X, X>() { @Override public Option<X> match(X o) { if (o.equals(other)) { return Option.Some(o); } return Option.None(); } }; } } }