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

studio.ui.action.QueryExecutor Maven / Gradle / Ivy

package studio.ui.action;

import kx.K4Exception;
import kx.KMessage;
import kx.ProgressCallback;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import studio.kdb.K;
import studio.kdb.Server;
import studio.kdb.Session;
import studio.ui.EditorTab;
import studio.ui.StudioWindow;

import javax.swing.*;
import java.util.concurrent.atomic.AtomicInteger;

public class QueryExecutor implements ProgressCallback {

    private static final Logger log = LogManager.getLogger();
    private static final Logger queryLog = LogManager.getLogger("Query");
    private static final AtomicInteger queryIndex = new AtomicInteger(1);

    private Worker worker = null;
    private final EditorTab editor;

    private volatile ProgressMonitor pm;
    private boolean compressed;
    private int msgLength;

    private static final String[] suffix = {"B", "K", "M"};
    private static final double[] factor = {1, 1024, 1024*1024};
    private int progressNoteIndex = 0;

    public QueryExecutor(EditorTab editor) {
        this.editor = editor;
    }

    public void execute(K.KBase query, String queryText) {
        worker = new Worker(queryIndex.getAndIncrement(), editor, query, queryText);
        worker.execute();
    }

    public void cancel() {
        if (worker == null) return;
        if (worker.isDone()) return;
        worker.closeConnection();
        worker.cancel(true);
        worker = null;
    }

    public boolean running() {
        return worker != null && ! worker.isDone();
    }

    @Override
    public void setCompressed(boolean compressed) {
        this.compressed = compressed;
    }

    private String formatProgressNote(int total) {
        if (progressNoteIndex == 0) {
            return String.format("%,d of %,d B", total, msgLength);
        } else {
            return String.format("%,.1f of %,.1f %s", total / factor[progressNoteIndex], msgLength / factor[progressNoteIndex], suffix[progressNoteIndex]);
        }
    }

    @Override
    public void setMsgLength(int msgLength) {
        this.msgLength = msgLength;

        if (msgLength < 2*1024) progressNoteIndex = 0;
        else if (msgLength < 2*1024*1024) progressNoteIndex = 1;
        else progressNoteIndex = 2;

        UIManager.put("ProgressMonitor.progressText", "Studio for kdb+");
        pm = new ProgressMonitor(editor.getTextArea(), "Receiving " + (compressed ? "compressed " : "") + "data ...",
                                    formatProgressNote(0), 0, msgLength);
        SwingUtilities.invokeLater( () -> {
            pm.setMillisToDecideToPopup(300);
            pm.setMillisToPopup(100);
            pm.setProgress(0);
        });
    }

    @Override
    public void setCurrentProgress(int total) {
        SwingUtilities.invokeLater( () -> {
            pm.setProgress(total);
            pm.setNote(formatProgressNote(total));
        });

        if (pm.isCanceled()) {
            cancel();
        }
    }

    private class Worker extends SwingWorker {

        private volatile EditorTab editor;
        private volatile Server server;
        private volatile K.KBase query;
        private volatile String queryText;
        private final int queryIndex;
        private volatile Session session = null;

        public Worker(int queryIndex, EditorTab editor, K.KBase query, String queryText) {
            this.queryIndex = queryIndex;
            this.editor = editor;
            this.server = editor.getServer();
            this.query = query;
            this.queryText = queryText;
        }

        void closeConnection() {
            if (session != null) {
                session.close();
            }
        }

        private Session getSession() {
            Session session = editor.getSession();
            session.validate();
            return session;
        }

        @Override
        protected QueryResult doInBackground() {
            QueryResult result = new QueryResult(server, queryText);
            queryLog.info("#{}: query {}({})\n{}",queryIndex, server.getFullName(), server.getConnectionString(), queryText);
            try {
                session = getSession();
                KMessage response = session.execute(query, QueryExecutor.this);
                result.setResult(response);
            } catch (Throwable e) {
                if (! (e instanceof K4Exception)) {
                    log.error("Error occurred during query execution",e);
                    closeConnection();
                }
                result.setError(e);
            }
            if (result.getError() != null) {
                if (result.getError() instanceof K4Exception) {
                    queryLog.info("#{}: server returns error {}", queryIndex, result.getError().getMessage());
                } else {
                    queryLog.info("#{}: error during execution {} {}", queryIndex, result.getError().getClass().getName(), result.getError().getMessage());
                }
            } else {
                queryLog.info("#{}: type={}, count={}, time={}", queryIndex, result.getResult().getType(), result.getResult().count(), result.getExecutionTimeInMS());
            }
            return result;
        }

        @Override
        protected void done() {
            if (pm != null) {
                pm.close();
            }
            try {
                QueryResult result;
                if (isCancelled()) {
                    result = new QueryResult(server, queryText);
                    queryLog.info("#{}: Cancelled", queryIndex);
                } else {
                    result = get();
                }
                StudioWindow.queryExecutionComplete(editor, result);
            } catch (Exception e) {
                log.error("Ops... It wasn't expected", e);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy