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

com.fluxtion.server.plugin.connector.chronicle.ChronicleEventSource Maven / Gradle / Ivy

/*
 * SPDX-FileCopyrightText: © 2025 Gregory Higgins 
 * SPDX-License-Identifier: AGPL-3.0-only
 */

package com.fluxtion.server.plugin.connector.chronicle;

import com.fluxtion.runtime.event.NamedFeedEvent;
import com.fluxtion.server.dispatch.EventToQueuePublisher;
import com.fluxtion.server.service.AbstractAgentHostedEventSourceService;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import net.openhft.chronicle.bytes.MethodReader;
import net.openhft.chronicle.map.ChronicleMap;
import net.openhft.chronicle.queue.ExcerptTailer;
import net.openhft.chronicle.queue.impl.single.SingleChronicleQueue;
import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.List;

@Log4j2
@SuppressWarnings("all")
public class ChronicleEventSource extends AbstractAgentHostedEventSourceService {

    @Getter
    @Setter
    private String chroniclePath;
    private String chronicleQueuePath;
    private String chronicleMapPath;
    @Getter
    @Setter
    private ReadStrategy readStrategy = ReadStrategy.COMMITED;
    @Getter
    @Setter
    private boolean cacheEventLog = false;
    private boolean publishToQueue = false;
    private MethodReader methodReader;
    private ChronicleMap readpointer;
    private @NotNull ExcerptTailer tailer;

    public ChronicleEventSource(String name) {
        super(name);
    }

    public ChronicleEventSource() {
        this("chronicle-event-source");
    }

    @SneakyThrows
    @Override
    public void onStart() {
        chronicleQueuePath = chroniclePath + "/chronicle-queue";
        chronicleMapPath = chroniclePath + "/chronicle-map";
        SingleChronicleQueue chronicleQueue = SingleChronicleQueueBuilder.binary(chronicleQueuePath).build();
        MessageSink messageSink = this::publish;
        tailer = chronicleQueue.createTailer();
        methodReader = tailer.methodReader(messageSink);
        File chronicleMapFile = new File(chronicleMapPath + "/readPointer.dat");
        chronicleMapFile.getAbsoluteFile().getParentFile().mkdirs();

        output.setCacheEventLog(cacheEventLog);

        readpointer = ChronicleMap
                .of(Long.class, Long.class)
                .name("country-map")
                .entries(50)
                .createPersistedTo(chronicleMapFile);
        switch (readStrategy) {
            case COMMITED -> tailer.moveToIndex(readpointer.getOrDefault(1l, 0l));
            case LATEST -> tailer.toEnd();
            case EARLIEST -> tailer.toStart();
        }

        if (cacheEventLog) {
            log.info("cacheEventLog: {}", cacheEventLog);
            doWork();
        }
    }

    @Override
    public void startComplete() {
        publishToQueue = true;
        output.dispatchCachedEventLog();
    }

    @Override
    public  NamedFeedEvent[] eventLog() {
        List eventLog = output.getEventLog();
        return eventLog.toArray(new NamedFeedEvent[0]);
    }

    @Override
    public int doWork() throws Exception {
        int count = 0;
        while (methodReader.readOne()) {
            count++;
        }
        readpointer.put(1l, tailer.index());
        return count;
    }

    private void publish(Object line) {
        if (publishToQueue) {
            log.debug("publish record:{}", line);
            output.publish(line);
        } else {
            log.debug("cache record:{}", line);
            output.cache(line);
        }
    }

    //for testing
    void setOutput(EventToQueuePublisher eventToQueue) {
        this.output = eventToQueue;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy