org.nuxeo.launcher.gui.NuxeoFrame.java Source code

Java tutorial

Introduction

Here is the source code for org.nuxeo.launcher.gui.NuxeoFrame.java

Source

/*
 * (C) Copyright 2011-2016 Nuxeo SA (http://nuxeo.com/) and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 *     Julien Carsique
 *
 */

package org.nuxeo.launcher.gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.LogManager;
import org.joda.time.DateTime;

import org.nuxeo.common.Environment;
import org.nuxeo.launcher.config.ConfigurationGenerator;
import org.nuxeo.log4j.Log4JHelper;
import org.nuxeo.shell.Shell;
import org.nuxeo.shell.cmds.Interactive;
import org.nuxeo.shell.cmds.InteractiveShellHandler;
import org.nuxeo.shell.swing.ConsolePanel;

/**
 * Launcher view for graphical user interface
 *
 * @author jcarsique
 * @since 5.4.2
 * @see NuxeoLauncherGUI
 */
public class NuxeoFrame extends JFrame {

    /**
     * @since 5.5
     */
    protected class LogsPanelListener extends ComponentAdapter {
        private String logFile;

        public LogsPanelListener(String logFile) {
            this.logFile = logFile;
        }

        @Override
        public void componentHidden(ComponentEvent e) {
            controller.notifyLogsObserver(logFile, false);
        }

        @Override
        public void componentShown(ComponentEvent e) {
            controller.notifyLogsObserver(logFile, true);
        }

    }

    protected final class ImagePanel extends JPanel {
        private static final long serialVersionUID = 1L;

        private Image backgroundImage;

        public ImagePanel(Icon image, ImageIcon backgroundImage) {
            this.backgroundImage = backgroundImage.getImage();
            setOpaque(false);
            add(new JLabel(image));
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(backgroundImage, 0, 0, this);
        }
    }

    /**
     * @since 5.5
     */
    protected Action startAction = new AbstractAction() {
        private static final long serialVersionUID = 1L;

        @Override
        public void actionPerformed(ActionEvent e) {
            mainButton.setEnabled(false);
            controller.start();
        }
    };

    protected boolean stopping = false;

    /**
     * @since 5.5
     */
    protected Action stopAction = new AbstractAction() {
        private static final long serialVersionUID = 1L;

        @Override
        public void actionPerformed(ActionEvent e) {
            mainButton.setEnabled(false);
            controller.stop();
        }
    };

    protected Action launchBrowserAction = new AbstractAction() {
        private static final long serialVersionUID = 1L;

        @Override
        public void actionPerformed(ActionEvent event) {
            try {
                Desktop.getDesktop().browse(java.net.URI.create(controller.getLauncher().getURL()));
            } catch (Exception e) {
                setError("An error occurred while launching browser", e);
            }
        }

    };

    /**
     * Log error and display its message in {@link #errorMessageLabel}
     *
     * @since 5.5
     * @param message Message to log
     * @param e Caught exception
     */
    public void setError(String message, Exception e) {
        log.error(message, e);
        errorMessageLabel.setText(NuxeoLauncherGUI.getMessage("error.occurred") + " <<" + e.getMessage() + ">>.");
    }

    /**
     * Log error and display its message in {@link #errorMessageLabel}
     *
     * @since 5.5
     * @param e Caught exception
     */
    public void setError(Exception e) {
        log.error(e);
        errorMessageLabel.setText(NuxeoLauncherGUI.getMessage("error.occurred") + " <<" + e.getMessage() + ">>.");
    }

    protected static final Log log = LogFactory.getLog(NuxeoFrame.class);

    private static final long serialVersionUID = 1L;

    protected static final int LOG_MAX_SIZE = 200000;

    protected final ImageIcon startIcon = getImageIcon("icons/start.png");

    protected final ImageIcon stopIcon = getImageIcon("icons/stop.png");

    protected final ImageIcon appIcon = getImageIcon("icons/control_panel_icon_32.png");

    protected JButton mainButton = null;

    protected NuxeoLauncherGUI controller;

    protected boolean logsShown = false;

    protected JButton logsButton;

    protected GridBagConstraints constraints;

    protected NuxeoFrame contentPane;

    protected Component filler;

    protected JTabbedPane tabbedPanel;

    protected ConsolePanel consolePanel;

    protected JLabel summaryStatus;

    protected JLabel summaryURL;

