com.codenvy.flux.watcher.core.FluxMessageBus.java Source code

Java tutorial

Introduction

Here is the source code for com.codenvy.flux.watcher.core.FluxMessageBus.java

Source

/*******************************************************************************
 * Copyright (c) 2014 Codenvy, S.A.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Codenvy, S.A. - initial API and implementation
 *******************************************************************************/
package com.codenvy.flux.watcher.core;

import static com.codenvy.flux.watcher.core.FluxMessage.Fields.CALLBACK_ID;
import static com.codenvy.flux.watcher.core.FluxMessageType.GET_PROJECT_RESPONSE;
import static com.codenvy.flux.watcher.core.FluxMessageType.GET_RESOURCE_RESPONSE;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.notNull;
import static java.util.Collections.emptySet;

import java.net.URL;
import java.util.Arrays;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;

import org.json.JSONObject;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;

/**
 * Message bus connected to Flux instance.
 *
 * @author Kevin Pollet
 */
@Singleton
public class FluxMessageBus {
    private final int id;
    private final ConcurrentMap<URL, FluxConnection> connections;
    private final Provider<Repository> repository;
    private final Set<FluxMessageHandler> messageHandlers;

    /**
     * Constructs an instance of {@link com.codenvy.flux.watcher.core.FluxMessageBus}.
     *
     * @param messageHandlers
     *         the {@link FluxMessageHandler} to register.
     * @param repository
     *         the {@link Repository} provider instance.
     * @throws java.lang.NullPointerException
     *         if {@code messageHandlers} is {@code null}.
     */
    @Inject
    FluxMessageBus(Set<FluxMessageHandler> messageHandlers, Provider<Repository> repository) {
        id = Long.valueOf(UUID.randomUUID().getMostSignificantBits()).intValue();
        this.repository = repository;
        this.messageHandlers = new CopyOnWriteArraySet<>(checkNotNull(messageHandlers));
        connections = new ConcurrentHashMap<>();
    }

    /**
     * Returns the {@link com.codenvy.flux.watcher.core.FluxMessageBus} unique id.
     *
     * @return the {@link com.codenvy.flux.watcher.core.FluxMessageBus} unique id.
     */
    public int id() {
        return id;
    }

    /**
     * Open a connection to the given server {@link java.net.URL}.
     *
     * @param serverURL
     *         the server {@link java.net.URL} to connect to.
     * @param credentials
     *         the {@link Credentials} to use for the connection.
     * @return the opened {@link com.codenvy.flux.watcher.core.FluxConnection} or the existing {@link
     * com.codenvy.flux.watcher.core.FluxConnection} if already opened.
     * @throws java.lang.NullPointerException
     *         if {@code serverURL} or {@code credentials} parameter is {@code null}.
     */
    public FluxConnection connect(URL serverURL, Credentials credentials) {
        checkNotNull(serverURL);
        checkNotNull(credentials);

        FluxConnection connection = connections.get(serverURL);
        if (connection == null) {
            FluxConnection newConnection = new FluxConnection(serverURL, credentials, this);
            connection = connections.putIfAbsent(serverURL, newConnection);
            if (connection == null) {
                connection = newConnection.open();
            }
        }

        return connection;
    }

    /**
     * Close the connection to the given server {@link java.net.URL}.
     *
     * @param serverURL
     *         the server {@link java.net.URL} to disconnect from.
     * @throws java.lang.NullPointerException
     *         if {@code serverURL} parameter is {@code null}.
     */
    public void disconnect(URL serverURL) {
        final FluxConnection connection = connections.remove(checkNotNull(serverURL));
        if (connection != null) {
            connection.close();
        }
    }

    /**
     * Adds a {@link FluxMessageHandler}.
     *
     * @param handler
     *         the {@link FluxMessageHandler} to add.
     * @return {@code true} if the {@code handler} is not already added, {@code false} otherwise.
     * @throws java.lang.NullPointerException
     *         if {@code handler} parameter is {@code null}.
     */
    public boolean addMessageHandler(FluxMessageHandler handler) {
        return messageHandlers.add(checkNotNull(handler));
    }

    /**
     * Removes a {@link FluxMessageHandler}.
     *
     * @param handler
     *         the {@link FluxMessageHandler} to remove.
     * @return {@code true} if the {@code handler} was already added, {@code false} otherwise.
     * @throws java.lang.NullPointerException
     *         if {@code handler} parameter is {@code null}.
     */
    public boolean removeMessageHandler(FluxMessageHandler handler) {
        return messageHandlers.remove(checkNotNull(handler));
    }

    /**
     * Broadcast messages to all opened {@link com.codenvy.flux.watcher.core.FluxConnection}.
     *
     * @param messages
     *         the {@link FluxMessage} to broadcast.
     * @throws java.lang.NullPointerException
     *         if {@code messages} parameter is {@code null}.
     */
    public void sendMessages(FluxMessage... messages) {
        checkNotNull(messages);

        for (FluxMessage oneMessage : messages) {
            checkNotNull(oneMessage);

            for (FluxConnection oneConnection : connections.values()) {
                oneConnection.sendMessage(oneMessage);
            }
        }
    }

    /**
     * Fires the given {@link FluxMessage} to all {@link FluxMessageHandler}
     * registered.
     *
     * @param message
     *         the message.
     * @throws java.lang.NullPointerException
     *         if {@code message} parameter is {@code null}.
     */
    public void messageReceived(FluxMessage message) {
        checkNotNull(message);

        if (message.type() == GET_RESOURCE_RESPONSE || message.type() == GET_PROJECT_RESPONSE) {
            final JSONObject content = message.content();
            if (content.optInt(CALLBACK_ID.value()) != id) {
                return;
            }
        }

        final Set<FluxMessageHandler> messageHandlers = getMessageHandlersFor(message.type().value());
        for (FluxMessageHandler oneMessageHandler : messageHandlers) {
            try {

                oneMessageHandler.onMessage(message, repository.get());

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    private Set<FluxMessageHandler> getMessageHandlersFor(final String messageType) {
        return ImmutableSet.copyOf(
                FluentIterable.from(messageHandlers).filter(notNull()).filter(new Predicate<FluxMessageHandler>() {
                    @Override
                    public boolean apply(FluxMessageHandler messageHandler) {
                        final Set<String> supportedTypes = getMessageTypesFor(messageHandler);
                        return supportedTypes.contains(messageType);
                    }
                }));
    }

    private Set<String> getMessageTypesFor(FluxMessageHandler messageHandler) {
        final FluxMessageTypes types = messageHandler.getClass().getAnnotation(FluxMessageTypes.class);
        if (types == null) {
            return emptySet();
        }

        return ImmutableSet.copyOf(FluentIterable.from(Arrays.asList(types.value())).filter(Predicates.notNull())
                .transform(new Function<FluxMessageType, String>() {
                    @Override
                    public String apply(FluxMessageType messageType) {
                        return messageType.value();
                    }
                }));
    }
}