/*
* Copyright (c) 2010-2015. 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.amqp.eventhandling.spring;
import com.rabbitmq.client.Channel;
import org.axonframework.amqp.eventhandling.AMQPMessageConverter;
import org.axonframework.amqp.eventhandling.DefaultAMQPMessageConverter;
import org.axonframework.common.Registration;
import org.axonframework.eventhandling.EventMessage;
import org.axonframework.messaging.SubscribableMessageSource;
import org.axonframework.serialization.Serializer;
import org.axonframework.serialization.UnknownSerializedTypeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
/**
* MessageListener implementation that deserializes incoming messages and forwards them to one or more event processors.
* <p>
* The SpringAMQPMessageSource must be registered with a Spring MessageListenerContainer and forwards each message
* to all subscribed processors.
* <p>
* Note that the Processors must be subscribed before the MessageListenerContainer is started. Otherwise, messages will
* be consumed from the AMQP Queue without any processor processing them.
*
* @author Allard Buijze
* @since 3.0
*/
public class SpringAMQPMessageSource implements ChannelAwareMessageListener,
SubscribableMessageSource<EventMessage<?>> {
private static final Logger logger = LoggerFactory.getLogger(SpringAMQPMessageSource.class);
private final List<Consumer<List<? extends EventMessage<?>>>> eventProcessors = new CopyOnWriteArrayList<>();
private final AMQPMessageConverter messageConverter;
/**
* Initializes an SpringAMQPMessageSource with {@link DefaultAMQPMessageConverter} using given {@code serializer}.
*
* @param serializer The serializer to serialize payload and metadata of events
*/
public SpringAMQPMessageSource(Serializer serializer) {
this(new DefaultAMQPMessageConverter(serializer));
}
/**
* Initializes an SpringAMQPMessageSource with given {@code messageConverter} to convert the incoming AMQP
* message into an EventMessage.
*
* @param messageConverter The message converter to use to convert AMQP Messages to Event Messages
*/
public SpringAMQPMessageSource(AMQPMessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
@Override
public Registration subscribe(Consumer<List<? extends EventMessage<?>>> messageProcessor) {
eventProcessors.add(messageProcessor);
return () -> eventProcessors.remove(messageProcessor);
}
@Override
public void onMessage(Message message, Channel channel) throws Exception {
if (!eventProcessors.isEmpty()) {
try {
EventMessage<?> event = messageConverter
.readAMQPMessage(message.getBody(), message.getMessageProperties().getHeaders()).orElse(null);
if (event != null) {
eventProcessors.forEach(ep -> ep.accept(Collections.singletonList(event)));
}
} catch (UnknownSerializedTypeException e) {
logger.warn("Unable to deserialize an incoming message. Ignoring it. {}", e.toString());
}
}
}
}