org.smartdeveloperhub.harvesters.it.notification.CollectorAggregator.java Source code

Java tutorial

Introduction

Here is the source code for org.smartdeveloperhub.harvesters.it.notification.CollectorAggregator.java

Source

/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the Smart Developer Hub Project:
 *     http://www.smartdeveloperhub.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2015-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.smartdeveloperhub.harvesters.it:it-harvester-notification:0.1.0
 *   Bundle      : it-harvester-notification-0.1.0.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.smartdeveloperhub.harvesters.it.notification;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import java.util.ArrayList;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

final class CollectorAggregator {

    private static final Logger LOGGER = LoggerFactory.getLogger(CollectorAggregator.class);

    private final String name;
    private final NotificationListener listener;

    private final Multimap<String, CollectorConfiguration> brokerCollectors;
    private final Multimap<String, String> brokerInstances;
    private final Map<String, CollectorController> brokerController;
    private final Map<String, String> instanceBroker;

    private final BlockingQueue<SuspendedNotification> notificationQueue;
    private final Deque<CollectorController> connectedControllers;

    private NotificationPump pump;

    private CollectorAggregator(final String name, final NotificationListener listener) {
        this.name = name;
        this.listener = listener;
        this.brokerCollectors = LinkedListMultimap.create();
        this.brokerInstances = LinkedListMultimap.create();
        this.instanceBroker = Maps.newLinkedHashMap();
        this.brokerController = Maps.newLinkedHashMap();
        this.notificationQueue = new LinkedBlockingQueue<>();
        this.connectedControllers = Lists.newLinkedList();
    }

    void connect(final List<CollectorConfiguration> collectors) throws ControllerException {
        LOGGER.info("Setting up collector aggregator for {}...", this.name);
        startNotificationPump();
        for (final CollectorConfiguration collector : collectors) {
            verifyCollectorIsNotConfigured(collector);
            addCollector(collector, queueName(collector));
        }
        LOGGER.info("Collector aggregator for {} connected", this.name);
    }

    List<String> instances() {
        return ImmutableList.copyOf(this.instanceBroker.keySet());
    }

    List<String> brokers() {
        return ImmutableList.copyOf(this.brokerController.keySet());
    }

    List<String> brokerInstances(final String brokerId) {
        return ImmutableList.copyOf(this.brokerInstances.get(brokerId));
    }

    CollectorController controller(final String instance) {
        checkNotNull(instance, "Instance cannot be null");
        final String queueName = this.instanceBroker.get(instance);
        checkArgument(queueName != null, "Unknown instance '%s'", instance);
        return this.brokerController.get(queueName);
    }

    void disconnect() {
        LOGGER.info("Disconnecting {} collector aggregator...", this.name);
        shutdownGracefully();
        LOGGER.info("Collector aggregator for {} disconnected", this.name);
    }

    private void addCollector(final CollectorConfiguration collector, final String queueName)
            throws ControllerException {
        final boolean isNew = !this.brokerCollectors.containsKey(queueName);
        this.brokerInstances.put(queueName, collector.getInstance());
        this.instanceBroker.put(collector.getInstance(), queueName);
        this.brokerCollectors.put(queueName, collector);
        if (isNew) {
            final CollectorController controller = startController(collector, queueName);
            this.brokerController.put(queueName, controller);
            this.connectedControllers.add(controller);
        }
    }

    private void verifyCollectorIsNotConfigured(final CollectorConfiguration collector) {
        if (this.brokerInstances.containsValue(collector.getInstance())) {
            shutdownGracefully();
            throw new IllegalArgumentException(
                    "Multiple configurations found for collector " + collector.getInstance());
        }
    }

    private CollectorController startController(final CollectorConfiguration collector, final String queueName)
            throws ControllerException {
        final CollectorController controller = CollectorController.createNamedReceiver(collector, queueName,
                this.notificationQueue);
        LOGGER.info("Connecting controller for collector {}...", collector.getInstance());
        try {
            controller.connect();
            return controller;
        } catch (final ControllerException e) {
            LOGGER.warn("Could not connect controller for collector {}. Full stacktrace follows",
                    collector.getInstance(), e);
            shutdownGracefully();
            throw e;
        }
    }

    private void startNotificationPump() {
        this.pump = new NotificationPump(this.notificationQueue, this.listener);
        this.pump.start();
    }

    private String queueName(final CollectorConfiguration collector) {
        final Integer hash = Objects.hash(collector.getBrokerHost(), collector.getBrokerPort(),
                collector.getVirtualHost(), collector.getExchangeName());
        return String.format("%s.collector.hash%08X", this.name, hash);
    }

    private void shutdownGracefully() {
        disconnectControllers();
        stopNotificationPump();
        this.brokerInstances.clear();
        this.brokerCollectors.clear();
        drainPendingNotifications();
    }

    private void stopNotificationPump() {
        if (this.pump != null) {
            this.pump.stop();
            this.pump = null;
        }
    }

    private void drainPendingNotifications() {
        final List<SuspendedNotification> discarded = new ArrayList<>();
        if (this.notificationQueue.drainTo(discarded) > 0) {
            LOGGER.warn("{} notifications were dropped", discarded.size());
        }
    }

    private void disconnectControllers() {
        final Iterator<CollectorController> iterator = this.connectedControllers.descendingIterator();
        while (iterator.hasNext()) {
            iterator.next().disconnect();
        }
        this.connectedControllers.clear();
        this.brokerController.clear();
    }

    static CollectorAggregator newInstance(final String name, final NotificationListener listener) {
        return new CollectorAggregator(name, listener);
    }

}