All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.canoo.dolphin.server.event.impl.AbstractEventBus Maven / Gradle / Ivy

Go to download

The Dolphin Platform is a framework that implements the presentation model pattern and provides amodern way to create enterprise applications. The Platform provides several client implementations that all canbe used in combination with a general sever API.

There is a newer version: 1.0.0.CR5
Show newest version
/*
 * Copyright 2015-2017 Canoo Engineering AG.
 *
 * 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 com.canoo.dolphin.server.event.impl;

import com.canoo.dolphin.event.Subscription;
import com.canoo.dolphin.server.DolphinSession;
import com.canoo.dolphin.server.context.DolphinContextUtils;
import com.canoo.dolphin.server.context.DolphinSessionLifecycleHandler;
import com.canoo.dolphin.server.context.DolphinSessionProvider;
import com.canoo.dolphin.server.event.DolphinEventBus;
import com.canoo.dolphin.server.event.EventSessionFilter;
import com.canoo.dolphin.server.event.MessageListener;
import com.canoo.dolphin.server.event.Topic;
import com.canoo.dolphin.util.Assert;
import com.canoo.dolphin.util.Callback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

public abstract class AbstractEventBus implements DolphinEventBus {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractEventBus.class);

    private final DolphinSessionProvider sessionProvider;

    private final Map, List>> topicToListenerMap = new ConcurrentHashMap<>();

    private final Map, String> listenerToSessionMap = new ConcurrentHashMap<>();

    private final Map> sessionStore = new ConcurrentHashMap<>();

    protected AbstractEventBus(final DolphinSessionProvider sessionProvider, final DolphinSessionLifecycleHandler lifecycleHandler) {
        this.sessionProvider = Assert.requireNonNull(sessionProvider, "sessionProvider");
        Assert.requireNonNull(lifecycleHandler, "lifecycleHandler").addSessionDestroyedListener(new Callback() {
            @Override
            public void call(final DolphinSession dolphinSession) {
                onSessionEnds(dolphinSession.getId());
            }
        });
    }

    @Override
    public  void publish(final Topic topic, final T data) {
        publish(topic, data, DefaultEventSessionFilter.getInstance());
    }

    @Override
    public  void publish(final Topic topic, final T data, final EventSessionFilter filter) {
        publishData(topic, data, filter);
    }

    private  List> getListenersForSessionAndTopic(final String sessionId, final Topic topic) {
        Assert.requireNonBlank(sessionId, "sessionId");
        Assert.requireNonNull(topic, "topic");

        final List> handlers = topicToListenerMap.get(topic);
        if (handlers == null) {
            return Collections.emptyList();
        }

        final List> ret = new ArrayList<>();
        for (MessageListener listener : handlers) {
            if (sessionId.equals(listenerToSessionMap.get(listener))) {
                ret.add((MessageListener) listener);
            }
        }
        return ret;
    }

    private  void publishData(final Topic topic, final T data, final EventSessionFilter filter) {
        final DolphinSession currentSession = getCurrentDolphinSession();
        final DolphinEvent event = new DolphinEvent(currentSession != null ? currentSession.getId() : null, new DefaultMessage(topic, data, System.currentTimeMillis()), filter);
        if (currentSession != null && (filter == null || filter.shouldHandleEvent(currentSession.getId()))) {
            final List> listenersInCurrentSession = getListenersForSessionAndTopic(currentSession.getId(), topic);
            for (MessageListener listener : listenersInCurrentSession) {
                listener.onMessage(event.getMessage());
            }
        }

        publishForOtherSessions(event);
    }

    protected abstract  void publishForOtherSessions(DolphinEvent event);

    protected  void triggerEventHandling(final DolphinEvent event) {
        Assert.requireNonNull(event, "event");

        final Topic topic = event.getTopic();
        LOG.trace("Handling data for topic {}", topic.getName());
        final List> listeners = topicToListenerMap.get(topic);
        if (listeners != null) {
            for (final MessageListener listener : listeners) {
                final String sessionId = listenerToSessionMap.get(listener);
                if (sessionId == null) {
                    throw new RuntimeException("Internal Error! No session id defined for event bus listener!");
                }
                if (sessionId.equals(event.getSenderSessionId())) {
                    //This listener was already called at the publish call
                    // since the event was called from the same session
                    LOG.trace("Event listener for topic {} was already called in Dolphin Platform context {}", topic.getName(), sessionId);
                } else {
                    LOG.trace("Event listener for topic {} must be called later in Dolphin Platform context {}", topic.getName(), sessionId);
                    DolphinContextUtils.runLaterInClientSession(sessionId, new Runnable() {

                        @Override
                        public void run() {
                            LOG.trace("Calling event listener for topic {} in Dolphin Platform context {}", topic.getName(), sessionId);
                            final EventSessionFilter sessionFilter = event.getSessionFilter();
                            if (sessionFilter == null || sessionFilter.shouldHandleEvent(sessionId)) {
                                ((MessageListener) listener).onMessage(event.getMessage());
                            }
                        }
                    });
                }
            }
        }
    }

    public  Subscription subscribe(final Topic topic, final MessageListener listener) {
        Assert.requireNonNull(topic, "topic");
        Assert.requireNonNull(listener, "listener");

        final DolphinSession subscriptionSession = getCurrentDolphinSession();
        if (subscriptionSession == null) {
            throw new IllegalStateException("Subscription can only be done from Dolphin Context!");
        }
        final String subscriptionSessionId = subscriptionSession.getId();
        LOG.trace("Adding subscription for topic {} in Dolphin Platform context {}", topic.getName(), subscriptionSessionId);
        List> listeners = topicToListenerMap.get(topic);
        if (listeners == null) {
            listeners = new CopyOnWriteArrayList<>();
            topicToListenerMap.put(topic, listeners);
        }
        listeners.add(listener);
        listenerToSessionMap.put(listener, subscriptionSessionId);
        final Subscription subscription = new Subscription() {
            @Override
            public void unsubscribe() {
                LOG.trace("Removing subscription for topic {} in Dolphin Platform context {}", topic.getName(), subscriptionSessionId);
                final List> listeners = topicToListenerMap.get(topic);
                if (listeners != null) {
                    listeners.remove(listener);
                }
                listenerToSessionMap.remove(listener);
                removeSubscriptionForSession(this, subscriptionSessionId);
            }
        };
        addSubscriptionForSession(subscription, subscriptionSessionId);
        return subscription;
    }

    private void addSubscriptionForSession(final Subscription subscription, final String dolphinSessionId) {
        List subscriptionsForSession = sessionStore.get(dolphinSessionId);
        if (subscriptionsForSession == null) {
            subscriptionsForSession = new CopyOnWriteArrayList<>();
            sessionStore.put(dolphinSessionId, subscriptionsForSession);
        }
        subscriptionsForSession.add(subscription);
    }

    private void removeSubscriptionForSession(final Subscription subscription, final String dolphinSessionId) {
        final List subscriptionsForSession = sessionStore.get(dolphinSessionId);
        if (subscriptionsForSession != null) {
            subscriptionsForSession.remove(subscription);
        }
    }

    private void onSessionEnds(final String dolphinSessionId) {
        Assert.requireNonBlank(dolphinSessionId, "dolphinSessionId");
        final List subscriptions = sessionStore.get(dolphinSessionId);
        if (subscriptions != null) {
            for (Subscription subscription : subscriptions) {
                subscription.unsubscribe();
            }
        }
    }

    private DolphinSession getCurrentDolphinSession() {
        return sessionProvider.getCurrentDolphinSession();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy