Package com.persistit.ui

Source Code of com.persistit.ui.AdminUI

/**
* Copyright © 2005-2012 Akiban Technologies, Inc.  All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This program may also be available under different license terms.
* For more information, see www.akiban.com or contact licensing@akiban.com.
*
* Contributors:
* Akiban Technologies, Inc.
*/

package com.persistit.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.FileInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.URL;
import java.rmi.Naming;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JWindow;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.FontUIResource;

import com.persistit.Management;
import com.persistit.Task;
import com.persistit.util.UtilControl;

public class AdminUI implements UtilControl, Runnable, AdminCommand {
    final static String BUNDLE_NAME = "com.persistit.ui.AdminUI";
    final static String SPLASH_FILE_NAME = "persistit_splash.png";
    final static String DEFAULT_RMI_HOST = "localhost:1099";
    final static boolean ENABLE_SPLASH = false;
    final static String DEFAULT_CONFIG_FILE = "adminui.properties";
    final static String CONFIG_FILE_PROPERTY = "com.persistit.ui.properties";
    final static String HELP_SET_NAME = "help/PersistitHelp.hs";

    private DecimalFormat _percentageFormat;
    private SimpleDateFormat _dateFormat;
    private DecimalFormat _timeFormat;
    private DecimalFormat _longFormat;
    private DecimalFormat _integerFormat;
    private String _fileLocationFormat;

    private ResourceBundle _bundle;
    private Properties _properties;
    private JFrame _frame = null;
    private JTabbedPane _tabbedPane = null;
    private Management _management;
    private final Map _actionMap = new HashMap();
    private final List _textComponentList = new ArrayList();
    private String _rmiHost = DEFAULT_RMI_HOST;
    private SplashWindow _splashWindow;
    private String[] _taskStates;

    int _selectedTab = -1;

    private Timer _refreshTimer = new Timer();
    private TimerTask _refreshTimerTask;
    private int _refreshInterval;
    private AbstractButton _refreshOnceButton;
    private boolean _refreshing;

    private FontUIResource _defaultFont;
    private FontUIResource _boldFont;
    private FontUIResource _fixedFont;
    private Color _persistitAccentColor;
    private String _waitingMessage;
    private String _nullMessage;

    private boolean _fixedFontMode = false;
    private boolean _wrapMode = false;
    private boolean _wrapWordMode = false;

    private String _myHostName = "unknown";

    private JavaHelpAdapter _javaHelpAdapter;

    /**
     * Implements the Closeable interface
     */
    @Override
    public boolean isAlive() {
        return _frame != null;
    }

