/*
* 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;
import org.axonframework.common.Assert;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Specialization of the SimpleCommandBus that processed Commands asynchronously from the calling thread. By default,
* the AsynchronousCommandBus uses a Cached Thread Pool (see
* {@link java.util.concurrent.Executors#newCachedThreadPool()}). It will reuse threads while possible, and shut them
* down after 60 seconds of inactivity.
* <p/>
* Each Command is dispatched in a separate task, which is processed by the Executor.
* <p/>
* Note that you should call {@link #shutdown()} to stop any threads waiting for new tasks. Failure to do so may cause
* the JVM to hang for up to 60 seconds on JVM shutdown.
*
* @author Allard Buijze
* @since 1.3.4
*/
public class AsynchronousCommandBus extends SimpleCommandBus {
private final Executor executor;
/**
* Initialize the AsynchronousCommandBus, using a Cached Thread Pool.
*/
public AsynchronousCommandBus() {
this(Executors.newCachedThreadPool());
}
/**
* Initialize the AsynchronousCommandBus using the given {@code executor}.
*
* @param executor The executor that processes Command dispatching threads
*/
public AsynchronousCommandBus(Executor executor) {
Assert.notNull(executor, () -> "executor may not be null");
this.executor = executor;
}
@Override
protected <C, R> void doDispatch(CommandMessage<C> command, CommandCallback<? super C, R> callback) {
executor.execute(new DispatchCommand<>(command, callback));
}
/**
* Shuts down the Executor used to asynchronously dispatch incoming commands. If the {@code Executor} provided
* in the constructor does not implement {@code ExecutorService}, this method does nothing.
*/
public void shutdown() {
if (executor instanceof ExecutorService) {
((ExecutorService) executor).shutdown();
try {
((ExecutorService) executor).awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// we've been interrupted. Reset the interruption flag and continue
Thread.currentThread().interrupt();
}
}
}
private final class DispatchCommand<C, R> implements Runnable {
private final CommandMessage<C> command;
private final CommandCallback<? super C, R> callback;
public DispatchCommand(CommandMessage<C> command, CommandCallback<? super C, R> callback) {
this.command = command;
this.callback = callback;
}
@Override
public void run() {
AsynchronousCommandBus.super.doDispatch(command, callback);
}
}
}