001package com.github.theholywaffle.teamspeak3.api;
002
003/*
004 * #%L
005 * TeamSpeak 3 Java API
006 * %%
007 * Copyright (C) 2014 Bert De Geyter
008 * %%
009 * Permission is hereby granted, free of charge, to any person obtaining a copy
010 * of this software and associated documentation files (the "Software"), to deal
011 * in the Software without restriction, including without limitation the rights
012 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
013 * copies of the Software, and to permit persons to whom the Software is
014 * furnished to do so, subject to the following conditions:
015 * 
016 * The above copyright notice and this permission notice shall be included in
017 * all copies or substantial portions of the Software.
018 * 
019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
020 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
021 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
022 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
023 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
024 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
025 * THE SOFTWARE.
026 * #L%
027 */
028
029import com.github.theholywaffle.teamspeak3.TS3ApiAsync;
030import com.github.theholywaffle.teamspeak3.api.exception.TS3Exception;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034import java.util.Arrays;
035import java.util.Collection;
036import java.util.Collections;
037import java.util.Iterator;
038import java.util.List;
039import java.util.concurrent.CancellationException;
040import java.util.concurrent.Future;
041import java.util.concurrent.TimeUnit;
042import java.util.concurrent.TimeoutException;
043import java.util.concurrent.atomic.AtomicInteger;
044import java.util.function.Function;
045
046/**
047 * Represents the result of an asynchronous execution of a query command.
048 * <p>
049 * Basically, this class is a container for a server response which will
050 * arrive at some time in the future. It also accounts for the possibility
051 * that a command might fail and that a future might be cancelled by a user.
052 * </p>
053 * A {@code CommandFuture} can therefore have 4 different states:
054 * <ul>
055 * <li><b>Waiting</b> - No response from the server has arrived yet</li>
056 * <li><b>Cancelled</b> - A user cancelled this future before a response from the server could arrive</li>
057 * <li><b>Failed</b> - The server received the command but responded with an error message</li>
058 * <li><b>Succeeded</b> - The server successfully processed the command and sent back a result</li>
059 * </ul>
060 * You can check the state of the future using the methods {@link #isDone()},
061 * {@link #isSuccessful()}, {@link #hasFailed()} and {@link #isCancelled()}.
062 * <p>
063 * A {@code CommandFuture}'s value can be retrieved by calling {@link #get()}
064 * or {@link #get(long, TimeUnit)}, which block the current thread until the
065 * server response arrives. The method with a timeout should be preferred
066 * as there's no guarantee that a proper response (or an error message)
067 * will ever arrive, e.g. in case of a permanent disconnect.
068 * There are also variations of these methods which ignore thread interrupts,
069 * {@link #getUninterruptibly()} and {@link #getUninterruptibly(long, TimeUnit)}.
070 * </p><p>
071 * Note that <b>these methods</b> all wait for the response to arrive and thereby
072 * <b>revert to synchronous</b> execution. If you want to handle the server response
073 * asynchronously, you need to register success and failure listeners.
074 * These listeners will be called in a separate thread once a response arrives.
075 * </p><p>
076 * Each {@code CommandFuture} can only ever have one {@link SuccessListener} and
077 * one {@link FailureListener} registered. All {@link TS3ApiAsync} methods are
078 * guaranteed to return a {@code CommandFuture} with no listeners registered.
079 * </p><p>
080 * To set the value of a {@code CommandFuture}, the {@link #set(Object)} method is used;
081 * to notify it of a failure, {@link #fail(TS3Exception)} is used. You usually
082 * shouldn't call these methods yourself, however. That's the job of the API.
083 * </p><p>
084 * {@code CommandFuture}s are thread-safe. All state-changing methods are synchronized.
085 * </p>
086 *
087 * @param <V>
088 *              the type of the value
089 *
090 * @see TS3ApiAsync
091 */
092public class CommandFuture<V> implements Future<V> {
093
094        private static final Logger log = LoggerFactory.getLogger(CommandFuture.class);
095
096        private enum FutureState {
097                WAITING,
098                CANCELLED,
099                FAILED,
100                SUCCEEDED
101        }
102
103        /**
104         * Just a plain object used for its monitor to synchronize access to the
105         * critical sections of this future and to signal state changes to any
106         * threads waiting in {@link #get()} and {@link #getUninterruptibly()} methods.
107         */
108        private final Object monitor = new Object();
109
110        /**
111         * The current state of the future. Marked as volatile so {@link #isDone()}
112         * and similar functions can work without synchronization.
113         * State transitions and check-then-acts must be guarded by monitor.
114         */
115        private volatile FutureState state = FutureState.WAITING;
116
117        // All guarded by monitor
118        private V value = null;
119        private TS3Exception exception = null;
120        private SuccessListener<? super V> successListener = null;
121        private FailureListener failureListener = null;
122
123        /**
124         * Waits indefinitely until the command completes.
125         * <p>
126         * If the thread is interrupted while waiting for the command
127         * to complete, this method will throw an {@code InterruptedException}
128         * and the thread's interrupt flag will be cleared.
129         * </p><p><i>
130         * Please note that this method is blocking and thus negates
131         * the advantage of the asynchronous nature of this class.
132         * Consider using {@link #onSuccess(SuccessListener)} and
133         * {@link #onFailure(FailureListener)} instead.
134         * </i></p>
135         *
136         * @throws InterruptedException
137         *              if the method is interrupted by calling {@link Thread#interrupt()}.
138         *              The interrupt flag will be cleared
139         */
140        public void await() throws InterruptedException {
141                synchronized (monitor) {
142                        while (state == FutureState.WAITING) {
143                                monitor.wait();
144                        }
145                }
146        }
147
148        /**
149         * Waits for at most the given time until the command completes.
150         * <p>
151         * If the thread is interrupted while waiting for the command
152         * to complete, this method will throw an {@code InterruptedException}
153         * and the thread's interrupt flag will be cleared.
154         * </p><p><i>
155         * Please note that this method is blocking and thus negates
156         * the advantage of the asynchronous nature of this class.
157         * Consider using {@link #onSuccess(SuccessListener)} and
158         * {@link #onFailure(FailureListener)} instead.
159         * </i></p>
160         *
161         * @param timeout
162         *              the maximum amount of the given time unit to wait
163         * @param unit
164         *              the time unit of the timeout argument
165         *
166         * @throws InterruptedException
167         *              if the method is interrupted by calling {@link Thread#interrupt()}.
168         *              The interrupt flag will be cleared
169         * @throws TimeoutException
170         *              if the given time elapsed without the command completing
171         */
172        public void await(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
173                synchronized (monitor) {
174                        final long end = System.currentTimeMillis() + unit.toMillis(timeout);
175                        while (state == FutureState.WAITING && System.currentTimeMillis() < end) {
176                                monitor.wait(end - System.currentTimeMillis());
177                        }
178
179                        if (state == FutureState.WAITING) throw new TimeoutException();
180                }
181        }
182
183        /**
184         * Waits indefinitely until the command completes.
185         * <p>
186         * If the thread is interrupted while waiting for the command
187         * to complete, the interrupt is simply ignored and no
188         * {@link InterruptedException} is thrown.
189         * </p><p><i>
190         * Please note that this method is blocking and thus negates
191         * the advantage of the asynchronous nature of this class.
192         * Consider using {@link #onSuccess(SuccessListener)} and
193         * {@link #onFailure(FailureListener)} instead.
194         * </i></p>
195         */
196        public void awaitUninterruptibly() {
197                synchronized (monitor) {
198                        boolean interrupted = false;
199                        while (state == FutureState.WAITING) {
200                                try {
201                                        monitor.wait();
202                                } catch (InterruptedException e) {
203                                        interrupted = true;
204                                }
205                        }
206
207                        if (interrupted) {
208                                // Restore the interrupt for the caller
209                                Thread.currentThread().interrupt();
210                        }
211                }
212        }
213
214        /**
215         * Waits for at most the given time until the command completes.
216         * <p>
217         * If the thread is interrupted while waiting for the command
218         * to complete, the interrupt is simply ignored and no
219         * {@link InterruptedException} is thrown.
220         * </p><p><i>
221         * Please note that this method is blocking and thus negates
222         * the advantage of the asynchronous nature of this class.
223         * Consider using {@link #onSuccess(SuccessListener)} and
224         * {@link #onFailure(FailureListener)} instead.
225         * </i></p>
226         *
227         * @param timeout
228         *              the maximum amount of the given time unit to wait
229         * @param unit
230         *              the time unit of the timeout argument
231         *
232         * @throws TimeoutException
233         *              if the given time elapsed without the command completing
234         */
235        public void awaitUninterruptibly(long timeout, TimeUnit unit) throws TimeoutException {
236                synchronized (monitor) {
237                        final long end = System.currentTimeMillis() + unit.toMillis(timeout);
238                        boolean interrupted = false;
239
240                        while (state == FutureState.WAITING && System.currentTimeMillis() < end) {
241                                try {
242                                        monitor.wait(end - System.currentTimeMillis());
243                                } catch (InterruptedException e) {
244                                        interrupted = true;
245                                }
246                        }
247
248                        if (interrupted) {
249                                // Restore the interrupt for the caller
250                                Thread.currentThread().interrupt();
251                        }
252
253                        if (state == FutureState.WAITING) throw new TimeoutException();
254                }
255        }
256
257        /**
258         * Waits indefinitely until the command completes
259         * and returns the result of the command.
260         * <p>
261         * If the thread is interrupted while waiting for the command
262         * to complete, this method will throw an {@code InterruptedException}
263         * and the thread's interrupt flag will be cleared.
264         * </p><p><i>
265         * Please note that this method is blocking and thus negates
266         * the advantage of the asynchronous nature of this class.
267         * Consider using {@link #onSuccess(SuccessListener)} and
268         * {@link #onFailure(FailureListener)} instead.
269         * </i></p>
270         *
271         * @return the server response to the command
272         *
273         * @throws InterruptedException
274         *              if the method is interrupted by calling {@link Thread#interrupt()}.
275         *              The interrupt flag will be cleared
276         * @throws CancellationException
277         *              if the {@code CommandFuture} was cancelled before the command completed
278         * @throws TS3Exception
279         *              if the command fails
280         */
281        @Override
282        public V get() throws InterruptedException {
283                synchronized (monitor) {
284                        await();
285
286                        checkForFailure();
287                        return value;
288                }
289        }
290
291        /**
292         * Waits for at most the given time until the command completes
293         * and returns the result of the command.
294         * <p>
295         * If the thread is interrupted while waiting for the command
296         * to complete, this method will throw an {@code InterruptedException}
297         * and the thread's interrupt flag will be cleared.
298         * </p><p><i>
299         * Please note that this method is blocking and thus negates
300         * the advantage of the asynchronous nature of this class.
301         * Consider using {@link #onSuccess(SuccessListener)} and
302         * {@link #onFailure(FailureListener)} instead.
303         * </i></p>
304         *
305         * @param timeout
306         *              the maximum amount of the given time unit to wait
307         * @param unit
308         *              the time unit of the timeout argument
309         *
310         * @return the server response to the command
311         *
312         * @throws InterruptedException
313         *              if the method is interrupted by calling {@link Thread#interrupt()}.
314         *              The interrupt flag will be cleared
315         * @throws TimeoutException
316         *              if the given time elapsed without the command completing
317         * @throws CancellationException
318         *              if the {@code CommandFuture} was cancelled before the command completed
319         * @throws TS3Exception
320         *              if the command fails
321         */
322        @Override
323        public V get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
324                synchronized (monitor) {
325                        await(timeout, unit);
326
327                        checkForFailure();
328                        return value;
329                }
330        }
331
332        /**
333         * Waits indefinitely until the command completes
334         * and returns the result of the command.
335         * <p>
336         * If the thread is interrupted while waiting for the command
337         * to complete, the interrupt is simply ignored and no
338         * {@link InterruptedException} is thrown.
339         * </p><p><i>
340         * Please note that this method is blocking and thus negates
341         * the advantage of the asynchronous nature of this class.
342         * Consider using {@link #onSuccess(SuccessListener)} and
343         * {@link #onFailure(FailureListener)} instead.
344         * </i></p>
345         *
346         * @return the server response to the command
347         *
348         * @throws CancellationException
349         *              if the {@code CommandFuture} was cancelled before the command completed
350         * @throws TS3Exception
351         *              if the command fails
352         */
353        public V getUninterruptibly() {
354                synchronized (monitor) {
355                        awaitUninterruptibly();
356
357                        checkForFailure();
358                        return value;
359                }
360        }
361
362        /**
363         * Waits for at most the given time until the command completes
364         * and returns the result of the command.
365         * <p>
366         * If the thread is interrupted while waiting for the command
367         * to complete, the interrupt is simply ignored and no
368         * {@link InterruptedException} is thrown.
369         * </p><p><i>
370         * Please note that this method is blocking and thus negates
371         * the advantage of the asynchronous nature of this class.
372         * Consider using {@link #onSuccess(SuccessListener)} and
373         * {@link #onFailure(FailureListener)} instead.
374         * </i></p>
375         *
376         * @param timeout
377         *              the maximum amount of the given time unit to wait
378         * @param unit
379         *              the time unit of the timeout argument
380         *
381         * @return the server response to the command
382         *
383         * @throws TimeoutException
384         *              if the given time elapsed without the command completing
385         * @throws CancellationException
386         *              if the {@code CommandFuture} was cancelled before the command completed
387         * @throws TS3Exception
388         *              if the command fails
389         */
390        public V getUninterruptibly(long timeout, TimeUnit unit) throws TimeoutException {
391                synchronized (monitor) {
392                        awaitUninterruptibly(timeout, unit);
393
394                        checkForFailure();
395                        return value;
396                }
397        }
398
399        /**
400         * Throws an exception if the future was either cancelled or the command failed.
401         * <p>
402         * <strong>Must be called with the monitor lock held!</strong>
403         * </p>
404         *
405         * @throws CancellationException
406         *              if the future was cancelled
407         * @throws TS3Exception
408         *              if the command failed
409         */
410        private void checkForFailure() {
411                if (state == FutureState.CANCELLED) {
412                        throw new CancellationException();
413                } else if (state == FutureState.FAILED) {
414                        // Make the stack trace of the exception point to this method and not
415                        // SocketReader#run -> TS3ApiAsync#hasFailed, which wouldn't be helpful
416                        exception.fillInStackTrace();
417                        throw exception;
418                }
419        }
420
421        @Override
422        public boolean isDone() {
423                return state != FutureState.WAITING;
424        }
425
426        /**
427         * Returns {@code true} if this command completed successfully,
428         * i.e. the future wasn't cancelled and the command completed without throwing an exception.
429         *
430         * @return {@code true} if the command completed successfully
431         */
432        public boolean isSuccessful() {
433                return state == FutureState.SUCCEEDED;
434        }
435
436        @Override
437        public boolean isCancelled() {
438                return state == FutureState.CANCELLED;
439        }
440
441        /**
442         * Returns {@code true} if the command failed and threw a {@link TS3Exception}.
443         *
444         * @return {@code true} if the command failed
445         */
446        public boolean hasFailed() {
447                return state == FutureState.FAILED;
448        }
449
450        /**
451         * Sets the value of this future. This will mark the future as successful.
452         * <p>
453         * Furthermore, this will run the {@link SuccessListener}, if one is registered.
454         * All exceptions thrown from the body of the {@code SuccessListener} are caught
455         * so no exceptions can leak into user code.
456         * </p><p>
457         * Note that a future's value can only be set once. Subsequent calls to
458         * this method will be ignored.
459         * </p>
460         *
461         * @param value
462         *              the value to set this future to
463         *
464         * @return {@code true} if the command was marked as successful
465         */
466        public boolean set(V value) {
467                SuccessListener<? super V> listener;
468
469                synchronized (monitor) {
470                        if (isDone()) return false; // Ignore
471
472                        this.state = FutureState.SUCCEEDED;
473                        this.value = value;
474                        listener = successListener;
475                        monitor.notifyAll();
476                }
477
478                if (listener != null) {
479                        try {
480                                listener.handleSuccess(value);
481                        } catch (Exception e) {
482                                // Whatever happens, we do not want a user error to leak into our logic
483                                log.error("SuccessListener threw an exception", e);
484                        }
485                }
486                return true;
487        }
488
489        /**
490         * Notifies this future that the command has failed.
491         * <p>
492         * Furthermore, this will run the {@link FailureListener}, if one is registered.
493         * All exceptions thrown from the body of the {@code FailureListener} are caught
494         * so no exceptions can leak into user code.
495         * </p><p>
496         * Note that a future can only fail once. Subsequent calls to this method will be ignored.
497         * </p>
498         *
499         * @param exception
500         *              the exception that occurred while executing this command
501         *
502         * @return {@code true} if the command was marked as failed
503         */
504        public boolean fail(TS3Exception exception) {
505                FailureListener listener;
506
507                synchronized (monitor) {
508                        if (isDone()) return false; // Ignore
509
510                        this.state = FutureState.FAILED;
511                        this.exception = exception;
512                        listener = failureListener;
513                        monitor.notifyAll();
514                }
515
516                if (listener != null) {
517                        try {
518                                listener.handleFailure(exception);
519                        } catch (Exception e) {
520                                // Whatever happens, we do not want a user error to leak into our logic
521                                log.error("FailureListener threw an exception", e);
522                        }
523                }
524                return true;
525        }
526
527        /**
528         * {@inheritDoc}
529         * <p>
530         * Cancelling a {@code CommandFuture} will <b>not</b> actually cancel the
531         * execution of the command which was sent to the TeamSpeak server.
532         * </p><p>
533         * It will, however, prevent the {@link SuccessListener} and the
534         * {@link FailureListener} from firing, provided a response from the
535         * server has not yet arrived.
536         * </p>
537         */
538        @Override
539        public boolean cancel(boolean mayInterruptIfRunning) {
540                synchronized (monitor) {
541                        if (isDone()) return false; // Ignore
542
543                        this.state = FutureState.CANCELLED;
544                        monitor.notifyAll();
545                }
546
547                return true;
548        }
549
550        /**
551         * Sets a {@link SuccessListener} which will be notified when this future
552         * succeeded and a value has been set.
553         * <p>
554         * If this future has already succeeded, this method will immediately call
555         * the listener method, which will be executed synchronously.
556         * </p>
557         *
558         * @param listener
559         *              the listener to notify of a success
560         *
561         * @return this object for chaining
562         */
563        public CommandFuture<V> onSuccess(SuccessListener<? super V> listener) {
564                boolean runSuccessListener;
565                V successValue;
566
567                synchronized (monitor) {
568                        if (successListener != null) {
569                                throw new IllegalStateException("Listener already set");
570                        }
571                        successListener = listener;
572
573                        runSuccessListener = isSuccessful();
574                        successValue = value;
575                }
576
577                if (runSuccessListener) {
578                        listener.handleSuccess(successValue);
579                }
580
581                return this;
582        }
583
584        /**
585         * Sets a {@link FailureListener} which will be notified when this future
586         * fails because of a error returned by the TeamSpeak server.
587         * <p>
588         * If this future has already failed, this method will immediately call
589         * the listener method, which will be executed synchronously.
590         * </p>
591         *
592         * @param listener
593         *              the listener to notify of a failure
594         *
595         * @return this object for chaining
596         */
597        public CommandFuture<V> onFailure(FailureListener listener) {
598                boolean runFailureListener;
599                TS3Exception failureException;
600
601                synchronized (monitor) {
602                        if (failureListener != null) {
603                                throw new IllegalStateException("Listener already set");
604                        }
605                        failureListener = listener;
606
607                        runFailureListener = hasFailed();
608                        failureException = exception;
609                }
610
611                if (runFailureListener) {
612                        listener.handleFailure(failureException);
613                }
614
615                return this;
616        }
617
618        /**
619         * Forwards a success to another future by calling {@link #set(Object)} on
620         * that future with the value this future was set to.
621         * <p>
622         * This will register a {@link SuccessListener}, meaning that you will not
623         * be able to register another {@code SuccessListener}.
624         * </p>
625         *
626         * @param otherFuture
627         *              the future to forward a success to
628         *
629         * @return this object for chaining
630         */
631        public CommandFuture<V> forwardSuccess(final CommandFuture<? super V> otherFuture) {
632                return onSuccess(otherFuture::set);
633        }
634
635        /**
636         * Forwards a failure to another future by calling {@link #fail(TS3Exception)}
637         * on that future with the error that caused this future to fail.
638         * <p>
639         * This will register a {@link FailureListener}, meaning that you will not
640         * be able to register another {@code FailureListener}.
641         * </p>
642         *
643         * @param otherFuture
644         *              the future to forward a failure to
645         *
646         * @return this object for chaining
647         */
648        public CommandFuture<V> forwardFailure(final CommandFuture<?> otherFuture) {
649                return onFailure(otherFuture::fail);
650        }
651
652        /**
653         * Forwards both a success as well as a failure to another {@code CommandFuture}.
654         * This method just calls both {@link #forwardSuccess(CommandFuture)} and
655         * {@link #forwardFailure(CommandFuture)}.
656         * <p>
657         * This will set both a {@link SuccessListener} as well as a {@link FailureListener},
658         * so no other listeners can be registered.
659         * </p>
660         *
661         * @param otherFuture
662         *              the future which should be notified about
663         */
664        public void forwardResult(final CommandFuture<V> otherFuture) {
665                forwardSuccess(otherFuture).forwardFailure(otherFuture);
666        }
667
668        /**
669         * Creates a new {@code CommandFuture} that succeeds with {@code fn(result)}
670         * if the original future succeeded with a value {@code result}, and fails
671         * if the original future failed or if the mapping function {@code fn} threw
672         * an exception.
673         *
674         * @param fn
675         *              a function that maps the result value of type {@code V} to a value of type {@code F}
676         * @param <F>
677         *              the result type of {@code fn}
678         *
679         * @return a new {@code CommandFuture} that will hold the return value of {@code fn}
680         */
681        public <F> CommandFuture<F> map(Function<? super V, ? extends F> fn) {
682                CommandFuture<F> target = new CommandFuture<>();
683                onSuccess(result -> {
684                        F output;
685                        try {
686                                output = fn.apply(result);
687                        } catch (Exception ex) {
688                                target.fail(new TS3Exception("CommandFuture 'map' function threw an exception", ex));
689                                return;
690                        }
691                        target.set(output);
692                }).forwardFailure(target);
693                return target;
694        }
695
696        /**
697         * Creates a new {@code CommandFuture} that succeeds with the result value of
698         * the {@code CommandFuture} returned by {@code fn} if both the original future
699         * and the future returned by {@code fn} succeed.
700         * <p>
701         * The created {@code CommandFuture} fails if the original future failed,
702         * the future returned by {@code fn} fails, or if {@code fn} throws an exception.
703         * </p><p>
704         * If {@code fn} returns {@code null}, the created {@code CommandFuture}
705         * will immediately succeed with a value of {@code null}. To create this effect
706         * with non-null values, return an {@link #immediate(Object)} future instead.
707         * </p>
708         *
709         * @param fn
710         *              a function that maps the result value of type {@code V} to a {@code CommandFuture<F>}
711         * @param <F>
712         *              the result type of the future returned by {@code fn}
713         *
714         * @return a new {@code CommandFuture} that will hold the result of the future returned by {@code fn}
715         */
716        public <F> CommandFuture<F> then(Function<? super V, CommandFuture<F>> fn) {
717                CommandFuture<F> target = new CommandFuture<>();
718                onSuccess(result -> {
719                        CommandFuture<F> nextFuture;
720                        try {
721                                nextFuture = fn.apply(result);
722                        } catch (Exception ex) {
723                                target.fail(new TS3Exception("CommandFuture 'then' function threw an exception", ex));
724                                return;
725                        }
726
727                        if (nextFuture == null) {
728                                target.set(null); // Propagate null shortcut
729                        } else {
730                                nextFuture.forwardResult(target);
731                        }
732                }).forwardFailure(target);
733                return target;
734        }
735
736        /**
737         * Returns a new {@code CommandFuture} that already has a value set.
738         *
739         * @param value
740         *              the default value for the new {@code CommandFuture}
741         * @param <V>
742         *              the dynamic type of the value, will usually be inferred
743         *
744         * @return a new {@code CommandFuture} with a default value
745         */
746        public static <V> CommandFuture<V> immediate(V value) {
747                final CommandFuture<V> future = new CommandFuture<>();
748                future.set(value);
749                return future;
750        }
751
752        /**
753         * Combines multiple {@code CommandFuture}s into a single future, which will
754         * succeed if all futures succeed and fail as soon as one future fails.
755         *
756         * @param futures
757         *              the futures to combine
758         * @param <F>
759         *              the common return type of the futures
760         *
761         * @return a future which succeeds if all supplied futures succeed
762         */
763        @SafeVarargs
764        public static <F> CommandFuture<List<F>> ofAll(CommandFuture<F>... futures) {
765                return ofAll(Arrays.asList(futures));
766        }
767
768        /**
769         * Combines a collection of {@code CommandFuture}s into a single future, which will
770         * succeed if all futures succeed and fail as soon as one future fails.
771         *
772         * @param futures
773         *              the futures to combine
774         * @param <F>
775         *              the common return type of the futures
776         *
777         * @return a future which succeeds if all supplied futures succeed
778         */
779        public static <F> CommandFuture<List<F>> ofAll(final Collection<CommandFuture<F>> futures) {
780                if (futures.isEmpty()) return immediate(Collections.emptyList());
781
782                @SuppressWarnings("unchecked") final F[] results = (F[]) new Object[futures.size()];
783                final AtomicInteger successCounter = new AtomicInteger(futures.size());
784                final CommandFuture<List<F>> combined = new CommandFuture<>();
785
786                final Iterator<CommandFuture<F>> iterator = futures.iterator();
787                for (int i = 0; iterator.hasNext(); ++i) {
788                        final int index = i;
789                        final CommandFuture<F> future = iterator.next();
790
791                        future.forwardFailure(combined).onSuccess(result -> {
792                                results[index] = result;
793
794                                if (successCounter.decrementAndGet() == 0) {
795                                        combined.set(Arrays.asList(results));
796                                }
797                        });
798                }
799
800                return combined;
801        }
802
803        /**
804         * Combines multiple {@code CommandFuture}s into a single future, which will
805         * succeed if any of the futures succeeds and fail if all of the futures fail.
806         *
807         * @param futures
808         *              the futures to combine
809         * @param <F>
810         *              the common return type of the futures
811         *
812         * @return a future which succeeds if one of the supplied futures succeeds
813         */
814        @SafeVarargs
815        public static <F> CommandFuture<F> ofAny(CommandFuture<F>... futures) {
816                return ofAny(Arrays.asList(futures));
817        }
818
819        /**
820         * Combines a collection of {@code CommandFuture}s into a single future, which will
821         * succeed as soon as one of the futures succeeds and fail if all futures fail.
822         *
823         * @param futures
824         *              the futures to combine
825         * @param <F>
826         *              the common return type of the futures
827         *
828         * @return a future which succeeds if one of the supplied futures succeeds
829         */
830        public static <F> CommandFuture<F> ofAny(final Collection<CommandFuture<F>> futures) {
831                if (futures.isEmpty()) throw new IllegalArgumentException("Requires at least 1 future");
832
833                final CommandFuture<F> any = new CommandFuture<>();
834                final AtomicInteger failureCounter = new AtomicInteger(futures.size());
835
836                for (CommandFuture<F> future : futures) {
837                        future.forwardSuccess(any).onFailure(exception -> {
838                                if (failureCounter.decrementAndGet() == 0) {
839                                        any.fail(exception);
840                                }
841                        });
842                }
843
844                return any;
845        }
846
847        /**
848         * A listener which will be notified if the {@link CommandFuture} succeeded.
849         * In that case, {@link #handleSuccess(Object)} will be called with the value
850         * the future has been set to.
851         * <p>
852         * A {@code CommandFuture}'s {@code SuccessListener} can be set by calling
853         * {@link #onSuccess(SuccessListener)}.
854         * </p>
855         *
856         * @param <V>
857         *              the type of the value
858         */
859        @FunctionalInterface
860        public interface SuccessListener<V> {
861
862                /**
863                 * The method to be executed when the command succeeds.
864                 *
865                 * @param result
866                 *              the result of the command
867                 */
868                void handleSuccess(V result);
869        }
870
871        /**
872         * A listener which will be notified if the {@link CommandFuture} failed.
873         * In that case, {@link #handleFailure(TS3Exception)} will be called with
874         * the exception that occurred while executing this command.
875         * <p>
876         * A {@code CommandFuture}'s {@code FailureListener} can be set by calling
877         * {@link #onFailure(FailureListener)}.
878         * </p>
879         */
880        @FunctionalInterface
881        public interface FailureListener {
882
883                /**
884                 * The method to be executed when the command failed.
885                 *
886                 * @param exception
887                 *              the exception that occurred while executing this command
888                 */
889                void handleFailure(TS3Exception exception);
890        }
891}