001    /*
002     * Copyright (C) 2008 Google Inc.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package com.google.common.util.concurrent;
018    
019    import com.google.common.annotations.Beta;
020    
021    import java.util.concurrent.CancellationException;
022    import java.util.concurrent.ExecutionException;
023    import java.util.concurrent.Executor;
024    import java.util.concurrent.TimeUnit;
025    import java.util.concurrent.TimeoutException;
026    
027    /**
028     * A delegating wrapper around a {@link ListenableFuture} that adds support for
029     * the {@link #checkedGet()} and {@link #checkedGet(long, TimeUnit)} methods.
030     * 
031     * @author Sven Mawson
032     * @since 1
033     */
034    @Beta
035    public abstract class AbstractCheckedFuture<V, E extends Exception>
036        implements CheckedFuture<V, E> {
037    
038      /** The delegate, used to pass along all our methods. */
039      protected final ListenableFuture<V> delegate;
040      
041      /**
042       * Constructs an {@code AbstractCheckedFuture} that wraps a delegate.
043       */
044      protected AbstractCheckedFuture(ListenableFuture<V> delegate) {
045        this.delegate = delegate;
046      }
047    
048      /**
049       * Translate from an {@link InterruptedException},
050       * {@link CancellationException} or {@link ExecutionException} to an exception
051       * of type {@code E}.  Subclasses must implement the mapping themselves.
052       * 
053       * The {@code e} parameter can be an instance of {@link InterruptedException},
054       * {@link CancellationException}, or {@link ExecutionException}.
055       */
056      protected abstract E mapException(Exception e);
057      
058      /*
059       * Just like get but maps the exceptions into appropriate application-specific
060       * exceptions.
061       */
062      public V checkedGet() throws E {
063        try {
064          return get();
065        } catch (InterruptedException e) {
066          cancel(true);
067          throw mapException(e);
068        } catch (CancellationException e) {
069          throw mapException(e);
070        } catch (ExecutionException e) {
071          throw mapException(e);
072        }
073      }
074    
075      /*
076       * The timed version of checkedGet maps the interrupted, cancellation or
077       * execution exceptions exactly the same as the untimed version does.
078       */
079      public V checkedGet(long timeout, TimeUnit unit) throws TimeoutException, E {
080        try {
081          return get(timeout, unit);
082        } catch (InterruptedException e) {
083          cancel(true);
084          throw mapException(e);
085        } catch (CancellationException e) {
086          throw mapException(e);
087        } catch (ExecutionException e) {
088          throw mapException(e);
089        }
090      }
091    
092      // Delegate methods for methods defined in the ListenableFuture interface.
093      
094      public boolean cancel(boolean mayInterruptIfRunning) {
095        return delegate.cancel(mayInterruptIfRunning);
096      }
097      
098      public boolean isCancelled() {
099        return delegate.isCancelled();
100      }
101      
102      public boolean isDone() {
103        return delegate.isDone();
104      }
105      
106      public V get() throws InterruptedException, ExecutionException {
107        return delegate.get();
108      }
109      
110      public V get(long timeout, TimeUnit unit) throws InterruptedException,
111          ExecutionException, TimeoutException {
112        return delegate.get(timeout, unit);
113      }
114      
115      public void addListener(Runnable listener, Executor exec) {
116        delegate.addListener(listener, exec);
117      }
118    }