    protected JButton launchBrowserButton;

    protected JLabel errorMessageLabel;

    private JTabbedPane logsTab;

    /**
     * @return JLabel for error display
     * @since 5.5
     */
    public JLabel getErrorMessageLabel() {
        return errorMessageLabel;
    }

    public NuxeoFrame(NuxeoLauncherGUI controller) throws HeadlessException {
        super("NuxeoCtl");
        setController(controller);

        // Main frame
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setIconImage(appIcon.getImage());
        getContentPane().setBackground(new Color(35, 37, 59));
        getContentPane().setLayout(new GridBagLayout());
        constraints = new GridBagConstraints();

        // Header (with main button inside)
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.gridx = 0;
        constraints.anchor = GridBagConstraints.PAGE_START;
        JComponent header = buildHeader();
        header.setPreferredSize(new Dimension(480, 110));
        getContentPane().add(header, constraints);

        // Tabs
        constraints.fill = GridBagConstraints.BOTH;
        constraints.ipady = 100;
        constraints.weightx = 1.0;
        constraints.weighty = 1.0;
        getContentPane().add(buildTabbedPanel(), constraints);

        // Footer
        constraints.fill = GridBagConstraints.NONE;
        constraints.anchor = GridBagConstraints.PAGE_END;
        constraints.ipady = 0;
        constraints.weightx = 0;
        constraints.weighty = 0;
        constraints.insets = new Insets(10, 0, 0, 0);
        getContentPane().add(buildFooter(), constraints);

        // debug((JComponent) this.getContentPane());
    }

    protected Component buildConsolePanel() {
        try {
            consolePanel = new ConsolePanel();
        } catch (Exception e) {
            log.error(e);
        }
        Interactive.setConsoleReaderFactory(consolePanel.getConsole());
        Interactive.setHandler(new InteractiveShellHandler() {
            @Override
            public void enterInteractiveMode() {
                Interactive.reset();
            }

            @Override
            public boolean exitInteractiveMode(int code) {
                if (code == 1) {
                    Interactive.reset();
                    Shell.reset();
                    return true;
                } else {
                    consolePanel.getConsole().reset();
                    return false;
                }
            }
        });
        new Thread() {
            @Override
            public void run() {
                try {
                    Shell.get().main(new String[] { controller.launcher.getURL() + "site/automation" });
                } catch (Exception e) {
                    setError(e);
                }
            }
        }.start();
        return consolePanel;
    }

    protected JComponent buildFooter() {
        JLabel label = new JLabel(NuxeoLauncherGUI.getMessage("footer.label", new DateTime().toString("Y")));
        label.setForeground(Color.WHITE);
        label.setPreferredSize(new Dimension(470, 16));
        label.setFont(new Font(label.getFont().getName(), label.getFont().getStyle(), 9));
        label.setHorizontalAlignment(SwingConstants.CENTER);
        return label;
    }

    protected JComponent buildHeader() {
        ImagePanel headerLogo = new ImagePanel(getImageIcon("img/nuxeo_control_panel_logo.png"),
                getImageIcon("img/nuxeo_control_panel_bg.png"));
        headerLogo.setLayout(new GridBagLayout());
        // Main button (start/stop) (added to header)

        GridBagConstraints headerConstraints = new GridBagConstraints();
        headerConstraints.gridx = 0;
        headerLogo.add(buildMainButton(), headerConstraints);
        headerLogo.add(buildLaunchBrowserButton(), headerConstraints);
        return headerLogo;
    }

    protected JComponent buildLaunchBrowserButton() {
        launchBrowserButton = createButton(null);
        launchBrowserButton.setAction(launchBrowserAction);
        launchBrowserButton.setText(NuxeoLauncherGUI.getMessage("browser.button.text"));
        updateLaunchBrowserButton();
        return launchBrowserButton;
    }

    protected JTabbedPane buildLogsTab() {
        JTabbedPane logsTabbedPane = new JTabbedPane(SwingConstants.TOP);
        // Get Launcher log file(s)
        ArrayList<String> logFiles = Log4JHelper.getFileAppendersFiles(LogManager.getLoggerRepository());
        // Add nuxeoctl log file
        File nuxeoctlLog = new File(controller.getConfigurationGenerator().getLogDir(), "nuxeoctl.log");
        if (nuxeoctlLog.exists()) {
            logFiles.add(nuxeoctlLog.getAbsolutePath());
        }
        // Get server log file(s)
        logFiles.addAll(controller.getConfigurationGenerator().getLogFiles());
        for (String logFile : logFiles) {
            addFileToLogsTab(logsTabbedPane, logFile);
        }
        return logsTabbedPane;
    }

