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

Java tutorial

Introduction

Here is the source code for org.smartdeveloperhub.harvesters.it.notification.NotificationConsumer.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.io.IOException;
import java.util.List;
import java.util.concurrent.BlockingQueue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smartdeveloperhub.harvesters.it.notification.event.CommitCreatedEvent;
import org.smartdeveloperhub.harvesters.it.notification.event.CommitDeletedEvent;
import org.smartdeveloperhub.harvesters.it.notification.event.ContributorCreatedEvent;
import org.smartdeveloperhub.harvesters.it.notification.event.ContributorDeletedEvent;
import org.smartdeveloperhub.harvesters.it.notification.event.Event;
import org.smartdeveloperhub.harvesters.it.notification.event.ProjectCreatedEvent;
import org.smartdeveloperhub.harvesters.it.notification.event.ProjectDeletedEvent;
import org.smartdeveloperhub.harvesters.it.notification.event.ProjectUpdatedEvent;

import com.google.common.collect.ImmutableList;
import com.google.common.net.HttpHeaders;
import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

final class NotificationConsumer extends DefaultConsumer {

    private interface NotificationHandler {

        boolean canHandle(String routingKey);

        SuspendedNotification suspend(AcknowledgeableNotification notification, String payload) throws IOException;

    }

    protected abstract static class CustomSuspendedNotification<T extends Event> implements SuspendedNotification {

        private final AcknowledgeableNotification notification;
        private final T event;

        protected CustomSuspendedNotification(final AcknowledgeableNotification notification, final T event) {
            this.notification = notification;
            this.event = event;
        }

