View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.http.pool;
28  
29  import java.io.IOException;
30  import java.util.Date;
31  import java.util.concurrent.ExecutionException;
32  import java.util.concurrent.Future;
33  import java.util.concurrent.TimeUnit;
34  import java.util.concurrent.TimeoutException;
35  import java.util.concurrent.locks.Condition;
36  import java.util.concurrent.locks.Lock;
37  
38  import org.apache.http.annotation.ThreadingBehavior;
39  import org.apache.http.annotation.Contract;
40  import org.apache.http.concurrent.FutureCallback;
41  import org.apache.http.util.Args;
42  
43  @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
44  abstract class PoolEntryFuture<T> implements Future<T> {
45  
46      private final Lock lock;
47      private final FutureCallback<T> callback;
48      private final Condition condition;
49      private volatile boolean cancelled;
50      private volatile boolean completed;
51      private T result;
52  
53      PoolEntryFuture(final Lock lock, final FutureCallback<T> callback) {
54          super();
55          this.lock = lock;
56          this.condition = lock.newCondition();
57          this.callback = callback;
58      }
59  
60      @Override
61      public boolean cancel(final boolean mayInterruptIfRunning) {
62          this.lock.lock();
63          try {
64              if (this.completed) {
65                  return false;
66              }
67              this.completed = true;
68              this.cancelled = true;
69              if (this.callback != null) {
70                  this.callback.cancelled();
71              }
72              this.condition.signalAll();
73              return true;
74          } finally {
75              this.lock.unlock();
76          }
77      }
78  
79      @Override
80      public boolean isCancelled() {
81          return this.cancelled;
82      }
83  
84      @Override
85      public boolean isDone() {
86          return this.completed;
87      }
88  
89      @Override
90      public T get() throws InterruptedException, ExecutionException {
91          try {
92              return get(0, TimeUnit.MILLISECONDS);
93          } catch (final TimeoutException ex) {
94              throw new ExecutionException(ex);
95          }
96      }
97  
98      @Override
99      public T get(
100             final long timeout,
101             final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
102         Args.notNull(unit, "Time unit");
103         this.lock.lock();
104         try {
105             if (this.completed) {
106                 return this.result;
107             }
108             this.result = getPoolEntry(timeout, unit);
109             this.completed = true;
110             if (this.callback != null) {
111                 this.callback.completed(this.result);
112             }
113             return result;
114         } catch (final IOException ex) {
115             this.completed = true;
116             this.result = null;
117             if (this.callback != null) {
118                 this.callback.failed(ex);
119             }
120             throw new ExecutionException(ex);
121         } finally {
122             this.lock.unlock();
123         }
124     }
125 
126     protected abstract T getPoolEntry(
127             long timeout, TimeUnit unit) throws IOException, InterruptedException, TimeoutException;
128 
129     public boolean await(final Date deadline) throws InterruptedException {
130         this.lock.lock();
131         try {
132             if (this.cancelled) {
133                 throw new InterruptedException("Operation interrupted");
134             }
135             final boolean success;
136             if (deadline != null) {
137                 success = this.condition.awaitUntil(deadline);
138             } else {
139                 this.condition.await();
140                 success = true;
141             }
142             if (this.cancelled) {
143                 throw new InterruptedException("Operation interrupted");
144             }
145             return success;
146         } finally {
147             this.lock.unlock();
148         }
149 
150     }
151 
152     public void wakeup() {
153         this.lock.lock();
154         try {
155             this.condition.signalAll();
156         } finally {
157             this.lock.unlock();
158         }
159     }
160 
161 }