/*
* Copyright (c) 2010-2017. 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.distributed;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* This class retains a list of callbacks for CommandCallbackConnectors to use.
*
* @param <A> The type of the endpoint identifier.
*/
public class CommandCallbackRepository<A> {
private final Map<String, CommandCallbackWrapper> callbacks = new ConcurrentHashMap<>();
/**
* Removes all callbacks for a given channel. Registered callbacks will receive a failure response containing a
* {@link CommandBusConnectorCommunicationException}.
*
* @param channelId the channel identifier
*/
public void cancelCallbacks(A channelId) {
Iterator<CommandCallbackWrapper> callbacks = this.callbacks.values().iterator();
while (callbacks.hasNext()) {
CommandCallbackWrapper wrapper = callbacks.next();
if (wrapper.getChannelIdentifier().equals(channelId)) {
wrapper.fail(new CommandBusConnectorCommunicationException(
String.format("Connection error while waiting for a response on command %s",
wrapper.getMessage().getCommandName())));
callbacks.remove();
}
}
}
/**
* Fetches and removes a callback. The callback will not be used a second time, so removal should be fine
*
* @param callbackId The Callback Id to fetch the callback for
* @param <E> The type of the remote endpoint identifier
* @param <C> The type of the command
* @param <R> The type of the result
* @return The stored CommandCallbackWrapper or null if not found
*/
@SuppressWarnings("unchecked")
public <E, C, R> CommandCallbackWrapper<E, C, R> fetchAndRemove(String callbackId) {
return callbacks.remove(callbackId);
}
/**
* Stores a callback
*
* @param callbackId The id to store the callback with
* @param commandCallbackWrapper The CommandCallbackWrapper to store
* @param <E> The type of the remote endpoint identifier
* @param <C> The type of the command
* @param <R> The type of the result
*/
public <E, C, R> void store(String callbackId, CommandCallbackWrapper<E, C, R> commandCallbackWrapper) {
CommandCallbackWrapper previous;
if ((previous = callbacks.put(callbackId, commandCallbackWrapper)) != null) {
//a previous callback with the same command ID was already found, we will cancel the callback as the command
//is likely to be retried, so the previous one likely failed
previous.fail(new CommandBusConnectorCommunicationException(
"Command-callback cancelled, a new command with the same ID is entered into the command bus"));
}
}
/**
* Returns the callbacks mapped by callback identifier.
*
* @return the command callbacks by id
*/
protected Map<String, CommandCallbackWrapper> callbacks() {
return callbacks;
}
}