All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.util.SharedBlockingCallback Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
// 
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// 
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// 
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// 
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
// 
package org.eclipse.jetty.util;

import java.io.Closeable;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

/**
 *  Provides a reusable {@link Callback} that can block the thread
 *  while waiting to be completed.
 *  

* A typical usage pattern is: *

 *  void someBlockingCall(Object... args) throws IOException
 *  {
 *      try(Blocker blocker = sharedBlockingCallback.acquire())
 *      {
 *          someAsyncCall(args, blocker);
 *          blocker.block();
 *      }
 *  }
 *  
* * @deprecated The Eclipse Jetty and Apache Felix Http Jetty packages are no longer supported. */ @Deprecated(since = "2021-05-27") public class SharedBlockingCallback { private static final Logger LOG = Log.getLogger(SharedBlockingCallback.class); private static final Throwable IDLE = new ConstantThrowable("IDLE"); private static final Throwable SUCCEEDED = new ConstantThrowable("SUCCEEDED"); private static final Throwable FAILED = new ConstantThrowable("FAILED"); private final ReentrantLock _lock = new ReentrantLock(); private final Condition _idle = _lock.newCondition(); private final Condition _complete = _lock.newCondition(); private Blocker _blocker = new Blocker(); @Deprecated protected long getIdleTimeout() { return -1; } public Blocker acquire() throws IOException { long idle = getIdleTimeout(); _lock.lock(); try { while (_blocker._state != IDLE) { if (idle > 0 && (idle < Long.MAX_VALUE / 2)) { // Wait a little bit longer than the blocker might block if (!_idle.await(idle * 2, TimeUnit.MILLISECONDS)) throw new IOException(new TimeoutException()); } else _idle.await(); } _blocker._state = null; return _blocker; } catch (InterruptedException x) { throw new InterruptedIOException(); } finally { _lock.unlock(); } } public boolean fail(Throwable cause) { Objects.requireNonNull(cause); _lock.lock(); try { if (_blocker._state == null) { _blocker._state = new BlockerFailedException(cause); _complete.signalAll(); return true; } } finally { _lock.unlock(); } return false; } protected void notComplete(Blocker blocker) { LOG.warn("Blocker not complete {}", blocker); if (LOG.isDebugEnabled()) LOG.debug(new Throwable()); } /** * A Closeable Callback. * Uses the auto close mechanism to check block has been called OK. *

Implements {@link Callback} because calls to this * callback do not blocak, rather they wakeup the thread that is blocked * in {@link #block()} * * @deprecated The Eclipse Jetty and Apache Felix Http Jetty packages are no longer supported. */ @Deprecated(since = "2021-05-27") public class Blocker implements Callback, Closeable { private Throwable _state = IDLE; protected Blocker() { } @Override public InvocationType getInvocationType() { return InvocationType.NON_BLOCKING; } @Override public void succeeded() { _lock.lock(); try { if (_state == null) { _state = SUCCEEDED; _complete.signalAll(); } else { LOG.warn("Succeeded after {}", _state.toString()); if (LOG.isDebugEnabled()) LOG.debug(_state); } } finally { _lock.unlock(); } } @Override public void failed(Throwable cause) { _lock.lock(); try { if (_state == null) { if (cause == null) _state = FAILED; else if (cause instanceof BlockerTimeoutException) // Not this blockers timeout _state = new IOException(cause); else _state = cause; _complete.signalAll(); } else if (_state instanceof BlockerTimeoutException || _state instanceof BlockerFailedException) { // Failure arrived late, block() already // modified the state, nothing more to do. if (LOG.isDebugEnabled()) LOG.debug("Failed after {}", _state); } else { LOG.warn("Failed after {}: {}", _state, cause); if (LOG.isDebugEnabled()) { LOG.debug(_state); LOG.debug(cause); } } } finally { _lock.unlock(); } } /** * 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 * repeatable use a FutureCallback to convert an asynchronous API to a blocking API. * * @throws IOException if exception was caught during blocking, or callback was cancelled */ public void block() throws IOException { long idle = getIdleTimeout(); _lock.lock(); try { while (_state == null) { if (idle > 0) { // Waiting here may compete with the idle timeout mechanism, // so here we wait a little bit longer to favor the normal // idle timeout mechanism that will call failed(Throwable). long excess = Math.min(idle / 2, 1000); if (!_complete.await(idle + excess, TimeUnit.MILLISECONDS)) { // Method failed(Throwable) has not been called yet, // so we will synthesize a special TimeoutException. _state = new BlockerTimeoutException(); } } else { _complete.await(); } } if (_state == SUCCEEDED) return; if (_state == IDLE) throw new IllegalStateException("IDLE"); if (_state instanceof IOException) throw (IOException) _state; if (_state instanceof CancellationException) throw (CancellationException) _state; if (_state instanceof RuntimeException) throw (RuntimeException) _state; if (_state instanceof Error) throw (Error) _state; throw new IOException(_state); } catch (final InterruptedException e) { _state = e; throw new InterruptedIOException(); } finally { _lock.unlock(); } } /** * Check the Callback has succeeded or failed and after the return leave in the state to allow reuse. */ @Override public void close() { _lock.lock(); try { if (_state == IDLE) throw new IllegalStateException("IDLE"); if (_state == null) notComplete(this); } finally { try { // If we have a failure if (_state != null && _state != SUCCEEDED) // create a new Blocker _blocker = new Blocker(); else // else reuse Blocker _state = IDLE; _idle.signalAll(); _complete.signalAll(); } finally { _lock.unlock(); } } } @Override public String toString() { _lock.lock(); try { return String.format("%s@%x{%s}", Blocker.class.getSimpleName(), hashCode(), _state); } finally { _lock.unlock(); } } } // @deprecated The Eclipse Jetty and Apache Felix Http Jetty packages are no longer supported. @Deprecated(since = "2021-05-27") private static class BlockerTimeoutException extends TimeoutException { } // @deprecated The Eclipse Jetty and Apache Felix Http Jetty packages are no longer supported. @Deprecated(since = "2021-05-27") private static class BlockerFailedException extends Exception { public BlockerFailedException(Throwable cause) { super(cause); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy