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

org.bidib.wizard.tracer.client.view.TracerClientView Maven / Gradle / Ivy

package org.bidib.wizard.tracer.client.view;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.LinkedList;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.BadLocationException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.bidib.wizard.api.locale.Resources;
import org.bidib.wizard.client.common.text.WizardComponentFactory;
import org.bidib.wizard.client.common.view.DockKeys;
import org.bidib.wizard.core.dialog.FileDialog;
import org.bidib.wizard.tracer.client.controller.listener.TracerClientControllerListener;
import org.bidib.wizard.tracer.client.model.TracerClientModel;
import org.bidib.wizard.tracer.client.view.listener.TracerClientViewListener;
import org.bidib.wizard.tracer.event.TracerMessageEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jgoodies.binding.beans.PropertyAdapter;
import com.jgoodies.binding.beans.PropertyConnector;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.builder.FormBuilder;
import com.jgoodies.forms.debug.FormDebugPanel;
import com.jgoodies.forms.factories.Paddings;
import com.jidesoft.swing.JideScrollPane;
import com.vlsolutions.swing.docking.DockKey;
import com.vlsolutions.swing.docking.Dockable;
import com.vlsolutions.swing.docking.DockableState;
import com.vlsolutions.swing.docking.DockingDesktop;
import com.vlsolutions.swing.docking.event.DockableStateChangeEvent;
import com.vlsolutions.swing.docking.event.DockableStateChangeListener;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;

public class TracerClientView implements Dockable {

    private static final Logger LOGGER = LoggerFactory.getLogger(TracerClientView.class);

    private static final String TRACER_CLIENT = "TracerClient";

    private static final Logger LOGGER_TRACER_CLIENT = LoggerFactory.getLogger(TRACER_CLIENT);

    private static final String ENCODED_DIALOG_COLUMN_SPECS =
        "pref, 3dlu, pref, 3dlu, pref, 3dlu, fill:pref:grow, 3dlu, pref, 3dlu, pref";

    private static final String ENCODED_DIALOG_ROW_SPECS = "pref, 3dlu, fill:50dlu:grow";

    private JComponent contentPanel;

    private final DockingDesktop desktop;

    private final TracerClientModel tracerClientModel;

    private final DockableStateChangeListener dockableStateChangeListener;

    private final Collection listeners = new LinkedList<>();

    private final JButton connectButton = new JButton(Resources.getString(TracerClientView.class, "connect"));

    private final JButton disconnectButton = new JButton(Resources.getString(TracerClientView.class, "disconnect"));

    private final JTextArea logsArea = new JTextArea();

    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");

    private StringBuilder sbLogger = new StringBuilder();

    private JCheckBox logToFile;

    private ValueModel selectedLogFileValueModel;

    private final JButton selectLogFileButton =
        new JButton(Resources.getString(TracerClientView.class, "select-logfile"));

    public TracerClientView(final DockingDesktop desktop, final TracerClientControllerListener listener,
        final TracerClientModel tracerClientModel) {
        this.desktop = desktop;
        this.tracerClientModel = tracerClientModel;

        DockKeys.DOCKKEY_TRACER_CLIENT_VIEW.setName(Resources.getString(TracerClientView.class, "title"));
        DockKeys.DOCKKEY_TRACER_CLIENT_VIEW.setFloatEnabled(true);
        DockKeys.DOCKKEY_TRACER_CLIENT_VIEW.setAutoHideEnabled(false);

        dockableStateChangeListener = new DockableStateChangeListener() {

            @Override
            public void dockableStateChanged(DockableStateChangeEvent event) {
                LOGGER
                    .info("The state has changed, newState: {}, prevState: {}", event.getNewState(),
                        event.getPreviousState());

                DockableState newState = event.getNewState();
                if (newState.getDockable().equals(TracerClientView.this) && newState.isClosed()) {
                    LOGGER.info("The NodesClientView is closed.");
                    // we are closed
                    desktop.removeDockableStateChangeListener(dockableStateChangeListener);

                    if (listener != null) {
                        LOGGER.info("Close the view.");

                        listener.viewClosed();
                    }
                }

            }
        };
        desktop.addDockableStateChangeListener(dockableStateChangeListener);
    }

