io.qdb.server.output.RabbitMQOutputHandler.java Source code

Java tutorial

Introduction

Here is the source code for io.qdb.server.output.RabbitMQOutputHandler.java

Source

/*
 * Copyright 2013 David Tinker
 *
 * 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 io.qdb.server.output;

import com.rabbitmq.client.*;
import io.qdb.server.ExpectedIOException;
import io.qdb.server.model.Output;
import io.qdb.server.model.Queue;

import java.io.IOException;
import java.net.ConnectException;

/**
 * Published messages to a RabbitMQ server.
 */
public class RabbitMQOutputHandler extends OutputHandlerAdapter implements ShutdownListener {

    public String exchange;
    public String[] queues;
    public int heartbeat = 30;
    public boolean persistentMessages;

    protected String outputPath;
    protected ConnectionFactory connectionFactory;
    protected Connection con;
    protected Channel channel;

    protected String exchangeType;
    protected boolean exchangeDurable;
    protected boolean[] queueDurable;

    protected AMQP.BasicProperties messageProperties;

    @SuppressWarnings("unchecked")
    @Override
    public void init(Queue q, Output output, String outputPath) throws Exception {
        this.outputPath = outputPath;

        if (output.getUrl() == null)
            throw new IllegalArgumentException("url is required");

        if (queues != null && queues.length == 0)
            queues = null;
        if (exchange != null && exchange.length() == 0)
            exchange = null;

        if (queues == null) {
            if (exchange == null)
                throw new IllegalArgumentException("queues or exchange is required");
        } else {
            queueDurable = new boolean[queues.length];
            for (int i = 0; i < queues.length; i++) {
                String[] toks = queues[i].split("[\\s]*#[\\s]*");
                queues[i] = toks[0];
                queueDurable[i] = toks.length == 1 || "true".equals(toks[1]);
                if (queues[i].length() == 0)
                    throw new IllegalArgumentException("empty queue name");
            }
            if (exchange == null) {
                if (queues.length > 1)
                    throw new IllegalArgumentException("exchange is required for multiple queues");
                exchange = queues[0];
            }
        }

        String[] toks = exchange.split("[\\s]*#[\\s]*");
        exchange = toks[0];
        exchangeType = toks.length >= 2 ? toks[1] : "fanout";
        exchangeDurable = toks.length < 3 || "true".equals(toks[2]);

        if (persistentMessages) {
            messageProperties = new AMQP.BasicProperties(null, null, null, 2, 0, null, null, null, null, null, null,
                    null, null, null);
        }

        connectionFactory = new ConnectionFactory();
        connectionFactory.setUri(output.getUrl());
        connectionFactory.setRequestedHeartbeat(heartbeat);
        ensureChannel();
    }

    @Override
    public long processMessage(long messageId, String routingKey, long timestamp, byte[] payload) throws Exception {
        if (log.isDebugEnabled())
            log.debug(outputPath + ": Publishing " + messageId);
        ensureChannel().basicPublish(exchange, routingKey, messageProperties, payload);
        return messageId;
    }

    @Override
    public void close() throws IOException {
        // this method cannot be synchronized or we get deadlock with shutdownCompleted
        if (con != null) {
            try {
                con.close();
            } catch (AlreadyClosedException ignore) {
            }
        }
    }

    protected synchronized Channel ensureChannel() throws Exception {
        if (channel == null) {
            try {
                con = connectionFactory.newConnection();
            } catch (ConnectException e) {
                throw new ExpectedIOException(e.getMessage() + ": " + getConnectionInfo());
            }
            channel = con.createChannel();
            if (log.isInfoEnabled())
                log.info(outputPath + ": Connected to " + getConnectionInfo());
            channel.addShutdownListener(this);
            initChannel(channel);
        }
        return channel;
    }

    protected void initChannel(Channel channel) throws IOException {
        channel.exchangeDeclare(exchange, exchangeType, exchangeDurable);
        if (queues != null) {
            for (int i = 0; i < queues.length; i++) {
                String q = queues[i];
                channel.queueDeclare(q, queueDurable[i], false, false, null);
                channel.queueBind(q, exchange, "");
            }
        }
    }

    @Override
    public synchronized void shutdownCompleted(ShutdownSignalException cause) {
        channel = null;
        if (!cause.isInitiatedByApplication()) {
            log.error(outputPath + ": Channel closed unexpectedly: " + cause.getMessage());
            try {
                if (con.isOpen())
                    con.close();
            } catch (Exception ignore) {
            }
            con = null;
        }
    }

    protected String getConnectionInfo() {
        if (connectionFactory == null)
            return "(null)";
        String host = connectionFactory.getHost();
        if (host.length() == 0)
            host = "mac-subs-009";
        return "amqp" + (connectionFactory.isSSL() ? "s" : "") + "://" + connectionFactory.getUsername() + "@"
                + host + ":" + connectionFactory.getPort() + connectionFactory.getVirtualHost();
    }
}