2 // ========================================================================
3 // Copyright (c) 1995-2014 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.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.util;
21 import java.io.Closeable;
22 import java.io.IOException;
23 import java.io.InterruptedIOException;
24 import java.util.concurrent.CancellationException;
25 import java.util.concurrent.TimeUnit;
26 import java.util.concurrent.TimeoutException;
27 import java.util.concurrent.locks.Condition;
28 import java.util.concurrent.locks.ReentrantLock;
30 import org.eclipse.jetty.util.log.Log;
31 import org.eclipse.jetty.util.log.Logger;
32 import org.eclipse.jetty.util.thread.NonBlockingThread;
35 /* ------------------------------------------------------------ */
36 /** Provides a reusable BlockingCallback.
37 * A typical usage pattern is:
39 * void someBlockingCall(Object... args) throws IOException
41 * try(Blocker blocker=sharedBlockingCallback.acquire())
43 * someAsyncCall(args,blocker);
49 public class SharedBlockingCallback
51 private static final Logger LOG = Log.getLogger(SharedBlockingCallback.class);
54 private static Throwable IDLE = new Throwable()
57 public String toString()
63 private static Throwable SUCCEEDED = new Throwable()
66 public String toString()
72 private static Throwable FAILED = new Throwable()
75 public String toString()
81 final Blocker _blocker;
83 public SharedBlockingCallback()
88 protected SharedBlockingCallback(Blocker blocker)
93 public Blocker acquire() throws IOException
95 _blocker._lock.lock();
98 while (_blocker._state != IDLE)
99 _blocker._idle.await();
100 _blocker._state = null;
102 catch (final InterruptedException e)
104 throw new InterruptedIOException()
113 _blocker._lock.unlock();
119 /* ------------------------------------------------------------ */
120 /** A Closeable Callback.
121 * Uses the auto close mechanism to check block has been called OK.
123 public static class Blocker implements Callback, Closeable
125 final ReentrantLock _lock = new ReentrantLock();
126 final Condition _idle = _lock.newCondition();
127 final Condition _complete = _lock.newCondition();
128 Throwable _state = IDLE;
135 public void succeeded()
143 _complete.signalAll();
145 else if (_state == IDLE)
146 throw new IllegalStateException("IDLE");
155 public void failed(Throwable cause)
162 // TODO remove when feedback received on 435322
164 LOG.warn("null failed cause (please report stack trace) ",new Throwable());
165 _state = cause==null?FAILED:cause;
166 _complete.signalAll();
168 else if (_state == IDLE)
169 throw new IllegalStateException("IDLE");
178 * Block until the Callback has succeeded or failed and after the return leave in the state to allow reuse. This is useful for code that wants to
179 * repeatable use a FutureCallback to convert an asynchronous API to a blocking API.
181 * @throws IOException
182 * if exception was caught during blocking, or callback was cancelled
184 public void block() throws IOException
186 if (NonBlockingThread.isNonBlockingThread())
187 LOG.warn("Blocking a NonBlockingThread: ",new Throwable());
192 while (_state == null)
194 // TODO remove this debug timout!
195 // This is here to help debug 435322,
196 if (!_complete.await(10,TimeUnit.MINUTES))
198 IOException x = new IOException("DEBUG timeout");
199 LOG.warn("Blocked too long (please report!!!) "+this, x);
204 if (_state == SUCCEEDED)
207 throw new IllegalStateException("IDLE");
208 if (_state instanceof IOException)
209 throw (IOException)_state;
210 if (_state instanceof CancellationException)
211 throw (CancellationException)_state;
212 if (_state instanceof RuntimeException)
213 throw (RuntimeException)_state;
214 if (_state instanceof Error)
216 throw new IOException(_state);
218 catch (final InterruptedException e)
220 throw new InterruptedIOException()
234 * Check the Callback has succeeded or failed and after the return leave in the state to allow reuse.
236 * @throws IOException
237 * if exception was caught during blocking, or callback was cancelled
240 public void close() throws IOException
246 throw new IllegalStateException("IDLE");
248 LOG.debug("Blocker not complete",new Throwable());
259 public String toString()
264 return String.format("%s@%x{%s}",SharedBlockingCallback.class.getSimpleName(),hashCode(),_state);