    public JComponent initComponents() {

        // create form builder
        FormBuilder dialogBuilder = null;
        boolean debugDialog = false;
        if (debugDialog) {
            JPanel panel = new FormDebugPanel();
            dialogBuilder =
                FormBuilder.create().columns(ENCODED_DIALOG_COLUMN_SPECS).rows(ENCODED_DIALOG_ROW_SPECS).panel(panel);
        }
        else {
            JPanel panel = new JPanel(new BorderLayout());
            dialogBuilder =
                FormBuilder.create().columns(ENCODED_DIALOG_COLUMN_SPECS).rows(ENCODED_DIALOG_ROW_SPECS).panel(panel);
        }
        dialogBuilder.border(Paddings.DIALOG);

        // add content

        connectButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                fireConnect();
            }
        });
        disconnectButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                fireDisconnect();
            }
        });
        disconnectButton.setEnabled(false);

        // prepare the connect and disconnect button
        // JPanel debugInterfaceActionButtons =
        // new ButtonBarBuilder().addButton(connectButton).addRelatedGap().addButton(disconnectButton).build();
        // dialogBuilder.add(debugInterfaceActionButtons).xyw(1, 1, 5);
        dialogBuilder.add(connectButton).xy(1, 1);
        dialogBuilder.add(disconnectButton).xy(3, 1);

        // logfile
        logToFile = new JCheckBox(Resources.getString(getClass(), "logToFile"));
        dialogBuilder.add(logToFile).xy(5, 1);

        selectedLogFileValueModel =
            new PropertyAdapter(tracerClientModel, TracerClientModel.PROPERTY_LOGFILE_NAME, true);
        JTextField selectedLogFileText = WizardComponentFactory.createTextField(selectedLogFileValueModel, true);
        selectedLogFileText.setEditable(false);
        dialogBuilder.add(selectedLogFileText).xyw(7, 1, 3);

        // prepare the select and save button

        selectLogFileButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                selectLogFile();
            }
        });
        dialogBuilder.add(selectLogFileButton).xy(11, 1);

        // add the log area

        logsArea.setEditable(false);
        logsArea.setFont(new Font("Monospaced", Font.PLAIN, 13));

        JScrollPane logsPane = new JScrollPane(logsArea);
        logsPane.setAutoscrolls(true);

        dialogBuilder.add(logsPane).xyw(1, 3, 11);

        JPanel contentPanelTemp = dialogBuilder.build();

        JideScrollPane scrollPane = new JideScrollPane(contentPanelTemp);
        this.contentPanel = scrollPane;

        PropertyConnector.connect(tracerClientModel, TracerClientModel.PROPERTY_DISCONNECTED, connectButton, "enabled");
        PropertyConnector.connect(tracerClientModel, TracerClientModel.PROPERTY_CONNECTED, disconnectButton, "enabled");

        logToFile.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                final boolean logToFileEnabled = e.getStateChange() == ItemEvent.SELECTED;

                tracerClientModel.setLogToFile(logToFileEnabled);

                // activate the logger
                if (logToFileEnabled) {
                    activateLogger(tracerClientModel.getLogFileName());
                }
                else {
                    deactivateLogger();
                }
            }
        });

        return this.contentPanel;
    }

    @Override
    public DockKey getDockKey() {
        return DockKeys.DOCKKEY_TRACER_CLIENT_VIEW;
    }

    @Override
    public Component getComponent() {
        return this.contentPanel;
    }

    public void addTracerClientViewListener(TracerClientViewListener l) {
        listeners.add(l);
    }

    private void fireConnect() {
        for (TracerClientViewListener listener : listeners) {
            listener.openConnection();
        }
    }

    private void fireDisconnect() {
        for (TracerClientViewListener listener : listeners) {
            listener.closeConnection();
        }
    }

    public void addLog(final TracerMessageEvent me) {

        try {
            LOGGER_TRACER_CLIENT.info(me.getMessage());

            sbLogger.append(formatter.format(me.getTimestamp()));
            sbLogger.append(" - ");
            sbLogger.append(me.getMessage());

            addLogMessage(sbLogger.toString());
        }
        catch (Exception ex) {
            LOGGER.warn("Add message to logsArea failed.", ex);
        }
        finally {
            sbLogger.setLength(0);
        }
    }

    private void addLogMessage(final String logMessage) {

        try {
            int lines = logsArea.getLineCount();
            if (lines > 500) {
                // remove the first 50 lines
                int end = logsArea.getLineEndOffset(/* lines - */50);
                logsArea.getDocument().remove(0, end);
            }

            logsArea.append(logMessage);
            logsArea.append("\n");
        }
        catch (BadLocationException ex) {
            LOGGER.warn("Remove some lines from logsArea failed.", ex);
        }
    }

    private void selectLogFile() {

        String storedWorkingDirectory = null;

        try {
            storedWorkingDirectory =
                tracerClientModel.getLogFileName() != null
                    ? FileUtils.getFile(tracerClientModel.getLogFileName()).getParent() : null;
        }
        catch (Exception ex) {
            LOGGER.warn("Get the storedWorkingDirectory from settings failed.", ex);
        }

        final FileDialog dialog =
            new FileDialog(contentPanel, FileDialog.SAVE, storedWorkingDirectory, null, ffLogFile) {
                @Override
                public void approve(String selectedFile) {
                    File file = new File(selectedFile);

                    selectedFile = file.getName();

                    tracerClientModel.setLogFileName(file.toString());
                }
            };
        dialog.showDialog();
    }

    private static final String SUFFIX_LOG = "log";

    private static final String SUFFIX_TXT = "txt";

    private final FileFilter ffLogFile = new FileFilter() {

        @Override
        public boolean accept(File file) {
            boolean result = false;

            if (file != null) {
                if (file.isDirectory()) {
                    result = true;
                }
                else if (FilenameUtils.wildcardMatch(file.getName(), "*." + SUFFIX_LOG)) {
                    result = true;
                }
                else if (FilenameUtils.wildcardMatch(file.getName(), "*." + SUFFIX_TXT)) {
                    result = true;
                }
            }
            return result;
        }

        @Override
        public String getDescription() {
            return Resources.getString(TracerClientView.class, "filterLogFile") + " (*." + SUFFIX_LOG + ",*."
                + SUFFIX_TXT + ")";
        }
    };

    private FileAppender fileAppender;

    protected void activateLogger(final String logFile) {

        if (this.fileAppender != null && this.fileAppender.isStarted()) {
            LOGGER.warn("The file appender for the tracer log is assigned and started already.");
            return;
        }

        if (this.fileAppender == null) {
            LOGGER.info("Create the appender for the tracer log.");

            LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
            PatternLayoutEncoder ple = new PatternLayoutEncoder();
            ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n");
            ple.setContext(lc);
            ple.start();
            this.fileAppender = new FileAppender();
            this.fileAppender.setFile(logFile);
            this.fileAppender.setEncoder(ple);
            this.fileAppender.setContext(lc);
        }
        LOGGER.info("Start the appender for the tracer log.");
        this.fileAppender.start();

        ch.qos.logback.classic.Logger logbackLogger =
            (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(TRACER_CLIENT);
        logbackLogger.addAppender(this.fileAppender);
        logbackLogger.setLevel(ch.qos.logback.classic.Level.DEBUG);
        logbackLogger.setAdditive(false);
    }

    protected void deactivateLogger() {

        if (this.fileAppender == null) {
            LOGGER.warn("The file appender for the tracer log is not assigned.");
            return;
        }

        LOGGER.info("Stop the appender for the tracer log.");

        ch.qos.logback.classic.Logger logbackLogger =
            (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(TRACER_CLIENT);
        logbackLogger.detachAppender(this.fileAppender);

        this.fileAppender.stop();

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy