/**
* Copyright 2005-2012 Akiban Technologies, Inc.
*
* 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.
*/
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);
}
}
}