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.TS3CommandFailedException;
031import com.github.theholywaffle.teamspeak3.api.wrapper.QueryError;
032
033import java.util.Arrays;
034import java.util.Collection;
035import java.util.Iterator;
036import java.util.List;
037import java.util.concurrent.CancellationException;
038import java.util.concurrent.Future;
039import java.util.concurrent.TimeUnit;
040import java.util.concurrent.TimeoutException;
041import java.util.concurrent.atomic.AtomicInteger;
042
043/**
044 * Represents the result of an asynchronous execution of a query command.
045 * <p>
046 * Basically, this class is a container for a server response which will
047 * arrive at some time in the future. It also accounts for the possibility
048 * that a command might fail and that a future might be cancelled by a user.
049 * </p>
050 * A {@code CommandFuture} can therefore have 4 different states:
051 * <ul>
052 * <li><b>Waiting</b> - No response from the server has arrived yet</li>
053 * <li><b>Cancelled</b> - A user cancelled this future before a response from the server could arrive</li>
054 * <li><b>Failed</b> - The server received the command but responded with an error message</li>
055 * <li><b>Succeeded</b> - The server successfully processed the command and sent back a result</li>
056 * </ul>
057 * You can check the state of the future using the methods {@link #isDone()},
058 * {@link #isSuccessful()}, {@link #isFailed()} and {@link #isCancelled()}.
059 * <p>
060 * A {@code CommandFuture}'s value can be retrieved by calling {@link #get()}
061 * or {@link #get(long, TimeUnit)}, which block the current thread until the
062 * server response arrives. The method with a timeout should be preferred
063 * as there's no guarantee that a proper response (or an error message)
064 * will ever arrive, e.g. in case of a permanent disconnect.
065 * There are also variations of these methods which ignore thread interrupts,
066 * {@link #getUninterruptibly()} and {@link #getUninterruptibly(long, TimeUnit)}.
067 * </p><p>
068 * Note that <b>these methods</b> all wait for the response to arrive and thereby
069 * <b>revert to synchronous</b> execution. If you want to handle the server response
070 * asynchronously, you need to register success and failure listeners.
071 * These listeners will be called in a separate thread once a response arrives.
072 * </p><p>
073 * Each {@code CommandFuture} can only ever have one {@link SuccessListener} and
074 * one {@link FailureListener} registered. All {@link TS3ApiAsync} methods are
075 * guaranteed to return a {@code CommandFuture} with no listeners registered.
076 * </p><p>
077 * To set the value of a {@code CommandFuture}, the {@link #set(Object)} method is used;
078 * to notify it of a failure, {@link #fail(QueryError)} is used. You usually
079 * shouldn't call these methods yourself, however. That's the job of the API.
080 * </p><p>
081 * {@code CommandFuture}s are thread-safe. All state-changing methods are synchronized.
082 * </p>
083 *
084 * @param <V>
085 *              the type of the value
086 *
087 * @see TS3ApiAsync
088 */
089public class CommandFuture<V> implements Future<V> {
090
091        private enum FutureState {
092                WAITING,
093                CANCELLED,
094                FAILED,
095                SUCCEEDED
096        }
097
098        /**
099         * Just a plain object used for its monitor to synchronize access to the
100         * critical sections of this future and to signal state changes to any
101         * threads waiting in {@link #get()} and {@link #getUninterruptibly()} methods.
102         */
103        private final Object monitor = new Object();
104
105        private volatile FutureState state = FutureState.WAITING;
106        private volatile V value = null;
107        private volatile QueryError queryError = null;
108        private volatile SuccessListener<? super V> successListener = null;
109        private volatile FailureListener failureListener = null;
110
111        /**
112         * Waits indefinitely until the command completes.
113         * <p>
114         * If the thread is interrupted while waiting for the command
115         * to complete, this method will throw an {@code InterruptedException}
116         * and the thread's interrupt flag will be cleared.
117         * </p><p><i>
118         * Please note that this method is blocking and thus negates
119         * the advantage of the asynchronous nature of this class.
120         * Consider using {@link #onSuccess(SuccessListener)} and
121         * {@link #onFailure(FailureListener)} instead.
122         * </i></p>
123         *
124         * @throws InterruptedException
125         *              if the method is interrupted by calling {@link Thread#interrupt()}.
126         *              The interrupt flag will be cleared
127         */
128        public void await() throws InterruptedException {
129                while (state == FutureState.WAITING) {
130                        synchronized (monitor) {
131                                monitor.wait();
132                        }
133                }
134        }
135
136        /**
137         * Waits for at most the given time until the command completes.
138         * <p>
139         * If the thread is interrupted while waiting for the command
140         * to complete, this method will throw an {@code InterruptedException}
141         * and the thread's interrupt flag will be cleared.
142         * </p><p><i>
143         * Please note that this method is blocking and thus negates
144         * the advantage of the asynchronous nature of this class.
145         * Consider using {@link #onSuccess(SuccessListener)} and
146         * {@link #onFailure(FailureListener)} instead.
147         * </i></p>
148         *
149         * @param timeout
150         *              the maximum amount of the given time unit to wait
151         * @param unit
152         *              the time unit of the timeout argument
153         *
154         * @throws InterruptedException
155         *              if the method is interrupted by calling {@link Thread#interrupt()}.
156         *              The interrupt flag will be cleared
157         * @throws TimeoutException
158         *              if the given time elapsed without the command completing
159         */
160        public void await(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
161                final long end = System.currentTimeMillis() + unit.toMillis(timeout);
162                while (state == FutureState.WAITING && System.currentTimeMillis() < end) {
163                        synchronized (monitor) {
164                                monitor.wait(end - System.currentTimeMillis());
165                        }
166                }
167
168                if (state == FutureState.WAITING) throw new TimeoutException();
169        }
170
171        /**
172         * Waits indefinitely until the command completes.
173         * <p>
174         * If the thread is interrupted while waiting for the command
175         * to complete, the interrupt is simply ignored and no
176         * {@link InterruptedException} is thrown.
177         * </p><p><i>
178         * Please note that this method is blocking and thus negates
179         * the advantage of the asynchronous nature of this class.
180         * Consider using {@link #onSuccess(SuccessListener)} and
181         * {@link #onFailure(FailureListener)} instead.
182         * </i></p>
183         */
184        public void awaitUninterruptibly() {
185                boolean interrupted = false;
186                while (state == FutureState.WAITING) {
187                        try {
188                                synchronized (monitor) {
189                                        monitor.wait();
190                                }
191                        } catch (InterruptedException e) {
192                                interrupted = true;
193                        }
194                }
195
196                if (interrupted) {
197                        // Restore the interrupt for the caller
198                        Thread.currentThread().interrupt();
199                }
200        }
201
202        /**
203         * Waits for at most the given time until the command completes.
204         * <p>
205         * If the thread is interrupted while waiting for the command
206         * to complete, the interrupt is simply ignored and no
207         * {@link InterruptedException} is thrown.
208         * </p><p><i>
209         * Please note that this method is blocking and thus negates
210         * the advantage of the asynchronous nature of this class.
211         * Consider using {@link #onSuccess(SuccessListener)} and
212         * {@link #onFailure(FailureListener)} instead.
213         * </i></p>
214         *
215         * @param timeout
216         *              the maximum amount of the given time unit to wait
217         * @param unit
218         *              the time unit of the timeout argument
219         *
220         * @throws TimeoutException
221         *              if the given time elapsed without the command completing
222         */
223        public void awaitUninterruptibly(long timeout, TimeUnit unit) throws TimeoutException {
224                final long end = System.currentTimeMillis() + unit.toMillis(timeout);
225                boolean interrupted = false;
226                while (state == FutureState.WAITING && System.currentTimeMillis() < end) {
227                        try {
228                                synchronized (monitor) {
229                                        monitor.wait(end - System.currentTimeMillis());
230                                }
231                        } catch (InterruptedException e) {
232                                interrupted = true;
233                        }
234                }
235
236                if (interrupted) {
237                        // Restore the interrupt for the caller
238                        Thread.currentThread().interrupt();
239                }
240
241                if (state == FutureState.WAITING) throw new TimeoutException();
242        }
243
244        /**
245         * Waits indefinitely until the command completes
246         * and returns the result of the command.
247         * <p>
248         * If the thread is interrupted while waiting for the command
249         * to complete, this method will throw an {@code InterruptedException}
250         * and the thread's interrupt flag will be cleared.
251         * </p><p><i>
252         * Please note that this method is blocking and thus negates
253         * the advantage of the asynchronous nature of this class.
254         * Consider using {@link #onSuccess(SuccessListener)} and
255         * {@link #onFailure(FailureListener)} instead.
256         * </i></p>
257         *
258         * @return the server response to the command
259         *
260         * @throws InterruptedException
261         *              if the method is interrupted by calling {@link Thread#interrupt()}.
262         *              The interrupt flag will be cleared
263         * @throws CancellationException
264         *              if the {@code CommandFuture} was cancelled before the command completed
265         * @throws TS3CommandFailedException
266         *              if the command fails
267         */
268        @Override
269        public V get() throws InterruptedException {
270                await();
271
272                checkForFailure();
273                return value;
274        }
275
276        /**
277         * Waits for at most the given time until the command completes
278         * and returns the result of the command.
279         * <p>
280         * If the thread is interrupted while waiting for the command
281         * to complete, this method will throw an {@code InterruptedException}
282         * and the thread's interrupt flag will be cleared.
283         * </p><p><i>
284         * Please note that this method is blocking and thus negates
285         * the advantage of the asynchronous nature of this class.
286         * Consider using {@link #onSuccess(SuccessListener)} and
287         * {@link #onFailure(FailureListener)} instead.
288         * </i></p>
289         *
290         * @param timeout
291         *              the maximum amount of the given time unit to wait
292         * @param unit
293         *              the time unit of the timeout argument
294         *
295         * @return the server response to the command
296         *
297         * @throws InterruptedException
298         *              if the method is interrupted by calling {@link Thread#interrupt()}.
299         *              The interrupt flag will be cleared
300         * @throws TimeoutException
301         *              if the given time elapsed without the command completing
302         * @throws CancellationException
303         *              if the {@code CommandFuture} was cancelled before the command completed
304         * @throws TS3CommandFailedException
305         *              if the command fails
306         */
307        @Override
308        public V get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
309                await(timeout, unit);
310
311                checkForFailure();
312                return value;
313        }
314
315        /**
316         * Waits indefinitely until the command completes
317         * and returns the result of the command.
318         * <p>
319         * If the thread is interrupted while waiting for the command
320         * to complete, the interrupt is simply ignored and no
321         * {@link InterruptedException} is thrown.
322         * </p><p><i>
323         * Please note that this method is blocking and thus negates
324         * the advantage of the asynchronous nature of this class.
325         * Consider using {@link #onSuccess(SuccessListener)} and
326         * {@link #onFailure(FailureListener)} instead.
327         * </i></p>
328         *
329         * @return the server response to the command
330         *
331         * @throws CancellationException
332         *              if the {@code CommandFuture} was cancelled before the command completed
333         * @throws TS3CommandFailedException
334         *              if the command fails
335         */
336        public V getUninterruptibly() {
337                awaitUninterruptibly();
338
339                checkForFailure();
340                return value;
341        }
342
343        /**
344         * Waits for at most the given time until the command completes
345         * and returns the result of the command.
346         * <p>
347         * If the thread is interrupted while waiting for the command
348         * to complete, the interrupt is simply ignored and no
349         * {@link InterruptedException} is thrown.
350         * </p><p><i>
351         * Please note that this method is blocking and thus negates
352         * the advantage of the asynchronous nature of this class.
353         * Consider using {@link #onSuccess(SuccessListener)} and
354         * {@link #onFailure(FailureListener)} instead.
355         * </i></p>
356         *
357         * @param timeout
358         *              the maximum amount of the given time unit to wait
359         * @param unit
360         *              the time unit of the timeout argument
361         *
362         * @return the server response to the command
363         *
364         * @throws TimeoutException
365         *              if the given time elapsed without the command completing
366         * @throws CancellationException
367         *              if the {@code CommandFuture} was cancelled before the command completed
368         * @throws TS3CommandFailedException
369         *              if the command fails
370         */
371        public V getUninterruptibly(long timeout, TimeUnit unit) throws TimeoutException {
372                awaitUninterruptibly(timeout, unit);
373
374                checkForFailure();
375                return value;
376        }
377
378        /**
379         * Throws an exception if the future was either cancelled or the command failed.
380         *
381         * @throws CancellationException
382         *              if the future was cancelled
383         * @throws TS3CommandFailedException
384         *              if the command failed
385         */
386        private void checkForFailure() {
387                if (state == FutureState.CANCELLED) {
388                        throw new CancellationException();
389                } else if (state == FutureState.FAILED) {
390                        throw new TS3CommandFailedException(queryError);
391                }
392        }
393
394        @Override
395        public boolean isDone() {
396                return state != FutureState.WAITING;
397        }
398
399        /**
400         * Returns {@code true} if this command completed successfully,
401         * i.e. the future wasn't cancelled and the command completed without throwing an exception.
402         *
403         * @return {@code true} if the command completed successfully
404         */
405        public boolean isSuccessful() {
406                return state == FutureState.SUCCEEDED;
407        }
408
409        @Override
410        public boolean isCancelled() {
411                return state == FutureState.CANCELLED;
412        }
413
414        /**
415         * Returns {@code true} if the command failed and threw a {@link TS3CommandFailedException}.
416         *
417         * @return {@code true} if the command failed
418         */
419        public boolean isFailed() {
420                return state == FutureState.FAILED;
421        }
422
423        /**
424         * Sets the value of this future. This will mark the future as successful.
425         * <p>
426         * Furthermore, this will run the {@link SuccessListener}, if one is registered.
427         * All exceptions thrown from the body of the {@code SuccessListener} are caught
428         * so no exceptions can leak into user code.
429         * </p><p>
430         * Note that a future's value can only be set once. Subsequent calls to
431         * this method will be ignored.
432         * </p>
433         *
434         * @param value
435         *              the value to set this future to
436         *
437         * @return {@code true} if the command was marked as successful
438         */
439        public boolean set(V value) {
440                synchronized (monitor) {
441                        if (isDone()) return false; // Ignore
442
443                        this.state = FutureState.SUCCEEDED;
444                        this.value = value;
445                        monitor.notifyAll();
446                }
447
448                if (successListener != null) {
449                        try {
450                                successListener.handleSuccess(value);
451                        } catch (Throwable t) {
452                                // Whatever happens, we do not want a user error to leak into our logic
453                                t.printStackTrace();
454                        }
455                }
456                return true;
457        }
458
459        /**
460         * Notifies this future that the command has failed.
461         * <p>
462         * Furthermore, this will run the {@link FailureListener}, if one is registered.
463         * All exceptions thrown from the body of the {@code FailureListener} are caught
464         * so no exceptions can leak into user code.
465         * </p><p>
466         * Note that a future can only fail once. Subsequent calls to this method will be ignored.
467         * </p>
468         *
469         * @param error
470         *              the error that was returned from the server
471         *
472         * @return {@code true} if the command was marked as failed
473         */
474        public boolean fail(QueryError error) {
475                synchronized (monitor) {
476                        if (isDone()) return false; // Ignore
477
478                        this.state = FutureState.FAILED;
479                        this.queryError = error;
480                        monitor.notifyAll();
481                }
482
483                if (failureListener != null) {
484                        try {
485                                failureListener.handleFailure(queryError);
486                        } catch (Throwable t) {
487                                // Whatever happens, we do not want a user error to leak into our logic
488                                t.printStackTrace();
489                        }
490                }
491                return true;
492        }
493
494        /**
495         * {@inheritDoc}
496         * <p>
497         * Cancelling a {@code CommandFuture} will <b>not</b> actually cancel the
498         * execution of the command which was sent to the TeamSpeak server.
499         * </p><p>
500         * It will, however, prevent the {@link SuccessListener} and the
501         * {@link FailureListener} from firing, provided a response from the
502         * server has not yet arrived.
503         * </p>
504         */
505        @Override
506        public boolean cancel(boolean mayInterruptIfRunning) {
507                synchronized (monitor) {
508                        if (isDone()) return false; // Ignore
509
510                        this.state = FutureState.CANCELLED;
511                        monitor.notifyAll();
512                }
513
514                return true;
515        }
516
517        /**
518         * Sets a {@link SuccessListener} which will be notified when this future
519         * succeeded and a value has been set.
520         * <p>
521         * If this future has already succeeded, this method will immediately call
522         * the listener method, which will be executed synchronously.
523         * </p>
524         *
525         * @param listener
526         *              the listener to notify of a success
527         *
528         * @return this object for chaining
529         */
530        public CommandFuture<V> onSuccess(SuccessListener<? super V> listener) {
531                synchronized (monitor) {
532                        if (successListener != null) {
533                                throw new IllegalStateException("Listener already set");
534                        }
535                        successListener = listener;
536                }
537
538                if (state == FutureState.SUCCEEDED) {
539                        listener.handleSuccess(value);
540                }
541
542                return this;
543        }
544
545        /**
546         * Sets a {@link FailureListener} which will be notified when this future
547         * fails because of a error returned by the TeamSpeak server.
548         * <p>
549         * If this future has already failed, this method will immediately call
550         * the listener method, which will be executed synchronously.
551         * </p>
552         *
553         * @param listener
554         *              the listener to notify of a failure
555         *
556         * @return this object for chaining
557         */
558        public CommandFuture<V> onFailure(FailureListener listener) {
559                synchronized (monitor) {
560                        if (failureListener != null) {
561                                throw new IllegalStateException("Listener already set");
562                        }
563                        failureListener = listener;
564                }
565
566                if (state == FutureState.FAILED) {
567                        listener.handleFailure(queryError);
568                }
569
570                return this;
571        }
572
573        /**
574         * Forwards a success to another future by calling {@link #set(Object)} on
575         * that future with the value this future was set to.
576         * <p>
577         * This will register a {@link SuccessListener}, meaning that you will not
578         * be able to register another {@code SuccessListener}.
579         * </p>
580         *
581         * @param otherFuture
582         *              the future to forward a success to
583         *
584         * @return this object for chaining
585         */
586        public CommandFuture<V> forwardSuccess(final CommandFuture<? super V> otherFuture) {
587                return onSuccess(new SuccessListener<V>() {
588                        @Override
589                        public void handleSuccess(V result) {
590                                otherFuture.set(result);
591                        }
592                });
593        }
594
595        /**
596         * Forwards a failure to another future by calling {@link #fail(QueryError)}
597         * on that future with the error that caused this future to fail.
598         * <p>
599         * This will register a {@link FailureListener}, meaning that you will not
600         * be able to register another {@code FailureListener}.
601         * </p>
602         *
603         * @param otherFuture
604         *              the future to forward a failure to
605         *
606         * @return this object for chaining
607         */
608        public CommandFuture<V> forwardFailure(final CommandFuture<?> otherFuture) {
609                return onFailure(new FailureListener() {
610                        @Override
611                        public void handleFailure(QueryError error) {
612                                otherFuture.fail(error);
613                        }
614                });
615        }
616
617        /**
618         * Forwards both a success as well as a failure to another {@code CommandFuture}.
619         * This method just calls both {@link #forwardSuccess(CommandFuture)} and
620         * {@link #forwardFailure(CommandFuture)}.
621         * <p>
622         * This will set both a {@link SuccessListener} as well as a {@link FailureListener},
623         * so no other listeners can be registered.
624         * </p>
625         *
626         * @param otherFuture
627         *              the future which should be notified about
628         */
629        public void forwardResult(final CommandFuture<V> otherFuture) {
630                forwardSuccess(otherFuture).forwardFailure(otherFuture);
631        }
632
633        /**
634         * Returns a new {@code CommandFuture} that already has a value set.
635         *
636         * @param value
637         *              the default value for the new {@code CommandFuture}
638         * @param <V>
639         *              the dynamic type of the value, will usually be inferred
640         *
641         * @return a new {@code CommandFuture} with a default value
642         */
643        public static <V> CommandFuture<V> immediate(V value) {
644                final CommandFuture<V> future = new CommandFuture<>();
645                future.set(value);
646                return future;
647        }
648
649        /**
650         * Combines multiple {@code CommandFuture}s into a single future, which will
651         * succeed if all futures succeed and fail as soon as one future fails.
652         *
653         * @param futures
654         *              the futures to combine
655         * @param <F>
656         *              the common return type of the futures
657         *
658         * @return a future which succeeds if all supplied futures succeed
659         */
660        @SafeVarargs
661        public static <F> CommandFuture<List<F>> ofAll(CommandFuture<F>... futures) {
662                return ofAll(Arrays.asList(futures));
663        }
664
665        /**
666         * Combines a collection of {@code CommandFuture}s into a single future, which will
667         * succeed if all futures succeed and fail as soon as one future fails.
668         *
669         * @param futures
670         *              the futures to combine
671         * @param <F>
672         *              the common return type of the futures
673         *
674         * @return a future which succeeds if all supplied futures succeed
675         */
676        public static <F> CommandFuture<List<F>> ofAll(final Collection<CommandFuture<F>> futures) {
677                if (futures.isEmpty()) throw new IllegalArgumentException("Requires at least 1 future");
678
679                @SuppressWarnings("unchecked") final F[] results = (F[]) new Object[futures.size()];
680                final AtomicInteger successCounter = new AtomicInteger(futures.size());
681                final CommandFuture<List<F>> combined = new CommandFuture<>();
682
683                final Iterator<CommandFuture<F>> iterator = futures.iterator();
684                for (int i = 0; iterator.hasNext(); ++i) {
685                        final int index = i;
686                        final CommandFuture<F> future = iterator.next();
687
688                        future.forwardFailure(combined).onSuccess(new SuccessListener<F>() {
689                                @Override
690                                public void handleSuccess(F result) {
691                                        results[index] = result;
692
693                                        if (successCounter.decrementAndGet() == 0) {
694                                                combined.set(Arrays.asList(results));
695                                        }
696                                }
697                        });
698                }
699
700                return combined;
701        }
702
703        /**
704         * Combines multiple {@code CommandFuture}s into a single future, which will
705         * succeed if any of the futures succeeds and fail if all of the futures fail.
706         *
707         * @param futures
708         *              the futures to combine
709         * @param <F>
710         *              the common return type of the futures
711         *
712         * @return a future which succeeds if one of the supplied futures succeeds
713         */
714        @SafeVarargs
715        public static <F> CommandFuture<F> ofAny(CommandFuture<F>... futures) {
716                return ofAny(Arrays.asList(futures));
717        }
718
719        /**
720         * Combines a collection of {@code CommandFuture}s into a single future, which will
721         * succeed as soon as one of the futures succeeds and fail if all futures fail.
722         *
723         * @param futures
724         *              the futures to combine
725         * @param <F>
726         *              the common return type of the futures
727         *
728         * @return a future which succeeds if one of the supplied futures succeeds
729         */
730        public static <F> CommandFuture<F> ofAny(final Collection<CommandFuture<F>> futures) {
731                if (futures.isEmpty()) throw new IllegalArgumentException("Requires at least 1 future");
732
733                final CommandFuture<F> any = new CommandFuture<>();
734                final AtomicInteger failureCounter = new AtomicInteger(futures.size());
735
736                for (CommandFuture<F> future : futures) {
737                        future.forwardSuccess(any).onFailure(new FailureListener() {
738                                @Override
739                                public void handleFailure(QueryError error) {
740                                        if (failureCounter.decrementAndGet() == 0) {
741                                                any.fail(error);
742                                        }
743                                }
744                        });
745                }
746
747                return any;
748        }
749
750        /**
751         * A listener which will be notified if the {@link CommandFuture} succeeded.
752         * In that case, {@link #handleSuccess(Object)} will be called with the value
753         * the future has been set to.
754         * <p>
755         * A {@code CommandFuture}'s {@code SuccessListener} can be set by calling
756         * {@link #onSuccess(SuccessListener)}.
757         * </p>
758         *
759         * @param <V>
760         *              the type of the value
761         */
762        public interface SuccessListener<V> {
763
764                /**
765                 * The method to be executed when the command succeeds.
766                 *
767                 * @param result
768                 *              the result of the command
769                 */
770                void handleSuccess(V result);
771        }
772
773        /**
774         * A listener which will be notified if the {@link CommandFuture} failed.
775         * In that case, {@link #handleFailure(QueryError)} will be called with
776         * the error sent by the TeamSpeak server.
777         * <p>
778         * A {@code CommandFuture}'s {@code FailureListener} can be set by calling
779         * {@link #onFailure(FailureListener)}.
780         * </p>
781         */
782        public interface FailureListener {
783
784                /**
785                 * The method to be executed when the command failed.
786                 *
787                 * @param error
788                 *              the error that was sent back from the TeamSpeak server.
789                 */
790                void handleFailure(QueryError error);
791        }
792}