View Javadoc
1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.util.concurrent;
16  
17  import static com.google.common.base.Preconditions.checkNotNull;
18  import static com.google.common.base.Throwables.throwIfUnchecked;
19  
20  import com.google.common.annotations.GwtIncompatible;
21  import com.google.common.collect.ImmutableList;
22  import com.google.errorprone.annotations.CanIgnoreReturnValue;
23  import java.util.Collection;
24  import java.util.List;
25  import java.util.concurrent.Callable;
26  import java.util.concurrent.ExecutionException;
27  import java.util.concurrent.ExecutorService;
28  import java.util.concurrent.Executors;
29  import java.util.concurrent.Future;
30  import java.util.concurrent.TimeUnit;
31  import java.util.concurrent.TimeoutException;
32  
33  /**
34   * An abstract {@code ExecutorService} that allows subclasses to {@linkplain #wrapTask(Callable)
35   * wrap} tasks before they are submitted to the underlying executor.
36   *
37   * <p>Note that task wrapping may occur even if the task is never executed.
38   *
39   * <p>For delegation without task-wrapping, see {@link ForwardingExecutorService}.
40   *
41   * @author Chris Nokleberg
42   */
43  @CanIgnoreReturnValue // TODO(cpovirk): Consider being more strict.
44  @GwtIncompatible
45  abstract class WrappingExecutorService implements ExecutorService {
46    private final ExecutorService delegate;
47  
48    protected WrappingExecutorService(ExecutorService delegate) {
49      this.delegate = checkNotNull(delegate);
50    }
51  
52    /**
53     * Wraps a {@code Callable} for submission to the underlying executor. This method is also applied
54     * to any {@code Runnable} passed to the default implementation of {@link #wrapTask(Runnable)}.
55     */
56    protected abstract <T> Callable<T> wrapTask(Callable<T> callable);
57  
58    /**
59     * Wraps a {@code Runnable} for submission to the underlying executor. The default implementation
60     * delegates to {@link #wrapTask(Callable)}.
61     */
62    protected Runnable wrapTask(Runnable command) {
63      final Callable<Object> wrapped = wrapTask(Executors.callable(command, null));
64      return new Runnable() {
65        @Override
66        public void run() {
67          try {
68            wrapped.call();
69          } catch (Exception e) {
70            throwIfUnchecked(e);
71            throw new RuntimeException(e);
72          }
73        }
74      };
75    }
76  
77    /**
78     * Wraps a collection of tasks.
79     *
80     * @throws NullPointerException if any element of {@code tasks} is null
81     */
82    private final <T> ImmutableList<Callable<T>> wrapTasks(Collection<? extends Callable<T>> tasks) {
83      ImmutableList.Builder<Callable<T>> builder = ImmutableList.builder();
84      for (Callable<T> task : tasks) {
85        builder.add(wrapTask(task));
86      }
87      return builder.build();
88    }
89  
90    // These methods wrap before delegating.
91    @Override
92    public final void execute(Runnable command) {
93      delegate.execute(wrapTask(command));
94    }
95  
96    @Override
97    public final <T> Future<T> submit(Callable<T> task) {
98      return delegate.submit(wrapTask(checkNotNull(task)));
99    }
100 
101   @Override
102   public final Future<?> submit(Runnable task) {
103     return delegate.submit(wrapTask(task));
104   }
105 
106   @Override
107   public final <T> Future<T> submit(Runnable task, T result) {
108     return delegate.submit(wrapTask(task), result);
109   }
110 
111   @Override
112   public final <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
113       throws InterruptedException {
114     return delegate.invokeAll(wrapTasks(tasks));
115   }
116 
117   @Override
118   public final <T> List<Future<T>> invokeAll(
119       Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
120       throws InterruptedException {
121     return delegate.invokeAll(wrapTasks(tasks), timeout, unit);
122   }
123 
124   @Override
125   public final <T> T invokeAny(Collection<? extends Callable<T>> tasks)
126       throws InterruptedException, ExecutionException {
127     return delegate.invokeAny(wrapTasks(tasks));
128   }
129 
130   @Override
131   public final <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
132       throws InterruptedException, ExecutionException, TimeoutException {
133     return delegate.invokeAny(wrapTasks(tasks), timeout, unit);
134   }
135 
136   // The remaining methods just delegate.
137 
138   @Override
139   public final void shutdown() {
140     delegate.shutdown();
141   }
142 
143   @Override
144   public final List<Runnable> shutdownNow() {
145     return delegate.shutdownNow();
146   }
147 
148   @Override
149   public final boolean isShutdown() {
150     return delegate.isShutdown();
151   }
152 
153   @Override
154   public final boolean isTerminated() {
155     return delegate.isTerminated();
156   }
157 
158   @Override
159   public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
160     return delegate.awaitTermination(timeout, unit);
161   }
162 }