amqp.spring.camel.component.SpringAMQPProducer.java Source code

Java tutorial

Introduction

Here is the source code for amqp.spring.camel.component.SpringAMQPProducer.java

Source

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

package amqp.spring.camel.component;

import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.impl.DefaultAsyncProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpConnectException;
import org.springframework.amqp.AmqpIOException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.amqp.support.converter.SimpleMessageConverter;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;

public class SpringAMQPProducer extends DefaultAsyncProducer {
    private static transient final Logger LOG = LoggerFactory.getLogger(SpringAMQPProducer.class);

    protected SpringAMQPEndpoint endpoint;
    private org.springframework.amqp.core.Exchange exchange;
    private ExecutorService threadPool;

    public SpringAMQPProducer(SpringAMQPEndpoint endpoint) {
        super(endpoint);
        this.endpoint = endpoint;
    }

    @Override
    public boolean process(Exchange exchange, AsyncCallback callback) {
        if (!isRunAllowed()) {
            if (exchange.getException() == null)
                exchange.setException(new RejectedExecutionException("SpringAMQPProducer not started yet!"));
            callback.done(true);
            return true;
        }

        if (this.threadPool == null) {
            if (exchange.getException() == null)
                exchange.setException(new RejectedExecutionException("SpringAMQPProducer is not yet initialized!"));
            callback.done(true);
            return true;
        }

        this.threadPool.submit(new AMQPProducerTask(exchange, callback));
        return false;
    }

    @Override
    public void process(Exchange exchange) throws Exception {
        if (!isRunAllowed() && exchange.getException() == null) {
            exchange.setException(new RejectedExecutionException("SpringAMQPProducer not started yet!"));
        }

        //This is an intentional synchronous invocation of run(), don't mock me
        new AMQPProducerTask(exchange).run();
    }

    @Override
    public void doStart() throws Exception {
        super.doStart();

        this.exchange = this.endpoint.createAMQPExchange();
        if (this.endpoint.isUsingDefaultExchange()) {
            LOG.info("Using default exchange of type {}", this.exchange.getClass().getSimpleName());
        } else {
            LOG.info("Declaring exchange {} of type {}", this.exchange.getName(),
                    this.exchange.getClass().getSimpleName());
            try {
                this.endpoint.amqpAdministration.declareExchange(this.exchange);
            } catch (AmqpIOException e) {
                //The actual reason for failed exceptions is often swallowed up by Camel or Spring, find it
                Throwable rootCause = SpringAMQPComponent.findRootCause(e);
                LOG.error("Could not initialize exchange!", rootCause);
                throw e;
            } catch (AmqpConnectException e) {
                LOG.error("Producer cannot connect to broker - stopping endpoint {}", this.endpoint.toString(), e);
                stop();
                this.endpoint.stop();
                return;
            }
        }

        //Initialize execution pool
        this.threadPool = this.endpoint.getCamelContext().getExecutorServiceManager().newDefaultThreadPool(this,
                "amqp-producer");
    }

    @Override
    public void doShutdown() throws Exception {
        super.doShutdown();

        if (this.threadPool != null) {
            this.threadPool.shutdown();
            this.threadPool = null;
        }
    }

    @Override
    public void doStop() throws Exception {
        super.doStop();

        if (this.threadPool != null) {
            this.threadPool.shutdown();
            this.threadPool = null;
        }
    }

    private class AMQPProducerTask implements Runnable {
        Exchange exchange;
        AsyncCallback callback;

        public AMQPProducerTask(Exchange exchange) {
            this(exchange, null);
        }

        public AMQPProducerTask(Exchange exchange, AsyncCallback callback) {
            this.exchange = exchange;
            this.callback = callback;
        }

        @Override
        public void run() {
            org.apache.camel.Message message = exchange.getIn();
            SpringAMQPMessage inMessage = new SpringAMQPMessage(message);
            exchange.setIn(inMessage); //Swap out the old message format

            MessageConverter msgConverter;
            if (endpoint.getAmqpTemplate() instanceof RabbitTemplate) {
                RabbitTemplate rabbitTemplate = (RabbitTemplate) endpoint.getAmqpTemplate();
                msgConverter = rabbitTemplate.getMessageConverter();
            } else {
                LOG.warn("Cannot find RabbitMQ AMQP Template, falling back to simple message converter");
                msgConverter = new SimpleMessageConverter();
            }

            String routingKeyHeader = message.getHeader(SpringAMQPComponent.ROUTING_KEY_HEADER, String.class);
            String routingKey = routingKeyHeader != null ? routingKeyHeader : endpoint.routingKey;

            try {
                if (exchange.getPattern().isOutCapable()) {
                    LOG.debug("Synchronous send and request for exchange {}", exchange.getExchangeId());
                    Message amqpResponse = endpoint.getAmqpTemplate().sendAndReceive(endpoint.exchangeName,
                            routingKey, inMessage.toAMQPMessage(msgConverter));
                    SpringAMQPMessage camelResponse = SpringAMQPMessage.fromAMQPMessage(msgConverter, amqpResponse);

                    Boolean isExceptionCaught = (Boolean) camelResponse
                            .getHeader(SpringAMQPMessage.IS_EXCEPTION_CAUGHT);
                    if (isExceptionCaught != null && isExceptionCaught.equals(Boolean.TRUE)) {
                        Object caughtObject = camelResponse.getBody();
                        if (caughtObject == null) {
                            exchange.setException(new RuntimeException("Null exception caught from Camel."));
                        } else if (caughtObject instanceof Throwable) {
                            exchange.setException((Throwable) caughtObject);
                        } else {
                            exchange.setException(new RuntimeException(caughtObject.toString()));
                        }
                    } else {
                        exchange.setOut(camelResponse);
                    }
                } else {
                    LOG.debug("Synchronous send for exchange {}", exchange.getExchangeId());
                    endpoint.getAmqpTemplate().send(endpoint.exchangeName, routingKey,
                            inMessage.toAMQPMessage(msgConverter));
                }
            } catch (Throwable t) {
                LOG.error("Could not deliver message via AMQP", t);
            }

            if (callback != null)
                callback.done(false);
        }
    }
}