        protected final T getEvent() {
            return this.event;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void consume() {
            this.notification.consume();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void discard(final Throwable exception) {
            this.notification.discard(exception);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final void resume(final NotificationListener listener) {
            try {
                doResume(listener);
            } finally {
                enforceAcknowledgement();
            }
        }

        private void enforceAcknowledgement() {
            if (!this.notification.isAcknowledged()) {
                this.notification.acknowledge();
            }
        }

        protected abstract void doResume(NotificationListener listener);

    }

    private abstract static class CustomNotificationHandler<T extends Event> implements NotificationHandler {

        private final String acceptedKey;
        private final Class<? extends T> clazz;

        protected CustomNotificationHandler(final Class<? extends T> clazz) {
            this.clazz = clazz;
            this.acceptedKey = Notifications.routingKey(clazz);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final boolean canHandle(final String routingKey) {
            return this.acceptedKey.equals(routingKey);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final SuspendedNotification suspend(final AcknowledgeableNotification notification,
                final String payload) throws IOException {
            return createPropagator(notification, EventUtil.unmarshall(payload, this.clazz));
        }

        protected abstract CustomSuspendedNotification<T> createPropagator(AcknowledgeableNotification notification,
                T event);

    }

    private static final class ContributorCreatedNotificationHandler
            extends CustomNotificationHandler<ContributorCreatedEvent> {

        protected ContributorCreatedNotificationHandler() {
            super(ContributorCreatedEvent.class);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected CustomSuspendedNotification<ContributorCreatedEvent> createPropagator(
                final AcknowledgeableNotification notification, final ContributorCreatedEvent event) {
            return new CustomSuspendedNotification<ContributorCreatedEvent>(notification, event) {
                @Override
                protected void doResume(final NotificationListener listener) {
                    listener.onContributorCreation(this, super.getEvent());
                }
            };
        }

    }

    private static final class ContributorDeletedNotificationHandler
            extends CustomNotificationHandler<ContributorDeletedEvent> {

        protected ContributorDeletedNotificationHandler() {
            super(ContributorDeletedEvent.class);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected CustomSuspendedNotification<ContributorDeletedEvent> createPropagator(
                final AcknowledgeableNotification notification, final ContributorDeletedEvent event) {
            return new CustomSuspendedNotification<ContributorDeletedEvent>(notification, event) {
                @Override
                protected void doResume(final NotificationListener listener) {
                    listener.onContributorDeletion(this, super.getEvent());
                }
            };
        }

    }

    private static final class CommitCreatedNotificationHandler
            extends CustomNotificationHandler<CommitCreatedEvent> {

        protected CommitCreatedNotificationHandler() {
            super(CommitCreatedEvent.class);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected CustomSuspendedNotification<CommitCreatedEvent> createPropagator(
                final AcknowledgeableNotification notification, final CommitCreatedEvent event) {
            return new CustomSuspendedNotification<CommitCreatedEvent>(notification, event) {
                @Override
                protected void doResume(final NotificationListener listener) {
                    listener.onCommitCreation(this, super.getEvent());
                }
            };
        }

    }

    private static final class CommitDeletedNotificationHandler
            extends CustomNotificationHandler<CommitDeletedEvent> {

        protected CommitDeletedNotificationHandler() {
            super(CommitDeletedEvent.class);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected CustomSuspendedNotification<CommitDeletedEvent> createPropagator(
                final AcknowledgeableNotification notification, final CommitDeletedEvent event) {
            return new CustomSuspendedNotification<CommitDeletedEvent>(notification, event) {
                @Override
                protected void doResume(final NotificationListener listener) {
                    listener.onCommitDeletion(this, super.getEvent());
                }
            };
        }

    }

    private static final class ProjectCreatedNotificationHandler
            extends CustomNotificationHandler<ProjectCreatedEvent> {

        protected ProjectCreatedNotificationHandler() {
            super(ProjectCreatedEvent.class);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected CustomSuspendedNotification<ProjectCreatedEvent> createPropagator(
                final AcknowledgeableNotification notification, final ProjectCreatedEvent event) {
            return new CustomSuspendedNotification<ProjectCreatedEvent>(notification, event) {
                @Override
                protected void doResume(final NotificationListener listener) {
                    listener.onProjectCreation(this, super.getEvent());
                }
            };
        }
    }

    private static final class ProjectDeletedNotificationHandler
            extends CustomNotificationHandler<ProjectDeletedEvent> {

        protected ProjectDeletedNotificationHandler() {
            super(ProjectDeletedEvent.class);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected CustomSuspendedNotification<ProjectDeletedEvent> createPropagator(
                final AcknowledgeableNotification notification, final ProjectDeletedEvent event) {
            return new CustomSuspendedNotification<ProjectDeletedEvent>(notification, event) {
                @Override
                protected void doResume(final NotificationListener listener) {
                    listener.onProjectDeletion(this, super.getEvent());
                }
            };
        }
    }

    private static final class ProjectUpdatedNotificationHandler
            extends CustomNotificationHandler<ProjectUpdatedEvent> {

        protected ProjectUpdatedNotificationHandler() {
            super(ProjectUpdatedEvent.class);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected CustomSuspendedNotification<ProjectUpdatedEvent> createPropagator(
                final AcknowledgeableNotification notification, final ProjectUpdatedEvent event) {
            return new CustomSuspendedNotification<ProjectUpdatedEvent>(notification, event) {
                @Override
                protected void doResume(final NotificationListener listener) {
                    listener.onProjectUpdate(this, super.getEvent());
                }
            };
        }

    }

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

    private final BlockingQueue<SuspendedNotification> notifications;
    private final List<NotificationHandler> handlers;

    NotificationConsumer(final Channel channel, final BlockingQueue<SuspendedNotification> pendingNotifications) {
        super(channel);
        this.notifications = pendingNotifications;
        this.handlers = ImmutableList.<NotificationHandler>builder()
                .add(new ContributorCreatedNotificationHandler()).add(new ContributorDeletedNotificationHandler())
                .add(new CommitCreatedNotificationHandler()).add(new CommitDeletedNotificationHandler())
                .add(new ProjectCreatedNotificationHandler()).add(new ProjectDeletedNotificationHandler())
                .add(new ProjectUpdatedNotificationHandler()).build();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void handleDelivery(final String consumerTag, final Envelope envelope, final BasicProperties properties,
            final byte[] body) throws IOException {
        final String payload = new String(body, "UTF-8");
        final String routingKey = envelope.getRoutingKey();
        final AcknowledgeableNotification notification = new AcknowledgeableNotification(super.getChannel(),
                envelope.getDeliveryTag());
        try {
            verifyHeader(properties);
            this.notifications.offer(findHandler(routingKey).suspend(notification, payload));
        } catch (final Exception e) {
            LOGGER.error("Discarding message:\n{}\nReason:\n", payload, e);
            notification.acknowledge();
        }
    }

    private NotificationHandler findHandler(final String routingKey) {
        for (final NotificationHandler handler : this.handlers) {
            if (handler.canHandle(routingKey)) {
                return handler;
            }
        }
        throw new IllegalStateException("Unsupported routing key " + routingKey);
    }

    private void verifyHeader(final BasicProperties properties) throws IOException {
        final Object header = properties.getHeaders().get(HttpHeaders.CONTENT_TYPE);
        checkNotNull(header, "No %s header defined", HttpHeaders.CONTENT_TYPE);
        checkArgument(Notifications.MIME.equals(header.toString()), "Unsupported %s header (%s)",
                HttpHeaders.CONTENT_TYPE, header);
    }

}