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

com.kolibrifx.plovercrest.server.internal.protocol.StreamSubscriptionsHandler Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2017, KolibriFX AS. Licensed under the Apache License, version 2.0.
 */

package com.kolibrifx.plovercrest.server.internal.protocol;

import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.kolibrifx.common.Disposable;
import com.kolibrifx.plovercrest.client.internal.SubscriptionQuery;
import com.kolibrifx.plovercrest.server.internal.StreamObservers;
import com.kolibrifx.plovercrest.server.streams.StreamEngine;
import com.kolibrifx.plovercrest.server.streams.StreamObserver;

public class StreamSubscriptionsHandler implements Disposable {
    private final StreamObservers observers;
    private final StreamConnection connection;
    private final Map activeSubscriptions = new ConcurrentHashMap<>();

    public StreamSubscriptionsHandler(final StreamEngine streamEngine, final StreamConnection connection) {
        this.observers = new StreamObservers(streamEngine);
        this.connection = connection;
    }

    public void add(final String tableName, final SubscriptionQuery query, final int subscriptionId) {
        if (activeSubscriptions.containsKey(subscriptionId)) {
            throw new IllegalStateException("Multiple subscriptions with ID: " + subscriptionId);
        }
        final StreamObserver observer = new StreamObserver() {
            boolean started = false;
            long lastValidTimestamp = Long.MIN_VALUE;

            @Override
            public void onObserve(final long timestamp, final long entryIndex, final ByteBuffer element) {
                postAckIfNeeded(entryIndex);
                connection.postEntryToSubscriber(subscriptionId, entryIndex, timestamp, element);
                lastValidTimestamp = Math.max(timestamp, lastValidTimestamp);
            }

            @Override
            public void onObserveEnd(final long lastValidTimestamp, final long entryCount) {
                postAckIfNeeded(entryCount);
                if (lastValidTimestamp >= 0 && lastValidTimestamp > this.lastValidTimestamp) {
                    connection.postLastValidTimestampToSubscriber(subscriptionId, entryCount, lastValidTimestamp);
                }
                this.lastValidTimestamp = lastValidTimestamp;
            }

            private void postAckIfNeeded(final long entryIndex) {
                if (started) {
                    return;
                }
                started = true;
                connection.postAckToSubscriber(subscriptionId, entryIndex);
            }

            @Override
            public void onObserveFrozen() {
                connection.postTableFrozenToSubscriber(subscriptionId);
            }
        };
        final Disposable disposable = observers.subscribe(tableName, query, observer, ByteBuffer.class);
        activeSubscriptions.put(subscriptionId, disposable);
    }

    public void remove(final int subscriptionId) {
        final Disposable d = activeSubscriptions.remove(subscriptionId);
        if (d != null) {
            d.close();
        }
    }

    @Override
    public void close() {
        for (final Disposable d : activeSubscriptions.values()) {
            d.close();
        }
        activeSubscriptions.clear();
        observers.close();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy