org.apache.nutch.rabbitmq.RabbitMQClient.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.nutch.rabbitmq.RabbitMQClient.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.nutch.rabbitmq;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * Client for RabbitMQ
 */
public class RabbitMQClient {

    private final static String DEFAULT_EXCHANGE_NAME = "";
    private final static String DEFAULT_EXCHANGE_TYPE = "direct";
    private final static String DEFAULT_EXCHANGE_DURABLE = "true";

    private final static String DEFAULT_QUEUE_NAME = "nutch.queue";
    private final static String DEFAULT_QUEUE_DURABLE = "true";
    private final static String DEFAULT_QUEUE_EXCLUSIVE = "false";
    private final static String DEFAULT_QUEUE_AUTO_DELETE = "false";
    private final static String DEFAULT_QUEUE_ARGUMENTS = "";

    private final static String DEFAULT_ROUTING_KEY = DEFAULT_QUEUE_NAME;

    private Connection connection;
    private Channel channel;

    /**
     * Builds a new instance of {@link RabbitMQClient}
     *
     * @param serverHost        The server host.
     * @param serverPort        The server port.
     * @param serverVirtualHost The virtual host into the RabbitMQ server.
     * @param serverUsername    The username to access the server.
     * @param serverPassword    The password to access the server.
     * @throws IOException It is thrown if there is some issue during the connection creation.
     */
    public RabbitMQClient(String serverHost, int serverPort, String serverVirtualHost, String serverUsername,
            String serverPassword) throws IOException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(getValue(serverHost, "localhost"));
        factory.setPort(getValue(serverPort, 5672));

        factory.setVirtualHost(getValue(serverVirtualHost, "/"));

        factory.setUsername(getValue(serverUsername, "guest"));
        factory.setPassword(getValue(serverPassword, "guest"));