    protected void addFileToLogsTab(JTabbedPane logsTabbedPane, String logFile) {
        if (!hideLogTab(logFile) && !controller.getLogsMap().containsKey(logFile)) {
            logsTabbedPane.addTab(new File(logFile).getName(), buildLogPanel(logFile));
        }
    }

    /**
     * Called by buildLogsTab to know if a log file should be display. Can be overridden. Return false by default.
     *
     * @param logFile
     * @return false
     */
    protected boolean hideLogTab(String logFile) {
        return false;
    }

    /**
     * @param logFile
     */
    protected JComponent buildLogPanel(String logFile) {
        ColoredTextPane textArea = new ColoredTextPane();
        textArea.setEditable(false);
        textArea.setAutoscrolls(true);
        textArea.setBackground(new Color(54, 55, 67));
        textArea.setMaxSize(LOG_MAX_SIZE);

        JScrollPane logsScroller = new JScrollPane(textArea);
        logsScroller.setVisible(true);
        logsScroller.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        logsScroller.setAutoscrolls(true);
        logsScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        logsScroller.setWheelScrollingEnabled(true);
        logsScroller.setPreferredSize(new Dimension(450, 160));

        controller.initLogsManagement(logFile, textArea);
        logsScroller.addComponentListener(new LogsPanelListener(logFile));
        return logsScroller;
    }

    protected JComponent buildMainButton() {
        mainButton = createButton(null);
        updateMainButton();
        return mainButton;
    }

    protected Component buildSummaryPanel() {
        JPanel summaryPanel = new JPanel();
        summaryPanel.setLayout(new BoxLayout(summaryPanel, BoxLayout.PAGE_AXIS));
        summaryPanel.setBackground(new Color(35, 37, 59));
        summaryPanel.setForeground(Color.WHITE);

        summaryPanel.add(
                new JLabel("<html><font color=#ffffdd>" + NuxeoLauncherGUI.getMessage("summary.status.label")));
        summaryStatus = new JLabel(controller.launcher.status());
        summaryStatus.setForeground(Color.WHITE);
        summaryPanel.add(summaryStatus);

        summaryPanel
                .add(new JLabel("<html><font color=#ffffdd>" + NuxeoLauncherGUI.getMessage("summary.url.label")));
        summaryURL = new JLabel(controller.launcher.getURL());
        summaryURL.setForeground(Color.WHITE);
        summaryPanel.add(summaryURL);

        errorMessageLabel = new JLabel();
        errorMessageLabel.setForeground(Color.RED);
        summaryPanel.add(errorMessageLabel);

        summaryPanel.add(new JSeparator());
        ConfigurationGenerator config = controller.launcher.getConfigurationGenerator();
        summaryPanel.add(
                new JLabel("<html><font color=#ffffdd>" + NuxeoLauncherGUI.getMessage("summary.homedir.label")));
        summaryPanel.add(new JLabel("<html><font color=white>" + config.getNuxeoHome().getPath()));
        summaryPanel.add(
                new JLabel("<html><font color=#ffffdd>" + NuxeoLauncherGUI.getMessage("summary.nuxeoconf.label")));
        summaryPanel.add(new JLabel("<html><font color=white>" + config.getNuxeoConf().getPath()));
        summaryPanel.add(
                new JLabel("<html><font color=#ffffdd>" + NuxeoLauncherGUI.getMessage("summary.datadir.label")));
        summaryPanel.add(new JLabel("<html><font color=white>" + config.getDataDir().getPath()));
        return summaryPanel;
    }

