/*
* 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.gateway;
import org.axonframework.commandhandling.CommandBus;
import org.axonframework.commandhandling.CommandCallback;
import org.axonframework.commandhandling.CommandMessage;
import org.axonframework.commandhandling.callbacks.LoggingCallback;
import org.axonframework.common.Assert;
import org.axonframework.messaging.MessageDispatchInterceptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.axonframework.commandhandling.GenericCommandMessage.asCommandMessage;
/**
* Abstract implementation of a CommandGateway, which handles the dispatch interceptors and retrying on failure. The
* actual dispatching of commands is left to the subclasses.
*
* @author Allard Buijze
* @since 2.2
*/
public abstract class AbstractCommandGateway {
private final CommandBus commandBus;
private final RetryScheduler retryScheduler;
private final List<MessageDispatchInterceptor<? super CommandMessage<?>>> dispatchInterceptors;
/**
* Initialize the AbstractCommandGateway with given {@code commandBus}, {@code retryScheduler} and
* {@code commandDispatchInterceptors}.
*
* @param commandBus The command bus on which to dispatch events
* @param retryScheduler The scheduler capable of performing retries of failed commands. May be
* {@code null} when to prevent retries.
* @param messageDispatchInterceptors The interceptors to invoke when dispatching a command
*/
protected AbstractCommandGateway(CommandBus commandBus, RetryScheduler retryScheduler,
List<MessageDispatchInterceptor<? super CommandMessage<?>>> messageDispatchInterceptors) {
Assert.notNull(commandBus, () -> "commandBus may not be null");
this.commandBus = commandBus;
if (messageDispatchInterceptors != null && !messageDispatchInterceptors.isEmpty()) {
this.dispatchInterceptors = new ArrayList<>(messageDispatchInterceptors);
} else {
this.dispatchInterceptors = Collections.emptyList();
}
this.retryScheduler = retryScheduler;
}
/**
* Sends the given {@code command}, and invokes the {@code callback} when the command is processed.
*
* @param command The command to dispatch
* @param callback The callback to notify with the processing result
* @param <R> The type of response expected from the command
*/
protected <C, R> void send(C command, CommandCallback<? super C, R> callback) {
CommandMessage<? extends C> commandMessage = processInterceptors(asCommandMessage(command));
CommandCallback<? super C, R> commandCallback = callback;
if (retryScheduler != null) {
commandCallback = new RetryingCallback<>(callback, retryScheduler, commandBus);
}
commandBus.dispatch(commandMessage, commandCallback);
}
/**
* Dispatches a command without callback. When dispatching fails, since there is no callback, the command will
* <em>not</em> be retried.
*
* @param command The command to dispatch
*/
protected void sendAndForget(Object command) {
if (retryScheduler == null) {
commandBus.dispatch(processInterceptors(asCommandMessage(command)));
} else {
CommandMessage<?> commandMessage = asCommandMessage(command);
send(commandMessage, LoggingCallback.INSTANCE);
}
}
/**
* Invokes all the dispatch interceptors and returns the CommandMessage instance that should be dispatched.
*
* @param commandMessage The incoming command message
* @return The command message to dispatch
*/
@SuppressWarnings("unchecked")
protected <C> CommandMessage<? extends C> processInterceptors(CommandMessage<C> commandMessage) {
CommandMessage<? extends C> message = commandMessage;
for (MessageDispatchInterceptor<? super CommandMessage<?>> dispatchInterceptor : dispatchInterceptors) {
message = (CommandMessage) dispatchInterceptor.handle(message);
}
return message;
}
/**
* Returns the CommandBus used by this gateway. Should be used to monitoring or testing.
*
* @return The CommandBus used by this gateway
*/
public CommandBus getCommandBus() {
return commandBus;
}
}