        try {
            connection = factory.newConnection();
        } catch (TimeoutException e) {
            throw makeIOException(e);
        }
    }

    /**
     * Builds a new instance of {@link RabbitMQClient}
     *
     * @param uri The connection parameters in the form amqp://userName:password@hostName:portNumber/virtualHost
     * @throws IOException It is thrown if there is some issue during the connection creation.
     */
    public RabbitMQClient(String uri) throws IOException {
        ConnectionFactory factory = new ConnectionFactory();

        try {
            factory.setUri(uri);

            connection = factory.newConnection();
        } catch (URISyntaxException | NoSuchAlgorithmException | KeyManagementException | TimeoutException e) {
            throw makeIOException(e);
        }
    }

    /**
     * Opens a new channel into the opened connection.
     *
     * @throws IOException It is thrown if there is some issue during the channel creation.
     */
    public void openChannel() throws IOException {
        channel = connection.createChannel();
    }

    /**
     * Creates a relationship between an exchange and a queue.
     *
     * @param exchangeName     The exchange's name.
     * @param exchangeOptions  Options used when the exchange is created.
     *                         <br />
     *                         It must have the form type={type},durable={durable} where:
     *                         <ul>
     *                         <li>{type} is fanout, direct, headers or topic</li>
     *                         <li>{durable} is true or false</li>
     *                         </ul>
     * @param queueName        The queue's name.
     * @param queueOptions     Options used when the queue is created.
     *                         <br />
     *                         It must have the form durable={type},exclusive={durable},auto-delete={durable},arguments={durable} where:
     *                         <ul>
     *                         <li>durable is true or false</li>
     *                         <li>exclusive is true or false</li>
     *                         <li>auto-delete is true or false</li>
     *                         <li>arguments must have the for {key1:value1;key2:value2}</li>
     *                         </ul>
     * @param bindingKey       The routine key to use for the binding.
     * @param bindingArguments This parameter is only used when the exchange's type is headers. In other cases is ignored.
     *                         <br />
     *                         It must have the form key1=value1,key2=value2
     * @throws IOException If there is some issue creating the relationship.
     */
    public void bind(String exchangeName, String exchangeOptions, String queueName, String queueOptions,
            String bindingKey, String bindingArguments) throws IOException {
        String exchangeType = exchangeDeclare(exchangeName, exchangeOptions);
        queueDeclare(queueName, queueOptions);

        switch (exchangeType) {
        case "fanout":
            channel.queueBind(queueName, exchangeName, "");
            break;
        case "direct":
            channel.queueBind(queueName, exchangeName, getValue(bindingKey, DEFAULT_ROUTING_KEY));
            break;
        case "headers":
            channel.queueBind(queueName, exchangeName, "",
                    RabbitMQOptionParser.parseOptionAndConvertValue(bindingArguments));
            break;
        case "topic":
            channel.queueBind(queueName, exchangeName, getValue(bindingKey, DEFAULT_ROUTING_KEY));
            break;
        default:
            break;
        }
    }

    /**
     * Publishes a new message over an exchange.
     *
     * @param exchangeName The exchange's name where the message will be published.
     * @param routingKey   The routing key used to route the message in the exchange.
     * @param message      The message itself.
     * @throws IOException If there is some issue publishing the message.
     */
    public void publish(String exchangeName, String routingKey, RabbitMQMessage message) throws IOException {
        channel.basicPublish(getValue(exchangeName, DEFAULT_EXCHANGE_NAME),
                getValue(routingKey, DEFAULT_ROUTING_KEY), new AMQP.BasicProperties.Builder()
                        .contentType(message.getContentType()).headers(message.getHeaders()).build(),
                message.getBody());
    }

    /**
     * Closes the channel and the connection with the server.
     *
     * @throws IOException If there is some issue trying to close the channel or connection.
     */
    public void close() throws IOException {
        try {
            channel.close();
            connection.close();
        } catch (TimeoutException e) {
            throw makeIOException(e);
        }
    }

    /**
     * Creates a new exchange into the server with the given name and options.
     *
     * @param name    The exchange's name.
     * @param options Options used when the exchange is created.
     *                <br />
     *                It must have the form type={type},durable={durable} where:
     *                <ul>
     *                <li>{type} is fanout, direct, headers or topic</li>
     *                <li>{durable} is true or false</li>
     *                </ul>
     * @return The exchange's type.
     * @throws IOException If there is some issue creating the exchange.
     */
    private String exchangeDeclare(String name, String options) throws IOException {
        Map<String, String> values = RabbitMQOptionParser.parseOption(options);

        String type = values.getOrDefault("type", DEFAULT_EXCHANGE_TYPE);

        channel.exchangeDeclare(getValue(name, DEFAULT_EXCHANGE_NAME), type,
                Boolean.parseBoolean(values.getOrDefault("durable", DEFAULT_EXCHANGE_DURABLE)));

        return type;
    }

    /**
     * Creates a queue into the server with the given name and options.
     *
     * @param name    The queue's name.
     * @param options Options used when the queue is created.
     *                <br />
     *                It must have the form durable={durable},exclusive={exclusive},auto-delete={auto-delete},arguments={arguments} where:
     *                <ul>
     *                <li>durable is true or false</li>
     *                <li>exclusive is true or false</li>
     *                <li>auto-delete is true or false</li>
     *                <li>arguments must have the for {key1:value1;key2:value2}</li>
     *                </ul>
     * @throws IOException If there is some issue creating the queue.
     */
    private void queueDeclare(String name, String options) throws IOException {
        Map<String, String> values = RabbitMQOptionParser.parseOption(options);

        channel.queueDeclare(getValue(name, DEFAULT_QUEUE_NAME),
                Boolean.parseBoolean(values.getOrDefault("durable", DEFAULT_QUEUE_DURABLE)),
                Boolean.parseBoolean(values.getOrDefault("exclusive", DEFAULT_QUEUE_EXCLUSIVE)),
                Boolean.parseBoolean(values.getOrDefault("auto-delete", DEFAULT_QUEUE_AUTO_DELETE)),
                RabbitMQOptionParser.parseSubOption(values.getOrDefault("arguments", DEFAULT_QUEUE_ARGUMENTS)));
    }

    private static String getValue(String value, String defaultValue) {
        if (value == null || value.trim().isEmpty()) {
            return defaultValue;
        }
        return value;
    }

    private static Integer getValue(Integer value, Integer defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        return value;
    }

    private static IOException makeIOException(Exception e) {
        return new IOException(e);
    }
}