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

com.github.chrisgleissner.jutil.sqllog.SqlRecording Maven / Gradle / Ivy

package com.github.chrisgleissner.jutil.sqllog;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier;

/**
 * Recording of SQL messages.
 */
@Slf4j
@RequiredArgsConstructor
public class SqlRecording implements Closeable {
    private final SqlLog sqlLog;
    @Getter private final String id;
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final List messages = new LinkedList<>();
    private final AtomicInteger messageCount = new AtomicInteger();
    private final long threadId;
    private final String threadName;
    private final File file;

    private boolean firstWrite = true;
    private OutputStreamWriter osw;

    SqlRecording(SqlLog sqlLog, String id, File file, Charset charset) {
        this.sqlLog = sqlLog;
        this.id = id;
        this.threadId = Thread.currentThread().getId();
        this.threadName = Thread.currentThread().getName();
        this.file = file;
        if (file != null) {
            try {
                this.osw = new OutputStreamWriter(new FileOutputStream(file, true), charset);
            } catch (Exception e) {
                throw new RuntimeException("Could not open output stream for " + file.getAbsolutePath(), e);
            }
        }
    }

    public void clear() {
        lock.writeLock().lock();
        try {
            messages.clear();
        } finally {
            lock.writeLock().unlock();
        }
    }

    public Collection getAndClearMessages() {
        return writeLocked(() -> {
            ArrayList msgs = new ArrayList<>(messages);
            messages.clear();
            return msgs;
        });
    }

    public Collection getMessages() {
        return readLocked(() -> new ArrayList<>(messages));
    }

    public int size() {
        return messageCount.get();
    }

    /**
     * Closes (and thus stops) this recording. If writing to an OutputStream, this flushes any pending messages, but
     * closing the OutputStream remains responsibility of the caller.
     */
    @Override
    public void close() {
        sqlLog.stopRecording(id);
    }

    void add(String msg) {
        messageCount.incrementAndGet();
        if (osw != null)
            write(msg);
        else {
            writeLocked(() -> messages.add(msg));
        }
    }

    void write(String msg) {
        if (firstWrite) {
            writeToStream("[");
            firstWrite = false;
        } else {
            writeToStream(",");
            writeToStream("\n");
        }
        writeToStream(msg);
    }

    void stopRecording() {
        if (osw != null) {
            if (!firstWrite) {
                writeToStream("]");
                writeToStream("\n");
            }
            try {
                osw.flush();
                osw.close();
                osw = null;
                log.debug("Closed OutputStream for ID {}", id);
            } catch (Exception e) {
                throw new RuntimeException("Could not close OutputStream for ID " + id, e);
            }
        }
    }

    private  T readLocked(Supplier t) {
        lock.readLock().lock();
        try {
            return t.get();
        } finally {
            lock.readLock().unlock();
        }
    }

    private  T writeLocked(Supplier t) {
        lock.writeLock().lock();
        try {
            return t.get();
        } finally {
            lock.writeLock().unlock();
        }
    }

    private void writeToStream(String s) {
        try {
            osw.write(s);
        } catch (Exception e) {
            throw new RuntimeException("Failed to write to stream: " + s, e);
        }
    }

    @Override
    public String toString() {
        return "SqlRecording{" +
                "id='" + id + '\'' +
                ", threadId=" + threadId +
                ", threadName=" + threadName +
                ", location=" + (file == null ? "heap" : file.getAbsolutePath()) +
                ", messageCount=" + messageCount.get() +
                '}';
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy