View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.util;
20  
21  import java.io.IOException;
22  import java.util.concurrent.CancellationException;
23  import java.util.concurrent.CountDownLatch;
24  import java.util.concurrent.ExecutionException;
25  import java.util.concurrent.Future;
26  import java.util.concurrent.TimeUnit;
27  import java.util.concurrent.TimeoutException;
28  import java.util.concurrent.atomic.AtomicReference;
29  
30  
31  public class FutureCallback<C> implements Future<C>,Callback<C>
32  {
33      private enum State {NOT_DONE,DOING,DONE};
34      private final AtomicReference<State> _state=new AtomicReference<>(State.NOT_DONE);
35      private CountDownLatch _done= new CountDownLatch(1);
36      private Throwable _cause;
37      private C _context;
38      private boolean _completed;
39      
40      public FutureCallback()
41      {}
42  
43      public FutureCallback(C ctx)
44      {
45          _state.set(State.DONE);
46          _context=ctx;
47          _completed=true;
48          _done.countDown();
49      }
50  
51      public FutureCallback(C ctx, Throwable failed)
52      {
53          _state.set(State.DONE);
54          _context=ctx;
55          _cause=failed;
56          _done.countDown();
57      }
58  
59      @Override
60      public void completed(C context)
61      {
62          if (_state.compareAndSet(State.NOT_DONE,State.DOING))
63          {
64              _context=context;
65              _completed=true;
66              if (_state.compareAndSet(State.DOING,State.DONE))
67              {
68                  _done.countDown();
69                  return;
70              }
71          }
72          else if (!isCancelled())
73              throw new IllegalStateException();
74      }
75  
76      @Override
77      public void failed(C context, Throwable cause)
78      {
79          if (_state.compareAndSet(State.NOT_DONE,State.DOING))
80          {
81              _context=context;
82              _cause=cause;
83              if (_state.compareAndSet(State.DOING,State.DONE))
84              {
85                  _done.countDown();
86                  return;
87              }
88          }
89          else if (!isCancelled())
90              throw new IllegalStateException();
91      }
92  
93      @Override
94      public boolean cancel(boolean mayInterruptIfRunning)
95      {
96          failed(null,new CancellationException());
97          return false;
98      }
99  
100     @Override
101     public boolean isCancelled()
102     {
103         return State.DONE.equals(_state.get())&&_cause instanceof CancellationException;
104     }
105 
106     @Override
107     public boolean isDone()
108     {
109         return State.DONE.equals(_state.get());
110     }
111 
112     @Override
113     public C get() throws InterruptedException, ExecutionException
114     {
115         _done.await();
116         if (_completed)
117             return _context;
118         if (_cause instanceof CancellationException)
119             throw (CancellationException) new CancellationException().initCause(_cause);
120         throw new ExecutionException(_cause);
121     }
122 
123     @Override
124     public C get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
125     {
126         if (!_done.await(timeout,unit))
127             throw new TimeoutException();
128         if (_completed)
129             return _context;
130         if (_cause instanceof TimeoutException)
131             throw (TimeoutException)_cause;
132         if (_cause instanceof CancellationException)
133             throw (CancellationException) new CancellationException().initCause(_cause);
134         throw new ExecutionException(_cause);
135     }
136 
137     public static void rethrow(ExecutionException e) throws IOException
138     {
139         Throwable cause=e.getCause();
140         if (cause instanceof IOException)
141             throw (IOException)cause;
142         if (cause instanceof Error)
143             throw (Error)cause;
144         if (cause instanceof RuntimeException)
145             throw (RuntimeException)cause;
146         throw new RuntimeException(cause);
147     }
148     
149     /* ------------------------------------------------------------ */
150     @Override
151     public String toString()
152     {
153         return String.format("FutureCallback@%x{%s,%b,%s}",hashCode(),_state,_completed,_context);
154     }
155     
156 }