    /**
     * Implements the Closeable interface
     */
    @Override
    public void close() {
        final Timer timer = _refreshTimer;
        if (timer != null) {
            timer.cancel();
            _refreshTimer = null;
        }

        final JFrame frame = _frame;
        final JavaHelpAdapter adapter = _javaHelpAdapter;
        _frame = null;
        _javaHelpAdapter = null;

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (adapter != null) {
                    adapter.dispose();
                }
                if (frame != null) {
                    frame.dispose();
                }
            }
        });
    }

    /**
     * Implements the Runnable interface
     */
    @Override
    public void run() {
        resetRefreshTimer();
        refreshMenuEnableState();
        refresh(true);
    }

    /**
     * Construct an AdminUI on the local Persistit instance.
     */
    public AdminUI(final Management management) {
        this();
        setManagement(management);
    }

    public AdminUI(final String rmiHost) {
        this();
        _rmiHost = rmiHost;
        if (rmiHost != null)
            connect(rmiHost);
    }

    public AdminUI() {
        //
        // This is a workaround for JVM bug 4030718 in JDK1.3.
        // (See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4030718).
        // Without this, the app won't shut down once the GUI has been
        // launched. You have to use Control-C. This workaround is
        // suggested by contributor nethi near the bottom of the comment
        // thread. The goal is to make the AWT event dispatch thread
        // a daemon thread so that the helper threads it launches are also
        // daemon threads. Then they will go away when no non-daemon
        // threads are left.
        //
        final Thread daemonThread = new Thread() {
            @Override
            public void run() {
                _frame = new JFrame();
                if (ENABLE_SPLASH) {
                    _splashWindow = new SplashWindow(_frame);
                    _splashWindow.display();
                }
                setupFrame();
            }
        };

        daemonThread.setDaemon(true);
        daemonThread.start();

        final Thread hostNameThread = new Thread() {
            @Override
            public void run() {
                try {
                    final InetAddress inetAddr = InetAddress.getLocalHost();
                    _myHostName = inetAddr.getHostName();
                } catch (final Exception e) {
                }
            }
        };
        hostNameThread.setDaemon(true);
        hostNameThread.start();
        try {
            daemonThread.join();
            if (ENABLE_SPLASH) {
                Thread.sleep(2000);
                final SplashWindow sp = _splashWindow;
                if (sp != null)
                    sp.dispose();
                _splashWindow = null;
            }
        } catch (final InterruptedException ie) {
        }
    }

    public void refresh(final boolean reset) {
        synchronized (this) {
            if (_refreshing)
                return;
            _refreshing = true;
        }
        try {
            Management management = _management;
            if (management != null) {
                try {
                    management.isInitialized();
                } catch (final RemoteException re) {
                    disconnect();
                    management = null;
                }
            }

            if (_tabbedPane != null) {
                try {
                    final AdminPanel mp = (AdminPanel) _tabbedPane.getSelectedComponent();
                    mp.refresh(reset || management == null);
                } catch (final Exception e) {
                    postException(e);
                }
            }

            // Reset toggle buttons to represent current state.
            for (final Iterator iter = _actionMap.values().iterator(); iter.hasNext();) {
                final AdminAction action = (AdminAction) iter.next();
                if (action.isToggle()) {
                    action.stateChanged(getManagementState(action));
                }
            }
        } finally {
            _refreshing = false;
        }
    }

    public Management getManagement() {
        return _management;
    }

    @Override
    public void setManagement(final Management newManagement) {
        final Management oldManagement = _management;
        if (oldManagement != null) {
            unfreeze(oldManagement);
        }
        _management = newManagement;
        SwingUtilities.invokeLater(this);
    }

    private void unfreeze(final Management management) {
        try {
            management.setShutdownSuspended(false);
            management.setUpdateSuspended(false);
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    public String getProperty(final String propertyName) {
        try {
            if (_bundle == null) {
                _bundle = ResourceBundle.getBundle(AdminUI.BUNDLE_NAME);
                String propFileName = null;
                try {
                    propFileName = System.getProperty(CONFIG_FILE_PROPERTY);
                } catch (final Exception e) {
                }
                if (propFileName == null)
                    propFileName = DEFAULT_CONFIG_FILE;
                try {
                    final FileInputStream fis = new FileInputStream(propFileName);
                    _properties = new Properties();
                    _properties.load(fis);
                } catch (final Exception e) {
                }
            }
            String value = null;
            if (_properties != null)
                value = _properties.getProperty(propertyName);
            if (value == null)
                value = _bundle.getString(propertyName);
            return value;
        } catch (final MissingResourceException mre) {
            return null;
        }
    }

    public int getRefreshInterval() {
        return _refreshInterval;
    }

    public String getHostName() {
        return _myHostName;
    }

    public FontUIResource getBoldFont() {
        return _boldFont;
    }

    public FontUIResource getDefaultFont() {
        return _defaultFont;
    }

    public FontUIResource getFixedFont() {
        return _fixedFont;
    }

    public Color getPersistitAccentColor() {
        return _persistitAccentColor;
    }

    public String getWaitingMessage() {
        return _waitingMessage;
    }

    public String getNullMessage() {
        return _nullMessage;
    }

    public String getTaskStateString(final int state) {
        if (state >= 0 && state < _taskStates.length) {
            return _taskStates[state];
        }
        return "?";
    }

    public String formatDate(final long ts) {
        if (ts == 0 || ts == Long.MAX_VALUE || ts == Long.MIN_VALUE)
            return "";
        return _dateFormat.format(new Date(ts));
    }

    public String formatTime(final long ts) {
        return _timeFormat.format(ts / 1000.0);
    }

    public String formatInteger(final int v) {
        return _integerFormat.format(v);
    }

    public String formatLong(final long v) {
        return _longFormat.format(v);
    }

    public String formatPercent(final double v) {
        return _percentageFormat.format(v);
    }

    public String formatFileLocation(final String path, final long address) {
        return path == null ? "" : String.format(_fileLocationFormat, path, address);
    }

    private void setFrameTitle(final String hostName) {
        String title = getProperty("title");
        if (title == null)
            title = "Persistit Admin Client";
        if (title.indexOf("Persistit") < 0)
            title = "Persistit - " + title;
        {
            if (hostName != null && hostName.length() > 0) {
                title += " - " + hostName;
            }
        }
        _frame.setTitle(title);
    }

    private void setupFrame() {
        _defaultFont = new FontUIResource("Dialog", Font.PLAIN, 12);
        _boldFont = new FontUIResource("Dialog", Font.BOLD, 12);
        _fixedFont = new FontUIResource("Monospaced", Font.PLAIN, 12);

        _persistitAccentColor = new Color(119, 17, 34);

        final String lnfClassName = getProperty("lnf");
        boolean lafLoaded = false;
        if (lnfClassName != null && lnfClassName.length() > 0) {
            try {
                final Class lnfClass = Class.forName(lnfClassName);

                Method setPropertyMethod = null;

                final Enumeration props = _bundle.getKeys();
                while (props.hasMoreElements()) {
                    final String propName = (String) props.nextElement();
                    if (propName.startsWith("lnf.")) {
                        final String propValue = _bundle.getString(propName);
                        if (setPropertyMethod == null) {
                            setPropertyMethod = lnfClass.getMethod("setProperty", new Class[] { String.class,
                                    String.class });
                        }

                        setPropertyMethod.invoke(null, new Object[] { propName, propValue });
                    }
                }
                final javax.swing.LookAndFeel lnf = (javax.swing.LookAndFeel) lnfClass.newInstance();

                javax.swing.UIManager.setLookAndFeel(lnf);
                lafLoaded = true;
            } catch (final Exception ex) {
                System.err.println("Could not load LnF class " + lnfClassName);
                ex.printStackTrace();
            }
        }

        if (!lafLoaded) {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (final Exception e) {
                // Ignore exception
            }
        }

        setUIFont(_defaultFont);
        _percentageFormat = new DecimalFormat(getProperty("PERCENTAGE_FORMAT"));
        _dateFormat = new SimpleDateFormat(getProperty("DATE_FORMAT"));
        _timeFormat = new DecimalFormat(getProperty("TIME_FORMAT"));
        _longFormat = new DecimalFormat(getProperty("LONG_FORMAT"));
        _integerFormat = new DecimalFormat(getProperty("INTEGER_FORMAT"));
        _fileLocationFormat = getProperty("FILE_LOCATION_FORMAT");
        _waitingMessage = getProperty("WaitingMessage");
        _nullMessage = getProperty("NullMessage");
        _taskStates = new String[7];
        for (int state = 0; state < 7; state++) {
            _taskStates[state] = getProperty("TaskState." + state);
        }

        _tabbedPane = new JTabbedPane();
        _frame.getContentPane().add(_tabbedPane);

        _frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        _frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(final WindowEvent we) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        // if (_frame != null)
                        // {
                        //
                        // Will restore normal operation to
                        // target Persistit instance
                        //
                        setManagement(null);
                        close();
                        // }
                    }
                });
            }
        });
        setupMenu();
        setupTabbedPanes();
        _tabbedPane.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(final ChangeEvent ce) {
                handleTabChanged();
            }
        });
        handleTabChanged();
        refreshMenuEnableState();
        final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setFrameTitle(null);
        _frame.pack();
        _frame.setLocation((screenSize.width - _frame.getWidth()) / 2, (screenSize.height - _frame.getHeight()) / 2);
        _frame.setVisible(true);
    }

    void setupMenu() {
        final JMenuBar bar = new JMenuBar();
        _frame.setJMenuBar(bar);

        final String menuBarItems = getProperty("MainMenu");
        final StringTokenizer st1 = new StringTokenizer(menuBarItems, ",");
        while (st1.hasMoreTokens()) {
            final String s = st1.nextToken();
            final AdminAction menuAction = createAction(this, s);
            final JMenu menu = new JMenu(menuAction);
            menuAction.addButton(menu);
            bar.add(menu);
            final StringTokenizer st2 = new StringTokenizer(s, ":");
            final String actionName = st2.nextToken();
            final JComponent[] items = createMenuArray(this, "MainMenu", actionName);
            for (int index = 0; index < items.length; index++) {
                menu.add(items[index]);
            }
        }
    }

    JComponent[] createMenuArray(final AdminCommand command, final String basePropertyName, final String actionName) {
        final ArrayList list = new ArrayList();
        for (int index = 0;; index++) {
            final String propName = basePropertyName + "." + actionName + "." + index;
            final String t = getProperty(propName);
            if (t == null || t.startsWith("."))
                break;
            if (t.startsWith("-")) {
                list.add(new JSeparator());
            } else {
                final AdminAction action = createAction(command, t);
                final AbstractButton item = action.menuItem(command, propName);
                action.addButton(item);
                list.add(item);
            }
        }
        return (JComponent[]) (list.toArray(new JComponent[list.size()]));
    }

    private void setupTabbedPanes() {
        for (int index = 0;; index++) {
            final String paneSpecification = getProperty("TabbedPane." + index);
            if (paneSpecification == null || paneSpecification.startsWith(".")) {
                break;
            }
            final StringTokenizer st = new StringTokenizer(paneSpecification, ":");
            final String className = st.nextToken();
            final String caption = st.nextToken();
            String iconName = null;
            if (st.hasMoreTokens()) {
                iconName = st.nextToken();
            }
            try {
                final Class cl = Class.forName(className);
                final AdminPanel panel = (AdminPanel) cl.newInstance();
                panel.setup(this);
                _tabbedPane.addTab(caption, panel);
            } catch (final Exception e) {
                showMessage(e, getProperty("SetupFailedMessage"), JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    private void handleTabChanged() {
        final int oldTab = _selectedTab;
        final int newTab = _tabbedPane.getSelectedIndex();
        if (oldTab == newTab)
            return;
        _selectedTab = newTab;
        final AdminPanel oldPanel = oldTab == -1 ? null : (AdminPanel) _tabbedPane.getComponent(oldTab);
        final AdminPanel newPanel = newTab == -1 ? null : (AdminPanel) _tabbedPane.getComponent(newTab);
        if (oldPanel != null) {
            oldPanel.setIsShowing(false);
            changeMenuMap(oldPanel.getMenuMap(), false);
        }
        if (newPanel != null) {
            newPanel.setIsShowing(true);
            changeMenuMap(newPanel.getMenuMap(), true);
            scheduleRefresh(-1);
        }
        newPanel.setDefaultButton();
    }

    void changeMenuMap(final Map menuMap, final boolean add) {
        for (final Iterator iter = menuMap.entrySet().iterator(); iter.hasNext();) {
            final Map.Entry entry = (Map.Entry) iter.next();
            String menuName = (String) entry.getKey();
            if (menuName.indexOf(".") >= 0) {
                menuName = menuName.substring(0, menuName.indexOf("."));
            }
            final JComponent[] items = (JComponent[]) entry.getValue();
            final Action menuAction = (Action) _actionMap.get(menuName);
            final JMenuBar bar = _frame.getJMenuBar();
            if (menuAction != null) {
                for (int index = 0; index < bar.getMenuCount(); index++) {
                    final JMenu menu = bar.getMenu(index);
                    if (menu.getAction() == menuAction) {
                        for (int k = 0; k < items.length; k++) {
                            final JComponent item = items[k];
                            if (add) {
                                menu.add(item);
                            } else {
                                menu.remove(item);
                            }
                        }
                    }
                }
            }
        }
    }

    void refreshMenuEnableState() {
        for (final Iterator iter = _actionMap.values().iterator(); iter.hasNext();) {
            final AdminAction action = (AdminAction) iter.next();
            if (action.isDisableSensitive()) {
                action.setEnabled(_management != null);
            }
        }
    }

    /**
     * Sets the default font for all Swing components.
     *
     * @param font
     *            The FontUIResource to be made the default
     */
    private static void setUIFont(final FontUIResource font) {
        final java.util.Enumeration keys = UIManager.getDefaults().keys();
        while (keys.hasMoreElements()) {
            final Object key = keys.nextElement();
            final Object value = UIManager.get(key);
            if (value instanceof javax.swing.plaf.FontUIResource) {
                UIManager.put(key, font);
            }
        }
    }

    JComponent addLabeledField(final JPanel panel, final GridBagConstraints gbc, final JComponent component,
            final String propertyName, final boolean newLine) {
        final String prop = getProperty(propertyName);
        final StringTokenizer st = new StringTokenizer(prop, ":");
        final String caption = st.nextToken();
        String widthStr = st.nextToken();
        final String alignment = st.nextToken();
        final String gridwidth = st.nextToken();
        final String tooltip = st.nextToken();
        String heightStr = "1";
        final int p = widthStr.indexOf(',');
        if (p >= 0) {
            heightStr = widthStr.substring(p + 1);
            widthStr = widthStr.substring(0, p);
        }

        final JLabel label = new JLabel(caption);
        label.setHorizontalAlignment(JLabel.TRAILING);
        gbc.gridwidth = 1;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 0.0;
        panel.add(label, gbc);
        gbc.gridx++;

        try {
            if ("REMAINDER".equals(gridwidth)) {
                gbc.gridwidth = GridBagConstraints.REMAINDER;
            } else if ("RELATIVE".equals(gridwidth)) {
                gbc.gridwidth = GridBagConstraints.RELATIVE;
            } else {
                gbc.gridwidth = Integer.parseInt(gridwidth);
            }
        } catch (final NumberFormatException nfe) {
            // ignore
        }

        component.setToolTipText(tooltip);
        JComponent wrappedComponent = component;
        if (component instanceof JTextField) {
            final JTextField textField = (JTextField) component;
            textField.setColumns(Integer.parseInt(widthStr));
            textField.setHorizontalAlignment(alignment.equals("R") ? SwingConstants.TRAILING
                    : alignment.equals("C") ? SwingConstants.CENTER : SwingConstants.LEADING);
            textField.setEditable(false);
            textField.setEnabled(true);
            textField.setBackground(Color.white);
        } else if (component instanceof JTextArea) {
            final JTextArea textArea = (JTextArea) component;
            textArea.setColumns(Integer.parseInt(widthStr));
            textArea.setRows(Integer.parseInt(heightStr));
            textArea.setEditable(false);
            textArea.setEnabled(true);
            textArea.setBackground(Color.white);
            wrappedComponent = new JScrollPane(textArea);
            wrappedComponent.setMinimumSize(textArea.getPreferredScrollableViewportSize());
            registerTextComponent(textArea);
        }
        gbc.weightx = 1.0;
        panel.add(wrappedComponent, gbc);

        if (newLine || gbc.gridwidth == GridBagConstraints.REMAINDER || gbc.gridwidth == GridBagConstraints.RELATIVE) {
            gbc.gridy++;
            gbc.gridx = 0;
        } else {
            gbc.gridx += gbc.gridwidth;
        }

        component.setMinimumSize(component.getPreferredSize());
        return component;
    }

    AdminAction createAction(final AdminCommand command, final String specification) {
        final StringTokenizer st = new StringTokenizer(specification, ":");
        String actionName = st.nextToken();
        String caption = null;
        String iconName = null;
        if (st.hasMoreTokens())
            caption = st.nextToken();
        if (st.hasMoreTokens())
            iconName = st.nextToken();

        final boolean isDisableSensitive = actionName.startsWith("?");
        if (isDisableSensitive)
            actionName = actionName.substring(1);

        final boolean isToggle = actionName.startsWith("*");
        if (isToggle)
            actionName = actionName.substring(1);

        final boolean isRadio = actionName.startsWith("!");
        if (isRadio)
            actionName = actionName.substring(1);

        final boolean hasSubActions = actionName.startsWith("+");
        if (hasSubActions)
            actionName = actionName.substring(1);

        int mnemonicIndex = -1;
        int acceleratorChar = 0;
        if (caption != null) {
            mnemonicIndex = caption.indexOf('&');
            if (mnemonicIndex >= 0) {
                caption = caption.substring(0, mnemonicIndex) + caption.substring(mnemonicIndex + 1);
            }

            final int acceleratorIndex = caption.indexOf('^');
            if (acceleratorIndex >= 0 && acceleratorIndex + 1 < caption.length()) {
                acceleratorChar = caption.charAt(acceleratorIndex + 1);
                caption = caption.substring(0, acceleratorIndex) + caption.substring(acceleratorIndex + 2);
            }
        }

        AdminAction action = null;
        if (caption == null) {
            action = new AdminAction(actionName);
        } else if (iconName == null || iconName.length() == 0) {
            action = new AdminAction(command, actionName, caption);
        } else {
            action = new AdminAction(command, actionName, caption, new ImageIcon(iconName));
        }
        action._isToggle = isToggle;
        action._isRadio = isRadio;
        action._hasSubActions = hasSubActions;
        action._isDisableSensitive = isDisableSensitive;
        action._mnemonicIndex = mnemonicIndex;
        action._acceleratorChar = acceleratorChar;
        _actionMap.put(actionName, action);
        return action;
    }

    public JTabbedPane getTabbedPane() {
        return _tabbedPane;
    }

    public AdminAction getAction(final String actionName) {
        return (AdminAction) _actionMap.get(actionName);
    }

    public TitledBorder createTitledBorder(final String captionProperty) {
        String caption = getProperty(captionProperty);
        if (caption == null || caption.length() == 0)
            caption = " ";

        return BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(10, 2, 2, 2), caption,
                TitledBorder.LEADING, TitledBorder.DEFAULT_POSITION, _boldFont, _persistitAccentColor);
    }

    private void connectDialog(final String defaultHost) {
        final Object value = JOptionPane.showInputDialog(_frame, "RMI Registry", "Connection Specification",
                JOptionPane.QUESTION_MESSAGE, null, null, defaultHost);
        if (value instanceof String) {
            final Thread thread = new Thread() {
                @Override
                public void run() {
                    connect((String) value);
                }
            };
            thread.setDaemon(true);
            thread.start();
        }
    }

    private boolean connect(final String rmiHost) {
        try {
            _rmiHost = rmiHost;
            final Management management = (Management) Naming.lookup("//" + rmiHost + "/PersistitManagementServer");
            setManagement(management);
            setFrameTitle(rmiHost);
            return true;
        } catch (final Exception e) {
            setManagement(null);
            showMessage(e, getProperty("ConnectionFailedMessage"), JOptionPane.ERROR_MESSAGE);
            return false;
        }
    }

    private void disconnect() {
        setManagement(null);
    }

    void showMessage(final Object message, final String title, final int type) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JOptionPane.showMessageDialog(_frame, message, title, type);
            }
        });
    }

    public static void main(final String[] args) {
        new AdminUI(args.length > 0 ? args[0] : null);
    }

    /**
     * Actions for this UI
     */
    class AdminAction extends AbstractAction {
        private String _name = "";
        private String _caption = "";
        private AdminCommand _command;
        private boolean _isToggle;
        private boolean _isRadio;
        private boolean _hasSubActions;
        boolean _isDisableSensitive;
        private ArrayList _buttonList;
        private int _mnemonicIndex;
        private int _acceleratorChar;

        AdminAction(final String actionName) {
            super();
            _name = actionName;
        }

        AdminAction(final AdminCommand command, final String actionName, final String caption) {
            super(caption);
            _name = actionName;
            _caption = caption;
            _command = command;
        }

        AdminAction(final AdminCommand command, final String actionName, final String caption, final Icon icon) {
            super(caption, icon);
            _name = actionName;
            _caption = caption;
            _command = command;
        }

        @Override
        public void actionPerformed(final ActionEvent ae) {
            if (!_refreshing) {
                _command.actionPerformed(this, ae);
            }
        }

        public String getName() {
            return _name;
        }

        public AdminCommand getActionCommand() {
            return _command;
        }

        @Override
        public String toString() {
            return _caption;
        }

        public boolean isToggle() {
            return _isToggle;
        }

        public boolean isRadio() {
            return _isRadio;
        }

        public boolean hasSubActions() {
            return _hasSubActions;
        }

        public boolean isDisableSensitive() {
            return _isDisableSensitive;
        }

        public ArrayList getButtonList() {

            return _buttonList;
        }

        public void addButton(final AbstractButton button) {
            if (_buttonList == null)
                _buttonList = new ArrayList();
            _buttonList.add(button);
            if (_mnemonicIndex >= 0) {
                final char mnemonicChar = _caption.charAt(_mnemonicIndex);
                button.setMnemonic((int) mnemonicChar);
            }
            if (_acceleratorChar > 0 && button instanceof JMenuItem && !(button instanceof JMenu)) {
                final KeyStroke accelerator = KeyStroke.getKeyStroke(_acceleratorChar, InputEvent.CTRL_MASK);
                ((JMenuItem) button).setAccelerator(accelerator);
            }
        }

        public void removeButton(final AbstractButton button) {
            if (_buttonList != null) {
                _buttonList.remove(button);
            }
            if (_buttonList.size() == 0)
                _buttonList = null;
        }

        public void stateChanged(final boolean selected) {
            if (_buttonList != null) {
                for (int i = 0; i < _buttonList.size(); i++) {
                    final AbstractButton button = (AbstractButton) _buttonList.get(i);
                    if (button.isSelected() != selected) {
                        button.setSelected(selected);
                    }
                }
            }
        }

        public AbstractButton menuItem(final AdminCommand command, final String propName) {
            AbstractButton item;
            if (isToggle()) {
                item = new JCheckBoxMenuItem(this);
                addButton(item);
            } else if (isRadio()) {
                item = new JRadioButtonMenuItem(this);
                addButton(item);
            } else {
                if (hasSubActions()) {
                    item = new JMenu(this);
                    ButtonGroup bg = null;
                    for (int subIndex = 0;; subIndex++) {
                        final String subName = propName + "." + subIndex;
                        final String u = getProperty(subName);
                        if (u == null)
                            break;
                        final AdminAction action = createAction(command, u);
                        final AbstractButton subItem = action.menuItem(command, subName);
                        item.add(subItem);
                        if (subItem instanceof JRadioButtonMenuItem) {
                            final boolean first = bg == null;
                            if (first)
                                bg = new ButtonGroup();
                            bg.add(subItem);
                            if (first)
                                subItem.setSelected(true);
                        }
                    }
                } else {
                    item = new JMenuItem(this);
                }
            }
            if ("REFRESH_0".equals(_name)) {
                _refreshOnceButton = item;
            }
            return item;
        }
    }

    ButtonModel getMenuItemModel(final String actionName) {
        final AdminAction action = (AdminAction) _actionMap.get(actionName);
        final ArrayList buttons = action.getButtonList();
        if (buttons != null) {
            for (final Iterator iter = buttons.iterator(); iter.hasNext();) {
                final AbstractButton button = (AbstractButton) iter.next();
                if (button instanceof JMenuItem) {
                    return button.getModel();
                }
            }
        }
        return null;
    }

    private void resetRefreshTimer() {
        if (_refreshOnceButton != null) {
            _refreshOnceButton.setSelected(true);
        }
    }

    @Override
    public void actionPerformed(final AdminAction action, final ActionEvent ae) {
        try {
            final String name = action._name;
            boolean textModeChanged = false;
            // System.out.println("AdminUI actionPerformed: " + name);
            final Management management = _management;

            if (name.startsWith("REFRESH")) {
                int interval = 0;
                if (name.startsWith("REFRESH_")) {
                    interval = Integer.parseInt(name.substring("REFRESH_".length()));
                }
                scheduleRefresh(interval);
            } else if ("EXIT".equals(name)) {
                setManagement(null);
                close();
            } else if ("CONNECT".equals(name)) {
                connectDialog(_rmiHost);
            } else if ("DISCONNECT".equals(name)) {
                disconnect();
            } else if ("ABOUT".equals(name)) {
                if (_splashWindow == null) {
                    _splashWindow = new SplashWindow(_frame);
                    _splashWindow.display();
                }
            } else if ("HELP".equals(name)) {
                showHelp(ae);
            } else if ("SSUSP".equals(name)) {
                boolean state = ((AbstractButton) ae.getSource()).isSelected();
                if (management != null && management.isInitialized()) {
                    if (state) {
                        final int confirm = JOptionPane.showConfirmDialog(_frame, getProperty("ssusp.confirm"));

                        if (confirm != JOptionPane.YES_OPTION) {
                            state = false;
                        }
                    }

                    management.setShutdownSuspended(state);
                    scheduleRefresh(-1);
                } else {
                    ((AbstractButton) ae.getSource()).setSelected(false);
                }
            } else if ("USUSP".equals(name)) {
                boolean state = ((AbstractButton) ae.getSource()).isSelected();
                if (management != null && management.isInitialized()) {
                    if (state) {

                        final int confirm = JOptionPane.showConfirmDialog(_frame, getProperty("ususp.confirm"));

                        if (confirm != JOptionPane.YES_OPTION) {
                            state = false;
                        }
                    }
                    management.setUpdateSuspended(state);
                    scheduleRefresh(-1);
                } else {
                    ((AbstractButton) ae.getSource()).setSelected(false);
                }
            } else if ("AONLY".equals(name)) {
                boolean state = ((AbstractButton) ae.getSource()).isSelected();
                if (management != null && management.isInitialized()) {
                    if (state) {

                        final int confirm = JOptionPane.showConfirmDialog(_frame, getProperty("aonly.confirm"));

                        if (confirm != JOptionPane.YES_OPTION) {
                            state = false;
                        }
                    }
                    management.setAppendOnly(state);
                    scheduleRefresh(-1);
                } else {
                    ((AbstractButton) ae.getSource()).setSelected(false);
                }
            } else if ("JCOPY".equals(name)) {
                boolean state = ((AbstractButton) ae.getSource()).isSelected();
                if (management != null && management.isInitialized()) {
                    if (state) {

                        final int confirm = JOptionPane.showConfirmDialog(_frame, getProperty("jcopy.confirm"));

                        if (confirm != JOptionPane.YES_OPTION) {
                            state = false;
                        }
                    }
                    management.setJournalCopyingFast(state);
                    scheduleRefresh(-1);
                } else {
                    ((AbstractButton) ae.getSource()).setSelected(false);
                }
            } else if ("FLUSH".equals(name)) {
                if (management != null && management.isInitialized()) {
                    management.flushAndForce();
                }
                // } else if ("SHUTDOWN".equals(name)) {
                // if (management != null && management.isInitialized()) {
                // int confirm = JOptionPane.showConfirmDialog(_frame,
                // getProperty("shutdown.confirm"));
                //
                // if (confirm == JOptionPane.YES_OPTION) {
                // management.close();
                // }
                // }
            } else if ("WRAP_MODE_NONE".equals(name)) {
                _wrapMode = false;
                textModeChanged = true;
            } else if ("WRAP_MODE_CHARACTER".equals(name)) {
                _wrapMode = true;
                _wrapWordMode = false;
                textModeChanged = true;
            } else if ("WRAP_MODE_WORD".equals(name)) {
                _wrapMode = true;
                _wrapWordMode = true;
                textModeChanged = true;
            } else if ("FONT_MODE_NORMAL".equals(name)) {
                _fixedFontMode = false;
                textModeChanged = true;
            } else if ("FONT_MODE_FIXED".equals(name)) {
                _fixedFontMode = true;
                textModeChanged = true;
            } else if (name.startsWith("TASK.")) {
                final String taskDescriptorPropName = "TaskDescriptor." + name.substring(5);
                final String taskDescriptorString = getProperty(taskDescriptorPropName);
                final TaskSetupPanel tsp = new TaskSetupPanel(this, taskDescriptorString);

                final JOptionPane optionPane = new JOptionPane(tsp, JOptionPane.QUESTION_MESSAGE,
                        JOptionPane.OK_CANCEL_OPTION);

                final JDialog dialog = optionPane.createDialog(_frame, tsp.getTaskName());
                dialog.setResizable(true);

                tsp.refresh(false);

                dialog.pack();
                dialog.setVisible(true);

                final Object value = optionPane.getValue();
                if (value != null && value instanceof Integer && ((Integer) value).intValue() == 0) {
                    doTask(tsp);
                }
            } else if ("START_NEW_TASK".equals(name)) {
                final JPopupMenu popup = new JPopupMenu(getProperty("SelectNewTaskMessage"));
                for (int index = 0;; index++) {
                    final AdminAction taskAction = getAction("TASK." + index);
                    if (taskAction == null)
                        break;
                    popup.add(new JMenuItem(taskAction));
                }
                final JComponent source = (JComponent) ae.getSource();
                popup.show(source, source.getWidth(), 0);
            } else {
                System.out.println("Undefined ACTION name " + name);
            }

            if (textModeChanged)
                handleTextModeChanged();
        } catch (final NoSuchObjectException ex) {
            setManagement(null);
            scheduleRefresh(0);
        } catch (final Exception ex) {
            postException(ex);
        }
    }

    public boolean getManagementState(final AdminAction action) {
        final String name = action.getName();
        try {
            if (_management == null)
                return false;
            if ("SSUSP".equals(name)) {
                return _management.isShutdownSuspended();
            }
            if ("USUSP".equals(name)) {
                return _management.isUpdateSuspended();
            }
            if ("AONLY".equals(name)) {
                return _management.getJournalInfo().isAppendOnly();
            }
            if ("USUSP".equals(name)) {
                return _management.getJournalInfo().isFastCopying();
            }
        } catch (final RemoteException re) {
        }
        return false;
    }

    void handleTextModeChanged() {
        for (final Iterator iter = _textComponentList.iterator(); iter.hasNext();) {
            final JComponent component = (JComponent) iter.next();
            component.setFont(_fixedFontMode ? _fixedFont : _defaultFont);
            if (component instanceof JTextArea) {
                final JTextArea tc = (JTextArea) component;
                tc.setLineWrap(_wrapMode);
                if (_wrapMode)
                    tc.setWrapStyleWord(_wrapWordMode);
            }
        }
    }

    void registerTextComponent(final JComponent component) {
        _textComponentList.add(component);
    }

    public void postException(Throwable throwable) {
        try {
            Throwable cause = null;
            if (throwable instanceof RemoteException) {
                try {
                    // Use reflection so this will compile and run (but not
                    // report the cause correctly) in JDK 1.3
                    final Method method = throwable.getClass().getMethod("getCause", new Class[0]);
                    if (method != null) {
                        cause = (Throwable) method.invoke(throwable, new Object[0]);
                    }
                } catch (final NoSuchMethodException e) {
                    // ignore for JDK 1.3
                }
            }
            if (cause != null)
                throwable = cause;
            if (throwable instanceof Management.WrappedRemoteException) {
                throwable = ((Management.WrappedRemoteException) throwable).getCause();
            }
            showMessage(throwable, getProperty("ExceptionMessage"), JOptionPane.ERROR_MESSAGE);
        } catch (final Exception e) {
            System.out.println("Exception while reporting throwable:");
            e.printStackTrace();
        }
    }

    public synchronized void scheduleRefresh(final int interval) {
        if (_refreshTimer == null)
            return;

        if (_refreshTimerTask != null) {
            _refreshTimerTask.cancel();
        }

        _refreshTimerTask = new TimerTask() {
            @Override
            public void run() {
                try {
                    SwingUtilities.invokeAndWait(new Runnable() {
                        @Override
                        public void run() {
                            refresh(false);
                        }
                    });
                } catch (final InterruptedException e) {
                } catch (final InvocationTargetException e) {
                }
            }
        };

        if (interval >= 0)
            _refreshInterval = interval;
        if (_refreshInterval > 0) {
            _refreshTimer.schedule(_refreshTimerTask, 0, _refreshInterval * 1000);
        } else {
            _refreshTimer.schedule(_refreshTimerTask, 0);
        }
    }

    protected void doTask(final TaskSetupPanel tsp) throws RemoteException {
        final Management management = getManagement();
        if (management != null) {
            // TODO - reinstate task interface
            management.startTask(tsp.getDescriptionString(), tsp.getOwnerString(), tsp.getCommandLine(),
                    tsp.getExpirationTime(), tsp.isVerboseEnabled() ? Task.LOG_VERBOSE : Task.LOG_NORMAL);
        }
        scheduleRefresh(1000);
    }

    private synchronized void showHelp(final ActionEvent ae) {
        // disabled and removed for now
        //
        // if (_javaHelpAdapter == null) {
        // try {
        // JavaHelpAdapter adapter = new JavaHelpAdapterImpl();
        // adapter.create(HELP_SET_NAME, ae);
        // } catch (Exception e) {
        // showMessage(e, "Exception while launching Help",
        // JOptionPane.ERROR_MESSAGE);
        // }
        // } else {
        // _javaHelpAdapter.showHelp(ae);
        // }
    }

    private class SplashWindow extends JWindow {
        Image _image;

        private SplashWindow(final JFrame frame) {
            super(frame);
        }

        private void display() {
            final URL url = AdminUI.class.getResource(SPLASH_FILE_NAME);
            _image = Toolkit.getDefaultToolkit().createImage(url);
            // Load the image
            final MediaTracker mt = new MediaTracker(this);
            mt.addImage(_image, 0);
            try {
                mt.waitForID(0);
            } catch (final InterruptedException ie) {
            }

            // Center the window on the screen.
            final int width = _image.getWidth(this);
            final int height = _image.getHeight(this);

            setSize(width, height);
            final Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
            setLocation((screenDim.width - width) / 2, (screenDim.height - height) / 2);
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(final MouseEvent evt) {
                    setVisible(false);
                    dispose();
                    _splashWindow = null;
                }
            });
            setVisible(true);
        }

        @Override
        public void update(final Graphics g) {
        }

        @Override
        public void paint(final Graphics g) {
            g.drawImage(_image, 0, 0, this);
        }
    }
}
TOP

Related Classes of com.persistit.ui.AdminUI

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.