    protected JComponent buildTabbedPanel() {
        tabbedPanel = new JTabbedPane(SwingConstants.TOP);
        tabbedPanel.addTab(NuxeoLauncherGUI.getMessage("tab.summary.title"), buildSummaryPanel());
        logsTab = buildLogsTab();
        tabbedPanel.addTab(NuxeoLauncherGUI.getMessage("tab.logs.title"), logsTab);
        tabbedPanel.addTab(NuxeoLauncherGUI.getMessage("tab.shell.title"), buildConsolePanel());
        tabbedPanel.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                JTabbedPane pane = (JTabbedPane) e.getSource();
                if (pane.getSelectedIndex() == 2) {
                    consolePanel.getConsole().requestFocusInWindow();
                }
            }
        });
        return tabbedPanel;
    }

    protected JButton createButton(ImageIcon icon) {
        JButton button = new JButton();
        button.setIcon(icon);
        return button;
    }

    public void debug(JComponent parent) {
        for (Component comp : parent.getComponents()) {
            if (comp instanceof JComponent) {
                ((JComponent) comp).setBorder(BorderFactory.createCompoundBorder(
                        BorderFactory.createLineBorder(Color.red), ((JComponent) comp).getBorder()));
                log.info(comp.getClass() + " size: " + ((JComponent) comp).getSize());
            }
        }
    }

    protected ImageIcon getImageIcon(String resourcePath) {
        BufferedImage image = null;
        try {
            ImageIO.setCacheDirectory(Environment.getDefault().getTemp());
            image = ImageIO.read(getClass().getClassLoader().getResource(resourcePath));
        } catch (IOException e) {
            log.error(e);
        }
        return new ImageIcon(image);
    }

    protected void updateMainButton() {
        if (controller.launcher.isStarted()) {
            mainButton.setAction(stopAction);
            mainButton.setText(NuxeoLauncherGUI.getMessage("mainbutton.stop.text"));
            mainButton.setToolTipText(NuxeoLauncherGUI.getMessage("mainbutton.stop.tooltip"));
            mainButton.setIcon(stopIcon);
        } else if (controller.launcher.isRunning()) {
            if (stopping) {
                mainButton.setAction(stopAction);
                mainButton.setText(NuxeoLauncherGUI.getMessage("mainbutton.stop.inprogress"));
            } else {
                mainButton.setAction(stopAction);
                mainButton.setText(NuxeoLauncherGUI.getMessage("mainbutton.start.inprogress"));
            }
            mainButton.setToolTipText(NuxeoLauncherGUI.getMessage("mainbutton.stop.tooltip"));
            mainButton.setIcon(stopIcon);
        } else {
            mainButton.setAction(startAction);
            mainButton.setText(NuxeoLauncherGUI.getMessage("mainbutton.start.text"));
            mainButton.setToolTipText(NuxeoLauncherGUI.getMessage("mainbutton.start.tooltip"));
            mainButton.setIcon(startIcon);
        }
        mainButton.setEnabled(true);
        mainButton.validate();
    }

    /**
     * @since 5.5
     */
    protected void updateLaunchBrowserButton() {
        launchBrowserButton.setEnabled(controller.launcher.isStarted());
    }

    /**
     * Update information displayed in summary tab
     */
    public void updateSummary() {
        String errorMessageLabelStr = "";
        Color summaryStatusFgColor = Color.WHITE;
        if (!controller.getConfigurationGenerator().isWizardRequired() && controller.launcher.isStarted()) {
            String startupSummary = controller.launcher.getStartupSummary();
            if (!controller.launcher.wasStartupFine()) {
                String[] lines = startupSummary.split("\n");
                // extract line with summary informations
                for (String line : lines) {
                    if (line.contains("Component Loading Status")) {
                        startupSummary = line;
                        break;
                    }
                }
                errorMessageLabelStr = "An error was detected during startup " + startupSummary + ".";
                summaryStatusFgColor = Color.RED;
            }
        }
        errorMessageLabel.setText(errorMessageLabelStr);
        summaryStatus.setForeground(summaryStatusFgColor);
        summaryStatus.setText(controller.launcher.status());
        summaryURL.setText(controller.launcher.getURL());
    }

    /**
     * Add Windows rotated console log
     *
     * @since 5.6
     */
    public void updateLogsTab(String consoleLogId) {
        if (consoleLogId != null) {
            addFileToLogsTab(logsTab,
                    new File(controller.getConfigurationGenerator().getLogDir(), "console" + consoleLogId + ".log")
                            .getPath());
        }
    }

    /**
     * @since 5.5
     * @return GUI controller
     */
    public NuxeoLauncherGUI getController() {
        return controller;
    }

    public void setController(NuxeoLauncherGUI controller) {
        this.controller = controller;
    }

    /**
     * @since 5.6
     */
    public void close() {
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        Toolkit.getDefaultToolkit().getSystemEventQueue()
                .postEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
    }

}