com.canoo.dp.impl.server.event.AbstractEventBus Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dolphin-platform-remoting-server Show documentation
Show all versions of dolphin-platform-remoting-server Show documentation
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.
The newest version!
/*
* Copyright 2015-2018 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.dp.impl.server.event;
import com.canoo.dp.impl.platform.core.Assert;
import com.canoo.dp.impl.server.client.ClientSessionLifecycleHandler;
import com.canoo.dp.impl.server.context.DolphinContext;
import com.canoo.dp.impl.server.context.DolphinContextProvider;
import com.canoo.platform.core.functional.Subscription;
import com.canoo.platform.remoting.server.event.ClientSessionEventFilter;
import com.canoo.platform.remoting.server.event.MessageEventContext;
import com.canoo.platform.remoting.server.event.MessageListener;
import com.canoo.platform.remoting.server.event.RemotingEventBus;
import com.canoo.platform.remoting.server.event.Topic;
import com.canoo.platform.server.client.ClientSession;
import org.apiguardian.api.API;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpSession;
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;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import static org.apiguardian.api.API.Status.INTERNAL;
@API(since = "0.x", status = INTERNAL)
public abstract class AbstractEventBus implements RemotingEventBus {
private static final Logger LOG = LoggerFactory.getLogger(AbstractEventBus.class);
private DolphinContextProvider contextProvider;
private final Map, List>> topicToListenerMap = new ConcurrentHashMap<>();
private final Map, String> listenerToSessionMap = new ConcurrentHashMap<>();
private final Map> sessionStore = new ConcurrentHashMap<>();
private final AtomicBoolean initialized = new AtomicBoolean(false);
public void init(final DolphinContextProvider contextProvider, final ClientSessionLifecycleHandler lifecycleHandler) {
this.contextProvider = Assert.requireNonNull(contextProvider, "contextProvider");
Assert.requireNonNull(lifecycleHandler, "lifecycleHandler").addSessionDestroyedListener((s) -> onSessionEnds(s.getId()));
initialized.set(true);
}
@Override
public void publish(final Topic topic, final T data) {
checkInitialization();
final DolphinEvent event = new DolphinEvent(topic, System.currentTimeMillis(), data);
event.addMetadata(EventConstants.TYPE_PARAM, EventConstants.TYPE_PLATFORM);
final DolphinContext currentContext = getCurrentContext();
if (currentContext != null) {
final ClientSession clientSession = currentContext.getClientSession();
if (clientSession != null) {
event.addMetadata(EventConstants.CLIENT_SESSION_PARAM, clientSession.getId());
final HttpSession httpSession = clientSession.getHttpSession();
if (httpSession != null) {
event.addMetadata(EventConstants.HTTP_SESSION_PARAM, httpSession.getId());
}
}
}
//Handle listener in same session
if (currentContext != null) {
final List> listenersInCurrentSession = getListenersForSessionAndTopic(currentContext.getId(), topic);
for (ListenerWithFilter listenerAndFilter : listenersInCurrentSession) {
final Predicate> filter = listenerAndFilter.getFilter();
final MessageListener listener = listenerAndFilter.getListener();
if (filter == null || filter.test(event.getMessageEventContext())) {
listener.onMessage(event);
}
}
}
publishForOtherSessions(event);
}
@Override
public Subscription subscribe(final Topic topic, final MessageListener super T> listener, final Predicate> filter) {
checkInitialization();
Assert.requireNonNull(topic, "topic");
Assert.requireNonNull(listener, "listener");
final DolphinContext subscriptionContext = getCurrentContext();
if (subscriptionContext == null) {
throw new IllegalStateException("Subscription can only be done from Dolphin Context!");
}
final String subscriptionSessionId = subscriptionContext.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);
}
final ListenerWithFilter listenerWithFilter = new ListenerWithFilter(listener, filter);
listeners.add(listenerWithFilter);
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(listenerWithFilter);
}
listenerToSessionMap.remove(listener);
removeSubscriptionForSession(this, subscriptionSessionId);
}
};
addSubscriptionForSession(subscription, subscriptionSessionId);
return subscription;
}
public Subscription subscribe(final Topic topic, final MessageListener super T> listener) {
return subscribe(topic, listener, null);
}
protected void triggerEventHandling(final DolphinEvent event) {
Assert.requireNonNull(event, "event");
final Topic topic = event.getMessageEventContext().getTopic();
LOG.trace("Handling data for topic {}", topic.getName());
final List> listeners = topicToListenerMap.get(topic);
if (listeners != null) {
for (final ListenerWithFilter> listenerAndFilter : listeners) {
final String sessionId = listenerToSessionMap.get(listenerAndFilter.getListener());
if (sessionId == null) {
throw new RuntimeException("Internal Error! No session id defined for event bus listener!");
}
if (sendInSameClientSession(event, (MessageListener) listenerAndFilter.getListener())) {
// 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);
contextProvider.getContextById(sessionId).runLater(new Runnable() {
@Override
public void run() {
LOG.trace("Calling event listener for topic {} in Dolphin Platform context {}", topic.getName(), sessionId);
final Predicate> sessionFilter = ((ListenerWithFilter) listenerAndFilter).getFilter();
final MessageListener listener = (MessageListener) listenerAndFilter.getListener();
try {
if (sessionFilter == null || sessionFilter.test(event.getMessageEventContext())) {
listener.onMessage(event);
}
} catch (final Exception e) {
LOG.error("Error in calling event listener for topic '" + topic.getName() + "' in Dolphin Platform context " + sessionId, e);
}
}
});
}
}
}
}
private boolean sendInSameClientSession(final DolphinEvent event, final MessageListener listener) {
Assert.requireNonNull(event, "event");
final String listenerSessionId = listenerToSessionMap.get(listener);
final MessageEventContext eventContext = event.getMessageEventContext();
if (eventContext != null) {
return new ClientSessionEventFilter(listenerSessionId).test(eventContext);
}
return false;
}
protected abstract void publishForOtherSessions(final DolphinEvent event);
private void checkInitialization() {
if (!initialized.get()) {
throw new RuntimeException("EventBus not initialized");
}
}
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 (ListenerWithFilter> listener : handlers) {
if (sessionId.equals(listenerToSessionMap.get(listener.getListener()))) {
ret.add((ListenerWithFilter) listener);
}
}
return ret;
}
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 DolphinContext getCurrentContext() {
return contextProvider.getCurrentDolphinContext();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy