Package org.axonframework.commandhandling.callbacks

Source Code of org.axonframework.commandhandling.callbacks.FutureCallback

/*
* Copyright (c) 2010-2014. Axon Framework
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.axonframework.commandhandling.callbacks;

import org.axonframework.commandhandling.CommandCallback;
import org.axonframework.commandhandling.CommandExecutionException;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
* Command Handler Callback that allows the dispatching thread to wait for the result of the callback, using the Future
* mechanism. This callback allows the caller to synchronize calls when an asynchronous command bus is being used.
*
* @param <R> the type of result of the command handling
* @author Allard Buijze
* @since 0.6
*/
public class FutureCallback<R> implements CommandCallback<R>, Future<R> {

    private volatile R result;
    private volatile Throwable failure;

    private final CountDownLatch latch = new CountDownLatch(1);

    @Override
    public void onSuccess(R executionResult) {
        this.result = executionResult;
        latch.countDown();
    }

    @Override
    public void onFailure(Throwable cause) {
        this.failure = cause;
        latch.countDown();
    }

    /**
     * Waits if necessary for the command handling to complete, and then returns its result.
     *
     * @return the result of the command handler execution.
     *
     * @throws InterruptedException if the current thread is interrupted while waiting
     * @throws ExecutionException   if the command handler threw an exception
     */
    @Override
    public R get() throws InterruptedException, ExecutionException {
        if (!isDone()) {
            latch.await();
        }
        return getFutureResult();
    }

    /**
     * Waits if necessary for at most the given time for the command handling to complete, and then retrieves its
     * result, if available.
     *
     * @param timeout the maximum time to wait
     * @param unit    the time unit of the timeout argument
     * @return the result of the command handler execution.
     *
     * @throws InterruptedException if the current thread is interrupted while waiting
     * @throws TimeoutException     if the wait timed out
     * @throws ExecutionException   if the command handler threw an exception
     * @see #getResult(long, java.util.concurrent.TimeUnit)
     */
    @Override
    public R get(long timeout, TimeUnit unit) throws TimeoutException, InterruptedException, ExecutionException {
        if (!isDone() && !latch.await(timeout, unit)) {
            throw new TimeoutException("A Timeout occurred while waiting for a Command Callback");
        }
        return getFutureResult();
    }

    /**
     * Waits if necessary for the command handling to complete, and then returns its result.
     * <p/>
     * Unlike {@link #get(long, java.util.concurrent.TimeUnit)}, this method will throw the original exception. Only
     * checked exceptions are wrapped in a {@link CommandExecutionException}.
     * <p/>
     * If the thread is interrupted while waiting, the interrupt flag is set back on the thread, and <code>null</code>
     * is returned. To distinguish between an interrupt and a <code>null</code> result, use the {@link #isDone()}
     * method.
     *
     * @return the result of the command handler execution.
     *
     * @see #get()
     */
    public R getResult() {
        if (!isDone()) {
            try {
                latch.await();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return null;
            }
        }
        return doGetResult();
    }

    /**
     * Waits if necessary for at most the given time for the command handling to complete, and then retrieves its
     * result, if available.
     * <p/>
     * Unlike {@link #get(long, java.util.concurrent.TimeUnit)}, this method will throw the original exception. Only
     * checked exceptions are wrapped in a {@link CommandExecutionException}.
     * <p/>
     * If the timeout expired or the thread is interrupted before completion, <code>null</code> is returned. In case of
     * an interrupt, the interrupt flag will have been set back on the thread. To distinguish between an interrupt and
     * a
     * <code>null</code> result, use the {@link #isDone()}
     *
     * @param timeout the maximum time to wait
     * @param unit    the time unit of the timeout argument
     * @return the result of the command handler execution.
     */
    public R getResult(long timeout, TimeUnit unit) {
        if (!awaitCompletion(timeout, unit)) {
            return null;
        }
        return doGetResult();
    }

    /**
     * Wait for completion of the command, or for the timeout to expire.
     *
     * @param timeout The amount of time to wait for command processing to complete
     * @param unit    The unit in which the timeout is expressed
     * @return <code>true</code> if command processing completed before the timeout expired, otherwise
     *         <code>false</code>.
     */
    public boolean awaitCompletion(long timeout, TimeUnit unit) {
        try {
            return isDone() || latch.await(timeout, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    /**
     * Always returns <code>false</code>, since command execution cannot be cancelled.
     *
     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing the command should be interrupted; otherwise,
     *                              in-progress tasks are allowed to complete
     * @return <code>false</code>
     */
    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    /**
     * Always returns false, since command execution cannot be cancelled.
     *
     * @return false
     */
    @Override
    public boolean isCancelled() {
        return false;
    }

    /**
     * Indicates whether command handler execution has finished.
     *
     * @return <code>true</code> if command handler execution has finished, otherwise <code>false</code>.
     */
    @Override
    public boolean isDone() {
        return latch.getCount() == 0L;
    }

    private R doGetResult() {
        if (failure != null) {
            if (failure instanceof Error) {
                throw (Error) failure;
            } else if (failure instanceof RuntimeException) {
                throw (RuntimeException) failure;
            } else {
                throw new CommandExecutionException("An exception occurred while executing a command", failure);
            }
        } else {
            return result;
        }
    }

    private R getFutureResult() throws ExecutionException {
        if (failure != null) {
            throw new ExecutionException(failure);
        } else {
            return result;
        }
    }
}
TOP

Related Classes of org.axonframework.commandhandling.callbacks.FutureCallback

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.