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

io.descoped.rawdata.memory.MemoryRawdataClient Maven / Gradle / Ivy

The newest version!
package io.descoped.rawdata.memory;

import de.huxhorn.sulky.ulid.ULID;
import io.descoped.rawdata.api.RawdataClient;
import io.descoped.rawdata.api.RawdataClosedException;
import io.descoped.rawdata.api.RawdataConsumer;
import io.descoped.rawdata.api.RawdataCursor;
import io.descoped.rawdata.api.RawdataMessage;
import io.descoped.rawdata.api.RawdataNoSuchPositionException;

import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import static java.util.Optional.ofNullable;

public class MemoryRawdataClient implements RawdataClient {

    final Map topicByName = new ConcurrentHashMap<>();
    final AtomicBoolean closed = new AtomicBoolean(false);
    final List producers = new CopyOnWriteArrayList<>();
    final List consumers = new CopyOnWriteArrayList<>();

    @Override
    public MemoryRawdataProducer producer(String topicName) {
        if (isClosed()) {
            throw new RawdataClosedException();
        }
        MemoryRawdataProducer producer = new MemoryRawdataProducer(topicByName.computeIfAbsent(topicName, MemoryRawdataTopic::new), producers::remove);
        this.producers.add(producer);
        return producer;
    }

    @Override
    public RawdataConsumer consumer(String topic, RawdataCursor cursor) {
        if (isClosed()) {
            throw new RawdataClosedException();
        }
        MemoryRawdataConsumer consumer = new MemoryRawdataConsumer(
                topicByName.computeIfAbsent(topic, MemoryRawdataTopic::new),
                (MemoryCursor) cursor,
                consumers::remove
        );
        consumers.add(consumer);
        return consumer;
    }

    @Override
    public RawdataCursor cursorOf(String topicName, ULID.Value ulid, boolean inclusive) {
        return new MemoryCursor(ulid, inclusive, true);
    }

    @Override
    public RawdataCursor cursorOf(String topicName, String position, boolean inclusive, long approxTimestamp, Duration tolerance) {
        MemoryRawdataTopic topic = topicByName.computeIfAbsent(topicName, MemoryRawdataTopic::new);
        topic.tryLock(5, TimeUnit.SECONDS);
        try {
            ULID.Value lowerBound = RawdataConsumer.beginningOf(approxTimestamp - tolerance.toMillis());
            ULID.Value upperBound = RawdataConsumer.beginningOf(approxTimestamp + tolerance.toMillis());
            return ofNullable(topic.ulidOf(position, lowerBound, upperBound))
                    .map(ulid -> new MemoryCursor(ulid, inclusive, true))
                    .orElseThrow(() -> new RawdataNoSuchPositionException(String.format("Position not found: %s", position)));
        } finally {
            topic.unlock();
        }
    }

    @Override
    public RawdataMessage lastMessage(String topicName) throws RawdataClosedException {
        if (isClosed()) {
            throw new RawdataClosedException();
        }
        MemoryRawdataTopic topic = topicByName.computeIfAbsent(topicName, MemoryRawdataTopic::new);
        topic.tryLock(5, TimeUnit.SECONDS);
        try {
            return topic.lastMessage();
        } finally {
            topic.unlock();
        }
    }

    @Override
    public boolean isClosed() {
        return closed.get();
    }

    @Override
    public MemoryRawdataMetadataClient metadata(String topic) {
        return new MemoryRawdataMetadataClient(topic);
    }

    @Override
    public void close() {
        for (MemoryRawdataProducer producer : producers) {
            producer.close();
        }
        producers.clear();
        for (MemoryRawdataConsumer consumer : consumers) {
            consumer.close();
        }
        consumers.clear();
        closed.set(true);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy