de.otto.synapse.consumer.MessageDispatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of synapse-core Show documentation
Show all versions of synapse-core Show documentation
A library used at otto.de to implement Spring Boot based event-sourcing microservices.
package de.otto.synapse.consumer;
import de.otto.synapse.message.Message;
import de.otto.synapse.message.TextMessage;
import org.slf4j.Logger;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import static de.otto.synapse.message.Message.message;
import static de.otto.synapse.translator.ObjectMappers.currentObjectMapper;
import static java.util.Collections.synchronizedList;
import static java.util.Collections.unmodifiableList;
import static java.util.regex.Pattern.compile;
import static org.slf4j.LoggerFactory.getLogger;
/**
* A MessageConsumer that is acting as a Message Dispatcher for multiple {@link MessageConsumer message consumers}.
*
*
*
*
* As it is implementing the MessageConsumer interface, the MessageDispatcher is an implementation
* of the GoF Composite Pattern.
*
*
* Messages are translated by the dispatcher using to the format expected by the registered consumers.
*
* @see EIP: Message Dispatcher
* @see Composite Pattern
*/
public class MessageDispatcher implements Consumer {
private static final Logger LOG = getLogger(MessageDispatcher.class);
private static final Pattern ACCEPT_ALL = compile(".*");
private final List> messageConsumers;
public MessageDispatcher() {
this.messageConsumers = synchronizedList(new ArrayList<>());
}
public MessageDispatcher(final List> messageConsumers) {
this.messageConsumers = synchronizedList(new ArrayList<>(messageConsumers));
}
public void add(final MessageConsumer> messageConsumer) {
this.messageConsumers.add(messageConsumer);
}
public List> getAll() {
return unmodifiableList(messageConsumers);
}
/**
* Returns the expected payload type of {@link Message events} consumed by this EventConsumer.
*
* @return payload type
*/
@Nonnull
public Class payloadType() {
return String.class;
}
/**
* Returns the pattern of {@link Message#getKey() event keys} accepted by this consumer.
*
* @return Pattern
*/
@Nonnull
public Pattern keyPattern() {
return ACCEPT_ALL;
}
/**
* Accepts a message with JSON String payload, dispatches this method to the different registered
* {@link MessageConsumer consumers} if their {@link MessageConsumer#keyPattern()} matches, and
* translates the JSON payload into the expected {@link MessageConsumer#payloadType()} of the receiving
* MessageConsumer.
*
* @param message the input argument
*/
@Override
@SuppressWarnings({"unchecked", "raw"})
public void accept(final TextMessage message) {
LOG.debug("Accepting message={}", message);
messageConsumers
.stream()
.filter(consumer -> matchesKeyPattern(message, consumer.keyPattern()))
.forEach((MessageConsumer consumer) -> {
try {
final Class> payloadType = consumer.payloadType();
if (payloadType.equals(String.class)) {
consumer.accept(message);
} else {
Object payload = null;
if (message.getPayload() != null) {
payload = currentObjectMapper().readValue(message.getPayload(), payloadType);
}
final Message> tMessage = message(message.getKey(), message.getHeader(), payload);
consumer.accept(tMessage);
}
} catch (final Exception e) {
LOG.error(e.getMessage(), e);
throw new IllegalStateException(e.getMessage(), e);
}
});
}
private boolean matchesKeyPattern(final TextMessage message,
final Pattern keyPattern) {
return keyPattern.matcher(message.getKey().compactionKey()).matches();
}
}