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, X extends Exception> 036 implements CheckedFuture<V, X> { 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 * Translates from an {@link InterruptedException}, 050 * {@link CancellationException} or {@link ExecutionException} thrown by 051 * {@code get} to an exception of type {@code X} to be thrown by 052 * {@code checkedGet}. Subclasses must implement this method. 053 * 054 * <p>If {@code e} is an {@code InterruptedException}, the calling 055 * {@code checkedGet} method has already restored the interrupt after catching 056 * the exception. If an implementation of {@link #mapException(Exception)} 057 * wishes to swallow the interrupt, it can do so by calling 058 * {@link Thread#interrupted()}. 059 */ 060 protected abstract X mapException(Exception e); 061 062 /** 063 * {@inheritDoc} 064 * 065 * <p>This implementation calls {@link #get()} and maps that method's standard 066 * exceptions to instances of type {@code X} using {@link #mapException}. 067 * 068 * <p>In addition, if {@code get} throws an {@link InterruptedException}, this 069 * implementation will set the current thread's interrupt status before 070 * calling {@code mapException}. 071 * 072 * @throws X if {@link #get()} throws an {@link InterruptedException}, 073 * {@link CancellationException}, or {@link ExecutionException} 074 */ 075 public V checkedGet() throws X { 076 try { 077 return get(); 078 } catch (InterruptedException e) { 079 Thread.currentThread().interrupt(); 080 throw mapException(e); 081 } catch (CancellationException e) { 082 throw mapException(e); 083 } catch (ExecutionException e) { 084 throw mapException(e); 085 } 086 } 087 088 /** 089 * {@inheritDoc} 090 * 091 * <p>This implementation calls {@link #get(long, TimeUnit)} and maps that 092 * method's standard exceptions (excluding {@link TimeoutException}, which is 093 * propagated) to instances of type {@code X} using {@link #mapException}. 094 * 095 * <p>In addition, if {@code get} throws an {@link InterruptedException}, this 096 * implementation will set the current thread's interrupt status before 097 * calling {@code mapException}. 098 * 099 * @throws X if {@link #get()} throws an {@link InterruptedException}, 100 * {@link CancellationException}, or {@link ExecutionException} 101 * @throws TimeoutException {@inheritDoc} 102 */ 103 public V checkedGet(long timeout, TimeUnit unit) throws TimeoutException, X { 104 try { 105 return get(timeout, unit); 106 } catch (InterruptedException e) { 107 Thread.currentThread().interrupt(); 108 throw mapException(e); 109 } catch (CancellationException e) { 110 throw mapException(e); 111 } catch (ExecutionException e) { 112 throw mapException(e); 113 } 114 } 115 116 // Delegate methods for methods defined in the ListenableFuture interface. 117 118 public boolean cancel(boolean mayInterruptIfRunning) { 119 return delegate.cancel(mayInterruptIfRunning); 120 } 121 122 public boolean isCancelled() { 123 return delegate.isCancelled(); 124 } 125 126 public boolean isDone() { 127 return delegate.isDone(); 128 } 129 130 public V get() throws InterruptedException, ExecutionException { 131 return delegate.get(); 132 } 133 134 public V get(long timeout, TimeUnit unit) throws InterruptedException, 135 ExecutionException, TimeoutException { 136 return delegate.get(timeout, unit); 137 } 138 139 public void addListener(Runnable listener, Executor exec) { 140 delegate.addListener(listener, exec); 141 } 142 }