org.trellisldp.amqp.AmqpPublisher.java Source code

Java tutorial

Introduction

Here is the source code for org.trellisldp.amqp.AmqpPublisher.java

Source

/*
 * 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.trellisldp.amqp;

import static java.util.Objects.requireNonNull;
import static java.util.Optional.of;
import static java.util.ServiceLoader.load;
import static org.apache.tamaya.ConfigurationProvider.getConfiguration;
import static org.slf4j.LoggerFactory.getLogger;

import com.rabbitmq.client.AMQP.BasicProperties;
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.GeneralSecurityException;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.concurrent.TimeoutException;

import javax.inject.Inject;

import org.apache.tamaya.Configuration;
import org.slf4j.Logger;
import org.trellisldp.api.ActivityStreamService;
import org.trellisldp.api.Event;
import org.trellisldp.api.EventService;
import org.trellisldp.api.RuntimeTrellisException;

/**
 * An AMQP message producer capable of publishing messages to an AMQP broker such as
 * RabbitMQ or Qpid.
 */
public class AmqpPublisher implements EventService {

    private static final Logger LOGGER = getLogger(AmqpPublisher.class);
    private static final ActivityStreamService service = of(load(ActivityStreamService.class))
            .map(ServiceLoader::iterator).filter(Iterator::hasNext).map(Iterator::next)
            .orElseThrow(() -> new RuntimeTrellisException("No ActivityStream service available!"));

    /** The configuration key controlling the AMQP exchange name. **/
    public static final String CONFIG_AMQP_EXCHANGE_NAME = "trellis.amqp.exchangename";

    /** The configuration key controlling the AMQP routing key. **/
    public static final String CONFIG_AMQP_ROUTING_KEY = "trellis.amqp.routingkey";

    /** The configuration key controlling whether publishing is mandatory. **/
    public static final String CONFIG_AMQP_MANDATORY = "trellis.amqp.mandatory";

    /** The configuration key controlling whether publishing is immediate. **/
    public static final String CONFIG_AMQP_IMMEDIATE = "trellis.amqp.immediate";

    /** The configuration key controlling the AMQP connection URI. **/
    public static final String CONFIG_AMQP_URI = "trellis.amqp.uri";

    private final Channel channel;
    private final String exchangeName;
    private final String routingKey;
    private final boolean mandatory;
    private final boolean immediate;

    /**
     * Create an AMQP publisher.
     * @throws IOException in the event that an I/O related error occurs when connecting
     * @throws GeneralSecurityException in the event that a security error occurs when connecting
     * @throws URISyntaxException in the event that the connection URI is syntactically incorrect
     * @throws TimeoutException in the event that the connection times out
     */
    @Inject
    public AmqpPublisher() throws IOException, GeneralSecurityException, URISyntaxException, TimeoutException {
        this(getConfiguration());
    }

    private AmqpPublisher(final Configuration config)
            throws IOException, GeneralSecurityException, URISyntaxException, TimeoutException {
        this(buildConnection(config.get(CONFIG_AMQP_URI)).createChannel(), config);
    }

    /**
     * Create an AMQP publisher.
     * @param channel the channel
     */
    public AmqpPublisher(final Channel channel) {
        this(channel, getConfiguration());
    }

    private AmqpPublisher(final Channel channel, final Configuration config) {
        this(channel, config.get(CONFIG_AMQP_EXCHANGE_NAME), config.get(CONFIG_AMQP_ROUTING_KEY),
                config.getOrDefault(CONFIG_AMQP_MANDATORY, Boolean.class, Boolean.TRUE),
                config.getOrDefault(CONFIG_AMQP_IMMEDIATE, Boolean.class, Boolean.FALSE));
    }

    /**
     * Create an AMQP publisher.
     * @param channel the channel
     * @param exchangeName the exchange name
     * @param routingKey the routing key
     */
    public AmqpPublisher(final Channel channel, final String exchangeName, final String routingKey) {
        this(channel, exchangeName, routingKey, true, false);
    }

    /**
     * Create an AMQP publisher.
     * @param channel the channel
     * @param exchangeName the exchange name
     * @param routingKey the routing key
     * @param mandatory the mandatory setting
     * @param immediate the immediate setting
     */
    public AmqpPublisher(final Channel channel, final String exchangeName, final String routingKey,
            final boolean mandatory, final boolean immediate) {
        this.channel = requireNonNull(channel, "AMQP Channel may not be null!");
        this.exchangeName = requireNonNull(exchangeName, "AMQP exchange name may not be null!");
        this.routingKey = requireNonNull(routingKey, "AMQP routing key may not be null!");

        this.mandatory = mandatory;
        this.immediate = immediate;
    }

    @Override
    public void emit(final Event event) {
        requireNonNull(event, "Cannot emit a null event!");

        final BasicProperties props = new BasicProperties().builder().contentType("application/ld+json")
                .contentEncoding("UTF-8").build();

        service.serialize(event).ifPresent(message -> {
            try {
                channel.basicPublish(exchangeName, routingKey, mandatory, immediate, props, message.getBytes());
            } catch (final IOException ex) {
                LOGGER.error("Error writing to broker: {}", ex.getMessage());
            }
        });
    }

    private static Connection buildConnection(final String uri)
            throws IOException, GeneralSecurityException, URISyntaxException, TimeoutException {
        final ConnectionFactory factory = new ConnectionFactory();
        factory.setUri(uri);
        return factory.newConnection();
    }
}