d57ded358f4ab7b1013c84ab4edd03119ceb327c
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / concurrent / AsyncNotifyingListeningExecutorService.java
1 /*
2  * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.yangtools.util.concurrent;
10
11 import com.google.common.base.MoreObjects;
12 import com.google.common.base.MoreObjects.ToStringHelper;
13 import com.google.common.base.Preconditions;
14 import com.google.common.util.concurrent.AbstractListeningExecutorService;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.util.List;
17 import java.util.concurrent.Callable;
18 import java.util.concurrent.Executor;
19 import java.util.concurrent.ExecutorService;
20 import java.util.concurrent.TimeUnit;
21 import javax.annotation.Nullable;
22
23 /**
24  * An {@link com.google.common.util.concurrent.ListeningExecutorService} implementation that also allows for an {@link Executor} to be
25  * specified on construction that is used to execute {@link ListenableFuture} callback Runnables,
26  * registered via {@link com.google.common.util.concurrent.Futures#addCallback} or {@link ListenableFuture#addListener} directly,
27  * asynchronously when a task that is run on this executor completes. This is useful when you want
28  * to guarantee listener callback executions are off-loaded onto another thread to avoid blocking
29  * the thread that completed the task, as a common use case is to pass an executor that runs tasks
30  * in the same thread as the caller (ie <code>MoreExecutors#sameThreadExecutor</code>}) to
31  * {@link ListenableFuture#addListener}.
32  * <p>
33  * Most commonly, this class would be used in lieu of <code>MoreExecutors#listeningDecorator</code>
34  * when the underlying delegate Executor is single-threaded, in which case, you may not want
35  * ListenableFuture callbacks to block the single thread.
36  * <p>
37  * Note: the Executor specified on construction does not replace the Executor specified in
38  * {@link ListenableFuture#addListener}. The latter Executor is still used however, if it is
39  * detected that the listener Runnable would execute in the thread that completed the task, the
40  * listener is executed on Executor specified on construction.
41  *
42  * @author Thomas Pantelis
43  * @see AsyncNotifyingListenableFutureTask
44  */
45 public class AsyncNotifyingListeningExecutorService extends AbstractListeningExecutorService {
46
47     private final ExecutorService delegate;
48     private final Executor listenableFutureExecutor;
49
50     /**
51      * Constructor.
52      *
53      * @param delegate the back-end ExecutorService.
54      * @param listenableFutureExecutor the executor used to run listener callbacks asynchronously.
55      *     If null, no executor is used.
56      */
57     public AsyncNotifyingListeningExecutorService( final ExecutorService delegate,
58             @Nullable final Executor listenableFutureExecutor ) {
59         this.delegate = Preconditions.checkNotNull( delegate );
60         this.listenableFutureExecutor = listenableFutureExecutor;
61     }
62
63     /**
64      * Creates an {@link AsyncNotifyingListenableFutureTask} instance with the listener Executor.
65      *
66      * @param task the Callable to execute
67      */
68     private <T> AsyncNotifyingListenableFutureTask<T> newFutureTask( final Callable<T> task ) {
69         return AsyncNotifyingListenableFutureTask.create( task, listenableFutureExecutor );
70     }
71
72     /**
73      * Creates an {@link AsyncNotifyingListenableFutureTask} instance with the listener Executor.
74      *
75      * @param task the Runnable to execute
76      */
77     private <T> AsyncNotifyingListenableFutureTask<T> newFutureTask( final Runnable task, final T result ) {
78         return AsyncNotifyingListenableFutureTask.create( task, result, listenableFutureExecutor );
79     }
80
81     /**
82      * Returns the delegate ExecutorService.
83      */
84     protected ExecutorService getDelegate() {
85         return delegate;
86     }
87
88     @Override
89     public boolean awaitTermination( final long timeout, final TimeUnit unit ) throws InterruptedException {
90         return delegate.awaitTermination( timeout, unit );
91     }
92
93     @Override
94     public boolean isShutdown() {
95         return delegate.isShutdown();
96     }
97
98     @Override
99     public boolean isTerminated() {
100         return delegate.isTerminated();
101     }
102
103     @Override
104     public void shutdown() {
105         delegate.shutdown();
106     }
107
108     @Override
109     public List<Runnable> shutdownNow() {
110         return delegate.shutdownNow();
111     }
112
113     @Override
114     public void execute( final Runnable command ) {
115         delegate.execute( command );
116     }
117
118     @Override
119     public <T> ListenableFuture<T> submit( final Callable<T> task ) {
120         AsyncNotifyingListenableFutureTask<T> futureTask = newFutureTask( task );
121         delegate.execute( futureTask );
122         return futureTask;
123     }
124
125     @Override
126     public ListenableFuture<?> submit( final Runnable task ) {
127         AsyncNotifyingListenableFutureTask<Void> futureTask = newFutureTask( task, null );
128         delegate.execute( futureTask );
129         return futureTask;
130     }
131
132     @Override
133     public <T> ListenableFuture<T> submit( final Runnable task, final T result ) {
134         AsyncNotifyingListenableFutureTask<T> futureTask = newFutureTask( task, result );
135         delegate.execute( futureTask );
136         return futureTask;
137     }
138
139     protected ToStringHelper addToStringAttributes( final ToStringHelper toStringHelper ) {
140         return toStringHelper;
141     }
142
143     @Override
144     public final String toString() {
145         return addToStringAttributes( MoreObjects.toStringHelper( this )
146                 .add( "delegate", delegate ) ).toString();
147     }
148 }