biospectra.classify.server.RabbitMQInputServer.java Source code

Java tutorial

Introduction

Here is the source code for biospectra.classify.server.RabbitMQInputServer.java

Source

/*
 * Copyright 2015 iychoi.
 *
 * 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 biospectra.classify.server;

import biospectra.ServerConfiguration;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.ReturnListener;
import com.rabbitmq.client.ShutdownListener;
import com.rabbitmq.client.ShutdownSignalException;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author iychoi
 */
public class RabbitMQInputServer implements Closeable {

    private static final Log LOG = LogFactory.getLog(RabbitMQInputServer.class);

    private ServerConfiguration conf;
    private RabbitMQInputServerEventHandler handler;
    private Connection connection;
    private Channel requestChannel;
    private Channel responseChannel;
    private Consumer consumer;
    private Thread workerThread;

    public static abstract class RabbitMQInputServerEventHandler {
        protected abstract void handleMessage(ClassificationRequestMessage req, String replyTo);
    }

    public RabbitMQInputServer(ServerConfiguration conf, RabbitMQInputServerEventHandler handler) {
        if (conf == null) {
            throw new IllegalArgumentException("conf is null");
        }

        if (handler == null) {
            throw new IllegalArgumentException("handler is null");
        }

        this.conf = conf;
        this.handler = handler;
    }

    public synchronized void connect() throws IOException, TimeoutException {
        LOG.info("Connecting to - " + this.conf.getRabbitMQHostname() + ":" + this.conf.getRabbitMQPort());

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(this.conf.getRabbitMQHostname());
        factory.setPort(this.conf.getRabbitMQPort());
        factory.setUsername(this.conf.getRabbitMQUserId());
        factory.setPassword(this.conf.getRabbitMQUserPwd());

        factory.setRequestedHeartbeat(60);

        factory.setAutomaticRecoveryEnabled(true);

        this.connection = factory.newConnection();
        this.connection.addShutdownListener(new ShutdownListener() {

            @Override
            public void shutdownCompleted(ShutdownSignalException sse) {
                LOG.error("connection shutdown", sse);
            }
        });

        this.requestChannel = this.connection.createChannel();
        this.responseChannel = this.connection.createChannel();

        LOG.info("connected.");

        this.requestChannel.basicQos(1);
        this.requestChannel.queueDeclare("request", false, false, true, null);

        this.responseChannel.addReturnListener(new ReturnListener() {

            @Override
            public void handleReturn(int replyCode, String replyText, String exchange, String routingKey,
                    AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body, "UTF-8");
                LOG.info("message not delivered to " + routingKey);
                LOG.info(message);
            }
        });

        this.consumer = new DefaultConsumer(this.requestChannel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
                    byte[] body) throws IOException {
                String message = new String(body, "UTF-8");

                this.getChannel().basicAck(envelope.getDeliveryTag(), false);

                if (handler != null) {
                    ClassificationRequestMessage req = ClassificationRequestMessage.createInstance(message);
                    handler.handleMessage(req, properties.getReplyTo());
                }
            }
        };

        this.workerThread = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    requestChannel.basicConsume("request", consumer);
                    LOG.info("Waiting for messages");
                } catch (IOException ex) {
                    LOG.error("Exception occurred while consuming a message", ex);
                }
            }
        });
        this.workerThread.start();
    }

    public synchronized void publishMessage(ClassificationResponseMessage res, String replyTo) {
        try {
            this.responseChannel.basicPublish("", replyTo, true, false, null, res.toJson().getBytes());
        } catch (IOException ex) {
            LOG.error("Cannot publish", ex);
        }
    }

    @Override
    public synchronized void close() throws IOException {
        if (this.workerThread != null) {
            this.workerThread.interrupt();
            this.workerThread = null;
        }

        if (this.requestChannel != null) {
            try {
                this.requestChannel.close();
            } catch (TimeoutException ex) {
            }
            this.requestChannel = null;
        }

        if (this.responseChannel != null) {
            try {
                this.responseChannel.close();
            } catch (TimeoutException ex) {
            }
            this.responseChannel = null;
        }

        if (this.connection != null) {
            this.connection.close();
            this.connection = null;
        }
    }
}