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

com.tangosol.util.AsynchronousAgent Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */
package com.tangosol.util;

import com.oracle.coherence.common.base.Continuation;
import com.oracle.coherence.common.base.Notifier;
import com.oracle.coherence.common.base.SingleWaiterMultiNotifier;
import com.oracle.coherence.common.base.Timeout;

import com.oracle.coherence.common.util.Duration;

import com.tangosol.net.FlowControl;

import com.tangosol.util.aggregator.AbstractAsynchronousAggregator;
import com.tangosol.util.aggregator.AsynchronousAggregator;

import com.tangosol.util.processor.AbstractAsynchronousProcessor;
import com.tangosol.util.processor.AsynchronousProcessor;

import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import java.util.function.Supplier;

/**
 * Base class for asynchronous operations that provides a simple implementation
 * of the {@link Future} interface. It is assumed that subclasses at some point
 * will either call {@link #complete(Supplier)} passing the result supplier
 * when completed successfully or call {@link #completeExceptionally} passing the
 * failure reason.
 *
 * @param   the type of the result
 *
 * @author gg/mf 2012.12.21
 * @author gg/bb 2015.04.06
 */
public abstract class AsynchronousAgent
        implements FlowControl, Future
    {
    /**
     * Construct the agent.
     *
     * @param iOrderId  a unit-of-order id associated with this agent. Ordering
     *                  semantics of operations based on this id are defined
     *                  by subclasses
     */
    protected AsynchronousAgent(int iOrderId)
        {
        m_iOrderId = iOrderId;
        }

    // ----- FlowControl support --------------------------------------------

    /**
     * Bind this agent with the specified underlying FlowControl object. This
     * method is to be used only internally by the service.
     *
     * @param control the underlying FlowControl
     */
    public void bind(FlowControl control)
        {
        m_control = control;
        }

    @Override
    public void flush()
        {
        FlowControl control = m_control;
        if (control == null)
            {
            throw new IllegalStateException();
            }
        control.flush();
        }

    @Override
    public long drainBacklog(long cMillis)
        {
        FlowControl control = m_control;
        if (control == null)
            {
            throw new IllegalStateException();
            }
        return control.drainBacklog(cMillis);
        }

    @Override
    public boolean checkBacklog(Continuation continueNormal)
        {
        FlowControl control = m_control;
        if (control == null)
            {
            throw new IllegalStateException();
            }
        return control.checkBacklog(continueNormal);
        }

    // ----- Future support -------------------------------------------------

    @Override
    public boolean cancel(boolean mayInterruptIfRunning)
        {
        return completeExceptionally(new CancellationException());
        }

    @Override
    public boolean isCancelled()
        {
        CompletableFuture future;
        if (m_fCompleted && (future = m_future) != null)
            {
            return future.isCancelled();
            }

        return false;
        }

    @Override
    public boolean isDone()
        {
        return m_fCompleted;
        }

    @Override
    public T get()
            throws InterruptedException, ExecutionException
        {
        try
            {
            return get(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
            }
        catch (TimeoutException e)
            {
            // will never happen
            throw new IllegalStateException();
            }
        }

    @Override
    public T get(long cTimeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException
        {
        long ldtTimeout = Base.getLastSafeTimeMillis() + unit.toMillis(cTimeout);

        try (Timeout t = Timeout.after(cTimeout, unit))
            {
            while (!m_fCompleted)
                {
                f_notifier.await();
                }

            return getCompletableFuture().get();
            }
        catch (InterruptedException e)
            {
            if (Base.getSafeTimeMillis() >= ldtTimeout)
                {
                throw new TimeoutException("Elapsed " + new Duration(unit.toNanos(cTimeout)));
                }
            else
                {
                throw e;
                }
            }
        }

     // ----- Subclasses support ---------------------------------------------

    /**
     * Return a unit-of-order id associated with this agent. By default,
     * the unit-of-order id is assigned to the calling thread's hashCode.
     * 

* Note 1: the ordering guarantee is respected between {@link * AsynchronousAggregator}s and {@link AsynchronousProcessor}s with the same * unit-of-order id; *
* Note 2: there is no ordering guarantee between asynchronous and synchronous * operations. * * @return the order id * * @see AbstractAsynchronousAggregator#getUnitOfOrderId() * @see AbstractAsynchronousProcessor#getUnitOfOrderId() */ public int getUnitOfOrderId() { return m_iOrderId; } /** * Should be called if the operation completed successfully. * * @param supplier the supplier of the result of the asynchronous execution * * @return {@code true} if agent could be marked to complete with the * given Supplier. */ protected synchronized boolean complete(Supplier supplier) { if (!m_fCompleted) { if (supplier == null) { throw new IllegalArgumentException("No supplier"); } CompletableFuture future = m_future; if (future == null || !future.isDone()) { if (future == null) { m_supplier = supplier; } else { future.complete(supplier.get()); } m_fCompleted = true; f_notifier.signal(); return true; } } return false; } /** * Should be called if the operation failed for any reason. * * @param eReason the reason of failure * * @return {@code true} if agent could be marked to complete with the * given exception. */ protected synchronized boolean completeExceptionally(Throwable eReason) { if (!m_fCompleted) { if (eReason == null) { throw new IllegalArgumentException("No reason"); } CompletableFuture future = m_future; if (future == null || !future.isDone()) { if (future == null) { future = m_future = new CompletableFuture<>(); } future.completeExceptionally(eReason); m_fCompleted = true; f_notifier.signal(); return true; } } return false; } /** * Helper method that calls {@link #get} and re-throws checked exceptions * as a RuntimeException. * * @return the result value */ public T getResult() { try { return get(); } catch (ExecutionException e) { throw Base.ensureRuntimeException(e.getCause()); } catch (InterruptedException e) { throw new RuntimeException(e); } } /** * Helper method that returns an exception (if completed exceptionally). * * @return the exception or null if the operation completed successfully */ public Throwable getException() { if (isCompletedExceptionally()) { try { get(); } catch (ExecutionException e) { return e.getCause(); } catch (InterruptedException e) { return e; } } return null; } /** * Helper method to check if the operation failed. * * @return true if the operation failed */ public boolean isCompletedExceptionally() { CompletableFuture future; if (m_fCompleted && (future = m_future) != null) { return future.isCompletedExceptionally(); } return false; } /** * Get the CompletableFuture. * * @return CompletableFuture */ public synchronized CompletableFuture getCompletableFuture() { CompletableFuture future = m_future; if (future == null) { future = m_future = new CompletableFuture<>(); if (m_fCompleted) { assert m_supplier != null; future.complete(m_supplier.get()); } } return future; } // ----- data fields ---------------------------------------------------- /** * The underlying FlowControl; could be null if the "automatic flow control" * is turned on. */ protected FlowControl m_control; /** * A unit-of-order id associated with this agent. */ protected final int m_iOrderId; /** * Indicates that the operation has completed. */ private volatile boolean m_fCompleted; /** * Supplier of the final result of operation (if successful). */ private Supplier m_supplier; /** * CompletableFuture tied to the agent. */ private CompletableFuture m_future; /** * Notification handler. */ private final Notifier f_notifier = new SingleWaiterMultiNotifier(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy