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

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

There is a newer version: 12.1.0.alpha0
Show newest version
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.util;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import org.eclipse.jetty.util.thread.Invocable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Utility class that provides blocking {@link java.lang.Runnable} and {@link org.eclipse.jetty.util.Callback}
 * instances.  These can either be shared (and mutually excluded from concurrent usage) or single usage.
 * The instances are autocloseable and will emit a warning if the instance is not completed within close.
 *
 * 

Non shared Runnable

*
 *     try(Blocker.Runnable onAction = Blocker.runnable())
 *     {
 *         someMethod(onAction);
 *         onAction.block();
 *     }
 * 
* *

Shared Runnable

*
 *     Blocker.SharedRunnable shared = new Blocker.Shared();
 *     // ...
 *     try(Blocker.Runnable onAction = shared.runnable())
 *     {
 *         someMethod(onAction);
 *         onAction.block();
 *     }
 * 
* *

Non shared Callback

*
 *     try(Blocker.Callback callback = Blocker.callback())
 *     {
 *         someMethod(callback);
 *         callback.block();
 *     }
 * 
* *

Shared Callback

*
 *     Blocker.Shared blocker = new Blocker.Shared();
 *     // ...
 *     try(Blocker.Callback callback = blocker.callback())
 *     {
 *         someMethod(callback);
 *         callback.block();
 *     }
 * 
*/ public class Blocker { private static final Logger LOG = LoggerFactory.getLogger(Blocker.class); private static final Throwable ACQUIRED = new Throwable() { @Override public Throwable fillInStackTrace() { return this; } }; private static final Throwable SUCCEEDED = new Throwable() { @Override public Throwable fillInStackTrace() { return this; } }; public interface Runnable extends java.lang.Runnable, AutoCloseable, Invocable { void block() throws IOException; @Override void close(); } public static Runnable runnable() { return new Runnable() { final CountDownLatch _complete = new CountDownLatch(1); @Override public void run() { _complete.countDown(); } @Override public InvocationType getInvocationType() { return InvocationType.NON_BLOCKING; } @Override public void block() throws IOException { try { _complete.await(); } catch (Throwable t) { throw IO.rethrow(t); } } @Override public void close() { if (_complete.getCount() != 0) { if (LOG.isDebugEnabled()) LOG.warn("Blocking.Runnable incomplete", new Throwable()); else LOG.warn("Blocking.Runnable incomplete"); } } }; } public interface Callback extends org.eclipse.jetty.util.Callback, AutoCloseable, Invocable { void block() throws IOException; @Override void close(); } public static Callback callback() { return new Callback() { private final CompletableFuture _future = new CompletableFuture<>(); @Override public InvocationType getInvocationType() { return InvocationType.NON_BLOCKING; } @Override public void succeeded() { _future.complete(SUCCEEDED); } @Override public void failed(Throwable x) { _future.complete(x == null ? new Throwable() : x); } @Override public void block() throws IOException { Throwable result; try { result = _future.get(); } catch (Throwable t) { result = t; } if (result == SUCCEEDED) return; throw IO.rethrow(result); } @Override public void close() { if (!_future.isDone()) { if (LOG.isDebugEnabled()) LOG.warn("Blocking.Callback incomplete", new Throwable()); else LOG.warn("Blocking.Callback incomplete"); } } }; } public interface Promise extends org.eclipse.jetty.util.Promise, AutoCloseable, Invocable { C block() throws IOException; @Override void close(); } public static Promise promise() { return new Promise<>() { private final CompletableFuture _future = new CompletableFuture<>(); @Override public InvocationType getInvocationType() { return InvocationType.NON_BLOCKING; } @Override public C block() throws IOException { try { return _future.get(); } catch (Throwable t) { throw IO.rethrow(t); } } @Override public void close() { if (!_future.isDone()) { if (LOG.isDebugEnabled()) LOG.warn("Blocking.Promise incomplete", new Throwable()); else LOG.warn("Blocking.Promise incomplete"); } } @Override public void succeeded(C result) { _future.complete(result); } @Override public void failed(Throwable x) { _future.completeExceptionally(x); } }; } /** * A shared reusable Blocking source. */ public static class Shared { private final ReentrantLock _lock = new ReentrantLock(); private final Condition _idle = _lock.newCondition(); private final Condition _complete = _lock.newCondition(); private Throwable _completed; private final Callback _callback = new Callback() { @Override public InvocationType getInvocationType() { return InvocationType.NON_BLOCKING; } @Override public void succeeded() { _lock.lock(); try { if (_completed == ACQUIRED) { _completed = SUCCEEDED; _complete.signalAll(); } } finally { _lock.unlock(); } } @Override public void failed(Throwable x) { _lock.lock(); try { if (_completed == ACQUIRED) { _completed = x; _complete.signalAll(); } } finally { _lock.unlock(); } } @Override public void block() throws IOException { _lock.lock(); Throwable result; try { while (_completed == ACQUIRED) { _complete.await(); } result = _completed; } catch (Throwable t) { result = t; } finally { _lock.unlock(); } if (result != SUCCEEDED) throw IO.rethrow(result); } @Override public void close() { boolean completed; _lock.lock(); try { completed = _completed != ACQUIRED; } finally { _completed = null; _idle.signalAll(); _lock.unlock(); } if (!completed) { if (LOG.isDebugEnabled()) LOG.warn("Blocking.Shared incomplete", new Throwable()); else LOG.warn("Blocking.Shared incomplete"); } } }; private final Runnable _runnable = new Runnable() { @Override public InvocationType getInvocationType() { return InvocationType.NON_BLOCKING; } @Override public void run() { _callback.succeeded(); } @Override public void block() throws IOException { _callback.block(); } @Override public void close() { _callback.close(); } }; public Callback callback() throws IOException { _lock.lock(); try { while (_completed != null) _idle.await(); _completed = ACQUIRED; return _callback; } catch (InterruptedException x) { throw new InterruptedIOException(); } finally { _lock.unlock(); } } public Runnable runnable() throws IOException { _lock.lock(); try { while (_completed != null) _idle.await(); _completed = ACQUIRED; return _runnable; } catch (InterruptedException x) { throw new InterruptedIOException(); } finally { _lock.unlock(); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy