com.kolibrifx.plovercrest.server.internal.protocol.StreamSubscriptionsHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of plovercrest-server Show documentation
Show all versions of plovercrest-server Show documentation
Plovercrest server library.
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();
}
}