Author: [log in to unmask] Date: Tue Apr 21 14:48:39 2015 New Revision: 2772 Log: Merge trunk changes into monitoring-app-dev branch.. Modified: java/branches/monitoring-app-dev/ (props changed) java/branches/monitoring-app-dev/pom.xml java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AddActionListener.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Commands.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DatePanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventDashboard.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventProcessing.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/FieldPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogTable.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Main.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MenuBar.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplication.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsDialog.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusTable.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/AbstractModel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/Configuration.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/RunModel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SteeringType.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/package-info.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/AIDAServer.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/DialogUtil.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/TableExporter.java Modified: java/branches/monitoring-app-dev/pom.xml ============================================================================= --- java/branches/monitoring-app-dev/pom.xml (original) +++ java/branches/monitoring-app-dev/pom.xml Tue Apr 21 14:48:39 2015 @@ -7,7 +7,7 @@ <groupId>org.hps</groupId> <artifactId>hps-parent</artifactId> <relativePath>../parent/pom.xml</relativePath> - <version>3.2-SNAPSHOT</version> + <version>3.3.1-SNAPSHOT</version> </parent> <scm> <url>http://java.freehep.org/svn/repos/hps/list/java/trunk/monitoring-app/</url> Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java Tue Apr 21 14:48:39 2015 @@ -16,305 +16,362 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; +import javax.swing.SwingConstants; import org.hps.monitoring.application.model.ConfigurationModel; import org.hps.monitoring.application.model.HasConfigurationModel; /** - * A <code>JPanel</code> which has a number of fields with the labels in the first column and the - * components for showing/editing the fields in the second. It uses <code>GridBagConstraints</code> - * for layout. + * A <code>JPanel</code> which has a number of fields with the labels in the first column and the components for + * showing/editing the fields in the second. It uses <code>GridBagConstraints</code> for layout. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -// TODO: This should use features of JFormattedTextField instead of plain JTextField. -abstract class AbstractFieldsPanel extends JPanel implements PropertyChangeListener, HasConfigurationModel, ActionListener, AddActionListener { - - private int currY = 0; - private Insets insets; +@SuppressWarnings("serial") +abstract class AbstractFieldsPanel extends JPanel implements PropertyChangeListener, HasConfigurationModel, +ActionListener, AddActionListener { + + /** + * Default button height in pixels. + */ + private static final int DEFAULT_BUTTON_HEIGHT = 50; + + /** + * Default button width in pixels. + */ + private static final int DEFAULT_BUTTON_WIDTH = 100; + + /** + * The configuration model for the component. + */ + private ConfigurationModel configurationModel; + + /** + * Grid Y which is incremented as components are added. + */ + private int currentGridY = 0; + + /** + * Flag which sets if this component and its children are editable. + */ private boolean editable = false; - - protected ConfigurationModel configurationModel; + + /** + * The default insets used for all internal <code>GridBagConstraints</code>. + */ + private final Insets insets; /** * Class constructor. + */ + protected AbstractFieldsPanel() { + this.insets = new Insets(1, 1, 1, 1); + } + + /** + * Class constructor. + * * @param insets The insets for the panel. * @param editable Editable setting. */ - protected AbstractFieldsPanel(Insets insets, boolean editable) { + protected AbstractFieldsPanel(final Insets insets, final boolean editable) { this.insets = insets; this.editable = editable; } /** - * Class constructor. - */ - protected AbstractFieldsPanel() { - this.insets = new Insets(1, 1, 1, 1); + * True if property change event should be accepted. + * + * @param evt the property change event + * @return <code>true</code> if property change event should be accepted + */ + boolean accept(final PropertyChangeEvent evt) { + return !"ancestor".equals(evt.getPropertyName()); + } + + /** + * Add an ActionListener to this component. By default this does nothing, but individual sub-components should + * attach this to individual components. + * + * @param listener the AcitonListener to add + */ + @Override + public void addActionListener(final ActionListener listener) { + // Sub-classes should add the listener to the appropriate child components. + } + + /** + * Add a button with text. + * + * @param text the text in the button + * @return the button component + */ + protected final JButton addButton(final String text) { + final GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.WEST; + c.gridwidth = 2; + final JButton button = new JButton(text); + button.setSize(new Dimension(DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT)); + this.add(button, c); + ++this.currentGridY; + return button; + } + + /** + * Add a check box. + * + * @param name the name of the check box + * @param selected whether the check box is selected or not + * @param enabled whether it is enabled or not + * @return the JCheckBox component + */ + protected final JCheckBox addCheckBox(final String name, final boolean selected, final boolean enabled) { + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.WEST; + final JLabel label = new JLabel(name + ":"); + this.add(label, c); + + c = new GridBagConstraints(); + c.gridx = 1; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.EAST; + final JCheckBox checkbox = new JCheckBox(); + checkbox.setSelected(selected); + checkbox.setEnabled(enabled); + this.add(checkbox, c); + + ++this.currentGridY; + + return checkbox; + } + + /** + * Add a check box. + * + * @param name the name of the check box + * @param tooltip the tooltip text + * @param selected <code>true</code> if component is selected + * @param enabled <code>true</code> if component enabled + * @return The JCheckBox component. + */ + protected final JCheckBox addCheckBox(final String name, final String tooltip, final boolean selected, + final boolean enabled) { + final JCheckBox c = this.addCheckBox(name, selected, enabled); + c.setToolTipText(tooltip); + return c; + } + + /** + * Add a combo box. + * + * @param name the name of the combo box + * @param values the set of values for the combo box + * @return the JComboBox component + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + protected final JComboBox addComboBox(final String name, final Object[] values) { + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.WEST; + final JLabel waitModeLabel = new JLabel(name); + waitModeLabel.setHorizontalAlignment(SwingConstants.LEFT); + this.add(waitModeLabel, c); + + c = new GridBagConstraints(); + c.gridx = 1; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.EAST; + final JComboBox combo = new JComboBox(values); + combo.setEditable(this.editable); + this.add(combo, c); + + ++this.currentGridY; + + return combo; + } + + /** + * Add a multiline combo box. + * + * @param name the name of the combo box + * @param values the values for the combo box + * @return the <code>JComboBox</code> component + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + protected final JComboBox addComboBoxMultiline(final String name, final String[] values) { + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridwidth = GridBagConstraints.REMAINDER; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.WEST; + final JLabel waitModeLabel = new JLabel(name + ":"); + waitModeLabel.setHorizontalAlignment(SwingConstants.LEFT); + this.add(waitModeLabel, c); + ++this.currentGridY; + + c = new GridBagConstraints(); + c.gridx = 0; + c.gridwidth = GridBagConstraints.REMAINDER; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.WEST; + final JComboBox combo = new JComboBox(values); + combo.setEditable(this.editable); + this.add(combo, c); + + ++this.currentGridY; + + return combo; + } + + /** + * Add a labeled JComponent to the panel. + * + * @param name the label text + * @param component the component to add + */ + void addComponent(final String name, final JComponent component) { + + // Add the label. + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.WEST; + final JLabel label = new JLabel(name + ":"); + this.add(label, c); + + // Add the component. + c = new GridBagConstraints(); + c.gridx = 1; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.EAST; + this.add(component, c); + + ++this.currentGridY; } /** * Add a field. - * @param name The name of the field. - * @param size The size of the field. - * @return The JTextField component. - */ - protected final JTextField addField(String name, int size) { - return addField(name, "", size, this.editable); + * + * @param name the name of the field + * @param size the size of the field + * @return the <code>JTextField</code> component + */ + protected final JTextField addField(final String name, final int size) { + return this.addField(name, "", size, this.editable); } /** * Add a field. - * @param name The name of the field. - * @param value The default value of the field. - * @param size The size of the field. - * @return The JTextField component. - */ - protected final JTextField addField(String name, String value, int size) { - return addField(name, value, size, this.editable); + * + * @param name the name of the field + * @param value the default value of the field + * @param size the size of the field + * @return the <code>JTextField</code> component + */ + protected final JTextField addField(final String name, final String value, final int size) { + return this.addField(name, value, size, this.editable); } /** * Add a field. - * @param name The name of the field. - * @param value The default value of the field. - * @param tooltip The tooltip text. - * @param size The size of the field. - * @param editable The editable setting. - * @return The JTextField component. - */ - protected final JFormattedTextField addField(String name, String value, String tooltip, int size, boolean editable) { - JFormattedTextField f = addField(name, value, size, editable); + * + * @param name the name of the field + * @param value the default value of the field + * @param size the size of the field + * @param editable the editable setting + * @return the <code>JTextField</code> component + */ + protected final JFormattedTextField addField(final String name, final String value, final int size, + final boolean editable) { + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.WEST; + final JLabel label = new JLabel(name + ":"); + this.add(label, c); + + c = new GridBagConstraints(); + c.gridx = 1; + c.gridy = this.currentGridY; + c.insets = this.insets; + c.anchor = GridBagConstraints.EAST; + // JFormattedTextField field = new JFormattedTextField(value, size); + final JFormattedTextField field = new JFormattedTextField(value); + field.setColumns(size); + field.setHorizontalAlignment(SwingConstants.RIGHT); + field.setEditable(editable); + field.setBackground(Color.WHITE); + this.add(field, c); + + ++this.currentGridY; + + return field; + } + + /** + * Add a field. + * + * @param name the name of the field + * @param value the default value of the field + * @param tooltip the tooltip text + * @param size the size of the field + * @param editable the editable setting + * @return the <code>JTextField</code> component + */ + protected final JFormattedTextField addField(final String name, final String value, final String tooltip, + final int size, final boolean editable) { + final JFormattedTextField f = this.addField(name, value, size, editable); f.setToolTipText(tooltip); return f; } /** - * Add a field. - * @param name The name of the field. - * @param value The default value of the field. - * @param size The size of the field. - * @param editable The editable setting. - * @return The JTextField component. - */ - protected final JFormattedTextField addField(String name, String value, int size, boolean editable) { - GridBagConstraints c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.WEST; - JLabel label = new JLabel(name + ":"); - add(label, c); - - c = new GridBagConstraints(); - c.gridx = 1; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.EAST; - // JFormattedTextField field = new JFormattedTextField(value, size); - JFormattedTextField field = new JFormattedTextField(value); - field.setColumns(size); - field.setHorizontalAlignment(JTextField.RIGHT); - field.setEditable(editable); - field.setBackground(Color.WHITE); - add(field, c); - - ++currY; - - return field; - } - - /** - * Add a combo box. - * @param name The name of the combo box. - * @param values The set of values for the combo box. - * @return The JComboBox component. - */ - protected final JComboBox addComboBox(String name, String[] values) { - - // System.out.println("addComboBox = " + name); - - GridBagConstraints c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.WEST; - JLabel waitModeLabel = new JLabel(name); - waitModeLabel.setHorizontalAlignment(JLabel.LEFT); - add(waitModeLabel, c); - - c = new GridBagConstraints(); - c.gridx = 1; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.EAST; - JComboBox combo = new JComboBox(values); - // System.out.println("combo width = " + combo.getWidth()); - // System.out.println("combo width = " + combo.getSize().getWidth()); - combo.setEditable(editable); - add(combo, c); - - ++currY; - - return combo; - } - - /** - * Add a multiline combo box. - * @param name The name of the combo box. - * @param values The values for the combo box. - * @return The JComboBox component. - */ - protected final JComboBox addComboBoxMultiline(String name, String[] values) { - - GridBagConstraints c = new GridBagConstraints(); - c.gridx = 0; - c.gridwidth = GridBagConstraints.REMAINDER; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.WEST; - JLabel waitModeLabel = new JLabel(name + ":"); - waitModeLabel.setHorizontalAlignment(JLabel.LEFT); - add(waitModeLabel, c); - ++currY; - - c = new GridBagConstraints(); - c.gridx = 0; - c.gridwidth = GridBagConstraints.REMAINDER; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.WEST; - JComboBox combo = new JComboBox(values); - // System.out.println("combo width = " + combo.getWidth()); - // System.out.println("combo width = " + combo.getSize().getWidth()); - combo.setEditable(editable); - add(combo, c); - - ++currY; - - return combo; - } - - /** - * Add a check box. - * @param name The name of the check box. - * @param tooltip The tooltip text. - * @param selected Whether the box is selected or not. - * @param enabled Whether it is enabled or not. - * @return The JCheckBox component. - */ - protected final JCheckBox addCheckBox(String name, String tooltip, boolean selected, boolean enabled) { - JCheckBox c = addCheckBox(name, selected, enabled); - c.setToolTipText(tooltip); - return c; - } - - /** - * Add a check box. - * @param name The name of the check box. - * @param selected Whether the check box is selected or not. - * @param enabled Whether it is enabled or not. - * @return The JCheckBox component. - */ - protected final JCheckBox addCheckBox(String name, boolean selected, boolean enabled) { - - GridBagConstraints c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.WEST; - JLabel label = new JLabel(name + ":"); - add(label, c); - - c = new GridBagConstraints(); - c.gridx = 1; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.EAST; - JCheckBox checkbox = new JCheckBox(); - checkbox.setSelected(selected); - checkbox.setEnabled(enabled); - add(checkbox, c); - - ++currY; - - return checkbox; - } - - protected final JButton addButton(String text) { - GridBagConstraints c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.WEST; - c.gridwidth = 2; - JButton button = new JButton(text); - button.setSize(new Dimension(100, 50)); - add(button, c); - ++currY; - return button; - } - - /** - * Add an ActionListener to this component. By default this does nothing, but individual - * sub-components should attach this to individual components. - * @param listener The AcitonListener to add. + * Get the {@link org.hps.monitoring.application.model.ConfigurationModel} for this component. + * + * @return the {@link org.hps.monitoring.application.model.ConfigurationModel} for this component */ @Override - public void addActionListener(ActionListener listener) { - // Sub-classes should add the listener to the appropriate child components. - } - + public ConfigurationModel getConfigurationModel() { + return this.configurationModel; + } + + /** + * Handle a property change event. + * + * @param evt the property change event + */ + @Override + public void propertyChange(final PropertyChangeEvent evt) { + } + /** * Sub-classes should override this method to add their own listeners to update from the model. + * + * @param model the configuration model */ @Override - public void setConfigurationModel(ConfigurationModel model) { + public void setConfigurationModel(final ConfigurationModel model) { this.configurationModel = model; - + // This listener is used to push GUI values into the model. this.configurationModel.addPropertyChangeListener(this); - } - - @Override - public ConfigurationModel getConfigurationModel() { - return configurationModel; - } - - /** - * Add a labeled JComponent to the panel. - * @param name The label text. - * @param component The component to add. - */ - void addComponent(String name, JComponent component) { - - // Add the label. - GridBagConstraints c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.WEST; - JLabel label = new JLabel(name + ":"); - add(label, c); - - // Add the component. - c = new GridBagConstraints(); - c.gridx = 1; - c.gridy = currY; - c.insets = insets; - c.anchor = GridBagConstraints.EAST; - add(component, c); - - ++currY; - } - - boolean accept(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals("ancestor")) { - return false; - } else { - return true; - } - } - - @Override - public void propertyChange(PropertyChangeEvent evt) { - } -} + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AddActionListener.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AddActionListener.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AddActionListener.java Tue Apr 21 14:48:39 2015 @@ -2,7 +2,18 @@ import java.awt.event.ActionListener; +/** + * Mix-in interface for components which can be assigned an <code>ActionListener</code>. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> + */ interface AddActionListener { + /** + * Set an <code>ActionListener</code> for this component, which should assign it to appropriate child components + * that emit <code>ActionEvent</code> objects. + * + * @param listener the <code>ActionListener</code> to assign to this component + */ void addActionListener(ActionListener listener); } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Commands.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Commands.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Commands.java Tue Apr 21 14:48:39 2015 @@ -1,85 +1,256 @@ package org.hps.monitoring.application; /** - * These strings are used to identify ActionEvents in the MonitoringApplication. - * A few commands handled only by sub-components are not listed here. + * These strings are used to identify <code>ActionEvent</code> commands in the MonitoringApplication. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ final class Commands { - // Settings + /** + * ET blocking setting changed. + */ + static final String BLOCKING_CHANGED = "blockingChanged"; + + /** + * Choose a compact file for the detector description. + */ + static final String CHOOSE_COMPACT_FILE = "chooseCompactFile"; + + /** + * Choose an LCSim job steering file. + */ + static final String CHOOSE_STEERING_FILE = "chooseSteeringFile"; + + /** + * Clear the log table of all messages. + */ + static final String CLEAR_LOG_TABLE = "clearLogTable"; + + /** + * Reset the underlying AIDA objects in the plot tree. + */ + static final String CLEAR_PLOTS = "resetPlots"; + + /** + * Close the current input data file. + */ + static final String CLOSE_FILE = "closeFile"; + + /** + * Change the current conditions tag. + */ + static final String CONDITIONS_TAG_CHANGED = "conditionsTagChanged"; + + /** + * Connect to a new session. + */ + static final String CONNECT = "connect"; + + /** + * Change the current data source. + */ + static final String DATA_SOURCE_CHANGED = "dataSourceChanged"; + + /** + * Reset the application window to its default settings including scroll pane positions. + */ + static final String DEFAULT_WINDOW = "defaultWindow"; + + /** + * Detector alias changed. + */ + static final String DETECTOR_ALIAS_CHANGED = "detectorAliasChanged"; + + /** + * Name of detector changed. + */ + static final String DETECTOR_NAME_CHANGED = "detectorNameChanged"; + + /** + * Disconnect the current session. + */ + static final String DISCONNECT = "disconnect"; + + /** + * Disconnect on end run changed. + */ + static final String DISCONNECT_ON_END_RUN_CHANGED = "disconnectOnEndRunChanged"; + + /** + * Disconnect on error changed. + */ + static final String DISCONNECT_ON_ERROR_CHANGED = "disconnectOnErrorChanged"; + + /** + * Event builder setting changed. + */ + static final String EVENT_BUILDER_CHANGED = "eventBuilderChanged"; + + /** + * Exit the application. + */ + static final String EXIT = "exit"; + + /** + * Freeze conditions system after initialization. + */ + static final String FREEZE_CONDITIONS_CHANGED = "freezeConditionsChanged"; + + /** + * Load the default properties file from a jar resource. + */ + static final String LOAD_DEFAULT_SETTINGS = "loadDefaultSettings"; + + /** + * Load a settings properties file. + */ static final String LOAD_SETTINGS = "loadSettings"; - static final String LOAD_DEFAULT_SETTINGS = "loadDefaultSettings"; + + /** + * Global log level changed. + */ + static final String LOG_LEVEL_CHANGED = "logLevelChanged"; + + /** + * Change the log level filter for showing messages in the log table. + */ + static final String LOG_LEVEL_FILTER_CHANGED = "logLevelFilterChanged"; + + /** + * Send log messages to an output file. + */ + static final String LOG_TO_FILE = "logToFile"; + + /** + * Send log messages to the terminal. + */ + static final String LOG_TO_TERMINAL = "logToTerminal"; + + /** + * Maximize the application window. + */ + static final String MAXIMIZE_WINDOW = "maximizeWindow"; + + /** + * Minimize the application window. + */ + static final String MINIMIZE_WINDOW = "minimizeWindow"; + + /** + * Get the next event if paused. + */ + static final String NEXT = "next"; + + /** + * Open an input data file. + */ + static final String OPEN_FILE = "openFile"; + + /** + * Pause the event processing. + */ + static final String PAUSE = "pause"; + + /** + * Action when plot is selected from a tab. + */ + static final String PLOT_SELECTED = "PlotSelected"; + + /** + * Processing stage changed. + */ + static final String PROCESSING_STAGE_CHANGED = "processingStageChanged"; + + /** + * Select one of the items from the recent files list to be the current data source. + */ + static final String RECENT_FILE_SELECTED = "recentFileSelected"; + + /** + * Resume event processing if paused. + */ + static final String RESUME = "resume"; + + /** + * Save the log table to a text file. + */ + static final String SAVE_LOG_TABLE = "saveLogTable"; + + /** + * Save the plots to a ROOT, AIDA or PDF file. + */ + static final String SAVE_PLOTS = "savePlots"; + + /** + * Save a screenshot from the window graphics. + */ + static final String SAVE_SCREENSHOT = "saveScreenshot"; + + /** + * Save the currently selected plots tab graphic to a PDF file. + */ + static final String SAVE_SELECTED_PLOTS = "saveSelectedPlots"; + + /** + * Save settings to a properties file. + */ static final String SAVE_SETTINGS = "saveSettings"; + + /** + * Set the steering resource. + */ + static final String SET_STEERING_RESOURCE = "setSteeringResource"; + + /** + * Okay button in settings panel. + */ + static final String SETTINGS_OKAY_COMMAND = "settingsOkay"; + + /** + * Show the settings dialog. + */ static final String SHOW_SETTINGS = "showSettings"; - - // File open and close - static final String OPEN_FILE = "openFile"; - static final String CLOSE_FILE = "closeFile"; - static final String RECENT_FILE_SELECTED = "recentFileSelected"; - - // Window - static final String MAXIMIZE_WINDOW = "maximizeWindow"; - static final String MINIMIZE_WINDOW = "minimizeWindow"; - static final String DEFAULT_WINDOW = "defaultWindow"; - - // Data source - static final String DATA_SOURCE_CHANGED = "dataSourceChanged"; - - // Event commands - static final String CONNECT = "connect"; - static final String DISCONNECT = "disconnect"; - static final String NEXT = "next"; - static final String PAUSE = "pause"; - static final String RESUME = "resume"; - - // Save a screenshot - static final String SAVE_SCREENSHOT = "saveScreenshot"; - - // Plotting actions - static final String SAVE_PLOTS = "savePlots"; - static final String CLEAR_PLOTS = "resetPlots"; - static final String SAVE_SELECTED_PLOTS = "saveSelectedPlots"; - - // Exit the application. - static final String EXIT = "exit"; - - // Log to file or standard print stream. - static final String LOG_TO_FILE = "logToFile"; - static final String LOG_TO_TERMINAL = "logToTerminal"; - - static final String LOG_LEVEL_FILTER_CHANGED = "logLevelFilterChanged"; - - static final String CONDITIONS_TAG_CHANGED = "conditionsTagChanged"; - + + /** + * Start the AIDA server. + */ static final String START_AIDA_SERVER = "startAIDAServer"; + + /** + * Steering resource changed. + */ + static final String STEERING_RESOURCE_CHANGED = "steeringResourceChanged"; + + /** + * Steering type changed (file or resource). + */ + static final String STEERING_TYPE_CHANGED = "steeringTypeChanged"; + + /** + * Stop the AIDA server. + */ static final String STOP_AIDA_SERVER = "stopAIDAServer"; - - //////////////////////////////////////////// - static final String BLOCKING_CHANGED = "blockingChanged"; - static final String CHOOSE_COMPACT_FILE = "chooseCompactFile"; - static final String CHOOSE_LOG_FILE = "chooseLogFile"; - - static final String CHOOSE_STEERING_FILE = "chooseSteeringFile"; - static final String CLEAR_LOG_TABLE = "clearLogTable"; - static final String DATA_SOURCE_TYPE_CHANGED = "dataSourceTypeChanged"; - static final String DETECTOR_NAME_CHANGED = "detectorNameChanged"; - static final String DETECTOR_ALIAS_CHANGED = "detectorAliasChanged"; - - static final String DISCONNECT_ON_ERROR_CHANGED = "disconnectOnErrorChanged"; - static final String DISCONNECT_ON_END_RUN_CHANGED = "disconnectOnEndRunChanged"; - static final String EVENT_BUILDER_CHANGED = "eventBuilderChanged"; - static final String FREEZE_CONDITIONS_CHANGED = "freezeConditionsChanged"; - - static final String LOG_LEVEL_CHANGED = "logLevelChanged"; - - static final String PROCESSING_STAGE_CHANGED = "processingStageChanged"; - static final String SAVE_LOG_TABLE = "saveLogTable"; - static final String SELECT_LOG_FILE = "logToFile"; - static final String SET_STEERING_RESOURCE = "setSteeringResource"; - static final String STEERING_TYPE_CHANGED = "steeringTypeChanged"; - static final String STEERING_RESOURCE_CHANGED = "steeringResourceChanged"; + + /** + * User run number in conditions system changed. + */ static final String USER_RUN_NUMBER_CHANGED = "userRunNumberChanged"; + + /** + * Verbose setting changed. + */ static final String VERBOSE_CHANGED = "verboseChanged"; - static final String VALIDATE_DATA_FILE = "validateDataFile"; + + /** + * ET wait mode changed. + */ static final String WAIT_MODE_CHANGED = "waitModeChanged"; -} + + /** + * Do not allow class instantiation. + */ + private Commands() { + throw new UnsupportedOperationException("Do no instantiate this class."); + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java Tue Apr 21 14:48:39 2015 @@ -9,85 +9,144 @@ /** * This is a table model for a collection of conditions objects. - * @author Jeremy McCormick <[log in to unmask]> * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class ConditionsCollectionTableModel extends DefaultTableModel { +@SuppressWarnings("serial") +final class ConditionsCollectionTableModel extends DefaultTableModel { - ConditionsObjectCollection<?> collection; - int columnCount; - int rowCount; - String[] columnNames; - Class<?>[] columnTypes; - DatabaseConditionsManager manager; - - ConditionsCollectionTableModel(DatabaseConditionsManager manager, ConditionsObjectCollection<?> collection) { - + /** + * The {@link org.hps.conditions.api.ConditionsObjectCollection} for the model. + */ + private final ConditionsObjectCollection<?> collection; + + /** + * The number of columns. + */ + private int columnCount; + + /** + * The column names. + */ + private String[] columnNames; + + /** + * The column classes. + */ + private Class<?>[] columnTypes; + + /** + * The row count. + */ + private final int rowCount; + + /** + * Class constructor. + * + * @param manager the global conditions manager instance + * @param collection the {@link org.hps.conditions.api.ConditionsObjectCollection} providing data for the model + */ + ConditionsCollectionTableModel(final DatabaseConditionsManager manager, + final ConditionsObjectCollection<?> collection) { + // Set collection data. this.collection = collection; - rowCount = this.collection.size(); - - String tableName = collection.getConditionsRecord().getTableName(); - TableMetaData tableInfo = manager.findTableMetaData(tableName); + this.rowCount = this.collection.size(); + + final String tableName = collection.getConditionsRecord().getTableName(); + final TableMetaData tableInfo = manager.findTableMetaData(tableName); // Set column names and count from table meta data. - setupColumns(tableInfo); + this.setupColumns(tableInfo); } - private void setupColumns(TableMetaData tableInfo) { - - int fieldNameCount = tableInfo.getFieldNames().length; - columnCount = fieldNameCount + 1; - - columnTypes = new Class<?>[columnCount]; - columnNames = new String[columnCount]; - - columnNames[0] = "id"; - columnTypes[0] = int.class; - - for (int i = 0; i < fieldNameCount; i++) { - String fieldName = tableInfo.getFieldNames()[i]; - columnNames[i + 1] = fieldName; - columnTypes[i + 1] = tableInfo.getFieldType(fieldName); - } - } - + /** + * Get the class of a column. + * + * @param columnIndex the index of the column + */ @Override - public int getRowCount() { - return rowCount; - } - - @Override - public int getColumnCount() { - return columnCount; - } - - @Override - public String getColumnName(int columnIndex) { - return columnNames[columnIndex]; - } - - @Override - public Class<?> getColumnClass(int columnIndex) { - Class<?> columnClass = columnTypes[columnIndex]; - if (columnClass.equals(int.class)) { + public Class<?> getColumnClass(final int columnIndex) { + final Class<?> columnClass = this.columnTypes[columnIndex]; + if (int.class.equals(columnClass)) { return Integer.class; - } else if (columnClass.equals(float.class)) { + } else if (float.class.equals(columnClass)) { return Float.class; - } else if (columnClass.equals(double.class)) { + } else if (double.class.equals(columnClass)) { return Double.class; } else { return columnClass; } } + /** + * Get the number of columns. + * + * @return the number of columns + */ @Override - public Object getValueAt(int rowIndex, int columnIndex) { - ConditionsObject object = collection.get(rowIndex); + public int getColumnCount() { + return this.columnCount; + } + + /** + * Get the name of the column. + * + * @param columnIndex the column index + * @return the name of the column + */ + @Override + public String getColumnName(final int columnIndex) { + return this.columnNames[columnIndex]; + } + + /** + * Get the row count. + * + * @return the row count + */ + @Override + public int getRowCount() { + return this.rowCount; + } + + /** + * Get a table cell value. + * + * @param rowIndex the row index + * @param columnIndex the column index + * @return the value of the cell + */ + @Override + public Object getValueAt(final int rowIndex, final int columnIndex) { + final ConditionsObject object = this.collection.get(rowIndex); if (columnIndex == 0) { return object.getRowId(); } else { - return object.getFieldValue(columnNames[columnIndex]); + return object.getFieldValue(this.columnNames[columnIndex]); } } -} + + /** + * Setup the columns from table meta data. + * + * @param tableInfo the {@link org.hps.conditions.database.TableMetaData} with the table info + */ + private void setupColumns(final TableMetaData tableInfo) { + + final int fieldNameCount = tableInfo.getFieldNames().length; + this.columnCount = fieldNameCount + 1; + + this.columnTypes = new Class<?>[this.columnCount]; + this.columnNames = new String[this.columnCount]; + + this.columnNames[0] = "id"; + this.columnTypes[0] = int.class; + + for (int i = 0; i < fieldNameCount; i++) { + final String fieldName = tableInfo.getFieldNames()[i]; + this.columnNames[i + 1] = fieldName; + this.columnTypes[i + 1] = tableInfo.getFieldType(fieldName); + } + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsPanel.java Tue Apr 21 14:48:39 2015 @@ -1,6 +1,3 @@ -/** - * - */ package org.hps.monitoring.application; import java.awt.BorderLayout; @@ -29,65 +26,96 @@ import org.lcsim.conditions.ConditionsListener; /** - * @author Jeremy McCormick <[log in to unmask]> + * The component for showing conditions table records in the monitoring application tabs. * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -public class ConditionsPanel extends JPanel { - - JList<String> conditionsList = new JList<String>(); - JTable conditionsTable = new JTable(); - Map<String, ConditionsCollectionTableModel> tableModels; - - ConditionsPanel() { - super(new BorderLayout()); - - conditionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - conditionsList.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - String tableName = (String) conditionsList.getSelectedValue(); - TableModel model = tableModels.get(tableName); - conditionsTable.setModel(model); - conditionsTable.setRowSorter(new TableRowSorter(model)); - conditionsTable.revalidate(); - } - }); - - conditionsTable.setModel(new DefaultTableModel()); - - JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, conditionsList, new JScrollPane(conditionsTable)); - splitPane.setResizeWeight(0.6); - - add(splitPane); - } - +@SuppressWarnings("serial") +final class ConditionsPanel extends JPanel { + + /** + * The listener for updating the panel when conditions are changed. + */ class ConditionsPanelListener implements ConditionsListener { + /** + * Handle conditions change event. + * + * @param event the conditions change event + */ @Override - public void conditionsChanged(ConditionsEvent event) { + public void conditionsChanged(final ConditionsEvent event) { - DatabaseConditionsManager manager = (DatabaseConditionsManager) event.getConditionsManager(); - - tableModels = new LinkedHashMap<String, ConditionsCollectionTableModel>(); - + final DatabaseConditionsManager manager = (DatabaseConditionsManager) event.getConditionsManager(); + + ConditionsPanel.this.tableModels = new LinkedHashMap<String, ConditionsCollectionTableModel>(); + // Set list of table names. - ConditionsRecordCollection records = - manager.getCachedConditions(ConditionsRecordCollection.class, "conditions").getCachedData(); + final ConditionsRecordCollection records = manager.getCachedConditions(ConditionsRecordCollection.class, + "conditions").getCachedData(); records.sortByKey(); - conditionsList.removeAll(); - Set<String> tableNames = new LinkedHashSet<String>(); - for (ConditionsRecord record : records) { + ConditionsPanel.this.conditionsList.removeAll(); + final Set<String> tableNames = new LinkedHashSet<String>(); + for (final ConditionsRecord record : records) { tableNames.add(record.getTableName()); - } - conditionsList.setListData(tableNames.toArray(new String[] {})); - - // Create list of table models. - for (String tableName : tableNames) { - ConditionsObjectCollection<?> collection = manager.getCachedConditions( - manager.findTableMetaData(tableName).getCollectionClass(), - tableName).getCachedData(); - tableModels.put(tableName, new ConditionsCollectionTableModel(manager, collection)); + } + ConditionsPanel.this.conditionsList.setListData(tableNames.toArray(new String[] {})); + + // Create list of table models. + for (final String tableName : tableNames) { + final ConditionsObjectCollection<?> collection = manager.getCachedConditions( + manager.findTableMetaData(tableName).getCollectionClass(), tableName).getCachedData(); + ConditionsPanel.this.tableModels + .put(tableName, new ConditionsCollectionTableModel(manager, collection)); } } } -} + + /** + * The GUI component listing the conditions sets for the run. + */ + private final JList<String> conditionsList = new JList<String>(); + + /** + * The table which shows the currently selected conditions set from the list. + */ + private final JTable conditionsTable = new JTable(); + + /** + * Map of conditions set names to table models. + */ + private Map<String, ConditionsCollectionTableModel> tableModels; + + /** + * Class constructor which will initialize sub-components. + */ + ConditionsPanel() { + super(new BorderLayout()); + + this.conditionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + this.conditionsList.addListSelectionListener(new ListSelectionListener() { + + /** + * The selection listener method implementation which will activate a new table in the conditions panel. + * + * @param e the list selection event + */ + @Override + public void valueChanged(final ListSelectionEvent e) { + final String tableName = ConditionsPanel.this.conditionsList.getSelectedValue(); + final TableModel model = ConditionsPanel.this.tableModels.get(tableName); + ConditionsPanel.this.conditionsTable.setModel(model); + ConditionsPanel.this.conditionsTable.setRowSorter(new TableRowSorter<TableModel>(model)); + ConditionsPanel.this.conditionsTable.revalidate(); + } + }); + + // Initialize with default table model. + this.conditionsTable.setModel(new DefaultTableModel()); + + final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, this.conditionsList, new JScrollPane( + this.conditionsTable)); + + this.add(splitPane); + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java Tue Apr 21 14:48:39 2015 @@ -15,189 +15,252 @@ /** * Connection settings panel. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class ConnectionSettingsPanel extends AbstractFieldsPanel { - - private JTextField etNameField; - private JTextField hostField; - private JTextField portField; - private JCheckBox blockingCheckBox; - private JCheckBox verboseCheckBox; - private JTextField stationNameField; - private JTextField chunkSizeField; - private JTextField queueSizeField; - private JTextField stationPositionField; - private JComboBox<?> waitModeComboBox; - private JTextField waitTimeField; - private JTextField prescaleField; - - static final String[] waitModes = { - Mode.SLEEP.name(), - Mode.TIMED.name(), - Mode.ASYNC.name() - }; - - /** - * Class constructor. - */ - ConnectionSettingsPanel() { - - super(new Insets(5, 5, 5, 5), true); - - setLayout(new GridBagLayout()); - - etNameField = addField("ET Name", "", 20); - etNameField.addPropertyChangeListener("value", this); - - hostField = addField("Host", 20); - hostField.addPropertyChangeListener("value", this); - - portField = addField("Port", 5); - portField.addPropertyChangeListener("value", this); - - blockingCheckBox = addCheckBox("Blocking", false, true); - blockingCheckBox.setActionCommand(Commands.BLOCKING_CHANGED); - blockingCheckBox.addActionListener(this); - - verboseCheckBox = addCheckBox("Verbose", false, true); - verboseCheckBox.setActionCommand(Commands.VERBOSE_CHANGED); - verboseCheckBox.addActionListener(this); - - stationNameField = addField("Station Name", 10); - stationNameField.addPropertyChangeListener("value", this); - - chunkSizeField = addField("Chunk Size", 3); - chunkSizeField.addPropertyChangeListener("value", this); - - queueSizeField = addField("Queue Size", 3); - queueSizeField.addPropertyChangeListener("value", this); - - stationPositionField = addField("Station Position", 3); - stationPositionField.addPropertyChangeListener("value", this); - - waitModeComboBox = addComboBox("Wait Mode", waitModes); - waitModeComboBox.setActionCommand(Commands.WAIT_MODE_CHANGED); - waitModeComboBox.addActionListener(this); - - waitTimeField = addField("Wait Time [microseconds]", 8); - waitTimeField.addPropertyChangeListener(this); - - prescaleField = addField("Prescale", 8); - prescaleField.addPropertyChangeListener(this); - } - - /** - * Enable or disable the connection panel GUI elements. - * @param e Set to true for enabled; false to disable. - */ - void enableConnectionPanel(boolean e) { - etNameField.setEnabled(e); - hostField.setEnabled(e); - portField.setEnabled(e); - blockingCheckBox.setEnabled(e); - verboseCheckBox.setEnabled(e); - stationNameField.setEnabled(e); - chunkSizeField.setEnabled(e); - queueSizeField.setEnabled(e); - stationPositionField.setEnabled(e); - waitModeComboBox.setEnabled(e); - waitTimeField.setEnabled(e); - prescaleField.setEnabled(e); - } - - /** - * Updates the GUI from changes in the ConfigurationModel. +@SuppressWarnings("serial") +final class ConnectionSettingsPanel extends AbstractFieldsPanel { + + /** + * Update the GUI from changes in the {@link org.hps.monitoring.application.model.ConfigurationModel}. */ public class ConnectionSettingsChangeListener implements PropertyChangeListener { + + /** + * Handle a property change from the model. + * + * @param the <code>PropertyChangeEvent</code> to handle + */ @Override - public void propertyChange(PropertyChangeEvent evt) { - configurationModel.removePropertyChangeListener(this); + public void propertyChange(final PropertyChangeEvent evt) { + ConnectionSettingsPanel.this.getConfigurationModel().removePropertyChangeListener(this); try { - Object value = evt.getNewValue(); + final Object value = evt.getNewValue(); if (evt.getPropertyName().equals(ConfigurationModel.ET_NAME_PROPERTY)) { - etNameField.setText((String) value); + ConnectionSettingsPanel.this.etNameField.setText((String) value); } else if (evt.getPropertyName().equals(ConfigurationModel.HOST_PROPERTY)) { - hostField.setText((String) value); + ConnectionSettingsPanel.this.hostField.setText((String) value); } else if (evt.getPropertyName().equals(ConfigurationModel.PORT_PROPERTY)) { - portField.setText(value.toString()); + ConnectionSettingsPanel.this.portField.setText(value.toString()); } else if (evt.getPropertyName().equals(ConfigurationModel.BLOCKING_PROPERTY)) { - blockingCheckBox.setSelected((Boolean) value); + ConnectionSettingsPanel.this.blockingCheckBox.setSelected((Boolean) value); } else if (evt.getPropertyName().equals(ConfigurationModel.VERBOSE_PROPERTY)) { - verboseCheckBox.setSelected((Boolean) value); + ConnectionSettingsPanel.this.verboseCheckBox.setSelected((Boolean) value); } else if (evt.getPropertyName().equals(ConfigurationModel.STATION_NAME_PROPERTY)) { - stationNameField.setText((String) value); + ConnectionSettingsPanel.this.stationNameField.setText((String) value); } else if (evt.getPropertyName().equals(ConfigurationModel.CHUNK_SIZE_PROPERTY)) { - chunkSizeField.setText(value.toString()); + ConnectionSettingsPanel.this.chunkSizeField.setText(value.toString()); } else if (evt.getPropertyName().equals(ConfigurationModel.QUEUE_SIZE_PROPERTY)) { - queueSizeField.setText(value.toString()); + ConnectionSettingsPanel.this.queueSizeField.setText(value.toString()); } else if (evt.getPropertyName().equals(ConfigurationModel.STATION_POSITION_PROPERTY)) { - stationPositionField.setText(value.toString()); + ConnectionSettingsPanel.this.stationPositionField.setText(value.toString()); } else if (evt.getPropertyName().equals(ConfigurationModel.WAIT_MODE_PROPERTY)) { - waitModeComboBox.setSelectedItem(((Mode) value).name()); + ConnectionSettingsPanel.this.waitModeComboBox.setSelectedItem(((Mode) value).name()); } else if (evt.getPropertyName().equals(ConfigurationModel.WAIT_TIME_PROPERTY)) { - waitTimeField.setText(value.toString()); + ConnectionSettingsPanel.this.waitTimeField.setText(value.toString()); } else if (evt.getPropertyName().equals(ConfigurationModel.PRESCALE_PROPERTY)) { - prescaleField.setText(value.toString()); + ConnectionSettingsPanel.this.prescaleField.setText(value.toString()); } } finally { - configurationModel.addPropertyChangeListener(this); + ConnectionSettingsPanel.this.getConfigurationModel().addPropertyChangeListener(this); } } } /** + * The available wait mode settings (sleep, timed and asynchronous). + */ + private static final String[] WAIT_MODES = {Mode.SLEEP.name(), Mode.TIMED.name(), Mode.ASYNC.name()}; + + /** + * Check box for blocking setting. + */ + private final JCheckBox blockingCheckBox; + + /** + * Field for chunk size. + */ + private final JTextField chunkSizeField; + + /** + * Field for ET name (file). + */ + private final JTextField etNameField; + + /** + * Field for host name. + */ + private final JTextField hostField; + + /** + * Field for TCP/IP port. + */ + private final JTextField portField; + + /** + * Field for prescale setting. + */ + private final JTextField prescaleField; + + /** + * Field for queue size. + */ + private final JTextField queueSizeField; + + /** + * Field for station name. + */ + private final JTextField stationNameField; + + /** + * Field for station position. + */ + private final JTextField stationPositionField; + + /** + * Check box for verbose flag. + */ + private final JCheckBox verboseCheckBox; + + /** + * Check box for wait mode selection. + */ + private final JComboBox<?> waitModeComboBox; + + /** + * Field for wait time. + */ + private final JTextField waitTimeField; + + /** + * Class constructor. + */ + ConnectionSettingsPanel() { + + super(new Insets(5, 5, 5, 5), true); + + this.setLayout(new GridBagLayout()); + + this.etNameField = this.addField("ET Name", "", 20); + this.etNameField.addPropertyChangeListener("value", this); + + this.hostField = this.addField("Host", 20); + this.hostField.addPropertyChangeListener("value", this); + + this.portField = this.addField("Port", 5); + this.portField.addPropertyChangeListener("value", this); + + this.blockingCheckBox = this.addCheckBox("Blocking", false, true); + this.blockingCheckBox.setActionCommand(Commands.BLOCKING_CHANGED); + this.blockingCheckBox.addActionListener(this); + + this.verboseCheckBox = this.addCheckBox("Verbose", false, true); + this.verboseCheckBox.setActionCommand(Commands.VERBOSE_CHANGED); + this.verboseCheckBox.addActionListener(this); + + this.stationNameField = this.addField("Station Name", 10); + this.stationNameField.addPropertyChangeListener("value", this); + + this.chunkSizeField = this.addField("Chunk Size", 3); + this.chunkSizeField.addPropertyChangeListener("value", this); + + this.queueSizeField = this.addField("Queue Size", 3); + this.queueSizeField.addPropertyChangeListener("value", this); + + this.stationPositionField = this.addField("Station Position", 3); + this.stationPositionField.addPropertyChangeListener("value", this); + + this.waitModeComboBox = this.addComboBox("Wait Mode", WAIT_MODES); + this.waitModeComboBox.setActionCommand(Commands.WAIT_MODE_CHANGED); + this.waitModeComboBox.addActionListener(this); + + this.waitTimeField = this.addField("Wait Time [microseconds]", 8); + this.waitTimeField.addPropertyChangeListener(this); + + this.prescaleField = this.addField("Prescale", 8); + this.prescaleField.addPropertyChangeListener(this); + } + + /** + * Used to update the ConfigurationModel from GUI components. + * + * @param e the <code>ActionEvent</code> to handle + */ + @Override + public void actionPerformed(final ActionEvent e) { + if (Commands.WAIT_MODE_CHANGED.equals(e.getActionCommand())) { + this.getConfigurationModel().setWaitMode(this.waitModeComboBox.getSelectedItem().toString()); + } else if (Commands.BLOCKING_CHANGED.equals(e.getActionCommand())) { + this.getConfigurationModel().setBlocking(this.blockingCheckBox.isSelected()); + } else if (Commands.VERBOSE_CHANGED.equals(e.getActionCommand())) { + this.getConfigurationModel().setVerbose(this.verboseCheckBox.isSelected()); + } + } + + /** + * Enable or disable the connection panel GUI elements. + * + * @param e <code>true</code> to enable the components in the panel + */ + void enableConnectionPanel(final boolean e) { + this.etNameField.setEnabled(e); + this.hostField.setEnabled(e); + this.portField.setEnabled(e); + this.blockingCheckBox.setEnabled(e); + this.verboseCheckBox.setEnabled(e); + this.stationNameField.setEnabled(e); + this.chunkSizeField.setEnabled(e); + this.queueSizeField.setEnabled(e); + this.stationPositionField.setEnabled(e); + this.waitModeComboBox.setEnabled(e); + this.waitTimeField.setEnabled(e); + this.prescaleField.setEnabled(e); + } + + /** * Updates ConfigurationModel from changes in the GUI components. */ @Override - public void propertyChange(PropertyChangeEvent evt) { - if (!accept(evt)) { + public void propertyChange(final PropertyChangeEvent evt) { + if (!this.accept(evt)) { return; - } - Object source = evt.getSource(); - configurationModel.removePropertyChangeListener(this); + } + final Object source = evt.getSource(); + this.getConfigurationModel().removePropertyChangeListener(this); try { - if (source.equals(etNameField)) { - configurationModel.setEtName(etNameField.getText()); - } else if (source.equals(hostField)) { - configurationModel.setHost(hostField.getText()); - } else if (source.equals(portField)) { - configurationModel.setPort(Integer.parseInt(portField.getText())); - } else if (source.equals(stationNameField)) { - configurationModel.setStationName(stationNameField.getText()); - } else if (source.equals(chunkSizeField)) { - configurationModel.setChunkSize(Integer.parseInt(chunkSizeField.getText())); - } else if (source.equals(queueSizeField)) { - configurationModel.setQueueSize(Integer.parseInt(queueSizeField.getText())); - } else if (source.equals(stationPositionField)) { - configurationModel.setStationPosition(Integer.parseInt(stationPositionField.getText())); - } else if (source.equals(waitTimeField)) { - configurationModel.setWaitTime(Integer.parseInt(waitTimeField.getText())); - } else if (source.equals(prescaleField)) { - configurationModel.setPrescale(Integer.parseInt(prescaleField.getText())); + if (source.equals(this.etNameField)) { + this.getConfigurationModel().setEtName(this.etNameField.getText()); + } else if (source.equals(this.hostField)) { + this.getConfigurationModel().setHost(this.hostField.getText()); + } else if (source.equals(this.portField)) { + this.getConfigurationModel().setPort(Integer.parseInt(this.portField.getText())); + } else if (source.equals(this.stationNameField)) { + this.getConfigurationModel().setStationName(this.stationNameField.getText()); + } else if (source.equals(this.chunkSizeField)) { + this.getConfigurationModel().setChunkSize(Integer.parseInt(this.chunkSizeField.getText())); + } else if (source.equals(this.queueSizeField)) { + this.getConfigurationModel().setQueueSize(Integer.parseInt(this.queueSizeField.getText())); + } else if (source.equals(this.stationPositionField)) { + this.getConfigurationModel().setStationPosition(Integer.parseInt(this.stationPositionField.getText())); + } else if (source.equals(this.waitTimeField)) { + this.getConfigurationModel().setWaitTime(Integer.parseInt(this.waitTimeField.getText())); + } else if (source.equals(this.prescaleField)) { + this.getConfigurationModel().setPrescale(Integer.parseInt(this.prescaleField.getText())); } } finally { - configurationModel.addPropertyChangeListener(this); - } - } - - /** - * Used to update the ConfigurationModel from GUI components. + this.getConfigurationModel().addPropertyChangeListener(this); + } + } + + /** + * Set configuration model (using <code>super</code> method) and add a property change listener for connection + * settings. */ @Override - public void actionPerformed(ActionEvent e) { - if (Commands.WAIT_MODE_CHANGED.equals(e.getActionCommand())) { - configurationModel.setWaitMode(Mode.valueOf((String) waitModeComboBox.getSelectedItem())); - } else if (Commands.BLOCKING_CHANGED.equals(e.getActionCommand())) { - configurationModel.setBlocking(blockingCheckBox.isSelected()); - } else if (Commands.VERBOSE_CHANGED.equals(e.getActionCommand())) { - configurationModel.setVerbose(verboseCheckBox.isSelected()); - } - } - - public void setConfigurationModel(ConfigurationModel model) { + public void setConfigurationModel(final ConfigurationModel model) { super.setConfigurationModel(model); - + // This listener updates the GUI from changes in the configuration. - this.configurationModel.addPropertyChangeListener(new ConnectionSettingsChangeListener()); - } -} + this.getConfigurationModel().addPropertyChangeListener(new ConnectionSettingsChangeListener()); + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java Tue Apr 21 14:48:39 2015 @@ -11,59 +11,82 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; +import javax.swing.SwingConstants; import org.hps.monitoring.application.model.ConnectionStatus; import org.hps.monitoring.application.model.ConnectionStatusModel; /** - * This is the panel for showing the current connection status (connected, disconnected, etc.). + * This is the panel for showing the current connection status (connected, disconnected, etc.) in the tool bar. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class ConnectionStatusPanel extends JPanel implements PropertyChangeListener { +@SuppressWarnings("serial") +final class ConnectionStatusPanel extends JPanel implements PropertyChangeListener { - JTextField statusField; - JTextField dateField; + /** + * Date formatting. + */ + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss"); - // Format for date field. - private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss"); - - ConnectionStatusModel model; + /** + * Field for date when status changed (read only). + */ + private final JTextField dateField; + + /** + * The model for getting connection status changes. + */ + private final ConnectionStatusModel model; + + /** + * The field showing the current connection status (read only). + */ + private final JTextField statusField; /** * Class constructor. + * + * @param model the model which notifies this component of connection status changes */ - ConnectionStatusPanel(ConnectionStatusModel model) { - + ConnectionStatusPanel(final ConnectionStatusModel model) { + this.model = model; this.model.addPropertyChangeListener(this); - + setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); - - statusField = new JTextField("", 10); - statusField.setHorizontalAlignment(JTextField.LEFT); - statusField.setEditable(false); - statusField.setBackground(Color.WHITE); - statusField.setFont(new Font("Arial", Font.BOLD, 16)); - statusField.setForeground(model.getConnectionStatus().getColor()); - statusField.setText(model.getConnectionStatus().name()); - add(statusField); - + + this.statusField = new JTextField("", 10); + this.statusField.setHorizontalAlignment(SwingConstants.LEFT); + this.statusField.setEditable(false); + this.statusField.setBackground(Color.WHITE); + this.statusField.setFont(new Font("Arial", Font.BOLD, 16)); + this.statusField.setForeground(model.getConnectionStatus().getColor()); + this.statusField.setText(model.getConnectionStatus().name()); + add(this.statusField); + add(new JLabel("@")); - - dateField = new JTextField("", 21); - dateField.setEditable(false); - dateField.setBackground(Color.WHITE); - dateField.setHorizontalAlignment(JTextField.LEFT); - dateField.setFont(new Font("Arial", Font.PLAIN, 14)); - add(dateField); + + this.dateField = new JTextField("", 21); + this.dateField.setEditable(false); + this.dateField.setBackground(Color.WHITE); + this.dateField.setHorizontalAlignment(SwingConstants.LEFT); + this.dateField.setFont(new Font("Arial", Font.PLAIN, 14)); + add(this.dateField); } + /** + * Handle a property change event coming from the model. + * + * @param evt the property change event + */ @Override - public void propertyChange(PropertyChangeEvent evt) { + public void propertyChange(final PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) { final ConnectionStatus status = (ConnectionStatus) evt.getNewValue(); - statusField.setForeground(status.getColor()); - statusField.setText(status.name()); - dateField.setText(dateFormat.format(new Date())); - } + this.statusField.setForeground(status.getColor()); + this.statusField.setText(status.name()); + this.dateField.setText(ConnectionStatusPanel.DATE_FORMAT.format(new Date())); + } } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java Tue Apr 21 14:48:39 2015 @@ -21,28 +21,48 @@ import org.hps.record.enums.DataSourceType; /** - * This is a combo box that shows the current data source such as an LCIO file, EVIO file or ET ring. - * It can also be used to select a new data source for the new session. + * This is a combo box that shows the current data source such as an LCIO file, EVIO file or ET ring. It can also be + * used to select a data source for the next monitoring session. * <p> - * The way this works is kind of odd because it is not directly connected to an event loop, so it must - * catch changes to the configuration and update its items accordingly. + * This component is not directly connected to an event loop, so it must catch changes to the configuration via property + * change events and then update its state accordingly. * <p> - * A single ET item is kept in the list and updated as changes are made to the global configuration. - * - * @author Jeremy McCormick <[log in to unmask]> + * Only a single "global" ET item is kept in the list, and it is updated as changes are made to the configuration model. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class DataSourceComboBox extends JComboBox<DataSourceItem> implements PropertyChangeListener, ActionListener{ - - ConnectionStatusModel connectionModel; - ConfigurationModel configurationModel; - +@SuppressWarnings("serial") +final class DataSourceComboBox extends JComboBox<DataSourceItem> implements PropertyChangeListener, ActionListener { + + /** + * This class represents a data source item in the combo box, which has a name for display, a full path to the file, + * and an implicit type (EVIO, LCIO or ET). + */ static class DataSourceItem { + /** + * The name of the data source which will show in the drop down box. + */ private String name; - private String path; - private DataSourceType type; - - DataSourceItem(String path, String name, DataSourceType type) { + + /** + * The full path used for the data source (for ET this is not used directly). + */ + private final String path; + + /** + * The implicit data type (EVIO, LCIO and ET). + */ + private final DataSourceType type; + + /** + * Create a data source item. + * + * @param path the data source path + * @param name the data source name + * @param type the data source type + */ + DataSourceItem(final String path, final String name, final DataSourceType type) { if (path == null) { throw new IllegalArgumentException("path is null"); } @@ -57,48 +77,81 @@ this.path = path; } - public String toString() { - return name; - } - - public String getPath() { - return path; - } - - public String getName() { - return name; - } - - public boolean equals(Object object) { + /** + * Implementation of equals operation. + * + * @param object the other object + */ + @Override + public boolean equals(final Object object) { if (!(object instanceof DataSourceItem)) { return false; } - DataSourceItem otherItem = (DataSourceItem) object; - if (this.name == otherItem.name && this.path == otherItem.path && this.type == otherItem.type) { - return true; - } else { - return false; - } - } - } - - @SuppressWarnings({ "rawtypes", "serial", "unchecked" }) - DataSourceComboBox(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel) { + final DataSourceItem otherItem = (DataSourceItem) object; + return this.name == otherItem.name && this.path == otherItem.path && this.type == otherItem.type; + } + + /** + * Get the name of the source that is used as text in the drop down menu. + * + * @return the name of the data source + */ + public String getName() { + return this.name; + } + + /** + * Get the full path to the data source which is used as tool tip text (not used directly for ET sources). + * + * @return the full path to the data source + */ + public String getPath() { + return this.path; + } + + /** + * Convert this object to a string. + * + * @return this object converted to a string + */ + @Override + public String toString() { + return this.name; + } + } + + /** + * The preferred width of this component in pixels. + */ + private static final int PREFERRED_WIDTH = 510; + + /** + * The backing configuration model. + */ + private ConfigurationModel configurationModel; + + /** + * Create a new data source combo box. + * + * @param configurationModel the underlying configuration data model + * @param connectionModel the underlying connection status data model + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + DataSourceComboBox(final ConfigurationModel configurationModel, final ConnectionStatusModel connectionModel) { addActionListener(this); setActionCommand(Commands.DATA_SOURCE_CHANGED); - setPreferredSize(new Dimension(510, this.getPreferredSize().height)); + setPreferredSize(new Dimension(PREFERRED_WIDTH, this.getPreferredSize().height)); setEditable(false); this.configurationModel = configurationModel; - connectionModel.addPropertyChangeListener(this); + connectionModel.addPropertyChangeListener(this); configurationModel.addPropertyChangeListener(this); - - ListCellRenderer renderer = new DefaultListCellRenderer() { + + final ListCellRenderer renderer = new DefaultListCellRenderer() { @Override - public Component getListCellRendererComponent(JList<?> list, - Object value, int index, boolean isSelected, - boolean cellHasFocus) { + public Component getListCellRendererComponent(final JList<?> list, final Object value, final int index, + final boolean isSelected, final boolean cellHasFocus) { if (value instanceof DataSourceItem) { - setToolTipText(((DataSourceItem)value).getPath()); + setToolTipText(((DataSourceItem) value).getPath()); } else { setToolTipText(null); } @@ -108,48 +161,142 @@ }; this.setRenderer(renderer); } - - boolean containsItem(DataSourceItem item) { + + /** + * Handle action events. + * + * @param evt the <code>ActionEvent</code> to handle + */ + @Override + public void actionPerformed(final ActionEvent evt) { + if (evt.getActionCommand().equals(Commands.DATA_SOURCE_CHANGED)) { + try { + // Update the model with data source settings. + this.configurationModel.removePropertyChangeListener(this); + final DataSourceItem item = (DataSourceItem) getSelectedItem(); + if (item != null) { + this.configurationModel.setDataSourceType(item.type); + if (item.type != DataSourceType.ET_SERVER) { + this.configurationModel.setDataSourcePath(item.getPath()); + } + } + } finally { + this.configurationModel.addPropertyChangeListener(this); + } + } + } + + /** + * Add a data source item with a specific type and path. + * + * @param path the data source path + * @param type the data source type + * @return the new data source item + */ + DataSourceItem addDataSourceItem(final String path, final DataSourceType type) { + final DataSourceItem newItem = new DataSourceItem(path, new File(path).getName(), type); + addItem(newItem); + return newItem; + } + + /** + * Add a data source item. Attempting to add an item that already exists will be ignored. + */ + @Override + public void addItem(final DataSourceItem item) { + if (containsItem(item)) { + return; + } + if (findItem(item.getPath()) == null) { + super.addItem(item); + } + } + + /** + * Return true if the (exact) given item exists in the combo box model. + * + * @param item the data source item + * @return <code>true</code> if data source item exists in the model + */ + boolean containsItem(final DataSourceItem item) { return ((DefaultComboBoxModel<DataSourceItem>) getModel()).getIndexOf(item) != -1; } + /** + * Find the single data source item for the ET configuration in the items. + * + * @return the data source item for the ET configuration or <code>null</code> if does not exist + */ + DataSourceItem findEtItem() { + for (int i = 0; i < this.getItemCount(); i++) { + final DataSourceItem item = this.getItemAt(i); + if (item.type == DataSourceType.ET_SERVER) { + return item; + } + } + return null; + } + + /** + * Find an item by its path. + * + * @param path the path of the item + * @return the item or <code>null</code> if does not exist + */ + DataSourceItem findItem(final String path) { + for (int i = 0; i < this.getItemCount(); i++) { + final DataSourceItem item = this.getItemAt(i); + if (item.getPath().equals(path)) { + return item; + } + } + return null; + } + + /** + * Handle property change events which is used to update the GUI from changes to the global configuration model. + * + * @param evt the property change event + */ @Override - public void propertyChange(PropertyChangeEvent evt) { - configurationModel.removePropertyChangeListener(this); + public void propertyChange(final PropertyChangeEvent evt) { + this.configurationModel.removePropertyChangeListener(this); try { if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) { - ConnectionStatus status = (ConnectionStatus) evt.getNewValue(); + final ConnectionStatus status = (ConnectionStatus) evt.getNewValue(); if (status.equals(ConnectionStatus.DISCONNECTED)) { setEnabled(true); } else { setEnabled(false); } } else if (evt.getPropertyName().equals(ConfigurationModel.DATA_SOURCE_PATH_PROPERTY)) { - if (configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_TYPE_PROPERTY)) { - String path = configurationModel.getDataSourcePath(); - DataSourceType type = DataSourceType.getDataSourceType(path); + if (this.configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_TYPE_PROPERTY)) { + final String path = this.configurationModel.getDataSourcePath(); + final DataSourceType type = DataSourceType.getDataSourceType(path); if (type.isFile()) { DataSourceItem item = findItem(path); if (item == null) { item = addDataSourceItem(path, type); } - if (configurationModel.getDataSourceType().isFile()) { + if (this.configurationModel.getDataSourceType().isFile()) { setSelectedItem(item); } } } } else if (evt.getPropertyName().equals(ConfigurationModel.DATA_SOURCE_TYPE_PROPERTY)) { - if (configurationModel.getDataSourceType() == DataSourceType.ET_SERVER) { + if (this.configurationModel.getDataSourceType() == DataSourceType.ET_SERVER) { DataSourceItem item = findEtItem(); if (item == null) { - item = new DataSourceItem(configurationModel.getEtPath(), configurationModel.getEtPath(), DataSourceType.ET_SERVER); + item = new DataSourceItem(this.configurationModel.getEtPath(), + this.configurationModel.getEtPath(), DataSourceType.ET_SERVER); } setSelectedItem(item); } else { - if (configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_PATH_PROPERTY)) { - DataSourceItem item = findItem(configurationModel.getDataSourcePath()); + if (this.configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_PATH_PROPERTY)) { + DataSourceItem item = findItem(this.configurationModel.getDataSourcePath()); if (item == null) { - item = addDataSourceItem(configurationModel.getDataSourcePath(), configurationModel.getDataSourceType()); + item = addDataSourceItem(this.configurationModel.getDataSourcePath(), + this.configurationModel.getDataSourceType()); } setSelectedItem(item); } @@ -162,76 +309,33 @@ updateEtItem(); } } finally { - configurationModel.addPropertyChangeListener(this); - } - } - + this.configurationModel.addPropertyChangeListener(this); + } + } + + /** + * Set the currently selected item. + * + * @param object the currently selected item (should be an instance of this class) + */ @Override - public void setSelectedItem(Object object) { + public void setSelectedItem(final Object object) { super.setSelectedItem(object); - this.setToolTipText(((DataSourceItem)object).getPath()); - } - - public void actionPerformed(ActionEvent evt) { - if (evt.getActionCommand().equals(Commands.DATA_SOURCE_CHANGED)) { - try { - // Update the model with data source settings. - configurationModel.removePropertyChangeListener(this); - DataSourceItem item = (DataSourceItem) getSelectedItem(); - if (item != null) { - configurationModel.setDataSourceType(item.type); - if (item.type != DataSourceType.ET_SERVER) { - configurationModel.setDataSourcePath(item.getPath()); - } - } - } finally { - configurationModel.addPropertyChangeListener(this); - } - } - } - - public void addItem(DataSourceItem item) { - if (containsItem(item)) { - return; - } - if (findItem(item.getPath()) == null) { - super.addItem(item); - } - } - - DataSourceItem findItem(String path) { - for (int i = 0; i < this.getItemCount(); i++) { - DataSourceItem item = this.getItemAt(i); - if (item.getPath().equals(path)) { - return item; - } - } - return null; - } - - DataSourceItem findEtItem() { - for (int i = 0; i < this.getItemCount(); i++) { - DataSourceItem item = this.getItemAt(i); - if (item.type == DataSourceType.ET_SERVER) { - return item; - } - } - return null; - } - - DataSourceItem addDataSourceItem(String path, DataSourceType type) { - DataSourceItem newItem = new DataSourceItem(path, new File(path).getName(), type); - addItem(newItem); - return newItem; - } - + this.setToolTipText(((DataSourceItem) object).getPath()); + } + + /** + * Update the path value of the current ET item from the current global configuration. There is only one ET item + * present in the list at one time so property changes to ET configuration will trigger this method. + */ void updateEtItem() { DataSourceItem item = findEtItem(); if (item == null) { - item = new DataSourceItem(configurationModel.getEtPath(), configurationModel.getEtPath(), DataSourceType.ET_SERVER); + item = new DataSourceItem(this.configurationModel.getEtPath(), this.configurationModel.getEtPath(), + DataSourceType.ET_SERVER); addItem(item); } else { - item.name = configurationModel.getEtPath(); - } - } -} + item.name = this.configurationModel.getEtPath(); + } + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DatePanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DatePanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DatePanel.java Tue Apr 21 14:48:39 2015 @@ -5,33 +5,72 @@ import java.util.Date; /** - * A small JPanel with a date field and a label on its border. + * A small <code>JPanel</code> with a date field and a label on its border. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class DatePanel extends FieldPanel { +@SuppressWarnings("serial") +final class DatePanel extends FieldPanel { + /** + * Default date formatting. + */ private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - DatePanel(String fieldName, String defaultValue, int size, boolean editable) { + /** + * Create a date panel. + * + * @param fieldName the field name for the label + * @param defaultValue the default value + * @param format the date formatter + * @param size the size of the field + * @param editable <code>true</code> to enable editing + */ + DatePanel(final String fieldName, final Date defaultValue, final SimpleDateFormat format, final int size, + final boolean editable) { + super(fieldName, format.format(defaultValue), size, editable); + } + + /** + * Create a date panel with default date formatting. + * + * @param fieldName the field name for the label + * @param defaultValue the default value + * @param size the size of the field + * @param editable <code>true</code> to enable editing + */ + DatePanel(final String fieldName, final String defaultValue, final int size, final boolean editable) { super(fieldName, defaultValue, size, editable); } - DatePanel(String fieldName, Date defaultValue, SimpleDateFormat format, int size, boolean editable) { - super(fieldName, format.format(defaultValue), size, editable); + /** + * Get the value of the field. + * + * @return the <code>Date</code> object + */ + Date getDateValue() { + try { + return this.dateFormat.parse(getValue()); + } catch (final ParseException e) { + throw new RuntimeException(e); + } } - void setDateFormat(SimpleDateFormat dateFormat) { + /** + * Set the date formatter. + * + * @param dateFormat the date formatter + */ + void setDateFormat(final SimpleDateFormat dateFormat) { this.dateFormat = dateFormat; } - void setValue(Date date) { - setValue(dateFormat.format(date)); - } - - Date getDateValue() { - try { - return dateFormat.parse(getValue()); - } catch (ParseException e) { - throw new RuntimeException(e); - } + /** + * Set the value of the field. + * + * @param date the <code>Date</code> object + */ + void setValue(final Date date) { + setValue(this.dateFormat.format(date)); } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java Tue Apr 21 14:48:39 2015 @@ -16,32 +16,94 @@ import org.hps.monitoring.application.model.ConnectionStatusModel; /** - * This is the panel with buttons for connecting or disconnecting from the session - * and controlling the application from pause mode. + * This is the panel with buttons for connecting or disconnecting from the session and controlling the application when + * event processing is paused. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class EventButtonsPanel extends JPanel implements PropertyChangeListener { +@SuppressWarnings("serial") +final class EventButtonsPanel extends JPanel implements PropertyChangeListener { - JButton nextButton; - JButton pauseButton; - JButton connectButton; - JButton resumeButton; - - static final ImageIcon connectedIcon = getImageIcon("/monitoringButtonGraphics/connected-128.png"); - static final ImageIcon disconnectedIcon = getImageIcon("/monitoringButtonGraphics/disconnected-128.png"); - - EventButtonsPanel(ConnectionStatusModel connectionModel, ActionListener listener) { - + /** + * Icon when application is connected to event processing session. + */ + static final ImageIcon CONNECTED_ICON = getImageIcon("/monitoringButtonGraphics/connected-128.png"); + + /** + * Icon when application is disconnected from event processing. + */ + static final ImageIcon DISCONNECTED_ICON = getImageIcon("/monitoringButtonGraphics/disconnected-128.png"); + + /** + * The icon size (width and height) in pixels. + */ + private static final int ICON_SIZE = 24; + + /** + * Get an image icon from a jar resource. + * + * @param resource the resource path + * @return the image icon + */ + static ImageIcon getImageIcon(final String resource) { + Image image = null; + try { + image = ImageIO.read(EventButtonsPanel.class.getResource(resource)); + image = image.getScaledInstance(ICON_SIZE, ICON_SIZE, 0); + } catch (final IOException e) { + } + return new ImageIcon(image); + } + + /** + * Button for connect and disconnect which is toggled depending on state. + */ + private final JButton connectButton; + + /** + * Button for getting next event when paused. + */ + private final JButton nextButton; + + /** + * Button for pausing the event processing. + */ + private final JButton pauseButton; + + /** + * Button for resuming the event processing. + */ + private final JButton resumeButton; + + /** + * Class constructor. + * + * @param connectionModel the global connection model + * @param listener the action listener + */ + EventButtonsPanel(final ConnectionStatusModel connectionModel, final ActionListener listener) { + connectionModel.addPropertyChangeListener(this); - + setLayout(new FlowLayout()); - connectButton = addButton(disconnectedIcon, Commands.CONNECT, listener, true); - resumeButton = addButton("/toolbarButtonGraphics/media/Play24.gif", Commands.RESUME, listener, false); - pauseButton = addButton("/toolbarButtonGraphics/media/Pause24.gif", Commands.PAUSE, listener, false); - nextButton = addButton("/toolbarButtonGraphics/media/StepForward24.gif", Commands.NEXT, listener, false); + this.connectButton = addButton(DISCONNECTED_ICON, Commands.CONNECT, listener, true); + this.resumeButton = addButton("/toolbarButtonGraphics/media/Play24.gif", Commands.RESUME, listener, false); + this.pauseButton = addButton("/toolbarButtonGraphics/media/Pause24.gif", Commands.PAUSE, listener, false); + this.nextButton = addButton("/toolbarButtonGraphics/media/StepForward24.gif", Commands.NEXT, listener, false); } - - final JButton addButton(ImageIcon icon, String command, ActionListener listener, boolean enabled) { - JButton button = new JButton(); + + /** + * Add a button to the panel. + * + * @param icon the button's image icon + * @param command the command for the action event + * @param listener the action listener which handles action events + * @param enabled <code>true</code> if button should be enabled initially + * @return the new button object + */ + private JButton addButton(final ImageIcon icon, final String command, final ActionListener listener, + final boolean enabled) { + final JButton button = new JButton(); button.setIcon(icon); button.setEnabled(enabled); button.addActionListener(listener); @@ -49,21 +111,26 @@ this.add(button); return button; } - - final JButton addButton(String resource, String actionCommand, ActionListener listener, boolean enabled) { + + /** + * Add a button to the panel. + * + * @param resource the resource for the image icon + * @param actionCommand the command for the action event + * @param listener the action listener which handles action events + * @param enabled <code>true</code> if button should be enabled initially + * @return the new button object + */ + private JButton addButton(final String resource, final String actionCommand, final ActionListener listener, + final boolean enabled) { return addButton(getImageIcon(resource), actionCommand, listener, enabled); } - - static ImageIcon getImageIcon(String resource) { - Image image = null; - try { - image = ImageIO.read(EventButtonsPanel.class.getResource(resource)); - image = image.getScaledInstance(24, 24, 0); - } catch (IOException e) { - } - return new ImageIcon(image); - } + /** + * Handle property change events to set status from changes to the connection status model. + * + * @param evt the <code>PropertyChangeEvent</code> to handle + */ @Override public void propertyChange(final PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) { @@ -72,35 +139,45 @@ setPaused((boolean) evt.getNewValue()); } } - - void setConnectionStatus(final ConnectionStatus status) { + + /** + * Set the connection status to update the button state. + * + * @param status the new connection status + */ + private void setConnectionStatus(final ConnectionStatus status) { if (status.equals(ConnectionStatus.DISCONNECTED)) { - nextButton.setEnabled(false); - pauseButton.setEnabled(false); - resumeButton.setEnabled(false); - connectButton.setActionCommand(Commands.CONNECT); - connectButton.setIcon(disconnectedIcon); - connectButton.setToolTipText("Start new session"); - connectButton.setEnabled(true); + this.nextButton.setEnabled(false); + this.pauseButton.setEnabled(false); + this.resumeButton.setEnabled(false); + this.connectButton.setActionCommand(Commands.CONNECT); + this.connectButton.setIcon(DISCONNECTED_ICON); + this.connectButton.setToolTipText("Start new session"); + this.connectButton.setEnabled(true); } else if (status.equals(ConnectionStatus.DISCONNECTING)) { - nextButton.setEnabled(false); - pauseButton.setEnabled(false); - resumeButton.setEnabled(false); - connectButton.setEnabled(false); + this.nextButton.setEnabled(false); + this.pauseButton.setEnabled(false); + this.resumeButton.setEnabled(false); + this.connectButton.setEnabled(false); } else if (status.equals(ConnectionStatus.CONNECTED)) { - nextButton.setEnabled(false); - pauseButton.setEnabled(true); - resumeButton.setEnabled(false); - connectButton.setActionCommand(Commands.DISCONNECT); - connectButton.setIcon(connectedIcon); - connectButton.setToolTipText("Disconnect from session"); - connectButton.setEnabled(true); + this.nextButton.setEnabled(false); + this.pauseButton.setEnabled(true); + this.resumeButton.setEnabled(false); + this.connectButton.setActionCommand(Commands.DISCONNECT); + this.connectButton.setIcon(CONNECTED_ICON); + this.connectButton.setToolTipText("Disconnect from session"); + this.connectButton.setEnabled(true); } - } - - void setPaused(final boolean paused) { - resumeButton.setEnabled(paused); - pauseButton.setEnabled(!paused); - nextButton.setEnabled(paused); } -} + + /** + * Set pause mode. + * + * @param paused <code>true</code> to set paused state + */ + private void setPaused(final boolean paused) { + this.resumeButton.setEnabled(paused); + this.pauseButton.setEnabled(!paused); + this.nextButton.setEnabled(paused); + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventDashboard.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventDashboard.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventDashboard.java Tue Apr 21 14:48:39 2015 @@ -20,248 +20,387 @@ import org.lcsim.event.EventHeader; /** - * Dashboard for displaying information about the current run. - * @author Jeremy McCormick <[log in to unmask]> + * This class implements a dashboard for displaying information about the current run. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class EventDashboard extends JPanel implements PropertyChangeListener { - - FieldPanel runNumberField = new FieldPanel("Run Number", "", 10, false); - DatePanel startDateField = new DatePanel("Run Start", "", 14, false); - DatePanel endDateField = new DatePanel("Run End", "", 14, false); - FieldPanel lengthField = new FieldPanel("Run Length [sec]", "", 12, false); - FieldPanel totalEventsField = new FieldPanel("Total Events in Run", "", 14, false); - FieldPanel elapsedTimeField = new FieldPanel("Elapsed Time [sec]", "", 14, false); - FieldPanel eventsReceivedField = new FieldPanel("Events Received", "", 14, false); - FieldPanel dataReceivedField = new FieldPanel("Data Received [MB]", "", 14, false); - FieldPanel eventNumberField = new FieldPanel("Event Number", "", 14, false); - FieldPanel dataRateField = new FieldPanel("Data Rate [MB/s]", "", 12, false); - FieldPanel eventRateField = new FieldPanel("Event Rate [Hz]", "", 14, false); - - RunModel runModel; - - static final NumberFormat formatter = new DecimalFormat("#0.0000"); - - public EventDashboard() { - build(); - } - - public EventDashboard(RunModel runModel) { - this.runModel = runModel; - this.runModel.addPropertyChangeListener(this); - build(); - } - - private void build() { - - setLayout(new FlowLayout(FlowLayout.LEADING)); - - add(runNumberField); - add(startDateField); - add(endDateField); - add(lengthField); - add(totalEventsField); - - add(elapsedTimeField); - add(eventsReceivedField); - add(dataReceivedField); - add(eventNumberField); - add(dataRateField); - add(eventRateField); - } - - public void setModel(RunModel runModel) { - this.runModel = runModel; - } - +@SuppressWarnings("serial") +final class EventDashboard extends JPanel implements PropertyChangeListener { + + /** + * Updates the fields as events are processed. + */ class EventDashboardUpdater extends CompositeRecordProcessor { - Timer timer; - - int eventsReceived; - double bytesReceived; - int totalEvents; - int eventNumber; - int runNumber = -1; - long jobStartMillis; - long lastTickMillis = 0; - static final long millis = 1000; - + /** + * Task to periodically update the fields as events are processed. + */ class RunTimerTask extends TimerTask { - - public void run() { - - double tickLengthSeconds = (System.currentTimeMillis() - lastTickMillis) / (double)millis; - int elapsedTime = (int) ((System.currentTimeMillis() - jobStartMillis) / (double)millis); - double megaBytesReceived = bytesReceived / 1000000; - totalEvents += eventsReceived; - - /* - System.out.println("tickLengthSeconds = " + tickLengthSeconds); - System.out.println("elapsedTime = " + elapsedTime); - System.out.println("eventsReceived = " + eventsReceived); - System.out.println("dataRate = " + (megaBytesReceived / tickLengthSeconds)); - System.out.println("eventNumber = " + eventNumber); - System.out.println("eventRate = " + (eventsReceived / tickLengthSeconds)); - System.out.println("totalEvents = " + totalEvents); - System.out.println("megaBytesReceived = " + megaBytesReceived); - */ - - runModel.setElapsedTime(elapsedTime); - runModel.setEventsReceived(totalEvents); - runModel.setDataRate(megaBytesReceived / tickLengthSeconds); - runModel.addDataReceived(megaBytesReceived); - runModel.setEventNumber(eventNumber); - runModel.setEventRate(eventsReceived / tickLengthSeconds); - - eventsReceived = 0; - bytesReceived = 0; - eventNumber = 0; - - lastTickMillis = System.currentTimeMillis(); - + + /** + * Run the timer task to update the GUI from the current values in the model. + */ + @Override + public void run() { + + final double tickLengthSeconds = (System.currentTimeMillis() - EventDashboardUpdater.this.lastTickMillis) + / (double) MILLIS; + final int elapsedTime = (int) ((System.currentTimeMillis() - EventDashboardUpdater.this.jobStartMillis) / (double) MILLIS); + final double megaBytesReceived = EventDashboardUpdater.this.bytesReceived / 1000000; + EventDashboardUpdater.this.totalEvents += EventDashboardUpdater.this.eventsReceived; + + // Print to System.out if debugging the processor (by default this is off). + if (DEBUG) { + System.out.println("tickLengthSeconds = " + tickLengthSeconds); + System.out.println("elapsedTime = " + elapsedTime); + System.out.println("eventsReceived = " + EventDashboardUpdater.this.eventsReceived); + System.out.println("dataRate = " + megaBytesReceived / tickLengthSeconds); + System.out.println("eventNumber = " + EventDashboardUpdater.this.eventNumber); + System.out.println("eventRate = " + EventDashboardUpdater.this.eventsReceived / tickLengthSeconds); + System.out.println("totalEvents = " + EventDashboardUpdater.this.totalEvents); + System.out.println("megaBytesReceived = " + megaBytesReceived); + + } + + EventDashboard.this.runModel.setElapsedTime(elapsedTime); + EventDashboard.this.runModel.setEventsReceived(EventDashboardUpdater.this.totalEvents); + EventDashboard.this.runModel.setDataRate(megaBytesReceived / tickLengthSeconds); + EventDashboard.this.runModel.addDataReceived(megaBytesReceived); + EventDashboard.this.runModel.setEventNumber(EventDashboardUpdater.this.eventNumber); + EventDashboard.this.runModel + .setEventRate(EventDashboardUpdater.this.eventsReceived / tickLengthSeconds); + + EventDashboardUpdater.this.eventsReceived = 0; + EventDashboardUpdater.this.bytesReceived = 0; + EventDashboardUpdater.this.eventNumber = 0; + + EventDashboardUpdater.this.lastTickMillis = System.currentTimeMillis(); + // System.out.println(); - } - } - + } + } + + /** + * Set to <code>true</code> to enable debugging. + */ + private static final boolean DEBUG = false; + + /** + * Helper for second to milliseconds conversion. + */ + private static final long MILLIS = 1000; + + /** + * Helper for second to nanoseconds conversion. + */ + private static final int NANOS = 1000000000; + + /** + * The number of bytes received. + */ + private double bytesReceived; + + /** + * The current event number. + */ + private int eventNumber; + + /** + * The number of events received. + */ + private int eventsReceived; + + /** + * The system time in milliseconds when the job started. + */ + private long jobStartMillis; + + /** + * The system time in milliseconds when the last timer tick occurred. + */ + private long lastTickMillis = 0; + + /** + * The current run number. + */ + private int runNumber = -1; + + /** + * The timer for running the update task. + */ + private Timer timer; + + /** + * The total number of events received. + */ + private int totalEvents; + + /** + * Check for head bank and update the run info if necessary. + * + * @param evioEvent the EVIO event + */ + private void checkHeadBank(final EvioEvent evioEvent) { + final BaseStructure headBank = EvioEventUtilities.getHeadBank(evioEvent); + if (headBank != null) { + final int headBankRun = headBank.getIntData()[1]; + if (headBankRun != this.runNumber) { + this.runNumber = headBankRun; + EventDashboard.this.runModel.setRunNumber(headBankRun); + EventDashboard.this.runModel.setStartDate(new Date(headBank.getIntData()[3] * MILLIS)); + } + } + } + + /** + * Perform end of job hook, which will cancel the update timer. + */ @Override - public void startJob() { - runModel.reset(); - jobStartMillis = System.currentTimeMillis(); - - // Start the timer to update GUI components about once per second. - timer = new Timer("RunModelUpdaterTimer"); - lastTickMillis = System.currentTimeMillis(); - timer.scheduleAtFixedRate(new RunTimerTask(), 0, 1000); - } - + public void endJob() { + this.timer.cancel(); + + // Push final values into GUI. + this.timer = new Timer("RunModelUpdaterEndJobTimer"); + this.timer.schedule(new RunTimerTask(), 0); + } + + /** + * Handle an EVIO END event. + * + * @param evioEvent the EVIO END event + */ + private void endRun(final EvioEvent evioEvent) { + // Get end run data. + final int[] data = EvioEventUtilities.getControlEventData(evioEvent); + if (data != null) { + final int seconds = data[0]; + final int eventCount = data[2]; + final long endMillis = (long) seconds * 1000; + + // Update the GUI. + EventDashboard.this.runModel.setEndDate(new Date(endMillis)); + EventDashboard.this.runModel.computeRunLength(); + EventDashboard.this.runModel.setTotalEvents(eventCount); + } + } + + /** + * Process a {@link org.hps.record.composite.CompositeRecord} to extract information from available event + * sources and update the running values. + */ @Override - public void process(CompositeRecord event) { + public void process(final CompositeRecord event) { // FIXME: CompositeRecord number is always -1 here. if (event.getEvioEvent() != null) { - EvioEvent evioEvent = event.getEvioEvent(); - bytesReceived += evioEvent.getTotalBytes(); + final EvioEvent evioEvent = event.getEvioEvent(); + this.bytesReceived += evioEvent.getTotalBytes(); if (EvioEventUtilities.isPreStartEvent(evioEvent)) { // Get run start info from pre start event. startRun(evioEvent); } else if (EvioEventUtilities.isEndEvent(evioEvent)) { // Get end run info from end event. endRun(evioEvent); - } else if (EvioEventUtilities.isPhysicsEvent(evioEvent)) { + } else if (EvioEventUtilities.isPhysicsEvent(evioEvent)) { // Check for run info in head bank. checkHeadBank(evioEvent); - eventNumber = evioEvent.getEventNumber(); - eventsReceived += 1; + this.eventNumber = evioEvent.getEventNumber(); + this.eventsReceived += 1; } } else if (event.getEtEvent() != null) { - bytesReceived += event.getEtEvent().getData().length; - eventNumber = event.getEtEvent().getId(); - eventsReceived += 1; + this.bytesReceived += event.getEtEvent().getData().length; + this.eventNumber = event.getEtEvent().getId(); + this.eventsReceived += 1; } else if (event.getLcioEvent() != null) { - EventHeader lcioEvent = event.getLcioEvent(); - eventNumber = lcioEvent.getEventNumber(); - if (lcioEvent.getRunNumber() != runNumber) { - runNumber = lcioEvent.getRunNumber(); + final EventHeader lcioEvent = event.getLcioEvent(); + this.eventNumber = lcioEvent.getEventNumber(); + if (lcioEvent.getRunNumber() != this.runNumber) { + this.runNumber = lcioEvent.getRunNumber(); startRun(lcioEvent); } - eventsReceived += 1; - } - } - - /** - * Check for head bank and update the run info if necessary. - * @param evioEvent The EVIO event. - */ - private void checkHeadBank(EvioEvent evioEvent) { - BaseStructure headBank = EvioEventUtilities.getHeadBank(evioEvent); - if (headBank != null) { - int headBankRun = headBank.getIntData()[1]; - if (headBankRun != runNumber) { - runNumber = headBankRun; - runModel.setRunNumber(headBankRun); - runModel.setStartDate(new Date(headBank.getIntData()[3] * 1000)); - } - } - } - - private void endRun(EvioEvent evioEvent) { - // Get end run data. - int[] data = EvioEventUtilities.getControlEventData(evioEvent); + this.eventsReceived += 1; + } + } + + /** + * Perform start of job hook which initializes this processor. + */ + @Override + public void startJob() { + EventDashboard.this.runModel.reset(); + this.jobStartMillis = System.currentTimeMillis(); + + // Start the timer to update GUI components about once per second. + this.timer = new Timer("RunModelUpdaterTimer"); + this.lastTickMillis = System.currentTimeMillis(); + this.timer.scheduleAtFixedRate(new RunTimerTask(), 0, MILLIS); + } + + /** + * Handle start of run using an LCIO event. + * + * @param lcioEvent the LCIO event + */ + private void startRun(final EventHeader lcioEvent) { + EventDashboard.this.runModel.setRunNumber(lcioEvent.getRunNumber()); + final long seconds = lcioEvent.getTimeStamp() / NANOS; + EventDashboard.this.runModel.setStartDate(new Date((int) seconds)); + } + + /** + * Handle start of run using an EVIO START event. + * + * @param evioEvent the EVIO START event + */ + private void startRun(final EvioEvent evioEvent) { + // Get start of run data. + final int[] data = EvioEventUtilities.getControlEventData(evioEvent); if (data != null) { - int seconds = data[0]; - int eventCount = data[2]; - long endMillis = ((long) seconds) * 1000; + final int seconds = data[0]; + this.runNumber = data[1]; // Update the GUI. - runModel.setEndDate(new Date(endMillis)); - runModel.computeRunLength(); - runModel.setTotalEvents(eventCount); - } - } - - private void startRun(EvioEvent evioEvent) { - // Get start of run data. - int[] data = EvioEventUtilities.getControlEventData(evioEvent); - if (data != null) { - int seconds = data[0]; - runNumber = data[1]; - - // Update the GUI. - runModel.setRunNumber(runNumber); - runModel.setStartDate(new Date(seconds * 1000)); - } - } - - private void startRun(EventHeader lcioEvent) { - runModel.setRunNumber(lcioEvent.getRunNumber()); - long seconds = lcioEvent.getTimeStamp() / 1000000000; - runModel.setStartDate(new Date((int)seconds)); - } - - @Override - public void endJob() { - timer.cancel(); - - // Push final values into GUI. - timer = new Timer("RunModelUpdaterEndJobTimer"); - timer.schedule(new RunTimerTask(), 0); + EventDashboard.this.runModel.setRunNumber(this.runNumber); + EventDashboard.this.runModel.setStartDate(new Date(seconds * MILLIS)); + } } } - - /** - * Update the GUI from changes to the backing RunModel object. + + /** + * The decimal format (shows decimal numbers to 4 places). + */ + static final NumberFormat DECIMAL_FORMAT = new DecimalFormat("#0.0000"); + + /** + * Field for showing the data rate in MB per second. + */ + private final FieldPanel dataRateField = new FieldPanel("Data Rate [MB/s]", "", 12, false); + + /** + * Field for showing the total data received in MB. + */ + private final FieldPanel dataReceivedField = new FieldPanel("Data Received [MB]", "", 14, false); + + /** + * Field for showing the elapsed job time in seconds. + */ + private final FieldPanel elapsedTimeField = new FieldPanel("Elapsed Time [sec]", "", 14, false); + + /** + * Field for showing the end date. + */ + private final DatePanel endDateField = new DatePanel("Run End", "", 14, false); + + /** + * Field for showing the current event number. + */ + private final FieldPanel eventNumberField = new FieldPanel("Event Number", "", 14, false); + + /** + * Field showing the event rate in Hertz. + */ + private final FieldPanel eventRateField = new FieldPanel("Event Rate [Hz]", "", 14, false); + + /** + * Field for showing the total number of events received. + */ + private final FieldPanel eventsReceivedField = new FieldPanel("Events Received", "", 14, false); + + /** + * Field for showing the length of the run in seconds. + */ + private final FieldPanel lengthField = new FieldPanel("Run Length [sec]", "", 12, false); + + /** + * The backing model with run and event information. + */ + private final RunModel runModel; + + /** + * Field for showing the run number. + */ + private final FieldPanel runNumberField = new FieldPanel("Run Number", "", 10, false); + + /** + * Field for showing the start date. + */ + private final DatePanel startDateField = new DatePanel("Run Start", "", 14, false); + + /** + * Field for showing the total events in the run. + */ + private final FieldPanel totalEventsField = new FieldPanel("Total Events in Run", "", 14, false); + + /** + * Class constructor which takes reference to backing model. + * + * @param runModel the backing {@link org.hps.monitoring.application.model.RunModel} with event and run information + */ + public EventDashboard(final RunModel runModel) { + this.runModel = runModel; + this.runModel.addPropertyChangeListener(this); + build(); + } + + /** + * Build the GUI components. + */ + private void build() { + + setLayout(new FlowLayout(FlowLayout.LEADING)); + + add(this.runNumberField); + add(this.startDateField); + add(this.endDateField); + add(this.lengthField); + add(this.totalEventsField); + + add(this.elapsedTimeField); + add(this.eventsReceivedField); + add(this.dataReceivedField); + add(this.eventNumberField); + add(this.dataRateField); + add(this.eventRateField); + } + + /** + * Update the GUI from changes to the backing {@link org.hps.monitoring.application.model.RunModel} object. + * + * @param evt the {@link java.beans.PropertyChangeEvent} to handle */ @Override - public void propertyChange(PropertyChangeEvent evt) { - //System.out.println("RunPanel.propertyChange - " + evt.getPropertyName()); - Object value = evt.getNewValue(); + public void propertyChange(final PropertyChangeEvent evt) { + // System.out.println("RunPanel.propertyChange - " + evt.getPropertyName()); + final Object value = evt.getNewValue(); if (RunModel.RUN_NUMBER_PROPERTY.equals(evt.getPropertyName())) { - runNumberField.setValue((Integer) value); + this.runNumberField.setValue((Integer) value); } else if (RunModel.START_DATE_PROPERTY.equals(evt.getPropertyName())) { - if (value != null) - startDateField.setValue((Date) value); - else - startDateField.setValue(""); + if (value != null) { + this.startDateField.setValue((Date) value); + } else { + this.startDateField.setValue(""); + } } else if (RunModel.END_DATE_PROPERTY.equals(evt.getPropertyName())) { - if (value != null) - endDateField.setValue((Date) value); - else - endDateField.setValue(""); + if (value != null) { + this.endDateField.setValue((Date) value); + } else { + this.endDateField.setValue(""); + } } else if (RunModel.RUN_LENGTH_PROPERTY.equals(evt.getPropertyName())) { - lengthField.setValue((Integer) value); + this.lengthField.setValue((Integer) value); } else if (RunModel.TOTAL_EVENTS_PROPERTY.equals(evt.getPropertyName())) { - totalEventsField.setValue((Integer) value); + this.totalEventsField.setValue((Integer) value); } else if (RunModel.EVENTS_RECEIVED_PROPERTY.equals(evt.getPropertyName())) { - eventsReceivedField.setValue((Integer) value); + this.eventsReceivedField.setValue((Integer) value); } else if (RunModel.ELAPSED_TIME_PROPERTY.equals(evt.getPropertyName())) { - elapsedTimeField.setValue((Integer) value); + this.elapsedTimeField.setValue((Integer) value); } else if (RunModel.DATA_RECEIVED_PROPERTY.equals(evt.getPropertyName())) { - dataReceivedField.setValue(formatter.format((Double) value)); + this.dataReceivedField.setValue(DECIMAL_FORMAT.format(value)); } else if (RunModel.EVENT_NUMBER_PROPERTY.equals(evt.getPropertyName())) { - eventNumberField.setValue((Integer) value); + this.eventNumberField.setValue((Integer) value); } else if (RunModel.DATA_RATE_PROPERTY.equals(evt.getPropertyName())) { - dataRateField.setValue(formatter.format((Double) value)); + this.dataRateField.setValue(DECIMAL_FORMAT.format(value)); } else if (RunModel.EVENT_RATE_PROPERTY.equals(evt.getPropertyName())) { - eventRateField.setValue(formatter.format((Double) value)); + this.eventRateField.setValue(DECIMAL_FORMAT.format(value)); } } -} +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventProcessing.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventProcessing.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventProcessing.java Tue Apr 21 14:48:39 2015 @@ -18,7 +18,6 @@ import org.hps.monitoring.application.model.SteeringType; import org.hps.monitoring.application.util.ErrorHandler; import org.hps.monitoring.application.util.EtSystemUtil; -import org.hps.monitoring.application.util.SyncEventProcessor; import org.hps.monitoring.subsys.et.EtSystemMonitor; import org.hps.monitoring.subsys.et.EtSystemStripCharts; import org.hps.record.LCSimEventBuilder; @@ -27,13 +26,9 @@ import org.hps.record.composite.CompositeRecordProcessor; import org.hps.record.composite.EventProcessingThread; import org.hps.record.enums.DataSourceType; -import org.hps.record.epics.EpicsEtProcessor; import org.hps.record.et.EtConnection; -import org.hps.record.et.EtEventProcessor; import org.hps.record.et.EtStationThread; -import org.hps.record.et.PreStartProcessor; import org.hps.record.evio.EvioDetectorConditionsProcessor; -import org.hps.record.evio.EvioEventConstants; import org.jlab.coda.et.EtConstants; import org.jlab.coda.et.exception.EtClosedException; import org.jlab.coda.et.exception.EtException; @@ -43,665 +38,722 @@ import org.lcsim.util.Driver; /** - * This class encapsulates all of the logic involved with processing events and managing the related - * state and objects within the monitoring application. - * - * @author Jeremy McCormick <[log in to unmask]> + * This class encapsulates all of the logic involved with processing events and managing the related state and objects + * within the monitoring application. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class EventProcessing { - - SessionState sessionState; - MonitoringApplication application; - ConfigurationModel configurationModel; - ConnectionStatusModel connectionModel; - ErrorHandler errorHandler; - Logger logger; - - /** - * This class is used to organize the objects for an event processing session. - */ - class SessionState { - - List<CompositeRecordProcessor> processors; - List<Driver> drivers; - List<ConditionsListener> conditionsListeners; - - JobManager jobManager; - LCSimEventBuilder eventBuilder; - CompositeLoop loop; - - boolean usingEtServer; - - EventProcessingThread processingThread; - Thread sessionWatchdogThread; - ThreadGroup stationThreadGroup = new ThreadGroup("Station Threads"); - List<EtStationThread> stations = new ArrayList<EtStationThread>(); - EtConnection connection; - } - - /** - * Initialize with reference to the current monitoring application and a list of extra - * processors to add to the loop after configuration. - * @param application The current monitoring application. - * @param processors A list of processors to add after configuration is performed. - */ - EventProcessing( - MonitoringApplication application, - List<CompositeRecordProcessor> processors, - List<Driver> drivers, - List<ConditionsListener> conditionsListeners) { - +final class EventProcessing { + + /** + * This class organizes and encapsulates most of the objects used by an event processing session. + */ + private final class SessionState { + + /** + * A list of extra {@link org.lcsim.conditions.ConditionsListener} objects to add to the loop. + */ + private List<ConditionsListener> conditionsListeners; + + /** + * An {@link org.hps.record.et.EtConnection} with ET configuration (can be null if using a file source). + */ + private EtConnection connection; + + /** + * A list of extra {@link org.lcsim.util.Driver} objects to add to the loop. + */ + private List<Driver> drivers; + + /** + * The class for building the LCSim events from EVIO data. + */ + private LCSimEventBuilder eventBuilder; + + /** + * The LCSim {@link org.hps.job.JobManager} which handles the <code>Driver</code> setup from XML steering files. + */ + private JobManager jobManager; + + /** + * The loop which manages the ET to EVIO to LCIO event building and processing. + */ + private CompositeLoop loop; + + /** + * The {@link org.hps.record.composite.EventProcessingThread} on which event processing executes. + */ + private EventProcessingThread processingThread; + + /** + * The list of extra {@link org.hps.record.composite.CompositeRecordProcessor} objects to add to the loop. + */ + private List<CompositeRecordProcessor> processors; + + /** + * A {@link java.lang.Thread} which is used to monitor the event processing. + */ + private Thread sessionWatchdogThread; + + /** + * A list of ET stations on separate threads (currently unused). + */ + private List<EtStationThread> stations = new ArrayList<EtStationThread>(); + + /** + * The ET station thread group (currently unused). + */ + private ThreadGroup stationThreadGroup = new ThreadGroup("Station Threads"); + + /** + * This is <code>true</code> if the session will connect to a network ET event server. + */ + private boolean usingEtServer; + } + + /** + * This class will cause the application to disconnect from the current event processing session if the event + * processing thread completes. + */ + private final class SessionWatchdogThread extends Thread { + + /** + * A reference to the current {{@link #EventProcessing(Thread)}. + */ + private final Thread processingThread; + + /** + * Class constructor. + * + * @param processingThread the current {{@link #EventProcessing(Thread)} + */ + private SessionWatchdogThread(final Thread processingThread) { + this.processingThread = processingThread; + } + + /** + * Run this thread, which will disconnect from the current session if the event processing ends for any reason. + */ + @Override + public void run() { + try { + // This thread waits on the event processing thread to die. + this.processingThread.join(); + + // Activate a disconnect using the ActionEvent which is used by the disconnect button. + EventProcessing.this.logger.finest("processing thread ended so automatic disconnect is happening"); + EventProcessing.this.application.actionPerformed(new ActionEvent(Thread.currentThread(), 0, + Commands.DISCONNECT)); + + } catch (final InterruptedException e) { + EventProcessing.this.logger.finest("SessionWatchdogThread got interrupted"); + // This happens when the thread is interrupted by the user pressing the disconnect button. + } + } + } + + /** + * Create the select array from event selection in ET stations (not currently used). + * + * @return The select array. + */ + static int[] createSelectArray() { + final int[] select = new int[EtConstants.stationSelectInts]; + Arrays.fill(select, -1); + return select; + } + + /** + * Reference to the current application. + */ + private MonitoringApplication application; + + /** + * Reference to the global configuration model. + */ + private ConfigurationModel configurationModel; + + /** + * Reference to the global connection model. + */ + private ConnectionStatusModel connectionModel; + + /** + * The error handler, which is just a reference to the application's error handler. + */ + private ErrorHandler errorHandler; + + /** + * The logger to use for message which is the application's logger. + */ + private Logger logger; + + /** + * The current {@link EventProcessing.SessionState} object which has all of the session state for event processing. + */ + private SessionState sessionState; + + /** + * Class constructor, which will initialize with reference to the current monitoring application and lists of extra + * processors to add to the loop, as well as supplemental conditions listeners that activate when the conditions + * change. + * + * @param application the current monitoring application object + * @param processors a list of processors to add after configuration is performed + * @param drivers a list of extra {@link org.lcsim.util.Driver} objects to add to the loop + * @param conditionsListeners a list of extra {@link org.lcsim.conditions.ConditionsListener} to add to the loop + */ + EventProcessing(final MonitoringApplication application, final List<CompositeRecordProcessor> processors, + final List<Driver> drivers, final List<ConditionsListener> conditionsListeners) { + this.application = application; - logger = MonitoringApplication.logger; - configurationModel = application.configurationModel; - connectionModel = application.connectionModel; - errorHandler = application.errorHandler; - - sessionState = new SessionState(); - sessionState.processors = processors; - sessionState.drivers = drivers; - sessionState.conditionsListeners = conditionsListeners; - sessionState.usingEtServer = application.configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER); - } - - /** - * Setup this class from the global configuration. - * @param configurationModel The global configuration. - */ - void setup(ConfigurationModel configurationModel) { - + this.logger = application.getLogger(); + this.configurationModel = application.getConfigurationModel(); + this.connectionModel = application.getConnectionModel(); + this.errorHandler = application.getErrorHandler(); + + this.sessionState = new SessionState(); + this.sessionState.processors = processors; + this.sessionState.drivers = drivers; + this.sessionState.conditionsListeners = conditionsListeners; + this.sessionState.usingEtServer = application.getConfigurationModel().getDataSourceType() + .equals(DataSourceType.ET_SERVER); + } + + /** + * Close the current ET connection. + * <p> + * This method does not need to be <code>synchronized</code>, because it is only called from the + * {@link #disconnect()} method which is itself <code>synchronized</code>. + */ + private void closeEtConnection() { + if (this.sessionState.connection != null) { + this.logger.fine("closing ET connection"); + if (this.sessionState.connection.getEtSystem().alive()) { + this.logger.finest("cleaning up the connection ..."); + this.sessionState.connection.cleanup(); + this.logger.finest("connection cleanup successful"); + } + this.sessionState.connection = null; + this.logger.fine("ET connection closed"); + } + } + + /** + * Connect to the ET system using the current connection settings. + * + * @throws IOException if any error occurs while creating the ET connection + */ + synchronized void connect() throws IOException { + // Setup the network connection if using an ET server. + if (this.usingEtServer()) { + // Create a connection to the ET server. + try { + this.logger.fine("connecting to ET system ..."); + + // Create the main ET system connection. + this.createEtConnection(); + + // FIXME: Separate event processing ET stations not currently used due to synchronization and ET issues. + + // Add an attachment that listens for DAQ configuration changes via physics SYNC events. + // createSyncStation(); + + // Add an attachment which listens for EPICs events with scalar data. + // createEpicsStation(); + + // Add an attachment that listens for PRESTART events. + // createPreStartStation(); + + } catch (final Exception e) { + throw new IOException(e); + } + + this.logger.fine("ET system is connected"); + } else { + // This is when a direct file source is used and ET is not needed. + this.connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED); + } + + } + + /** + * Create a connection to an ET system using current parameters from the GUI. + * <p> + * This method does not need to be <code>synchronized</code>, because it is only called from the {@link #connect()} + * method which is itself <code>synchronized</code>. + */ + private void createEtConnection() { + // Setup connection to ET system. + this.sessionState.connection = EtSystemUtil.createEtConnection(this.configurationModel); + + if (this.sessionState.connection != null) { + // Set status to connected as there is now a live ET connection. + this.connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED); + } else { + this.errorHandler.setError(new RuntimeException("Failed to create ET connection.")).log().printStackTrace() + .raiseException(); + } + } + + /** + * Create the event builder for converting EVIO events to LCSim. + * + * @param configurationModel the current global {@link org.hps.monitoring.application.ConfigurationModel} object + */ + private void createEventBuilder(final ConfigurationModel configurationModel) { + + // Get the class for the event builder. + final String eventBuilderClassName = configurationModel.getEventBuilderClassName(); + + try { + // Create a new instance of the builder class. + this.sessionState.eventBuilder = (LCSimEventBuilder) Class.forName(eventBuilderClassName, true, + Thread.currentThread().getContextClassLoader()).newInstance(); + } catch (final Exception e) { + throw new RuntimeException("Failed to create LCSimEventBuilder.", e); + } + + // Add the builder as a listener so it is notified when conditions change. + ConditionsManager.defaultInstance().addConditionsListener(this.sessionState.eventBuilder); + } + + /** + * Disconnect from the current session, closing the ET connection if necessary. + */ + synchronized void disconnect() { + + // Cleanup the ET connection. + if (this.usingEtServer()) { + this.closeEtConnection(); + } + + // Change application state to disconnected. + this.connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTED); + } + + /** + * Invalidate all of the local variables and session state so that this object is not usable after a disconnect. + */ + void invalidate() { + + this.application = null; + this.logger = null; + this.configurationModel = null; + this.connectionModel = null; + this.errorHandler = null; + + this.sessionState.conditionsListeners = null; + this.sessionState.drivers = null; + this.sessionState.processors = null; + this.sessionState.jobManager = null; + this.sessionState.eventBuilder = null; + this.sessionState.loop = null; + this.sessionState.processingThread = null; + this.sessionState.sessionWatchdogThread = null; + this.sessionState.stationThreadGroup = null; + this.sessionState.stations = null; + this.sessionState.connection = null; + + this.sessionState = null; + } + + /** + * Return <code>true</code> if the event processing thread is valid (non-null) and active. + * + * @return <code>true</code> if event processing thread is active + */ + boolean isActive() { + return this.sessionState.processingThread != null && this.sessionState.processingThread.isAlive(); + } + + /** + * Interrupt and join the processing watchdog thread. + * <p> + * This will happen if there is a user requested disconnect from pushing the button in the GUI. + */ + synchronized void killWatchdogThread() { + // Is the session watchdog thread not null? + if (this.sessionState.sessionWatchdogThread != null) { + this.logger.finest("killing watchdog thread ..."); + // Is the thread still alive? + if (this.sessionState.sessionWatchdogThread.isAlive()) { + // Interrupt the thread which should cause it to stop. + this.sessionState.sessionWatchdogThread.interrupt(); + try { + // This should always work once the thread is interrupted. + this.sessionState.sessionWatchdogThread.join(); + } catch (final InterruptedException e) { + } + } + // Set the thread object to null. + this.sessionState.sessionWatchdogThread = null; + this.logger.finest("watchdog thread killed"); + } + } + + /** + * Get the next event from the loop if in pause mode. + */ + synchronized void next() { + this.logger.finest("getting next event"); + if (this.connectionModel.getPaused()) { + this.connectionModel.setPaused(false); + this.sessionState.loop.execute(Command.GO_N, 1L, true); + this.connectionModel.setPaused(true); + } + this.logger.finest("got next event"); + } + + /** + * Notify the loop to pause the event processing. + */ + synchronized void pause() { + this.logger.finest("pausing"); + if (!this.connectionModel.getPaused()) { + this.sessionState.loop.pause(); + this.connectionModel.setPaused(true); + } + this.logger.finest("paused"); + } + + /** + * Resume processing events from pause mode by resuming loop event processing. + */ + synchronized void resume() { + this.logger.finest("resuming"); + if (this.connectionModel.getPaused()) { + // Notify event processor to continue. + this.sessionState.loop.resume(); + this.connectionModel.setPaused(false); + } + this.logger.finest("resumed"); + } + + /** + * Setup this class from the global {@link org.hps.monitoring.model.ConfigurationModel} object. + * + * @param configurationModel the global @link org.hps.monitoring.model.ConfigurationModel} object + */ + void setup(final ConfigurationModel configurationModel) { + // Setup LCSim from the configuration. - setupLcsim(configurationModel); + this.setupLcsim(configurationModel); // Now setup the CompositeLoop. - setupLoop(configurationModel); - } - - /** - * @param configurationModel - */ - void setupLcsim(ConfigurationModel configurationModel) { - MonitoringApplication.logger.info("setting up lcsim"); + this.setupLoop(configurationModel); + } + + /** + * Setup LCSim event processing from the global {@link org.hps.monitoring.model.ConfigurationModel} object. + * + * @param configurationModel the global @link org.hps.monitoring.model.ConfigurationModel} object + */ + private void setupLcsim(final ConfigurationModel configurationModel) { + this.logger.info("setting up lcsim"); // Get steering resource or file as a String parameter. String steering = null; - SteeringType steeringType = configurationModel.getSteeringType(); + final SteeringType steeringType = configurationModel.getSteeringType(); if (steeringType.equals(SteeringType.FILE)) { steering = configurationModel.getSteeringFile(); } else { steering = configurationModel.getSteeringResource(); } - MonitoringApplication.logger.config("set steering " + steering + " with type " + (steeringType == SteeringType.RESOURCE ? "RESOURCE" : "FILE")); + this.logger.config("set steering " + steering + " with type " + + (steeringType == SteeringType.RESOURCE ? "RESOURCE" : "FILE")); try { // Create the job manager. A new conditions manager is instantiated from this call but not configured. - sessionState.jobManager = new JobManager(); + this.sessionState.jobManager = new JobManager(); // Add conditions listeners after new database conditions manager is initialized from the job manager. - DatabaseConditionsManager conditionsManager = DatabaseConditionsManager.getInstance(); - for (ConditionsListener conditionsListener : sessionState.conditionsListeners) { - logger.config("adding conditions listener " + conditionsListener.getClass().getName()); + final DatabaseConditionsManager conditionsManager = DatabaseConditionsManager.getInstance(); + for (final ConditionsListener conditionsListener : this.sessionState.conditionsListeners) { + this.logger.config("adding conditions listener " + conditionsListener.getClass().getName()); conditionsManager.addConditionsListener(conditionsListener); } if (configurationModel.hasValidProperty(ConfigurationModel.DETECTOR_ALIAS_PROPERTY)) { // Set a detector alias. - ConditionsReader.addAlias(configurationModel.getDetectorName(), "file://" + configurationModel.getDetectorAlias()); - logger.config("using detector alias " + configurationModel.getDetectorAlias()); + ConditionsReader.addAlias(configurationModel.getDetectorName(), + "file://" + configurationModel.getDetectorAlias()); + this.logger.config("using detector alias " + configurationModel.getDetectorAlias()); } // Setup the event builder to translate from EVIO to LCIO. // This must happen before Driver setup so the builder's listeners are activated first! - createEventBuilder(configurationModel); + this.createEventBuilder(configurationModel); // Configure the job manager for the XML steering. - sessionState.jobManager.setPerformDryRun(true); + this.sessionState.jobManager.setPerformDryRun(true); if (steeringType == SteeringType.RESOURCE) { - setupSteeringResource(steering); + this.setupSteeringResource(steering); } else if (steeringType.equals(SteeringType.FILE)) { - setupSteeringFile(steering); - } - - // Set conditions tag. - if (configurationModel.hasValidProperty(ConfigurationModel.CONDITIONS_TAG_PROPERTY) && !configurationModel.getConditionsTag().equals("")) { - logger.config("conditions tag is set to " + configurationModel.getConditionsTag()); + this.setupSteeringFile(steering); + } + + // Set conditions tag if applicable. + if (configurationModel.hasValidProperty(ConfigurationModel.CONDITIONS_TAG_PROPERTY) + && !configurationModel.getConditionsTag().equals("")) { + this.logger.config("conditions tag is set to " + configurationModel.getConditionsTag()); } else { - logger.config("conditions NOT using a tag"); + this.logger.config("conditions NOT using a tag"); } // Is there a user specified run number from the JobPanel? if (configurationModel.hasValidProperty(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)) { - int userRunNumber = configurationModel.getUserRunNumber(); - String detectorName = configurationModel.getDetectorName(); - logger.config("setting user run number " + userRunNumber + " with detector " + detectorName); + final int userRunNumber = configurationModel.getUserRunNumber(); + final String detectorName = configurationModel.getDetectorName(); + this.logger.config("setting user run number " + userRunNumber + " with detector " + detectorName); conditionsManager.setDetector(configurationModel.getDetectorName(), userRunNumber); if (configurationModel.hasPropertyKey(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) { // Freeze the conditions system to ignore run numbers from the events. - logger.config("user configured to freeze conditions system"); + this.logger.config("user configured to freeze conditions system"); conditionsManager.freeze(); } else { // Allow run numbers to be picked up from the events. - logger.config("user run number provided but conditions system is NOT frozen"); + this.logger.config("user run number provided but conditions system is NOT frozen"); conditionsManager.unfreeze(); } } - logger.info("lcsim setup was successful"); - - } catch (Throwable t) { + this.logger.info("lcsim setup was successful"); + + } catch (final Throwable t) { throw new RuntimeException("Error setting up LCSim.", t); } } /** - * Create the event builder for converting EVIO events to LCSim. - */ - void createEventBuilder(ConfigurationModel configurationModel) { - - // Get the class for the event builder. - String eventBuilderClassName = configurationModel.getEventBuilderClassName(); - - try { - // Create a new instance of the builder class. - sessionState.eventBuilder = (LCSimEventBuilder) Class.forName(eventBuilderClassName, true, Thread.currentThread().getContextClassLoader()).newInstance(); - } catch (Exception e) { - throw new RuntimeException("Failed to create LCSimEventBuilder.", e); - } - - // Add the builder as a listener so it is notified when conditions change. - ConditionsManager.defaultInstance().addConditionsListener(sessionState.eventBuilder); - } - - /** - * Setup the loop from the global configuration. - * @param configurationModel The global configuration. - */ - void setupLoop(ConfigurationModel configurationModel) { - - logger.config("setting up record loop ..."); - - CompositeLoopConfiguration loopConfig = new CompositeLoopConfiguration() - .setStopOnEndRun(configurationModel.getDisconnectOnEndRun()) - .setStopOnErrors(configurationModel.getDisconnectOnError()) - .setDataSourceType(configurationModel.getDataSourceType()) - .setProcessingStage(configurationModel.getProcessingStage()) - .setEtConnection(sessionState.connection) - .setFilePath(configurationModel.getDataSourcePath()) - .setLCSimEventBuilder(sessionState.eventBuilder); - - logger.config("data source path is " + configurationModel.getDataSourcePath()); - logger.config("data source type is " + configurationModel.getDataSourceType()); - + * Setup the {@link org.hps.record.composite.CompositeLoop} from the global + * {@link org.hps.monitoring.model.ConfigurationModel} object. + * + * @param configurationModel the global {@link org.hps.monitoring.model.ConfigurationModel} object + */ + private void setupLoop(final ConfigurationModel configurationModel) { + + this.logger.config("setting up record loop ..."); + + // Initialize the loop from the ConfigurationModel. + final CompositeLoopConfiguration loopConfig = new CompositeLoopConfiguration() + .setStopOnEndRun(configurationModel.getDisconnectOnEndRun()) + .setStopOnErrors(configurationModel.getDisconnectOnError()) + .setDataSourceType(configurationModel.getDataSourceType()) + .setProcessingStage(configurationModel.getProcessingStage()) + .setEtConnection(this.sessionState.connection).setFilePath(configurationModel.getDataSourcePath()) + .setLCSimEventBuilder(this.sessionState.eventBuilder); + + this.logger.config("data source path is " + configurationModel.getDataSourcePath()); + this.logger.config("data source type is " + configurationModel.getDataSourceType()); + + // Set the max events. if (configurationModel.hasValidProperty(ConfigurationModel.MAX_EVENTS_PROPERTY)) { - long maxEvents = configurationModel.getMaxEvents(); + final long maxEvents = configurationModel.getMaxEvents(); if (maxEvents > 0L) { loopConfig.setMaxRecords(maxEvents); } } // Add all Drivers from the JobManager. - for (Driver driver : sessionState.jobManager.getDriverExecList()) { + for (final Driver driver : this.sessionState.jobManager.getDriverExecList()) { loopConfig.add(driver); - logger.config("added Driver " + driver.getName()); + this.logger.config("added Driver " + driver.getName()); } // Using ET server? if (configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) { // ET system monitor. - logger.config("added EtSystemMonitor"); + this.logger.config("added EtSystemMonitor"); loopConfig.add(new EtSystemMonitor()); // ET system strip charts. - logger.config("added EtSystemStripCharts"); + this.logger.config("added EtSystemStripCharts"); loopConfig.add(new EtSystemStripCharts()); } // Add extra CompositeRecordProcessors to the loop config. - for (CompositeRecordProcessor processor : sessionState.processors) { + for (final CompositeRecordProcessor processor : this.sessionState.processors) { loopConfig.add(processor); - logger.config("added extra processor " + processor.getClass().getSimpleName()); + this.logger.config("added extra processor " + processor.getClass().getSimpleName()); } // Add extra Drivers to the loop config. - for (Driver driver : sessionState.drivers) { + for (final Driver driver : this.sessionState.drivers) { loopConfig.add(driver); - logger.config("added extra Driver " + driver.getName()); + this.logger.config("added extra Driver " + driver.getName()); } // Enable conditions system activation from EVIO event data in case the PRESTART is missed. loopConfig.add(new EvioDetectorConditionsProcessor(configurationModel.getDetectorName())); - logger.config("added EvioDetectorConditionsProcessor to job with detector " + configurationModel.getDetectorName()); + this.logger.config("added EvioDetectorConditionsProcessor to job with detector " + + configurationModel.getDetectorName()); // Create the CompositeLoop with the configuration. - sessionState.loop = new CompositeLoop(loopConfig); - - logger.config("record loop is setup"); - } - - /** - * Setup a steering file on disk. - * @param steering The steering file. - */ - void setupSteeringFile(String steering) { - sessionState.jobManager.setup(new File(steering)); - } - - /** - * Setup a steering resource. - * @param steering The steering resource. - * @throws IOException if there is a problem setting up or accessing the resource. - */ - void setupSteeringResource(String steering) throws IOException { - InputStream is = this.getClass().getClassLoader().getResourceAsStream(steering); - if (is == null) + this.sessionState.loop = new CompositeLoop(loopConfig); + + this.logger.config("record loop is setup"); + } + + /** + * Setup XML steering from a file from disk. + * + * @param steering the steering file path + */ + private void setupSteeringFile(final String steering) { + this.sessionState.jobManager.setup(new File(steering)); + } + + /** + * Setup XML steering from a jar resource. + * + * @param steering the steering resource + * @throws IOException if there is a problem accessing or setting up the resource + */ + private void setupSteeringResource(final String steering) throws IOException { + final InputStream is = this.getClass().getClassLoader().getResourceAsStream(steering); + if (is == null) { throw new IOException("Steering resource is not accessible or does not exist."); - sessionState.jobManager.setup(is); + } + this.sessionState.jobManager.setup(is); is.close(); } + /** + * Start event processing on a separate thread and also start the watchdog thread. + * <p> + * This method is called externally by the app to activate event processing after it is initialized and configured. + */ + synchronized void start() { + + this.logger.fine("event processing threads are starting"); + + // Start the event processing thread. + this.sessionState.processingThread = new EventProcessingThread(this.sessionState.loop); + this.sessionState.processingThread.start(); + + // Start the watch dog thread which will auto-disconnect when event processing is done. + this.sessionState.sessionWatchdogThread = new SessionWatchdogThread(this.sessionState.processingThread); + this.sessionState.sessionWatchdogThread.start(); + + this.logger.fine("started event processing threads"); + } + + /** + * Stop the current session, which will bring down the current ET client connection and activate end-of-job and + * end-of-run hooks on all registered event processors. + * <p> + * This method is called externally by the app to stop an event processing session e.g. from action event handling. + */ synchronized void stop() { // Kill session watchdog thread. - killWatchdogThread(); - - // Wake up all ET stations to unblock the system and make sure secondary stations are detached. - if (usingEtServer()) { - wakeUpEtStations(); - } - - // Stop the event processing now that ET system is unblocked. - logger.fine("sending STOP command to loop ..."); - sessionState.loop.execute(Command.STOP); - logger.fine("loop got command STOP"); - - // Cleanup the event processing thread since it was told to stop now. + this.killWatchdogThread(); + + // Wake up all ET stations to unblock the system and make sure stations are detached properly. + if (this.usingEtServer()) { + this.wakeUpEtStations(); + } + + // Stop the event processing now that ET system should be unblocked. + this.logger.finer("sending STOP command to loop ..."); + this.sessionState.loop.execute(Command.STOP); + this.logger.finer("loop got STOP command"); + + this.logger.finer("processing thread is alive: " + this.sessionState.processingThread.isAlive()); + try { - logger.fine("waiting for event processing thread to end ..."); - sessionState.processingThread.join(); - logger.fine("event processing thread ended"); - } catch (InterruptedException e) { + // Give the event processing thread a chance to end cleanly. + this.logger.finer("waiting for event processing thread to end ..."); + this.sessionState.processingThread.join(5000); + this.logger.finer("processing thread is alive: " + this.sessionState.processingThread.isAlive()); + // this.logger.finer("event processing thread ended cleanly"); + } catch (final InterruptedException e) { e.printStackTrace(); } + try { + this.logger.finer("processing thread is alive: " + this.sessionState.processingThread.isAlive()); + // In this case the thread needs to be interrupted and then joined. + this.logger.finer("interrupting event processing thread"); + this.sessionState.processingThread.interrupt(); + this.sessionState.processingThread.join(); + this.logger.finer("event processing thread ended after interrupt"); + } catch (final InterruptedException e) { + e.printStackTrace(); + } + // Notify of last error that occurred in event processing. - if (sessionState.loop.getLastError() != null) { + if (this.sessionState.loop.getLastError() != null) { // Log the error. - errorHandler.setError(sessionState.loop.getLastError()).log(); + this.errorHandler.setError(this.sessionState.loop.getLastError()).log(); } // Invalidate the loop. - sessionState.loop = null; + this.sessionState.loop = null; // Disconnect from the ET system. - disconnect(); - + this.disconnect(); + // Invalidate the event processing object so it is unusable now. - invalidate(); - } - - /** - * Wake up all ET stations associated with event processing. - */ - void wakeUpEtStations() { - if (sessionState.connection != null) { - logger.fine("waking up ET stations ..."); + this.invalidate(); + } + + /** + * Return <code>true</code> if using an ET server. + * + * @return <code>true</code> if using an ET server in the current session + */ + private boolean usingEtServer() { + return this.sessionState.usingEtServer; + } + + /** + * Wake up all ET stations associated with the event processing. + */ + private void wakeUpEtStations() { + if (this.sessionState.connection != null) { + this.logger.fine("waking up ET stations ..."); // Wake up secondary ET stations. - for (EtStationThread station : sessionState.stations) { - + for (final EtStationThread station : this.sessionState.stations) { + // First unblock if in ET call. station.wakeUp(); - + // Next interrupt so that it will definitely stop. station.interrupt(); } // Wait for station threads to die after being woken up. - while (sessionState.stationThreadGroup.activeCount() != 0) { - logger.finest("waiting for station threads to die ..."); - Object lock = new Object(); + while (this.sessionState.stationThreadGroup.activeCount() != 0) { + this.logger.finest("waiting for station threads to die ..."); + final Object lock = new Object(); synchronized (lock) { try { lock.wait(500); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { e.printStackTrace(); } } } - - sessionState.stationThreadGroup.destroy(); - - logger.finest("station threads destroyed"); + + this.sessionState.stationThreadGroup.destroy(); + + this.logger.finest("station threads destroyed"); // Wake up the primary ET station doing the event processing. - logger.finest("waking up event processing station ..."); + this.logger.finest("waking up event processing station ..."); try { - sessionState.connection.getEtSystem().wakeUpAll(sessionState.connection.getEtStation()); - logger.finest("event processing station was woken up"); + this.sessionState.connection.getEtSystem().wakeUpAll(this.sessionState.connection.getEtStation()); + this.logger.finest("event processing station was woken up"); } catch (IOException | EtException | EtClosedException e) { e.printStackTrace(); } - logger.finest("ET stations all woken up"); - } - } - - /** - * Start event processing on the event processing thread and start the watchdog thread. - */ - synchronized void start() { - - logger.fine("event processing threads are starting"); - - // Start the event processing thread. - sessionState.processingThread = new EventProcessingThread(sessionState.loop); - sessionState.processingThread.start(); - - // Start the watch dog thread which will auto-disconnect when event processing is done. - sessionState.sessionWatchdogThread = new SessionWatchdogThread(sessionState.processingThread); - sessionState.sessionWatchdogThread.start(); - - logger.fine("started event processing threads"); - } - - /** - * Notify the event processor to pause processing. - */ - synchronized void pause() { - logger.finest("pausing"); - if (!connectionModel.getPaused()) { - sessionState.loop.pause(); - connectionModel.setPaused(true); - } - logger.finest("paused"); - } - - /** - * Get next event if in pause mode. - */ - synchronized void next() { - logger.finest("getting next event"); - if (connectionModel.getPaused()) { - connectionModel.setPaused(false); - sessionState.loop.execute(Command.GO_N, 1L, true); - connectionModel.setPaused(true); - } - logger.finest("got next event"); - } - - /** - * Resume processing events from pause mode. - */ - synchronized void resume() { - logger.finest("resuming"); - if (connectionModel.getPaused()) { - // Notify event processor to continue. - sessionState.loop.resume(); - connectionModel.setPaused(false); - } - logger.finest("resumed"); - } - - /** - * Interrupt and join to the processing watchdog thread. - */ - synchronized void killWatchdogThread() { - // Is the session watchdog thread not null? - if (sessionState.sessionWatchdogThread != null) { - logger.finest("killing watchdog thread ..."); - // Is the thread still alive? - if (sessionState.sessionWatchdogThread.isAlive()) { - // Interrupt the thread which should cause it to stop. - sessionState.sessionWatchdogThread.interrupt(); - try { - // This should always work once the thread is interrupted. - sessionState.sessionWatchdogThread.join(); - } catch (InterruptedException e) { - // This should never happen. - e.printStackTrace(); - } - } - // Set the thread object to null. - sessionState.sessionWatchdogThread = null; - logger.finest("watchdog thread killed"); - } - } - - /** - * Cleanup the ET connection. - */ - synchronized void closeEtConnection() { - if (sessionState.connection != null) { - logger.fine("closing ET connection"); - if (sessionState.connection.getEtSystem().alive()) { - logger.finest("cleaning up the connection ..."); - sessionState.connection.cleanup(); - logger.finest("connection cleanup successful"); - } - sessionState.connection = null; - logger.fine("ET connection closed"); - } - } - - /** - * True if the processing thread is valid and active. - * @return True if processing thread is active. - */ - boolean isActive() { - return sessionState.processingThread != null && sessionState.processingThread.isAlive(); - } - - /** - * Connect to the ET system using the current connection settings. - */ - synchronized void connect() throws IOException { - // Setup the network connection if using an ET server. - if (usingEtServer()) { - // Create a connection to the ET server. - try { - logger.fine("connecting to ET system ..."); - - // Create the main ET system connection. - createEtConnection(); - - // Add an attachment that listens for DAQ configuration changes via physics SYNC events. - //createSyncStation(); - - // Add an attachment which listens for EPICs events with scalar data. - //createEpicsStation(); - - // Add an attachment that listens for PRESTART events. - //createPreStartStation(); - - } catch (Exception e) { - throw new IOException(e); - } - - logger.fine("ET system is connected"); - } else { - // This is when a direct file source is used and ET is not needed. - connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED); - } - - } - - /** - * True if using an ET server. - * @return True if using an ET server. - */ - boolean usingEtServer() { - return sessionState.usingEtServer; - } - - /** - * Create a connection to an ET system using current parameters from the GUI. - */ - synchronized void createEtConnection() { - // Setup connection to ET system. - sessionState.connection = EtSystemUtil.createEtConnection(configurationModel); - - if (sessionState.connection != null) { - // Set status to connected as there is now a live ET connection. - connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED); - } else { - errorHandler.setError(new RuntimeException("Failed to create ET connection.")).log().printStackTrace().raiseException(); - } - } - - /** - * Create the select array from event selection in ET stations. - * @return The select array. - */ - static int[] createSelectArray() { - int select[] = new int[EtConstants.stationSelectInts]; - Arrays.fill(select, -1); - return select; - } - - /** - * Create a station that listens for physics sync events - * containing DAQ configuration. - */ - void createSyncStation() { - - // Sync events have bits 6 and 7 set. - int syncEventType = 0; - syncEventType = syncEventType ^ (1 << 6); - syncEventType = syncEventType ^ (1 << 7); - int select[] = createSelectArray(); - select[1] = syncEventType; - - createStationThread( - new SyncEventProcessor(), - "SYNC", - 1, - select); - } - - /** - * Create a station that listens for PRESTART events - * to initialize the conditions system. - */ - void createPreStartStation() { - - // Select only PRESTART events. - int[] select = createSelectArray(); - select[0] = EvioEventConstants.PRESTART_EVENT_TAG; - - createStationThread( - new PreStartProcessor(configurationModel.getDetectorName()), - "PRESTART", - 1, - select); - } - - /** - * Create a station that listens for EPICS control events (currently not activated). - */ - void createEpicsStation() { - - // Select only EPICS events. - int[] select = createSelectArray(); - select[0] = EvioEventConstants.EPICS_EVENT_TAG; - - createStationThread( - new EpicsEtProcessor(), - "EPICS", - 1, - select); - } - - /** - * Create an ET station thread. - * @param processor The event processor to run on the thread. - * @param nameAppend The string to append for naming this station. - * @param stationPosition The position of the station. - * @param select The event selection data array. - */ - void createStationThread(EtEventProcessor processor, String nameAppend, int stationPosition, int[] select) { - EtStationThread stationThread = new EtStationThread( - processor, - sessionState.connection.getEtSystem(), - sessionState.connection.getEtStation().getName() + "_" + nameAppend, - stationPosition, - select); - new Thread(sessionState.stationThreadGroup, stationThread).start(); - sessionState.stations.add(stationThread); - logger.config("started ET station " + nameAppend); - StringBuffer sb = new StringBuffer(); - for (int word : select) { - sb.append(word + " "); - } - logger.config("station has select array: " + sb.toString()); - } - - /** - * Disconnect from the current ET session. - * @param status The connection status. - */ - synchronized void disconnect() { - - // Cleanup the ET connection. - if (usingEtServer()) { - closeEtConnection(); - } - - // Change application state to disconnected. - connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTED); - } - - /** - * This class notifies the application to disconnect if the event processing thread completes. - */ - class SessionWatchdogThread extends Thread { - - Thread processingThread; - - SessionWatchdogThread(Thread processingThread) { - this.processingThread = processingThread; - } - - public void run() { - try { - // This thread waits on the event processing thread to die. - processingThread.join(); - - // Activate a disconnect using the ActionEvent which is used by the disconnect button. - logger.finest("processing thread ended so automatic disconnect is happening"); - application.actionPerformed(new ActionEvent(Thread.currentThread(), 0, Commands.DISCONNECT)); - - } catch (InterruptedException e) { - logger.finest("SessionWatchdogThread got interrupted"); - // This happens when the thread is interrupted by the user pressing the disconnect button. - } - } - } - - /** - * Invalidate all - */ - void invalidate() { - - application = null; - logger = null; - configurationModel = null; - connectionModel = null; - errorHandler = null; - - sessionState.conditionsListeners = null; - sessionState.drivers = null; - sessionState.processors = null; - sessionState.jobManager = null; - sessionState.eventBuilder = null; - sessionState.loop = null; - sessionState.processingThread = null; - sessionState.sessionWatchdogThread = null; - sessionState.stationThreadGroup = null; - sessionState.stations = null; - sessionState.connection = null; - - sessionState = null; + this.logger.finest("ET stations all woken up"); + } } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/FieldPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/FieldPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/FieldPanel.java Tue Apr 21 14:48:39 2015 @@ -3,81 +3,138 @@ import javax.swing.BorderFactory; import javax.swing.JPanel; import javax.swing.JTextField; +import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.border.Border; import javax.swing.border.TitledBorder; /** * A panel with a label and a text field. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ +@SuppressWarnings("serial") class FieldPanel extends JPanel { - String fieldName; - String defaultValue; - JTextField field; + /** + * The default component border. + */ + private static final Border DEFAULT_BORDER = BorderFactory.createLoweredBevelBorder(); - static Border border = BorderFactory.createLoweredBevelBorder(); + /** + * The component with the field value. + */ + private final JTextField field; - FieldPanel(String fieldName, String defaultValue, int size, boolean editable) { + /** + * Class constructor. + * + * @param fieldName the name of the field for the label + * @param defaultValue the default value + * @param size the size of the field + * @param editable <code>true</code> if field is editable + */ + protected FieldPanel(final String fieldName, final String defaultValue, final int size, final boolean editable) { - this.fieldName = fieldName; - this.defaultValue = defaultValue; - - TitledBorder title = BorderFactory.createTitledBorder(border, fieldName); + final TitledBorder title = BorderFactory.createTitledBorder(DEFAULT_BORDER, fieldName); title.setTitleJustification(TitledBorder.LEFT); - field = new JTextField(defaultValue, size); - field.setHorizontalAlignment(JTextField.RIGHT); - field.setEditable(editable); - field.setBorder(title); - add(field); + this.field = new JTextField(defaultValue, size); + this.field.setHorizontalAlignment(SwingConstants.RIGHT); + this.field.setEditable(editable); + this.field.setBorder(title); + add(this.field); } - void setValue(final String value) { + /** + * Get a <code>Double</code> value from the field. + * + * @return the <code>Double</code> value + */ + final Double getDoubleValue() { + return Double.parseDouble(getValue()); + } + + /** + * Get an <code>Integer</code> value from the field. + * + * @return the <code>Integer</code> value + */ + final Integer getIntegerValue() { + return Integer.parseInt(getValue()); + } + + /** + * Get a <code>Long</code> value from the field. + * + * @return the <code>Long</code> value + */ + final Long getLongValue() { + return Long.parseLong(getValue()); + } + + /** + * Get the <code>String</code> value from the field. + * + * @return the <code>String</code> value from the field + */ + final String getValue() { + return this.field.getText(); + } + + /** + * Set the field value from a <code>double</code>. + * + * @param value the <code>double</code> value + */ + final void setValue(final double value) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - field.setText(value); + FieldPanel.this.field.setText(new Double(value).toString()); } }); } - void setValue(final int value) { + /** + * Set the field value from an <code>int</code>. + * + * @param value the <code>int</code> value + */ + final void setValue(final int value) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - field.setText(new Integer(value).toString()); + FieldPanel.this.field.setText(new Integer(value).toString()); } }); } - void setValue(final double value) { + /** + * Set the field value from a <code>long</code>. + * + * @param value the <code>long</code> value + */ + final void setValue(final long value) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - field.setText(new Double(value).toString()); + FieldPanel.this.field.setText(new Long(value).toString()); } }); } - void setValue(final long value) { + /** + * Set the field value from a <code>String</code>. + * + * @param value the <code>String</code> value + */ + void setValue(final String value) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - field.setText(new Long(value).toString()); + FieldPanel.this.field.setText(value); } }); } - - String getValue() { - return field.getText(); - } - - Integer getIntegerValue() { - return Integer.parseInt(getValue()); - } - - Double getDoubleValue() { - return Double.parseDouble(getValue()); - } - - Long getLongValue() { - return Long.parseLong(getValue()); - } -} +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java Tue Apr 21 14:48:39 2015 @@ -28,400 +28,502 @@ import org.jdom.input.SAXBuilder; /** - * This is the GUI panel for setting job parameters. It is connected to the global configuration via - * a {@link org.hps.monitoring.model.ConfigurationModel} object. + * This is the GUI panel for setting job parameters. It is connected to the global configuration settings via a + * {@link org.hps.monitoring.model.ConfigurationModel} object. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -// FIXME: Combo boxes should use explicit types. -class JobSettingsPanel extends AbstractFieldsPanel { - - private JComboBox<?> steeringResourcesComboBox; - private JTextField steeringFileField; - private JComboBox<?> steeringTypeComboBox; - private JComboBox<ProcessingStage> processingStageComboBox; - private JComboBox<String> detectorNameComboBox; - private JTextField detectorAliasField; - private JComboBox<String> conditionsTagComboBox; - private JComboBox<String> eventBuilderComboBox; - private JTextField userRunNumberField; - private JCheckBox freezeConditionsCheckBox; - private JTextField maxEventsField; - private JCheckBox disconnectOnErrorCheckBox; - private JCheckBox disconnectOnEndRunCheckBox; - private JComboBox<?> logLevelComboBox; - private JCheckBox logToFileCheckbox; - private JTextField logFileNameField; - private JTextField aidaServerNameField; - - // The package where steering resources must be located. - static final String STEERING_PACKAGE = "org/hps/steering/monitoring/"; - - // The available LogLevel settings as an array of strings. - static final String[] LOG_LEVELS = new String[] { - Level.ALL.toString(), - Level.FINEST.toString(), - Level.FINER.toString(), - Level.FINE.toString(), - Level.CONFIG.toString(), - Level.INFO.toString(), - Level.WARNING.toString(), - Level.SEVERE.toString(), - Level.OFF.toString() - }; +@SuppressWarnings("serial") +final class JobSettingsPanel extends AbstractFieldsPanel { + + /** + * This filter will accept only files called compact.xml which should be an LCSim detector description file. + */ + static class CompactFileFilter extends FileFilter { + + /** + * Class constructor. + */ + public CompactFileFilter() { + } + + /** + * Returns <code>true</code> if the path passes the filter. + * + * @return <code>true</code> if the path passes the filter + */ + @Override + public boolean accept(final File pathname) { + return "compact.xml".equals(pathname.getName()); + } + + /** + * Get the description of the filter. + * + * @return the description of the filter + */ + @Override + public String getDescription() { + return "Compact XML files"; + } + } + + /** + * Update the GUI from changes in the underlying model. The changes are distinguishable by their property name. + */ + private class JobSettingsChangeListener implements PropertyChangeListener { + + /** + * Handle {@link java.beans.PropertyChangeEvent} by updating the GUI from changes to the model. + * + * @param evt the {@link java.beans.PropertyChangeEvent} to handle + */ + @Override + public void propertyChange(final PropertyChangeEvent evt) { + if (evt.getSource() instanceof ConfigurationModel) { + final Object value = evt.getNewValue(); + final String property = evt.getPropertyName(); + JobSettingsPanel.this.getConfigurationModel().removePropertyChangeListener(this); + try { + if (property.equals(ConfigurationModel.DETECTOR_NAME_PROPERTY)) { + JobSettingsPanel.this.detectorNameComboBox.setSelectedItem(value); + } else if (property.equals(ConfigurationModel.DETECTOR_ALIAS_PROPERTY)) { + JobSettingsPanel.this.detectorAliasField.setText((String) value); + } else if (property.equals(ConfigurationModel.DISCONNECT_ON_ERROR_PROPERTY)) { + JobSettingsPanel.this.disconnectOnErrorCheckBox.setSelected((Boolean) value); + } else if (property.equals(ConfigurationModel.DISCONNECT_ON_END_RUN_PROPERTY)) { + JobSettingsPanel.this.disconnectOnEndRunCheckBox.setSelected((Boolean) value); + } else if (property.equals(ConfigurationModel.EVENT_BUILDER_PROPERTY)) { + JobSettingsPanel.this.eventBuilderComboBox.setSelectedItem(value); + } else if (property.equals(ConfigurationModel.LOG_FILE_NAME_PROPERTY)) { + JobSettingsPanel.this.logFileNameField.setText((String) value); + } else if (property.equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) { + JobSettingsPanel.this.logLevelComboBox.setSelectedItem(value.toString()); + } else if (property.equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) { + JobSettingsPanel.this.logToFileCheckbox.setSelected((Boolean) value); + } else if (property.equals(ConfigurationModel.STEERING_TYPE_PROPERTY)) { + JobSettingsPanel.this.steeringTypeComboBox.setSelectedItem(value); + } else if (property.equals(ConfigurationModel.STEERING_FILE_PROPERTY)) { + if (value != null) { + JobSettingsPanel.this.steeringFileField.setText((String) evt.getNewValue()); + } else { + // A null value here is actually okay and means this field should be reset to have no value. + JobSettingsPanel.this.steeringFileField.setText(null); + } + } else if (property.equals(ConfigurationModel.STEERING_RESOURCE_PROPERTY)) { + JobSettingsPanel.this.steeringResourcesComboBox.setSelectedItem(value); + } else if (property.equals(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)) { + if (value != null) { + JobSettingsPanel.this.userRunNumberField.setText(Integer.toString((int) value)); + } else { + JobSettingsPanel.this.userRunNumberField.setText(null); + } + } else if (property.equals(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) { + if (value != null) { + JobSettingsPanel.this.freezeConditionsCheckBox.setSelected((Boolean) value); + } + } else if (property.equals(ConfigurationModel.MAX_EVENTS_PROPERTY)) { + if (value != null) { + JobSettingsPanel.this.maxEventsField.setText(value.toString()); + } + } else if (property.equals(ConfigurationModel.PROCESSING_STAGE_PROPERTY)) { + JobSettingsPanel.this.processingStageComboBox.setSelectedItem(evt.getNewValue()); + } else if (property.equals(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) { + JobSettingsPanel.this.aidaServerNameField.setText((String) evt.getNewValue()); + } + } finally { + JobSettingsPanel.this.getConfigurationModel().addPropertyChangeListener(this); + } + } + } + } + + /** + * The available LogLevel settings as an array of strings. + */ + static final String[] LOG_LEVELS = new String[] {Level.ALL.toString(), Level.FINEST.toString(), + Level.FINER.toString(), Level.FINE.toString(), Level.CONFIG.toString(), Level.INFO.toString(), + Level.WARNING.toString(), Level.SEVERE.toString(), Level.OFF.toString()}; + + /** + * The package where steering resources must be located. + */ + private static final String STEERING_PACKAGE = "org/hps/steering/monitoring/"; + + /** + * Field for name of remote AIDA server. + */ + private final JTextField aidaServerNameField; + + /** + * Combo box for selecting a conditions system tag. + */ + private final JComboBox<String> conditionsTagComboBox; + + /** + * Field setting a detector alias to a local file. + */ + private final JTextField detectorAliasField; + + /** + * Combo box for selecting a detector model. + */ + private final JComboBox<String> detectorNameComboBox; + + /** + * Check box for enabling disconnect on end run. + */ + private final JCheckBox disconnectOnEndRunCheckBox; + + /** + * Check box for enabling disconnect on event processing errors. + */ + private final JCheckBox disconnectOnErrorCheckBox; + + /** + * Combo box for selecting the event builder class. + */ + private final JComboBox<String> eventBuilderComboBox; + + /** + * Check box for freezing conditions system provided there is a user selected run number and detector. + */ + private final JCheckBox freezeConditionsCheckBox; + + /** + * Field for specifying an output log file. + */ + private final JTextField logFileNameField; + + /** + * Field for setting the log level. + */ + private final JComboBox<?> logLevelComboBox; + + /** + * Check box for enabling logging to a file. + */ + private final JCheckBox logToFileCheckbox; + + /** + * Field for setting the maximum number of events to process in the session. + */ + private final JTextField maxEventsField; + + /** + * Combo box for selecting the processing stage(s) to execute (ET, EVIO or LCIO). + */ + private final JComboBox<ProcessingStage> processingStageComboBox; + + /** + * Field for setting an XML steering file. + */ + private final JTextField steeringFileField; + + /** + * Combo box for selecting a steering file resource. + */ + private final JComboBox<?> steeringResourcesComboBox; + + /** + * Combo box for selecting between current file or resource for XML steering. + */ + private final JComboBox<SteeringType> steeringTypeComboBox; + + /** + * Field for setting a user run number for conditions system activation. + */ + private final JTextField userRunNumberField; /** * Class constructor. - */ - JobSettingsPanel(ConfigurationModel model) { + * + * @param model the current {@link org.hps.monitoring.application.model.ConfigurationModel} with global + * configuration + */ + @SuppressWarnings("unchecked") + JobSettingsPanel(final ConfigurationModel model) { super(new Insets(5, 3, 3, 5), true); - - setBorder(new EmptyBorder(10, 10, 10, 10)); - - setLayout(new GridBagLayout()); - + + this.setBorder(new EmptyBorder(10, 10, 10, 10)); + + this.setLayout(new GridBagLayout()); + // Listen on changes to the configuration which will then be automatically pushed to the GUI. model.addPropertyChangeListener(this); - steeringResourcesComboBox = addComboBoxMultiline("Steering File Resource", ResourceUtil.findSteeringResources(STEERING_PACKAGE)); - steeringResourcesComboBox.setActionCommand(Commands.STEERING_RESOURCE_CHANGED); - steeringResourcesComboBox.addActionListener(this); - - steeringFileField = addField("Steering File", 50); - steeringFileField.addPropertyChangeListener("value", this); - - JButton steeringFileButton = addButton("Select Steering File"); + this.steeringResourcesComboBox = this.addComboBoxMultiline("Steering File Resource", + ResourceUtil.findSteeringResources(STEERING_PACKAGE)); + this.steeringResourcesComboBox.setActionCommand(Commands.STEERING_RESOURCE_CHANGED); + this.steeringResourcesComboBox.addActionListener(this); + + this.steeringFileField = this.addField("Steering File", 50); + this.steeringFileField.addPropertyChangeListener("value", this); + + final JButton steeringFileButton = this.addButton("Select Steering File"); steeringFileButton.setActionCommand(Commands.CHOOSE_STEERING_FILE); steeringFileButton.addActionListener(this); - - steeringTypeComboBox = addComboBox("Steering Type", new String[] { SteeringType.RESOURCE.name(), SteeringType.FILE.name() }); - steeringTypeComboBox.setActionCommand(Commands.STEERING_TYPE_CHANGED); - steeringTypeComboBox.addActionListener(this); - - processingStageComboBox = new JComboBox<ProcessingStage>(ProcessingStage.values()); - addComponent("Processing Stage", processingStageComboBox); - processingStageComboBox.setActionCommand(Commands.PROCESSING_STAGE_CHANGED); - processingStageComboBox.addActionListener(this); - - detectorNameComboBox = addComboBox("Detector Name", ResourceUtil.findDetectorNames()); - detectorNameComboBox.setActionCommand(Commands.DETECTOR_NAME_CHANGED); - detectorNameComboBox.addActionListener(this); - - detectorAliasField = addField("Detector Resources Directory", "", 35, true); - detectorAliasField.setActionCommand(Commands.DETECTOR_ALIAS_CHANGED); - detectorAliasField.addPropertyChangeListener("value", this); - detectorAliasField.addActionListener(this); - - JButton compactXmlButton = addButton("Select Compact Xml File"); + + this.steeringTypeComboBox = this.addComboBox("Steering Type", SteeringType.values()); + this.steeringTypeComboBox.setActionCommand(Commands.STEERING_TYPE_CHANGED); + this.steeringTypeComboBox.addActionListener(this); + + this.processingStageComboBox = new JComboBox<ProcessingStage>(ProcessingStage.values()); + this.addComponent("Processing Stage", this.processingStageComboBox); + this.processingStageComboBox.setActionCommand(Commands.PROCESSING_STAGE_CHANGED); + this.processingStageComboBox.addActionListener(this); + + this.detectorNameComboBox = this.addComboBox("Detector Name", ResourceUtil.findDetectorNames()); + this.detectorNameComboBox.setActionCommand(Commands.DETECTOR_NAME_CHANGED); + this.detectorNameComboBox.addActionListener(this); + + this.detectorAliasField = this.addField("Detector Resources Directory", "", 35, true); + this.detectorAliasField.setActionCommand(Commands.DETECTOR_ALIAS_CHANGED); + this.detectorAliasField.addPropertyChangeListener("value", this); + this.detectorAliasField.addActionListener(this); + + final JButton compactXmlButton = this.addButton("Select Compact Xml File"); compactXmlButton.setActionCommand(Commands.CHOOSE_COMPACT_FILE); compactXmlButton.addActionListener(this); - userRunNumberField = addField("User Run Number", "", 10, true); - userRunNumberField.addPropertyChangeListener("value", this); - userRunNumberField.setActionCommand(Commands.USER_RUN_NUMBER_CHANGED); - userRunNumberField.setEnabled(true); - userRunNumberField.setEditable(true); - - conditionsTagComboBox = addComboBox("Conditions Tag", ResourceUtil.getConditionsTags()); - conditionsTagComboBox.addItem(""); - conditionsTagComboBox.setSelectedItem(""); - conditionsTagComboBox.setActionCommand(Commands.CONDITIONS_TAG_CHANGED); - conditionsTagComboBox.addActionListener(this); - conditionsTagComboBox.setEditable(false); - conditionsTagComboBox.setEnabled(true); - - freezeConditionsCheckBox = addCheckBox("Freeze detector conditions", false, true); - freezeConditionsCheckBox.addActionListener(this); - freezeConditionsCheckBox.setActionCommand(Commands.FREEZE_CONDITIONS_CHANGED); - - maxEventsField = addField("Max Events", "-1", 10, false); - maxEventsField.addPropertyChangeListener("value", this); - maxEventsField.setEnabled(true); - maxEventsField.setEditable(true); - - eventBuilderComboBox = addComboBox("LCSim Event Builder", ResourceUtil.findEventBuilderClassNames()); - eventBuilderComboBox.setSize(24, eventBuilderComboBox.getPreferredSize().height); - eventBuilderComboBox.setActionCommand(Commands.EVENT_BUILDER_CHANGED); - eventBuilderComboBox.addActionListener(this); - - disconnectOnErrorCheckBox = addCheckBox("Disconnect on error", false, true); - disconnectOnErrorCheckBox.setActionCommand(Commands.DISCONNECT_ON_ERROR_CHANGED); - disconnectOnErrorCheckBox.addActionListener(this); - - disconnectOnEndRunCheckBox = addCheckBox("Disconnect on end run", false, true); - disconnectOnEndRunCheckBox.setActionCommand(Commands.DISCONNECT_ON_END_RUN_CHANGED); - disconnectOnEndRunCheckBox.addActionListener(this); - - logLevelComboBox = addComboBox("Log Level", LOG_LEVELS); - logLevelComboBox.setActionCommand(Commands.LOG_LEVEL_CHANGED); - logLevelComboBox.addActionListener(this); - - logToFileCheckbox = addCheckBox("Log to File", false, false); - logToFileCheckbox.setEnabled(false); - - logFileNameField = addField("Log File Name", "", "Full path to log file", 50, false); - logFileNameField.setEditable(false); - - aidaServerNameField = addField("AIDA Server Name", "", "Name of AIDA server", 30, true); - aidaServerNameField.addPropertyChangeListener("value", this); - } - + this.userRunNumberField = this.addField("User Run Number", "", 10, true); + this.userRunNumberField.addPropertyChangeListener("value", this); + this.userRunNumberField.setActionCommand(Commands.USER_RUN_NUMBER_CHANGED); + this.userRunNumberField.setEnabled(true); + this.userRunNumberField.setEditable(true); + + this.conditionsTagComboBox = this.addComboBox("Conditions Tag", ResourceUtil.getConditionsTags()); + this.conditionsTagComboBox.addItem(""); + this.conditionsTagComboBox.setSelectedItem(""); + this.conditionsTagComboBox.setActionCommand(Commands.CONDITIONS_TAG_CHANGED); + this.conditionsTagComboBox.addActionListener(this); + this.conditionsTagComboBox.setEditable(false); + this.conditionsTagComboBox.setEnabled(true); + + this.freezeConditionsCheckBox = this.addCheckBox("Freeze detector conditions", false, true); + this.freezeConditionsCheckBox.addActionListener(this); + this.freezeConditionsCheckBox.setActionCommand(Commands.FREEZE_CONDITIONS_CHANGED); + + this.maxEventsField = this.addField("Max Events", "-1", 10, false); + this.maxEventsField.addPropertyChangeListener("value", this); + this.maxEventsField.setEnabled(true); + this.maxEventsField.setEditable(true); + + this.eventBuilderComboBox = this.addComboBox("LCSim Event Builder", ResourceUtil.findEventBuilderClassNames()); + this.eventBuilderComboBox.setSize(24, this.eventBuilderComboBox.getPreferredSize().height); + this.eventBuilderComboBox.setActionCommand(Commands.EVENT_BUILDER_CHANGED); + this.eventBuilderComboBox.addActionListener(this); + + this.disconnectOnErrorCheckBox = this.addCheckBox("Disconnect on error", false, true); + this.disconnectOnErrorCheckBox.setActionCommand(Commands.DISCONNECT_ON_ERROR_CHANGED); + this.disconnectOnErrorCheckBox.addActionListener(this); + + this.disconnectOnEndRunCheckBox = this.addCheckBox("Disconnect on end run", false, true); + this.disconnectOnEndRunCheckBox.setActionCommand(Commands.DISCONNECT_ON_END_RUN_CHANGED); + this.disconnectOnEndRunCheckBox.addActionListener(this); + + this.logLevelComboBox = this.addComboBox("Log Level", LOG_LEVELS); + this.logLevelComboBox.setActionCommand(Commands.LOG_LEVEL_CHANGED); + this.logLevelComboBox.addActionListener(this); + + this.logToFileCheckbox = this.addCheckBox("Log to File", false, false); + this.logToFileCheckbox.setEnabled(false); + + this.logFileNameField = this.addField("Log File Name", "", "Full path to log file", 50, false); + this.logFileNameField.setEditable(false); + + this.aidaServerNameField = this.addField("AIDA Server Name", "", "Name of AIDA server", 30, true); + this.aidaServerNameField.addPropertyChangeListener("value", this); + } + + /** + * Handle {@link java.awt.event.ActionEvent} objects by pushing changes from the GUI into the model. + * + * @param event the {@link java.awt.event.ActionEvent} to handle + */ @Override - public ConfigurationModel getConfigurationModel() { - return configurationModel; - } - - /** - * Attaches the ActionListener from the main app to specific GUI components in this class. - */ - public void addActionListener(ActionListener listener) { - steeringResourcesComboBox.addActionListener(listener); - freezeConditionsCheckBox.addActionListener(listener); - } - - /** - * Choose an lcsim steering file. - */ - void chooseSteeringFile() { - JFileChooser fc = new JFileChooser(); + public void actionPerformed(final ActionEvent event) { + try { + this.getConfigurationModel().removePropertyChangeListener(this); + final String command = event.getActionCommand(); + if (event.getActionCommand().equals(Commands.CHOOSE_STEERING_FILE)) { + this.chooseSteeringFile(); + } else if (event.getActionCommand().equals(Commands.CHOOSE_COMPACT_FILE)) { + this.chooseCompactFile(); + } else if (Commands.DISCONNECT_ON_ERROR_CHANGED.equals(command)) { + this.getConfigurationModel().setDisconnectOnError(this.disconnectOnErrorCheckBox.isSelected()); + } else if (Commands.DISCONNECT_ON_END_RUN_CHANGED.equals(command)) { + this.getConfigurationModel().setDisconnectOnEndRun(this.disconnectOnEndRunCheckBox.isSelected()); + } else if (Commands.STEERING_TYPE_CHANGED.equals(command)) { + this.getConfigurationModel().setSteeringType(this.steeringTypeComboBox.getSelectedItem().toString()); + } else if (Commands.STEERING_RESOURCE_CHANGED.equals(command)) { + this.getConfigurationModel().setSteeringResource( + this.steeringResourcesComboBox.getSelectedItem().toString()); + } else if (Commands.LOG_LEVEL_CHANGED.equals(command)) { + this.getConfigurationModel().setLogLevel(Level.parse((String) this.logLevelComboBox.getSelectedItem())); + } else if (Commands.EVENT_BUILDER_CHANGED.equals(command)) { + this.getConfigurationModel().setEventBuilderClassName( + (String) this.eventBuilderComboBox.getSelectedItem()); + } else if (Commands.DETECTOR_NAME_CHANGED.equals(command)) { + try { + this.getConfigurationModel().setDetectorName((String) this.detectorNameComboBox.getSelectedItem()); + } catch (final Exception exception) { + exception.printStackTrace(); + } + } else if (Commands.FREEZE_CONDITIONS_CHANGED.equals(command)) { + if (this.getConfigurationModel().hasPropertyKey(ConfigurationModel.USER_RUN_NUMBER_PROPERTY) + && this.getConfigurationModel().getUserRunNumber() != null) { + this.getConfigurationModel().setFreezeConditions(this.freezeConditionsCheckBox.isSelected()); + } else { + throw new IllegalArgumentException( + "Conditions system may only be frozen if there is a valid user run number."); + } + } else if (Commands.DETECTOR_ALIAS_CHANGED.equals(command)) { + this.getConfigurationModel().setDetectorName(this.detectorAliasField.getText()); + } else if (Commands.CONDITIONS_TAG_CHANGED.equals(command)) { + this.getConfigurationModel().setConditionsTag((String) this.conditionsTagComboBox.getSelectedItem()); + } else if (Commands.PROCESSING_STAGE_CHANGED.equals(command)) { + this.getConfigurationModel().setProcessingStage( + this.processingStageComboBox.getSelectedItem().toString()); + } + } finally { + this.getConfigurationModel().addPropertyChangeListener(this); + } + } + + /** + * Attaches the ActionListener from the main application to specific GUI components in this class. + * + * @param the {@link java.awt.event.ActionListener} to register with the relevant components + */ + @Override + public void addActionListener(final ActionListener listener) { + this.steeringResourcesComboBox.addActionListener(listener); + this.freezeConditionsCheckBox.addActionListener(listener); + } + + /** + * Parse the LCSim XML steering file to see if it looks valid. + * + * @param file the input steering file + * @throws IOException if there is a basic IO problem like reading the file + * @throws JDOMException if the XML is not valid + */ + private void checkSteeringFile(final File file) throws IOException, JDOMException { + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(file); + final Element rootNode = document.getRootElement(); + if (!"lcsim".equals(rootNode.getName())) { + throw new IOException("not an LCSim XML file: " + file.getPath()); + } + } + + /** + * Choose a compact XML file to override the one embedded in the jar as a resource. + */ + private void chooseCompactFile() { + final JFileChooser fc = new JFileChooser(); + fc.setDialogTitle("Choose a Compact XML File"); + fc.setCurrentDirectory(new File(".")); + fc.setFileFilter(new CompactFileFilter()); + final int r = fc.showDialog(this, "Select ..."); + if (r == JFileChooser.APPROVE_OPTION) { + final File file = fc.getSelectedFile(); + this.getConfigurationModel().setDetectorAlias(file.getParent()); + } + } + + /** + * Choose an LCSim steering file. + */ + private void chooseSteeringFile() { + final JFileChooser fc = new JFileChooser(); fc.setDialogTitle("Choose an LCSim Steering File"); fc.setCurrentDirectory(new File(".")); - int r = fc.showDialog(this, "Select ..."); + final int r = fc.showDialog(this, "Select ..."); if (r == JFileChooser.APPROVE_OPTION) { - File file = fc.getSelectedFile(); + final File file = fc.getSelectedFile(); try { - checkSteeringFile(file); - configurationModel.setSteeringFile(file.getCanonicalPath()); - configurationModel.setSteeringType(SteeringType.FILE); + this.checkSteeringFile(file); + this.getConfigurationModel().setSteeringFile(file.getCanonicalPath()); + this.getConfigurationModel().setSteeringType(SteeringType.FILE.toString()); } catch (IOException | JDOMException e) { throw new RuntimeException("Error parsing the selected steering file.", e); } } } - - /** - * This filter will accept only files called compact.xml which - * should be an LCSim detector description file. - */ - static class CompactFileFilter extends FileFilter { - - public CompactFileFilter() { - } - - @Override - public boolean accept(File pathname) { - if (pathname.getName().equals("compact.xml")) { - return true; - } else { - return false; - } - } - - @Override - public String getDescription() { - return "Compact XML files"; - } - } - - - /** - * Choose a compact XML file to override the one embedded in the jar as a resource. - */ - void chooseCompactFile() { - JFileChooser fc = new JFileChooser(); - fc.setDialogTitle("Choose a Compact XML File"); - fc.setCurrentDirectory(new File(".")); - fc.setFileFilter(new CompactFileFilter()); - int r = fc.showDialog(this, "Select ..."); - if (r == JFileChooser.APPROVE_OPTION) { - File file = fc.getSelectedFile(); - configurationModel.setDetectorAlias(file.getParent()); - } - } - - /** - * Parse the lcsim steering file to see if it appears to be valid. - * @param file The input steering file. - * @throws IOException if there is a basic IO problem. - * @throws JDOMException if the XML is not valid. - */ - private void checkSteeringFile(File file) throws IOException, JDOMException { - SAXBuilder builder = new SAXBuilder(); - Document document = builder.build(file); - Element rootNode = document.getRootElement(); - if (!rootNode.getName().equals("lcsim")) { - throw new IOException("Not an LCSim XML file: " + file.getPath()); - } - } - + + /** + * Updates the configuration with changes from the GUI component values. The changes from the GUI are + * distinguishable by their component object. + */ @Override - public void actionPerformed(ActionEvent event) { + public void propertyChange(final PropertyChangeEvent evt) { + this.getConfigurationModel().removePropertyChangeListener(this); try { - configurationModel.removePropertyChangeListener(this); - String command = event.getActionCommand(); - if (event.getActionCommand().equals(Commands.CHOOSE_STEERING_FILE)) { - chooseSteeringFile(); - } else if (event.getActionCommand().equals(Commands.CHOOSE_COMPACT_FILE)) { - chooseCompactFile(); - } else if (Commands.DISCONNECT_ON_ERROR_CHANGED.equals(command)) { - configurationModel.setDisconnectOnError(disconnectOnErrorCheckBox.isSelected()); - } else if (Commands.DISCONNECT_ON_END_RUN_CHANGED.equals(command)) { - configurationModel.setDisconnectOnEndRun(disconnectOnEndRunCheckBox.isSelected()); - } else if (Commands.STEERING_TYPE_CHANGED.equals(command)) { - configurationModel.setSteeringType(SteeringType.valueOf((String) steeringTypeComboBox.getSelectedItem())); - } else if (Commands.STEERING_RESOURCE_CHANGED.equals(command)) { - configurationModel.setSteeringResource((String) steeringResourcesComboBox.getSelectedItem()); - } else if (Commands.LOG_LEVEL_CHANGED.equals(command)) { - configurationModel.setLogLevel(Level.parse((String) logLevelComboBox.getSelectedItem())); - } else if (Commands.EVENT_BUILDER_CHANGED.equals(command)) { - configurationModel.setEventBuilderClassName((String) eventBuilderComboBox.getSelectedItem()); - } else if (Commands.DETECTOR_NAME_CHANGED.equals(command)) { - try { - configurationModel.setDetectorName((String) detectorNameComboBox.getSelectedItem()); - } catch (Exception exception) { - exception.printStackTrace(); - } - } else if (Commands.FREEZE_CONDITIONS_CHANGED.equals(command)) { - if (configurationModel.hasPropertyKey(ConfigurationModel.USER_RUN_NUMBER_PROPERTY) && configurationModel.getUserRunNumber() != null) { - configurationModel.setFreezeConditions(freezeConditionsCheckBox.isSelected()); - } else { - throw new IllegalArgumentException("Conditions system may only be frozen if there is a valid user run number."); - } - } else if (Commands.DETECTOR_ALIAS_CHANGED.equals(command)) { - configurationModel.setDetectorName(detectorAliasField.getText()); - } else if (Commands.CONDITIONS_TAG_CHANGED.equals(command)) { - configurationModel.setConditionsTag((String) conditionsTagComboBox.getSelectedItem()); - } else if (Commands.PROCESSING_STAGE_CHANGED.equals(command)) { - configurationModel.setProcessingStage((ProcessingStage) processingStageComboBox.getSelectedItem()); - } - } finally { - configurationModel.addPropertyChangeListener(this); - } - } - - /** - * Updates the configuration with changes from the GUI component values. - * The changes from the GUI are distinguishable by their component object. - */ - @Override - public void propertyChange(PropertyChangeEvent evt) { - configurationModel.removePropertyChangeListener(this); - try { - Object source = evt.getSource(); - if (source == steeringFileField) { - configurationModel.setSteeringFile(steeringFileField.getText()); - } else if (source == userRunNumberField) { + final Object source = evt.getSource(); + if (source == this.steeringFileField) { + this.getConfigurationModel().setSteeringFile(this.steeringFileField.getText()); + } else if (source == this.userRunNumberField) { // Is run number being reset to null or empty? - if (userRunNumberField.getText() == null || userRunNumberField.getText().isEmpty()) { + if (this.userRunNumberField.getText() == null || this.userRunNumberField.getText().isEmpty()) { // Update the model to null user run number and do not freeze the conditions system. - configurationModel.setUserRunNumber(null); - configurationModel.setFreezeConditions(false); + this.getConfigurationModel().setUserRunNumber(null); + this.getConfigurationModel().setFreezeConditions(false); } else { try { // Parse the run number. Need to catch errors because it might be an invalid string. - int userRunNumber = Integer.parseInt(userRunNumberField.getText()); - configurationModel.setUserRunNumber(userRunNumber); - configurationModel.setFreezeConditions(true); - } catch (NumberFormatException e) { + final int userRunNumber = Integer.parseInt(this.userRunNumberField.getText()); + this.getConfigurationModel().setUserRunNumber(userRunNumber); + this.getConfigurationModel().setFreezeConditions(true); + } catch (final NumberFormatException e) { System.out.println("bad number format so ignoring user run number " + evt.getNewValue()); - userRunNumberField.setText((String) evt.getOldValue()); - // throw new IllegalArgumentException("The value " + evt.getNewValue() + " is not a valid run number."); + this.userRunNumberField.setText((String) evt.getOldValue()); + // throw new IllegalArgumentException("The value " + evt.getNewValue() + + // " is not a valid run number."); } } - } else if (source == maxEventsField) { - configurationModel.setMaxEvents(Long.parseLong(maxEventsField.getText())); - //System.out.println("setMaxEvents - " + configurationModel.getMaxEvents()); - } else if (source == aidaServerNameField) { - configurationModel.setAIDAServerName(aidaServerNameField.getText()); + } else if (source == this.maxEventsField) { + this.getConfigurationModel().setMaxEvents(Long.parseLong(this.maxEventsField.getText())); + // System.out.println("setMaxEvents - " + configurationModel.getMaxEvents()); + } else if (source == this.aidaServerNameField) { + this.getConfigurationModel().setAIDAServerName(this.aidaServerNameField.getText()); } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) { - // This is getting the log to file prop change from the ConfigurationModel to update a read only component. - Boolean logToFile = (Boolean) evt.getNewValue(); + // This is getting the log to file prop change from the ConfigurationModel to update a read only + // component. + final Boolean logToFile = (Boolean) evt.getNewValue(); if (logToFile != null) { - logToFileCheckbox.setSelected(logToFile); + this.logToFileCheckbox.setSelected(logToFile); } } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_FILE_NAME_PROPERTY)) { - // This is getting the log file name prop change from the ConfigurationModel to update a read only component. - String logFileName = (String) evt.getNewValue(); + // This is getting the log file name prop change from the ConfigurationModel to update a read only + // component. + final String logFileName = (String) evt.getNewValue(); if (logFileName != null && logFileName.length() > 0) { - logFileNameField.setText(logFileName); + this.logFileNameField.setText(logFileName); } else { - logFileNameField.setText(""); + this.logFileNameField.setText(""); } } else if (evt.getPropertyName().equals(ConfigurationModel.CONDITIONS_TAG_PROPERTY)) { - conditionsTagComboBox.setSelectedItem(evt.getNewValue()); - } + this.conditionsTagComboBox.setSelectedItem(evt.getNewValue()); + } } finally { - configurationModel.addPropertyChangeListener(this); - } - } - - /** - * Update the GUI from changes in the underlying model. - * The changes are distinguishable by their property name. - */ - private class JobSettingsChangeListener implements PropertyChangeListener { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getSource() instanceof ConfigurationModel) { - Object value = evt.getNewValue(); - String property = evt.getPropertyName(); - configurationModel.removePropertyChangeListener(this); - try { - if (property.equals(ConfigurationModel.DETECTOR_NAME_PROPERTY)) { - detectorNameComboBox.setSelectedItem((String) value); - } else if (property.equals(ConfigurationModel.DETECTOR_ALIAS_PROPERTY)) { - detectorAliasField.setText((String) value); - } else if (property.equals(ConfigurationModel.DISCONNECT_ON_ERROR_PROPERTY)) { - disconnectOnErrorCheckBox.setSelected((Boolean) value); - } else if (property.equals(ConfigurationModel.DISCONNECT_ON_END_RUN_PROPERTY)) { - disconnectOnEndRunCheckBox.setSelected((Boolean) value); - } else if (property.equals(ConfigurationModel.EVENT_BUILDER_PROPERTY)) { - eventBuilderComboBox.setSelectedItem((String) value); - } else if (property.equals(ConfigurationModel.LOG_FILE_NAME_PROPERTY)) { - logFileNameField.setText((String) value); - } else if (property.equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) { - logLevelComboBox.setSelectedItem(value.toString()); - } else if (property.equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) { - logToFileCheckbox.setSelected((Boolean) value); - } else if (property.equals(ConfigurationModel.STEERING_TYPE_PROPERTY)) { - steeringTypeComboBox.setSelectedIndex(((SteeringType) value).ordinal()); - } else if (property.equals(ConfigurationModel.STEERING_FILE_PROPERTY)) { - if (value != null) { - steeringFileField.setText((String) evt.getNewValue()); - } else { - // A null value here is actually okay and means this field should be reset to have no value. - steeringFileField.setText(null); - } - } else if (property.equals(ConfigurationModel.STEERING_RESOURCE_PROPERTY)) { - steeringResourcesComboBox.setSelectedItem(value); - } else if (property.equals(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)) { - if (value != null) { - userRunNumberField.setText(Integer.toString((int) value)); - } else { - userRunNumberField.setText(null); - } - } else if (property.equals(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) { - if (value != null) { - freezeConditionsCheckBox.setSelected((Boolean) value); - } - } else if (property.equals(ConfigurationModel.MAX_EVENTS_PROPERTY)) { - if (value != null) { - maxEventsField.setText(value.toString()); - } - } else if (property.equals(ConfigurationModel.PROCESSING_STAGE_PROPERTY)) { - processingStageComboBox.setSelectedItem(evt.getNewValue()); - } else if (property.equals(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) { - aidaServerNameField.setText((String) evt.getNewValue()); - } - } finally { - configurationModel.addPropertyChangeListener(this); - } - } - } - } - + this.getConfigurationModel().addPropertyChangeListener(this); + } + } + + /** + * Sets the {@link org.hps.monitoring.application.model.ConfigurationModel} for the component containing global + * configuration. + * <p> + * The job settings will be updated automatically if the model changes. + * + * @param the {@link org.hps.monitoring.application.model.ConfigurationModel} for the component + */ @Override - public void setConfigurationModel(ConfigurationModel model) { + public void setConfigurationModel(final ConfigurationModel model) { super.setConfigurationModel(model); model.addPropertyChangeListener(new JobSettingsChangeListener()); } -} +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java Tue Apr 21 14:48:39 2015 @@ -14,62 +14,74 @@ /** * This is a combo box used to filter the log table messages by level. - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class LogLevelFilterComboBox extends JComboBox<Level> implements ActionListener, PropertyChangeListener { - - ConfigurationModel configurationModel; - - static final Level[] LOG_LEVELS = new Level[] { - Level.ALL, - Level.FINEST, - Level.FINER, - Level.FINE, - Level.CONFIG, - Level.INFO, - Level.WARNING, - Level.SEVERE - }; - - LogLevelFilterComboBox(ConfigurationModel configurationModel) { - +@SuppressWarnings("serial") +final class LogLevelFilterComboBox extends JComboBox<Level> implements ActionListener, PropertyChangeListener { + + /** + * Available log levels. + */ + private static final Level[] LOG_LEVELS = new Level[] { Level.ALL, Level.FINEST, Level.FINER, Level.FINE, + Level.CONFIG, Level.INFO, Level.WARNING, Level.SEVERE }; + + /** + * The {@link org.hps.monitoring.application.model.ConfigurationModel} providing the backing model. + */ + private final ConfigurationModel configurationModel; + + /** + * Class constructor. + * + * @param configurationModel the {@link org.hps.monitoring.application.model.ConfigurationModel} providing the + * backing model + */ + LogLevelFilterComboBox(final ConfigurationModel configurationModel) { + configurationModel.addPropertyChangeListener(this); - this.configurationModel = configurationModel; - + this.configurationModel = configurationModel; + setModel(new DefaultComboBoxModel<Level>(LOG_LEVELS)); setPrototypeDisplayValue(Level.WARNING); - setSelectedItem(Level.ALL); + setSelectedItem(Level.ALL); setActionCommand(Commands.LOG_LEVEL_FILTER_CHANGED); addActionListener(this); setPreferredSize(new Dimension(100, getPreferredSize().height)); setSize(new Dimension(100, getPreferredSize().height)); - } - + } + /** - * Push change in log level filtering to the configuration model. + * The {@link java.awt.event.ActionEvent} handling, which is used to push changes to the global data model. + * + * @param event the {@link java.awt.event.ActionEvent} object */ - public void actionPerformed(ActionEvent event) { + @Override + public void actionPerformed(final ActionEvent event) { if (event.getActionCommand().equals(Commands.LOG_LEVEL_FILTER_CHANGED)) { - configurationModel.removePropertyChangeListener(this); - try { - configurationModel.setLogLevelFilter((Level) getSelectedItem()); + this.configurationModel.removePropertyChangeListener(this); + try { + this.configurationModel.setLogLevelFilter((Level) getSelectedItem()); } finally { - configurationModel.addPropertyChangeListener(this); + this.configurationModel.addPropertyChangeListener(this); } } } - + /** - * Get change in log level filtering from the configuration model. + * The {@link java.beans.PropertyChangeEvent} handling, which is used to get changes from the model into the GUI. + * + * @param event the {@link java.beans.PropertyChangeEvent} object to handle */ - public void propertyChange(PropertyChangeEvent event) { + @Override + public void propertyChange(final PropertyChangeEvent event) { if (event.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_FILTER_PROPERTY)) { - Level newLevel = (Level) event.getNewValue(); - configurationModel.removePropertyChangeListener(this); + final Level newLevel = (Level) event.getNewValue(); + this.configurationModel.removePropertyChangeListener(this); try { setSelectedItem(newLevel); } finally { - configurationModel.addPropertyChangeListener(this); + this.configurationModel.addPropertyChangeListener(this); } } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogPanel.java Tue Apr 21 14:48:39 2015 @@ -15,46 +15,67 @@ /** * This is a simple GUI component for the log table and its controls. - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class LogPanel extends JPanel{ +@SuppressWarnings("serial") +final class LogPanel extends JPanel { - LogTable logTable; - LogLevelFilterComboBox logFilterComboBox; - - ConfigurationModel configurationModel; - - LogPanel(ConfigurationModel configurationModel, ActionListener listener) { - - this.configurationModel = configurationModel; - + /** + * The combo box for filtering which messages are currently showing in the table. + */ + private final LogLevelFilterComboBox logFilterComboBox; + + /** + * The table containing the log messages. + */ + private final LogTable logTable; + + /** + * Class constructor. + * + * @param configurationModel the {@link org.hps.monitoring.application.model.ConfigurationModel} providing the data + * model + * @param listener an {@link java.awt.event.ActionListener} to register on certain components + */ + LogPanel(final ConfigurationModel configurationModel, final ActionListener listener) { + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); - - logTable = new LogTable(configurationModel); - - JPanel controlsPanel = new JPanel(); + + this.logTable = new LogTable(configurationModel); + + final JPanel controlsPanel = new JPanel(); controlsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5)); - - JLabel label = new JLabel("Log Level Filter"); - logFilterComboBox = new LogLevelFilterComboBox(configurationModel); - logFilterComboBox.setToolTipText("Messages below this level will be filtered out."); - controlsPanel.add(label); - controlsPanel.add(logFilterComboBox); - - JButton exportButton = new JButton("Export ..."); + + final JLabel label = new JLabel("Log Level Filter"); + this.logFilterComboBox = new LogLevelFilterComboBox(configurationModel); + this.logFilterComboBox.setToolTipText("Messages below this level will be filtered out."); + controlsPanel.add(label); + controlsPanel.add(this.logFilterComboBox); + + final JButton exportButton = new JButton("Export ..."); exportButton.setActionCommand(Commands.SAVE_LOG_TABLE); exportButton.addActionListener(listener); controlsPanel.add(exportButton); - - JButton clearButton = new JButton("Clear"); + + final JButton clearButton = new JButton("Clear"); clearButton.setActionCommand(Commands.CLEAR_LOG_TABLE); clearButton.addActionListener(listener); controlsPanel.add(clearButton); - - JScrollPane tablePane = new JScrollPane(logTable); + + final JScrollPane tablePane = new JScrollPane(this.logTable); controlsPanel.setMaximumSize(new Dimension(tablePane.getPreferredSize().width, 200)); - + add(controlsPanel, BorderLayout.PAGE_START); add(tablePane, BorderLayout.PAGE_END); - } + } + + /** + * Get the log table. + * + * @return the log table + */ + LogTable getLogTable() { + return this.logTable; + } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogTable.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogTable.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogTable.java Tue Apr 21 14:48:39 2015 @@ -18,79 +18,144 @@ import org.hps.monitoring.application.model.ConfigurationModel; /** - * This is a simple Swing component for the table of log messages. - * @author Jeremy McCormick <[log in to unmask]> + * This is a simple {@link avax.swing.JTable} component for displaying log messages. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class LogTable extends JTable implements PropertyChangeListener { - - static final String[] COLUMN_NAMES = { "Date", "Level", "Message" }; - - LogRecordModel model; - TableRowSorter<LogRecordModel> sorter; - - Level filterLevel = Level.ALL; - - final static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - - LogTable(ConfigurationModel configurationModel) { - configurationModel.addPropertyChangeListener(this); - model = new LogRecordModel(); - setModel(model); - sorter = new TableRowSorter<LogRecordModel>(model); - sorter.setRowFilter(new LevelFilter()); - getColumnModel().getColumn(0).setCellRenderer(new DateRenderer()); - setRowSorter(sorter); - getColumnModel().getColumn(0).setPreferredWidth(142); - getColumnModel().getColumn(0).setMaxWidth(142); - getColumnModel().getColumn(1).setPreferredWidth(60); - getColumnModel().getColumn(1).setMaxWidth(60); - setEnabled(false); - } - +@SuppressWarnings("serial") +final class LogTable extends JTable implements PropertyChangeListener { + + /** + * The table cell renderer for displaying dates. + */ static class DateRenderer extends DefaultTableCellRenderer { - public void setValue(Object value) { - setText((value == null) ? "" : formatter.format(value)); - } - } - - class LevelFilter extends RowFilter<LogRecordModel, Integer> { - - public boolean include(Entry<? extends LogRecordModel, ? extends Integer> entry) { - LogRecordModel model = entry.getModel(); - LogRecord record = model.get(entry.getIdentifier()); - if (record.getLevel().intValue() >= filterLevel.intValue()) { + @Override + public void setValue(final Object value) { + setText(value == null ? "" : DATE_FORMAT.format(value)); + } + } + + /** + * A filter which determines what level of messages to display in the table. + */ + private class LevelFilter extends RowFilter<LogRecordModel, Integer> { + + /** + * Return <code>true</code> to display the entry. + * + * @param entry the table entry (model with a row ID) + */ + @Override + public boolean include(final Entry<? extends LogRecordModel, ? extends Integer> entry) { + final LogRecordModel model = entry.getModel(); + final LogRecord record = model.get(entry.getIdentifier()); + if (record.getLevel().intValue() >= LogTable.this.filterLevel.intValue()) { return true; } return false; } } - - static class LogRecordModel extends AbstractTableModel { - - List<LogRecord> records = new ArrayList<LogRecord>(); - - LogRecord get(Integer rowIndex) { - return records.get(rowIndex); - } - - void add(LogRecord record) { - records.add(record); + + /** + * The table model implementation. + */ + static class LogRecordModel extends AbstractTableModel { + + /** + * The list of {@link java.util.logging.LogRecord} objects to display in the table. + */ + private final List<LogRecord> records = new ArrayList<LogRecord>(); + + /** + * Add a new {@link java.util.logging.LogRecord} object to the table. + * + * @param record the new {@link java.util.logging.LogRecord} object + */ + void add(final LogRecord record) { + this.records.add(record); fireTableDataChanged(); } - @Override - public int getRowCount() { - return records.size(); - } - + /** + * Clear all the records from the table. + */ + void clear() { + this.records.clear(); + fireTableDataChanged(); + } + + /** + * Get a record by its index. + * + * @param rowIndex the row index + * @return the {@link java.util.logging.LogRecord} object + * @throws IndexOutOfBoundsException if rowIndex is invalid + */ + private LogRecord get(final Integer rowIndex) { + return this.records.get(rowIndex); + } + + /** + * Get the class of a column. + * + * @param columnIndex the column's index + * @return the column's class + */ + @Override + public Class<?> getColumnClass(final int columnIndex) { + switch (columnIndex) { + case 0: + return Date.class; + case 1: + return Level.class; + case 2: + return String.class; + default: + return Object.class; + } + } + + /** + * Get the number of columns. + * + * @return the number of columns + */ @Override public int getColumnCount() { return COLUMN_NAMES.length; } - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - LogRecord record = records.get(rowIndex); + /** + * Get the column name. + * + * @param columnIndex the column index + * @return the name of the column + */ + @Override + public String getColumnName(final int columnIndex) { + return COLUMN_NAMES[columnIndex]; + } + + /** + * Get the number of rows. + * + * @return the number of rows + */ + @Override + public int getRowCount() { + return this.records.size(); + } + + /** + * Get a cell value from the table. + * + * @param rowIndex the row index + * @param column the column index + * @return the cell value or <code>null</code> if does not exist (e.g. invalid column number) + */ + @Override + public Object getValueAt(final int rowIndex, final int columnIndex) { + final LogRecord record = this.get(rowIndex); switch (columnIndex) { case 0: return new Date(record.getMillis()); @@ -102,39 +167,70 @@ return null; } } - - @Override - public Class<?> getColumnClass(int columnIndex) { - switch (columnIndex) { - case 0: - return Date.class; - case 1: - return Level.class; - case 2: - return String.class; - default: - return Object.class; - } - } - - @Override - public String getColumnName(int columnIndex) { - return COLUMN_NAMES[columnIndex]; - } - - void clear() { - records.clear(); - fireTableDataChanged(); - } + } + + /** + * The column names. + */ + static final String[] COLUMN_NAMES = { "Date", "Level", "Message" }; + + /** + * Date formatting. + */ + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + /** + * The current filtering level. + */ + private Level filterLevel = Level.ALL; + + /** + * The backing table model. + */ + private final LogRecordModel model; + + /** + * The table sorer. + */ + private final TableRowSorter<LogRecordModel> sorter; + + /** + * Class constructor. + * + * @param configurationModel the {@link org.hps.monitoring.application.model.ConfigurationModel} for the application + */ + LogTable(final ConfigurationModel configurationModel) { + configurationModel.addPropertyChangeListener(this); + this.model = new LogRecordModel(); + setModel(this.model); + this.sorter = new TableRowSorter<LogRecordModel>(this.model); + this.sorter.setRowFilter(new LevelFilter()); + getColumnModel().getColumn(0).setCellRenderer(new DateRenderer()); + setRowSorter(this.sorter); + getColumnModel().getColumn(0).setPreferredWidth(142); + getColumnModel().getColumn(0).setMaxWidth(142); + getColumnModel().getColumn(1).setPreferredWidth(60); + getColumnModel().getColumn(1).setMaxWidth(60); + setEnabled(false); + } + + /** + * Get the table model. + * + * @return the table model + */ + LogRecordModel getLogRecordModel() { + return this.model; } /** * Get change in log level filtering from the configuration model. */ - public void propertyChange(PropertyChangeEvent event) { + @Override + public void propertyChange(final PropertyChangeEvent event) { if (event.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_FILTER_PROPERTY)) { - filterLevel = (Level) event.getNewValue(); - model.fireTableDataChanged(); - } - } + this.filterLevel = (Level) event.getNewValue(); + this.model.fireTableDataChanged(); + } + } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Main.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Main.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Main.java Tue Apr 21 14:48:39 2015 @@ -12,42 +12,55 @@ import org.hps.monitoring.application.model.Configuration; /** - * This is the front-end for running the monitoring app via a {@link #main(String[])} method. + * This is the front-end for running the monitoring application via a {@link #main(String[])} method. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class Main { - private Main() { - } - - public static void main(String[] args) { - + /** + * The main method which starts the monitoring application, which is how users should start the application. + * + * @param args the command line arguments + */ + public static void main(final String[] args) { + // Set up command line parsing. - Options options = new Options(); + final Options options = new Options(); options.addOption(new Option("h", false, "Print help.")); options.addOption(new Option("c", true, "Load a properties file with configuration parameters.")); - CommandLineParser parser = new PosixParser(); - + final CommandLineParser parser = new PosixParser(); + // Parse command line arguments. final CommandLine cl; try { cl = parser.parse(options, args); - } catch (ParseException e) { + } catch (final ParseException e) { throw new RuntimeException("Problem parsing command line options.", e); } // Print help and exit. if (cl.hasOption("h")) { - HelpFormatter help = new HelpFormatter(); + final HelpFormatter help = new HelpFormatter(); help.printHelp(" ", options); System.exit(1); } - + // Load the connection settings. Configuration configuration = null; if (cl.hasOption("c")) { configuration = new Configuration(new File(cl.getOptionValue("c"))); - } - + } + MonitoringApplication.create(configuration); - } -} + } + + /** + * Class constructor, which should not be used. + * <p> + * Call the {@link #main(String[])} method instead. + */ + private Main() { + throw new UnsupportedOperationException("Do not instantiate this class."); + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MenuBar.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MenuBar.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MenuBar.java Tue Apr 21 14:48:39 2015 @@ -18,116 +18,173 @@ /** * This is the primary menu bar for the monitoring application. - * - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ @SuppressWarnings("serial") -class MenuBar extends JMenuBar implements PropertyChangeListener, ActionListener { - - ConfigurationModel configurationModel; - - JMenuItem closeFileItem; - JMenuItem openFileItem; - JMenu settingsMenu; - JMenuItem logItem; - JMenuItem serverItem; - JMenu recentFilesMenu; - - class RecentFileItem extends JMenuItem { - - String path; - - RecentFileItem(String path, int mnemonic) { - setText((mnemonic - KeyEvent.VK_0) + " " + path); +final class MenuBar extends JMenuBar implements PropertyChangeListener, ActionListener { + + /** + * The implementation of {@link javax.swing.JMenuItem} for recent file items. + */ + private class RecentFileItem extends JMenuItem { + + /** + * The recent file's path. + */ + private final String path; + + /** + * Class constructor with file's path and its numerical mnemonic (0-9). + * + * @param path the path + * @param mnemonic the item's mnemonic shortcut (0-9) + */ + RecentFileItem(final String path, final int mnemonic) { + setText(mnemonic - KeyEvent.VK_0 + " " + path); setMnemonic(mnemonic); this.path = path; } - - String getPath() { - return path; - } - } - - MenuBar(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel, ActionListener listener) { - - this.configurationModel = configurationModel; + + /** + * Get the file path of the item. + * + * @return the file path + */ + private String getPath() { + return this.path; + } + } + + /** + * Starting mnemonic for recent files (this is equivalent to '0'). + */ + private static final int RECENT_FILES_START_INDEX = 48; + + /** + * Menu item for closing a file source. + */ + private final JMenuItem closeFileItem; + + /** + * The application backing model. + */ + private final ConfigurationModel configurationModel; + + /** + * Menu item for logging to a file. + */ + private final JMenuItem logItem; + + /** + * Menu item for opening a file data source. + */ + private final JMenuItem openFileItem; + + /** + * Menu with list of recent files (10 max). + */ + private final JMenu recentFilesMenu; + + /** + * Menu item for activating the remote AIDA server. + */ + private final JMenuItem serverItem; + + /** + * Menu item for opening the settings dialog window. + */ + private final JMenu settingsMenu; + + /** + * Class constructor. + * + * @param configurationModel the {@link org.hps.monitoring.application.model.ConfigurationModel} providing the model + * @param connectionModel the {@link org.hps.monitoring.application.model.ConnectionStatusModel} providing + * connection status + * @param listener an {@link ava.awt.event.ActionListener} which is assigned to certain components + */ + MenuBar(final ConfigurationModel configurationModel, final ConnectionStatusModel connectionModel, + final ActionListener listener) { + + this.configurationModel = configurationModel; this.configurationModel.addPropertyChangeListener(this); - + // Need to listen for connection status changes. - connectionModel.addPropertyChangeListener(this); - - JMenu fileMenu = new JMenu("File"); + connectionModel.addPropertyChangeListener(this); + + final JMenu fileMenu = new JMenu("File"); fileMenu.setMnemonic(KeyEvent.VK_F); add(fileMenu); - - openFileItem = new JMenuItem("Open File ..."); - openFileItem.setMnemonic(KeyEvent.VK_P); - openFileItem.setActionCommand(Commands.OPEN_FILE); - openFileItem.addActionListener(listener); - openFileItem.setToolTipText("Open an EVIO or LCIO data file"); - fileMenu.add(openFileItem); - - closeFileItem = new JMenuItem("Close File"); - closeFileItem.setMnemonic(KeyEvent.VK_C); - closeFileItem.setActionCommand(Commands.CLOSE_FILE); - closeFileItem.addActionListener(listener); - closeFileItem.setToolTipText("Close the current file data source"); - fileMenu.add(closeFileItem); - - recentFilesMenu = new JMenu("RecentFiles"); - recentFilesMenu.setMnemonic(KeyEvent.VK_R); - recentFilesMenu.setToolTipText("List of recent data files"); - JMenuItem noRecentFilesItem = new JMenuItem("No recent files"); + + this.openFileItem = new JMenuItem("Open File ..."); + this.openFileItem.setMnemonic(KeyEvent.VK_P); + this.openFileItem.setActionCommand(Commands.OPEN_FILE); + this.openFileItem.addActionListener(listener); + this.openFileItem.setToolTipText("Open an EVIO or LCIO data file"); + fileMenu.add(this.openFileItem); + + this.closeFileItem = new JMenuItem("Close File"); + this.closeFileItem.setMnemonic(KeyEvent.VK_C); + this.closeFileItem.setActionCommand(Commands.CLOSE_FILE); + this.closeFileItem.addActionListener(listener); + this.closeFileItem.setToolTipText("Close the current file data source"); + fileMenu.add(this.closeFileItem); + + this.recentFilesMenu = new JMenu("Recent Files"); + this.recentFilesMenu.setMnemonic(KeyEvent.VK_R); + this.recentFilesMenu.setToolTipText("List of recent data files"); + final JMenuItem noRecentFilesItem = new JMenuItem("No recent files"); noRecentFilesItem.setEnabled(false); - recentFilesMenu.add(noRecentFilesItem); - fileMenu.add(recentFilesMenu); - + this.recentFilesMenu.add(noRecentFilesItem); + fileMenu.add(this.recentFilesMenu); + fileMenu.addSeparator(); - - JMenuItem exitItem = new JMenuItem("Exit"); + + final JMenuItem exitItem = new JMenuItem("Exit"); exitItem.setMnemonic(KeyEvent.VK_X); exitItem.setActionCommand(Commands.EXIT); exitItem.addActionListener(listener); exitItem.setToolTipText("Exit from the application"); fileMenu.add(exitItem); - - settingsMenu = new JMenu("Settings"); - settingsMenu.setMnemonic(KeyEvent.VK_S); - add(settingsMenu); - - JMenuItem settingsItem = new JMenuItem("Open Settings Window ..."); + + this.settingsMenu = new JMenu("Settings"); + this.settingsMenu.setMnemonic(KeyEvent.VK_S); + add(this.settingsMenu); + + final JMenuItem settingsItem = new JMenuItem("Open Settings Window ..."); settingsItem.setMnemonic(KeyEvent.VK_O); settingsItem.setActionCommand(Commands.SHOW_SETTINGS); settingsItem.addActionListener(listener); settingsItem.setToolTipText("Show settings dialog"); - settingsMenu.add(settingsItem); - - JMenuItem loadConfigItem = new JMenuItem("Load Settings ..."); + this.settingsMenu.add(settingsItem); + + final JMenuItem loadConfigItem = new JMenuItem("Load Settings ..."); loadConfigItem.addActionListener(listener); loadConfigItem.setMnemonic(KeyEvent.VK_L); loadConfigItem.setActionCommand(Commands.LOAD_SETTINGS); loadConfigItem.setToolTipText("Load settings from a properties file"); - settingsMenu.add(loadConfigItem); - - JMenuItem saveConfigItem = new JMenuItem("Save Settings ..."); + this.settingsMenu.add(loadConfigItem); + + final JMenuItem saveConfigItem = new JMenuItem("Save Settings ..."); saveConfigItem.addActionListener(listener); saveConfigItem.setMnemonic(KeyEvent.VK_S); saveConfigItem.setActionCommand(Commands.SAVE_SETTINGS); saveConfigItem.setToolTipText("Save configuration to a properties file"); - settingsMenu.add(saveConfigItem); - - JMenuItem defaultSettingsItem = new JMenuItem("Load Default Settings"); + this.settingsMenu.add(saveConfigItem); + + final JMenuItem defaultSettingsItem = new JMenuItem("Load Default Settings"); defaultSettingsItem.addActionListener(listener); defaultSettingsItem.setMnemonic(KeyEvent.VK_D); defaultSettingsItem.setActionCommand(Commands.LOAD_DEFAULT_SETTINGS); defaultSettingsItem.setToolTipText("Load the default settings"); - settingsMenu.add(defaultSettingsItem); - - JMenu plotsMenu = new JMenu("Plots"); + this.settingsMenu.add(defaultSettingsItem); + + final JMenu plotsMenu = new JMenu("Plots"); plotsMenu.setMnemonic(KeyEvent.VK_P); add(plotsMenu); - - JMenuItem savePlotsItem = new JMenuItem("Save plots ..."); + + final JMenuItem savePlotsItem = new JMenuItem("Save plots ..."); savePlotsItem.setMnemonic(KeyEvent.VK_S); savePlotsItem.setActionCommand(Commands.SAVE_PLOTS); savePlotsItem.addActionListener(listener); @@ -135,140 +192,162 @@ savePlotsItem.setToolTipText("Save all plots to a file"); plotsMenu.add(savePlotsItem); - JMenuItem clearPlotsItem = new JMenuItem("Clear plots"); + final JMenuItem clearPlotsItem = new JMenuItem("Clear plots"); clearPlotsItem.setMnemonic(KeyEvent.VK_C); clearPlotsItem.setActionCommand(Commands.CLEAR_PLOTS); clearPlotsItem.addActionListener(listener); clearPlotsItem.setEnabled(true); clearPlotsItem.setToolTipText("Clear the AIDA plots"); plotsMenu.add(clearPlotsItem); - - JMenu toolsMenu = new JMenu("Tools"); + + final JMenu toolsMenu = new JMenu("Tools"); toolsMenu.setMnemonic(KeyEvent.VK_T); add(toolsMenu); - - JMenuItem screenshotItem = new JMenuItem("Save Screenshot ..."); + + final JMenuItem screenshotItem = new JMenuItem("Save Screenshot ..."); screenshotItem.setMnemonic(KeyEvent.VK_S); screenshotItem.setActionCommand(Commands.SAVE_SCREENSHOT); screenshotItem.addActionListener(listener); screenshotItem.setEnabled(true); screenshotItem.setToolTipText("Save a screenshot to a graphics file"); toolsMenu.add(screenshotItem); - - logItem = new JMenuItem("Log to File ..."); - logItem.setMnemonic(KeyEvent.VK_L); - logItem.setActionCommand(Commands.LOG_TO_FILE); - logItem.addActionListener(listener); - logItem.setEnabled(true); - logItem.setToolTipText("Redirect System.out to a file instead of terminal"); - toolsMenu.add(logItem); - - serverItem = new JMenuItem("Start AIDA Server ..."); - serverItem.setMnemonic(KeyEvent.VK_A); - serverItem.setActionCommand(Commands.START_AIDA_SERVER); - serverItem.setEnabled(true); - serverItem.setToolTipText("Start AIDA RMI Server"); - serverItem.addActionListener(listener); - toolsMenu.add(serverItem); - - JMenu windowMenu = new JMenu("Window"); + + this.logItem = new JMenuItem("Log to File ..."); + this.logItem.setMnemonic(KeyEvent.VK_L); + this.logItem.setActionCommand(Commands.LOG_TO_FILE); + this.logItem.addActionListener(listener); + this.logItem.setEnabled(true); + this.logItem.setToolTipText("Redirect System.out to a file instead of terminal"); + toolsMenu.add(this.logItem); + + this.serverItem = new JMenuItem("Start AIDA Server ..."); + this.serverItem.setMnemonic(KeyEvent.VK_A); + this.serverItem.setActionCommand(Commands.START_AIDA_SERVER); + this.serverItem.setEnabled(true); + this.serverItem.setToolTipText("Start AIDA RMI Server"); + this.serverItem.addActionListener(listener); + toolsMenu.add(this.serverItem); + + final JMenu windowMenu = new JMenu("Window"); windowMenu.setMnemonic(KeyEvent.VK_W); add(windowMenu); - - JMenuItem maximizeItem = new JMenuItem("Maximize"); + + final JMenuItem maximizeItem = new JMenuItem("Maximize"); maximizeItem.setMnemonic(KeyEvent.VK_M); maximizeItem.setActionCommand(Commands.MAXIMIZE_WINDOW); maximizeItem.addActionListener(listener); maximizeItem.setEnabled(true); maximizeItem.setToolTipText("Maximize the application window"); windowMenu.add(maximizeItem); - - JMenuItem minimizeItem = new JMenuItem("Minimize"); + + final JMenuItem minimizeItem = new JMenuItem("Minimize"); minimizeItem.setMnemonic(KeyEvent.VK_I); minimizeItem.setActionCommand(Commands.MINIMIZE_WINDOW); minimizeItem.addActionListener(listener); minimizeItem.setEnabled(true); minimizeItem.setToolTipText("Minimize the application window"); windowMenu.add(minimizeItem); - - JMenuItem defaultsItem = new JMenuItem("Restore Defaults"); + + final JMenuItem defaultsItem = new JMenuItem("Restore Defaults"); defaultsItem.setMnemonic(KeyEvent.VK_D); defaultsItem.setActionCommand(Commands.DEFAULT_WINDOW); defaultsItem.addActionListener(listener); defaultsItem.setEnabled(true); defaultsItem.setToolTipText("Restore the window defaults"); - windowMenu.add(defaultsItem); - } - + windowMenu.add(defaultsItem); + } + + /** + * The {@link java.awt.event.ActionEvent} handling which sets GUI values from the model. + * + * @param the {@link java.awt.event.ActionEvent} to handle + */ @Override - public void propertyChange(PropertyChangeEvent evt) { - configurationModel.removePropertyChangeListener(this); - try { + public void actionPerformed(final ActionEvent e) { + if (e.getActionCommand().equals(Commands.DATA_SOURCE_CHANGED)) { + if (!this.configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) { + this.closeFileItem.setEnabled(true); + } else { + this.closeFileItem.setEnabled(false); + } + } + } + + /** + * The {@link java.beans.PropertyChangeEvent} handling which sets GUI values from the model. + * + * @param the {@link java.beans.PropertyChangeEvent} to handle + */ + @Override + public void propertyChange(final PropertyChangeEvent evt) { + this.configurationModel.removePropertyChangeListener(this); + try { if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) { - ConnectionStatus status = (ConnectionStatus) evt.getNewValue(); - boolean connected = status.equals(ConnectionStatus.CONNECTED); - closeFileItem.setEnabled(!connected); - openFileItem.setEnabled(!connected); + final ConnectionStatus status = (ConnectionStatus) evt.getNewValue(); + final boolean connected = status.equals(ConnectionStatus.CONNECTED); + this.closeFileItem.setEnabled(!connected); + this.openFileItem.setEnabled(!connected); } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) { - Boolean logToFile = (Boolean) evt.getNewValue(); - if (logToFile == true) { + final Boolean logToFile = (Boolean) evt.getNewValue(); + if (logToFile) { // Toggle log item state to send to terminal. - logItem.setText("Log to Terminal ..."); - logItem.setActionCommand(Commands.LOG_TO_TERMINAL); - logItem.setToolTipText("Log messages to the terminal"); + this.logItem.setText("Log to Terminal ..."); + this.logItem.setActionCommand(Commands.LOG_TO_TERMINAL); + this.logItem.setToolTipText("Log messages to the terminal"); } else { // Toggle log item state to send to file. - logItem.setText("Log to File ..."); - logItem.setActionCommand(Commands.LOG_TO_FILE); - logItem.setToolTipText("Log messages to a file"); + this.logItem.setText("Log to File ..."); + this.logItem.setActionCommand(Commands.LOG_TO_FILE); + this.logItem.setToolTipText("Log messages to a file"); } } else if (evt.getPropertyName().equals(ConfigurationModel.RECENT_FILES_PROPERTY)) { - setRecentFiles(configurationModel.getRecentFilesList()); - } - + setRecentFiles(this.configurationModel.getRecentFilesList()); + } + } finally { - configurationModel.addPropertyChangeListener(this); - } - } - - @Override - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals(Commands.DATA_SOURCE_CHANGED)) { - if (!configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) { - closeFileItem.setEnabled(true); - } else { - closeFileItem.setEnabled(false); - } - } - } - - void setRecentFiles(List<String> recentFiles) { - recentFilesMenu.removeAll(); - int fileMnemonic = 48; /* starts at KeyEvent.VK_0 */ - for (String recentFile : recentFiles) { - RecentFileItem recentFileItem = new RecentFileItem(recentFile, fileMnemonic); + this.configurationModel.addPropertyChangeListener(this); + } + } + + /** + * Set the recent file menu items. + * + * @param recentFiles the list of recent files from the model + */ + private void setRecentFiles(final List<String> recentFiles) { + this.recentFilesMenu.removeAll(); + int fileMnemonic = RECENT_FILES_START_INDEX; /* starts at KeyEvent.VK_0 */ + for (final String recentFile : recentFiles) { + final RecentFileItem recentFileItem = new RecentFileItem(recentFile, fileMnemonic); recentFileItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - String recentFile = ((RecentFileItem) e.getSource()).getPath(); - DataSourceType dst = DataSourceType.getDataSourceType(recentFile); - configurationModel.setDataSourcePath(recentFile); - configurationModel.setDataSourceType(dst); + @Override + public void actionPerformed(final ActionEvent e) { + final String recentFile = ((RecentFileItem) e.getSource()).getPath(); + final DataSourceType dst = DataSourceType.getDataSourceType(recentFile); + MenuBar.this.configurationModel.setDataSourcePath(recentFile); + MenuBar.this.configurationModel.setDataSourceType(dst); } - }); - recentFilesMenu.add(recentFileItem); + }); + this.recentFilesMenu.add(recentFileItem); ++fileMnemonic; - } - } - + } + } + + /** + * Set state for AIDA server started. + */ void startAIDAServer() { - serverItem.setActionCommand(Commands.STOP_AIDA_SERVER); - serverItem.setText("Stop AIDA Server"); - serverItem.setToolTipText("Stop the remote AIDA server"); - } - + this.serverItem.setActionCommand(Commands.STOP_AIDA_SERVER); + this.serverItem.setText("Stop AIDA Server"); + this.serverItem.setToolTipText("Stop the remote AIDA server"); + } + + /** + * Set state for AIDA server stopped. + */ void stopAIDAServer() { - serverItem.setActionCommand(Commands.START_AIDA_SERVER); - serverItem.setText("Start AIDA Server"); - serverItem.setToolTipText("Start the remote AIDA server"); + this.serverItem.setActionCommand(Commands.START_AIDA_SERVER); + this.serverItem.setText("Start AIDA Server"); + this.serverItem.setToolTipText("Start the remote AIDA server"); } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplication.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplication.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplication.java Tue Apr 21 14:48:39 2015 @@ -3,8 +3,8 @@ import hep.aida.jfree.AnalysisFactory; import hep.aida.jfree.plotter.PlotterRegion; import hep.aida.jfree.plotter.PlotterRegionListener; -import hep.aida.ref.remote.rmi.client.RmiStoreFactory; - + +import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; @@ -19,6 +19,7 @@ import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.logging.Handler; import java.util.logging.Level; @@ -28,7 +29,6 @@ import javax.imageio.ImageIO; import javax.swing.JFileChooser; -import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.filechooser.FileFilter; @@ -59,217 +59,278 @@ import org.lcsim.util.log.DefaultLogFormatter; /** - * This is the primary class that implements the monitoring GUI application. - * It should not be used directly. Instead the {@link Main} class should be - * used from the command line. - * - * @author Jeremy McCormick <[log in to unmask]> + * This is the primary class that implements the data monitoring GUI application. + * <p> + * It should not be used directly. Instead the {@link Main} class should be used from the command line. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ final class MonitoringApplication implements ActionListener, PropertyChangeListener { - // Statically initialize logging, which will be fully setup later. - static final Logger logger; - static { - logger = Logger.getLogger(MonitoringApplication.class.getSimpleName()); - } - static final Level DEFAULT_LEVEL = Level.ALL; - - // Default log stream. - MonitoringApplicationStreamHandler streamHandler; - LogHandler logHandler; - PrintStream sysOut = System.out; - PrintStream sysErr = System.err; - - // Application error handling. - ErrorHandler errorHandler; - - // The main GUI components inside a JFrame. - MonitoringApplicationFrame frame; - - // The primary data models. - final RunModel runModel = new RunModel(); - final ConfigurationModel configurationModel = new ConfigurationModel(); - final ConnectionStatusModel connectionModel = new ConnectionStatusModel(); - - // The default configuration resource embedded in the jar. - static final String DEFAULT_CONFIGURATION = "/org/hps/monitoring/config/default_config.prop"; - - // Encapsulation of ET connection and event processing. - EventProcessing processing; - - // Filters for opening files. - static final FileFilter lcioFilter = new FileNameExtensionFilter("LCIO files", "slcio"); - static final EvioFileFilter evioFilter = new EvioFileFilter(); - - AIDAServer server = new AIDAServer("hps-monitoring-app"); - static final RmiStoreFactory rsf = new RmiStoreFactory(); - - /** - * Default log handler. + /** + * The default log handler which puts records into the table GUI component. */ class LogHandler extends Handler { + + /** + * Close the handler. + * + * @throws SecurityException never + */ + @Override + public void close() throws SecurityException { + // Does nothing. + } + + /** + * Flush the handler. + */ + @Override + public void flush() { + // Does nothing. + } /** * This method inserts a record into the log table. */ - public void publish(LogRecord record) { + @Override + public void publish(final LogRecord record) { + // Add the record to the table's model. getLogRecordModel().add(record); } - - public void close() throws SecurityException { - } - - public void flush() { - } - } - - LogRecordModel getLogRecordModel() { - return frame.logPanel.logTable.model; - } - - LogTable getLogTable() { - return frame.logPanel.logTable; - } - + } + + /** + * Log handler which publishes messages to a stream (console or file in this case). + */ class MonitoringApplicationStreamHandler extends StreamHandler { - - MonitoringApplicationStreamHandler(PrintStream ps) { + + /** + * Class constructor. + * + * @param ps the output stream + */ + MonitoringApplicationStreamHandler(final PrintStream ps) { super(ps, new DefaultLogFormatter()); } - - public void publish(LogRecord record) { + + /** + * Publish a record which will automatically flush the handler. + * + * @param record the <code>LogRecord</code> to publish + */ + @Override + public void publish(final LogRecord record) { super.publish(record); + + // FIXME: Is this efficient? Should this always happen here? flush(); } - - public void setOutputStream(OutputStream out) { + + /** + * Set the output stream. + * + * @param out the output stream + */ + @Override + public void setOutputStream(final OutputStream out) { super.setOutputStream(out); - } - } - + } + } + + /** + * The default configuration resource from the jar. + */ + private static final String DEFAULT_CONFIGURATION = "/org/hps/monitoring/config/default_config.prop"; + + /** + * The default log level (shows all messages). + */ + private static final Level DEFAULT_LEVEL = Level.ALL; + + /** + * A filter for selecting EVIO files. + */ + private static final EvioFileFilter EVIO_FILTER = new EvioFileFilter(); + + /** + * A filter for selecting LCIO files. + */ + private static final FileFilter LCIO_FILTER = new FileNameExtensionFilter("LCIO files", "slcio"); + + /** + * Global logging object. + */ + private static final Logger LOGGER; + + /** + * Saved reference to <code>System.err</code> for convenience. + */ + private static final PrintStream SYS_ERR = System.err; + + /** + * Saved reference to <code>System.out</code> for convenience. + */ + private static final PrintStream SYS_OUT = System.out; + + /** + * Initialize logging which will be fully configured later. + */ + static { + LOGGER = Logger.getLogger(MonitoringApplication.class.getSimpleName()); + } + + /** + * Static utility method for creating new instance. + * + * @param configuration the application settings + * @return the new monitoring application instance + */ + static MonitoringApplication create(final Configuration configuration) { + return new MonitoringApplication(configuration); + } + + /** + * The global configuration model. + */ + private final ConfigurationModel configurationModel = new ConfigurationModel(); + + /** + * The global connection status model. + */ + private final ConnectionStatusModel connectionModel = new ConnectionStatusModel(); + + /** + * The error handling object. + */ + private ErrorHandler errorHandler; + + /** + * The primary GUI component which is a <code>JFrame</code>. + */ + private MonitoringApplicationFrame frame; + + /** + * The current log handler. + */ + private LogHandler logHandler; + + /** + * Event processing wrapper. + */ + private EventProcessing processing; + + /** + * The model which has information about the current run and events being processed. + */ + private final RunModel runModel = new RunModel(); + + /** + * A remote AIDA server instance. + */ + private final AIDAServer server = new AIDAServer("hps-monitoring-app"); + + /** + * The handler for putting messages into the log table. + */ + private MonitoringApplicationStreamHandler streamHandler; + /** * Instantiate and show the monitoring application with the given configuration. - * @param userConfiguration The Configuration object containing application settings. - */ - MonitoringApplication(Configuration userConfiguration) { - + * + * @param userConfiguration the Configuration object containing application settings + */ + MonitoringApplication(final Configuration userConfiguration) { + try { - + // Setup the main GUI component. - frame = new MonitoringApplicationFrame(this); - + this.frame = new MonitoringApplicationFrame(this); + // Add window listener to perform clean shutdown. - frame.addWindowListener(new WindowListener() { + this.frame.addWindowListener(new WindowListener() { @Override - public void windowOpened(WindowEvent e) { + public void windowActivated(final WindowEvent e) { } + /** + * Activate cleanup when window closes. + * + * @param e the window event + */ @Override - public void windowClosing(WindowEvent e) { - } - - @Override - public void windowClosed(WindowEvent e) { + public void windowClosed(final WindowEvent e) { exit(); } @Override - public void windowIconified(WindowEvent e) { + public void windowClosing(final WindowEvent e) { } @Override - public void windowDeiconified(WindowEvent e) { + public void windowDeactivated(final WindowEvent e) { } @Override - public void windowActivated(WindowEvent e) { + public void windowDeiconified(final WindowEvent e) { } @Override - public void windowDeactivated(WindowEvent e) { + public void windowIconified(final WindowEvent e) { + } + + @Override + public void windowOpened(final WindowEvent e) { } }); - + // Setup the error handler. - errorHandler = new ErrorHandler(frame, logger); - + this.errorHandler = new ErrorHandler(this.frame, LOGGER); + // Add this class as a listener on the configuration model. - configurationModel.addPropertyChangeListener(this); - + this.configurationModel.addPropertyChangeListener(this); + // Setup the logger. setupLogger(); - + // Setup AIDA plotting and connect it to the GUI. setupAida(); - + // Load the default configuration. loadConfiguration(new Configuration(DEFAULT_CONFIGURATION), false); - + if (userConfiguration != null) { // Load user configuration. loadConfiguration(userConfiguration, true); - } - + } + // Enable the GUI now that initialization is complete. - frame.setEnabled(true); - - logger.info("application initialized successfully"); - - } catch (Exception e) { + this.frame.setEnabled(true); + + LOGGER.info("application initialized successfully"); + + } catch (final Exception e) { // Don't use the ErrorHandler here because we don't know that it initialized successfully. System.err.println("MonitoringApplication failed to initialize without errors!"); - DialogUtil.showErrorDialog(null, "Error Starting Monitoring Application", "Monitoring application failed to initialize."); + DialogUtil.showErrorDialog(null, "Error Starting Monitoring Application", + "Monitoring application failed to initialize."); e.printStackTrace(); System.exit(1); - } - } - - /** - * Setup the logger. - */ - void setupLogger() { - logger.setUseParentHandlers(false); - logHandler = new LogHandler(); - logger.addHandler(logHandler); - streamHandler = new MonitoringApplicationStreamHandler(System.out); - logger.addHandler(streamHandler); - for (Handler handler : logger.getHandlers()) { - handler.setLevel(DEFAULT_LEVEL); - } - logger.setLevel(DEFAULT_LEVEL); - logger.info("logging initialized"); - } - - /** - * Static utility method for creating new instance. - * @param configuration The application settings. - * @return The new monitoring application instance. - */ - static MonitoringApplication create(Configuration configuration) { - return new MonitoringApplication(configuration); - } - - /** - * Handle property changes. - * @param evt The property change event. + } + } + + /** + * The primary action handler for the application. + * + * @param e the {@link java.awt.ActionEvent} to handle */ @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) { - setLogLevel(); - } - } - - /** - * The primary action handler for the application. - * @param e The ActionEvent to handle. - */ - public void actionPerformed(ActionEvent e) { - - //logger.finest("actionPerformed - " + e.getActionCommand()); - - String command = e.getActionCommand(); + public void actionPerformed(final ActionEvent e) { + + // logger.finest("actionPerformed - " + e.getActionCommand()); + + final String command = e.getActionCommand(); if (Commands.CONNECT.equals(command)) { startSession(); } else if (Commands.DISCONNECT.equals(command)) { @@ -278,20 +339,20 @@ savePlots(); } else if (Commands.EXIT.equals(command)) { // This will trigger the window closing action that cleans everything up. - frame.dispose(); - } else if (Commands.PAUSE.equals(command)) { - processing.pause(); + this.frame.dispose(); + } else if (Commands.PAUSE.equals(command)) { + this.processing.pause(); } else if (Commands.NEXT.equals(command)) { - processing.next(); + this.processing.next(); } else if (Commands.RESUME.equals(command)) { - processing.resume(); + this.processing.resume(); } else if (Commands.SHOW_SETTINGS.equals(command)) { showSettingsDialog(); } else if (Commands.LOAD_SETTINGS.equals(command)) { loadSettings(); } else if (Commands.SAVE_SETTINGS.equals(command)) { saveSettings(); - } else if (Commands.CLEAR_PLOTS.equals(command)) { + } else if (Commands.CLEAR_PLOTS.equals(command)) { clearPlots(); } else if (Commands.LOAD_DEFAULT_SETTINGS.equals(command)) { loadDefaultSettings(); @@ -320,545 +381,672 @@ } else if (Commands.STOP_AIDA_SERVER.equals(command)) { stopAIDAServer(); } - } - - /** - * Setup AIDA plotting into the GUI components. - */ - void setupAida() { - // Register the factory for displaying plots in tabs. - MonitoringAnalysisFactory.register(); - - // Set the root tab pane for displaying plots. - MonitoringPlotFactory.setRootPane(frame.plotPanel.getPlotPane()); - - // Setup the region listener to connect the plot info window. - MonitoringPlotFactory.setPlotterRegionListener(new PlotterRegionListener() { - @Override - public void regionSelected(PlotterRegion region) { - if (region != null) { - frame.plotInfoPanel.setCurrentRegion(region); - } + } + + /** + * Redirect <code>System.out</code> and <code>System.err</code> to a file chosen by a file chooser. + */ + private void chooseLogFile() { + final JFileChooser fc = new JFileChooser(); + fc.setAcceptAllFileFilterUsed(false); + fc.setDialogTitle("Save Log Messages to File"); + fc.setCurrentDirectory(new File(".")); + final int r = fc.showSaveDialog(this.frame); + if (r == JFileChooser.APPROVE_OPTION) { + final String fileName = fc.getSelectedFile().getPath(); + if (new File(fileName).exists()) { + DialogUtil.showErrorDialog(this.frame, "File Exists", "File already exists."); + } else { + logToFile(new File(fileName)); } - }); - - // Perform global configuration of the JFreeChart back end. - AnalysisFactory.configure(); - } - + } + } + + /** + * Clear the current set of AIDA plots in the default data tree. + */ + private void clearPlots() { + final int confirmation = DialogUtil.showConfirmationDialog(this.frame, + "Are you sure you want to clear the plots", "Clear Plots Confirmation"); + if (confirmation == JOptionPane.YES_OPTION) { + AIDA.defaultInstance().clearAll(); + DialogUtil.showInfoDialog(this.frame, "Plots Clear", "The AIDA plots were cleared."); + } + LOGGER.info("plots were cleared"); + } + + /** + * Remove the currently selected file from the data source list. + */ + private void closeFile() { + if (!this.configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) { + final DataSourceItem item = (DataSourceItem) this.frame.getToolbarPanel().getDataSourceComboBox() + .getSelectedItem(); + if (item.getPath().equals(this.configurationModel.getDataSourcePath())) { + this.frame.getToolbarPanel().getDataSourceComboBox() + .removeItem(this.frame.getToolbarPanel().getDataSourceComboBox().getSelectedItem()); + } + } + } + + /** + * Exit from the application from exit menu item or hitting close window button. + */ + private void exit() { + if (this.connectionModel.isConnected()) { + this.processing.stop(); + } + this.logHandler.setLevel(Level.OFF); + LOGGER.info("exiting the application"); + this.streamHandler.flush(); + System.exit(0); + } + + /** + * Get the current configuration model. + * + * @return the current configuration model + */ + ConfigurationModel getConfigurationModel() { + return this.configurationModel; + } + + /** + * Get the current connection status model. + * + * @return the current connections status model + */ + ConnectionStatusModel getConnectionModel() { + return this.connectionModel; + } + + /** + * Get the application's error handling object. + * + * @return the error handling object + */ + ErrorHandler getErrorHandler() { + return this.errorHandler; + } + + /** + * Get the logger. + * + * @return the logger + */ + Logger getLogger() { + return LOGGER; + } + + /** + * Get the table model for log records. + * + * @return the table model for log records + */ + LogRecordModel getLogRecordModel() { + return this.frame.getLogPanel().getLogTable().getLogRecordModel(); + } + + /** + * Get the log table. + * + * @return the log table + */ + LogTable getLogTable() { + return this.frame.getLogPanel().getLogTable(); + } + + /** + * Get a list of relevant run data from the model for writing to a PDF. + * + * @return the list of run data from the model + */ + private List<String> getRunData() { + final List<String> data = new ArrayList<String>(); + data.add("Created: " + new Date()); + data.add("Run Number: " + this.runModel.getRunNumber()); + data.add("Started: " + this.runModel.getStartDate()); + data.add("Ended: " + this.runModel.getEndDate()); + data.add("Length: " + this.runModel.getRunLength() + " seconds"); + data.add("Total Events: " + this.runModel.getTotalEvents()); + data.add("Elapsed Time: " + this.runModel.getElapsedTime()); + data.add("Events Processed: " + this.runModel.getEventsReceived()); + return data; + } + + /** + * Get the run model with information about the run and event(s) currently being processed. + * + * @return the run model + */ + RunModel getRunModel() { + return this.runModel; + } + /** * This method sets the configuration on the model, which fires a change for every property. - * @param configuration The new configuration. - * @param merge True to merge the configuration into the current one rather than replace it. - */ - void loadConfiguration(Configuration configuration, boolean merge) { - + * + * @param configuration the new configuration + * @param merge <code>true</code> to merge the configuration into the current one rather than replace it + */ + private void loadConfiguration(final Configuration configuration, final boolean merge) { + if (merge) { // This will merge in additional properties so that default or current settings are preserved. - configurationModel.merge(configuration); + this.configurationModel.merge(configuration); } else { // HACK: Clear data source combo box for clean configuration. - frame.toolbarPanel.dataSourceComboBox.removeAllItems(); - + this.frame.getToolbarPanel().getDataSourceComboBox().removeAllItems(); + // This will reset all configuration properties. - configurationModel.setConfiguration(configuration); - } - - if (configuration.getFile() != null) - logger.config("loaded config from file " + configuration.getFile().getPath()); - else - logger.config("loaded config from resource " + configuration.getResourcePath()); - } - + this.configurationModel.setConfiguration(configuration); + } + + if (configuration.getFile() != null) { + LOGGER.config("loaded config from file " + configuration.getFile().getPath()); + } else { + LOGGER.config("loaded config from resource " + configuration.getResourcePath()); + } + } + + /** + * Load default application settings. + */ + private void loadDefaultSettings() { + loadConfiguration(new Configuration(MonitoringApplication.DEFAULT_CONFIGURATION), false); + DialogUtil.showInfoDialog(this.frame, "Default Configuration Loaded", "The default configuration was loaded."); + LOGGER.config("default settings loaded"); + } + + /** + * Load settings from a properties file using a file chooser. + */ + private void loadSettings() { + final JFileChooser fc = new JFileChooser(); + fc.setDialogTitle("Load Settings"); + fc.setCurrentDirectory(new File(".")); + final int r = fc.showDialog(this.frame, "Load ..."); + if (r == JFileChooser.APPROVE_OPTION) { + final File f = fc.getSelectedFile(); + loadConfiguration(new Configuration(f), true); + LOGGER.info("loaded configuration from file: " + f.getPath()); + DialogUtil.showInfoDialog(this.frame, "Settings Loaded", "Settings were loaded successfully."); + } + } + + /** + * Redirect <code>System.out</code> and <code>System.err</code> to a file. + * + * @param file the output log file + * @throws FileNotFoundException if the file does not exist + */ + private void logToFile(final File file) { + try { + + // Create the output file stream. + final PrintStream fileStream = new PrintStream(new FileOutputStream(file.getPath())); + System.setOut(fileStream); + System.setErr(fileStream); + + // Flush the current handler, but do NOT close here or System.out gets clobbered! + this.streamHandler.flush(); + + // Replace the current handler with one using the file stream. + LOGGER.removeHandler(this.streamHandler); + this.streamHandler = new MonitoringApplicationStreamHandler(fileStream); + this.streamHandler.setLevel(LOGGER.getLevel()); + LOGGER.addHandler(this.streamHandler); + + // Set the properties on the model. + this.configurationModel.setLogFileName(file.getPath()); + this.configurationModel.setLogToFile(true); + + LOGGER.info("Saving log messages to " + this.configurationModel.getLogFileName()); + DialogUtil.showInfoDialog(this.frame, "Logging to File", "Log messages redirected to file" + '\n' + + this.configurationModel.getLogFileName()); + + } catch (final FileNotFoundException e) { + this.errorHandler.setError(e).log().showErrorDialog(); + } + } + + /** + * Send <code>System.out</code> and <code>System.err</code> back to the terminal, e.g. if they were previously sent + * to a file. + */ + private void logToTerminal() { + + // Reset System.out and err back to original streams. + System.setOut(MonitoringApplication.SYS_OUT); + System.setErr(MonitoringApplication.SYS_ERR); + + // Flush and close the current handler, which is using a file stream. + this.streamHandler.flush(); + this.streamHandler.close(); + + // Replace the handler with the one printing to the terminal. + LOGGER.removeHandler(this.streamHandler); + this.streamHandler = new MonitoringApplicationStreamHandler(System.out); + this.streamHandler.setLevel(LOGGER.getLevel()); + LOGGER.addHandler(this.streamHandler); + + LOGGER.log(Level.INFO, "log messages redirected to terminal"); + + // Update the model to indicate logging to file has been disabled. + this.configurationModel.setLogToFile(false); + + DialogUtil.showInfoDialog(this.frame, "Log to Terminal", "Log messages will be sent to the terminal."); + } + + /** + * Maximize the application window. + */ + private void maximizeWindow() { + this.frame.setExtendedState(Frame.MAXIMIZED_BOTH); + } + + /** + * Minimize the application window. + */ + private void minimizeWindow() { + this.frame.setExtendedState(Frame.ICONIFIED); + } + + /** + * Open a file data source using a <code>JFileChooser</code>. + */ + private void openFile() { + final JFileChooser fc = new JFileChooser(System.getProperty("user.dir")); + fc.setAcceptAllFileFilterUsed(false); + fc.addChoosableFileFilter(LCIO_FILTER); + fc.addChoosableFileFilter(EVIO_FILTER); + fc.setDialogTitle("Select Data File"); + final int r = fc.showDialog(this.frame, "Select ..."); + if (r == JFileChooser.APPROVE_OPTION) { + + // Set data source path. + final String filePath = fc.getSelectedFile().getPath(); + + // Set data source type. + final FileFilter filter = fc.getFileFilter(); + DataSourceType type = null; + if (filter == LCIO_FILTER) { + type = DataSourceType.LCIO_FILE; + } else if (filter == EVIO_FILTER) { + type = DataSourceType.EVIO_FILE; + } else { + // This should never happen. + throw new RuntimeException(); + } + + this.configurationModel.setDataSourcePath(filePath); + this.configurationModel.setDataSourceType(type); + + this.configurationModel.addRecentFile(filePath); + + LOGGER.config("set new data source " + filePath + " with type " + type); + } + } + + /** + * Handle property changes. + * + * @param evt the <code>PropertyChangeEvent</code> to handle + */ + @Override + public void propertyChange(final PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) { + setLogLevel(); + } + } + /** * Reset the plots and clear the tabs in the plot window. */ - void resetPlots() { - + private void resetPlots() { + // Clear global list of registered plotters. - MonitoringPlotFactory.getPlotterRegistry().clear(); - + MonitoringPlotFactory.getPlotterRegistry().clear(); + // Clear the static AIDA tree in case plots are hanging around from previous sessions. AIDA.defaultInstance().clearAll(); // Reset plot panel which removes all its tabs. - frame.plotPanel.reset(); - - logger.info("plots were cleared"); - } - - /** - * Configure the system status monitor panel for a new job. - */ - void setupSystemStatusMonitor() { - - // Clear the system status monitor table. - frame.systemStatusPanel.clear(); - - // Get the global registry of SystemStatus objects. - SystemStatusRegistry registry = SystemStatusRegistry.getSystemStatusRegistery(); - - // Process the SystemStatus objects. - for (SystemStatus systemStatus : registry.getSystemStatuses()) { - // This will add the status to the two tables. - frame.systemStatusPanel.addSystemStatus(systemStatus); - } - - logger.info("system status monitor initialized successfully"); - } - - /** - * Start a new monitoring session. - */ - synchronized void startSession() { - - logger.info("starting new session"); - - try { - - // Reset the plot panel and global AIDA state. - resetPlots(); - - // The system status registry is cleared here before any event processors - // which might create a SystemStatus are added to the event processing chain - // e.g. an LCSim Driver, etc. - SystemStatusRegistry.getSystemStatusRegistery().clear(); - - // List of extra composite record processors including the updater for the RunPanel. - List<CompositeRecordProcessor> processors = new ArrayList<CompositeRecordProcessor>(); - processors.add(frame.dashboardPanel.new EventDashboardUpdater()); - - // Add Driver to update the trigger diagnostics tables. - List<Driver> drivers = new ArrayList<Driver>(); - drivers.add(frame.triggerPanel.new TriggerDiagnosticGUIDriver()); - - // Add listener to push conditions changes to conditions panel. - List<ConditionsListener> conditionsListeners = new ArrayList<ConditionsListener>(); - conditionsListeners.add(frame.conditionsPanel.new ConditionsPanelListener()); - - // Instantiate the event processing wrapper. - processing = new EventProcessing(this, processors, drivers, conditionsListeners); - - // Connect to the ET system, if applicable. - processing.connect(); - - // Configure event processing from the global application settings, including setup of record loop. - logger.info("setting up event processing on source " + configurationModel.getDataSourcePath() - + " with type " + configurationModel.getDataSourceType()); - processing.setup(configurationModel); - - // Setup the system status monitor table. - setupSystemStatusMonitor(); - - // Start the event processing thread. - processing.start(); - - logger.info("new session successfully initialized"); - - } catch (Exception e) { - - // Disconnect from the ET system. - processing.disconnect(); - - // Log the error that occurred and show a pop up dialog. - errorHandler.setError(e).log().printStackTrace().showErrorDialog("There was an error while starting the session." - + '\n' + "See the log for details.", "Session Error"); - - logger.severe("failed to start new session"); - } - } - - /** - * Exit from the application from exit menu item or hitting close window button. - */ - void exit() { - if (connectionModel.isConnected()) { - processing.stop(); - } - logHandler.setLevel(Level.OFF); - logger.info("exiting the application"); - streamHandler.flush(); - System.exit(0); - } - + this.frame.getPlotPanel().reset(); + + LOGGER.info("plots were cleared"); + } + + /** + * Restore the default GUI layout. + */ + private void restoreDefaultWindow() { + maximizeWindow(); + this.frame.restoreDefaults(); + } + + /** + * Run the disconnection on a separate thread. + */ + private void runDisconnectThread() { + new Thread() { + @Override + public void run() { + LOGGER.fine("disconnect thread is running ..."); + MonitoringApplication.this.connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTING); + MonitoringApplication.this.processing.stop(); + LOGGER.fine("disconnect thread finished!"); + } + }.run(); + } + + /** + * Save the log table to a file using a file chooser. + */ + private void saveLogTable() { + saveTable(this.frame.getLogPanel().getLogTable()); + } + /** * Save plots to an AIDA, ROOT or PDF file using a file chooser. */ - void savePlots() { - JFileChooser fc = new JFileChooser(); + private void savePlots() { + final JFileChooser fc = new JFileChooser(); fc.addChoosableFileFilter(new FileNameExtensionFilter("ROOT file", "root")); - FileFilter filter = new FileNameExtensionFilter("AIDA file", "aida"); + final FileFilter filter = new FileNameExtensionFilter("AIDA file", "aida"); fc.addChoosableFileFilter(filter); fc.addChoosableFileFilter(new FileNameExtensionFilter("PDF file", "pdf")); fc.setAcceptAllFileFilterUsed(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setFileFilter(filter); - int r = fc.showSaveDialog(frame); + final int r = fc.showSaveDialog(this.frame); if (r == JFileChooser.APPROVE_OPTION) { - File selectedFile = fc.getSelectedFile(); + final File selectedFile = fc.getSelectedFile(); if (!selectedFile.exists()) { String fileName = fc.getSelectedFile().getAbsolutePath(); - String extension = ((FileNameExtensionFilter) fc.getFileFilter()).getExtensions()[0]; + final String extension = ((FileNameExtensionFilter) fc.getFileFilter()).getExtensions()[0]; if (!fileName.endsWith(".aida") && !fileName.endsWith(".root") && !fileName.endsWith(".pdf")) { fileName += "." + extension; } try { - if (extension.equals("pdf")) { + if ("pdf".equals(extension)) { // Write to a single PDF file. - ExportPdf.write(MonitoringPlotFactory.getPlotterRegistry().getPlotters(), fileName); + ExportPdf.write(MonitoringPlotFactory.getPlotterRegistry().getPlotters(), fileName, + getRunData()); } else { // Save plot object data to AIDA or ROOT file. AIDA.defaultInstance().saveAs(fileName); } - logger.info("saved plots to " + fileName); - DialogUtil.showInfoDialog(frame, "Plots Saved", "Plots were successfully saved to " + '\n' + fileName); - } catch (IOException e) { - errorHandler.setError(e).setMessage("Error Saving Plots").printStackTrace().log().showErrorDialog(); + LOGGER.info("saved plots to " + fileName); + DialogUtil.showInfoDialog(this.frame, "Plots Saved", "Plots were successfully saved to " + '\n' + + fileName); + } catch (final IOException e) { + this.errorHandler.setError(e).setMessage("Error Saving Plots").printStackTrace().log() + .showErrorDialog(); } } else { - DialogUtil.showErrorDialog(frame, "File Exists", "Selected file already exists."); + DialogUtil.showErrorDialog(this.frame, "File Exists", "Selected file already exists."); } } } - - /** - * Clear the current set of AIDA plots in the default data tree. - */ - void clearPlots() { - int confirmation = DialogUtil.showConfirmationDialog(frame, - "Are you sure you want to clear the plots", "Clear Plots Confirmation"); - if (confirmation == JOptionPane.YES_OPTION) { - AIDA.defaultInstance().clearAll(); - DialogUtil.showInfoDialog(frame, "Plots Clear", "The AIDA plots were cleared."); - } - logger.info("plots were cleared"); - } - - /** - * Load default application settings. - */ - void loadDefaultSettings() { - loadConfiguration(new Configuration(MonitoringApplication.DEFAULT_CONFIGURATION), false); - DialogUtil.showInfoDialog(frame, "Default Configuration Loaded", "The default configuration was loaded."); - logger.config("default settings loaded"); - } - - /** - * Show the settings dialog window. - */ - void showSettingsDialog() { - frame.settingsDialog.setVisible(true); - } - - /** - * Open a file data source using a <code>JFileChooser</code>. - */ - void openFile() { - JFileChooser fc = new JFileChooser(System.getProperty("user.dir")); - fc.setAcceptAllFileFilterUsed(false); - fc.addChoosableFileFilter(lcioFilter); - fc.addChoosableFileFilter(evioFilter); - fc.setDialogTitle("Select Data File"); - int r = fc.showDialog(frame, "Select ..."); - if (r == JFileChooser.APPROVE_OPTION) { - - // Set data source path. - final String filePath = fc.getSelectedFile().getPath(); - - // Set data source type. - FileFilter filter = fc.getFileFilter(); - DataSourceType type = null; - if (filter == lcioFilter) { - type = DataSourceType.LCIO_FILE; - } else if (filter == evioFilter) { - type = DataSourceType.EVIO_FILE; - } else { - // This should never happen. - throw new RuntimeException(); - } - - configurationModel.setDataSourcePath(filePath); - configurationModel.setDataSourceType(type); - - configurationModel.addRecentFile(filePath); - - logger.config("set new data source " + filePath + " with type " + type); - } - } - - /** - * Save current settings to a file using a file chooser. - */ - void saveSettings() { - JFileChooser fc = new JFileChooser(); - fc.setDialogTitle("Save Configuration"); - fc.setCurrentDirectory(new File(".")); - int r = fc.showSaveDialog(frame); - if (r == JFileChooser.APPROVE_OPTION) { - File f = fc.getSelectedFile(); - configurationModel.getConfiguration().writeToFile(f); - logger.info("saved configuration to file: " + f.getPath()); - DialogUtil.showInfoDialog(frame, "Settings Saved", "Settings were saved successfully."); - } - } - - /** - * Load settings from a properties file using a file chooser. - */ - void loadSettings() { - JFileChooser fc = new JFileChooser(); - fc.setDialogTitle("Load Settings"); - fc.setCurrentDirectory(new File(".")); - int r = fc.showDialog(frame, "Load ..."); - if (r == JFileChooser.APPROVE_OPTION) { - File f = fc.getSelectedFile(); - loadConfiguration(new Configuration(f), true); - logger.info("loaded configuration from file: " + f.getPath()); - DialogUtil.showInfoDialog(frame, "Settings Loaded", "Settings were loaded successfully."); - } - } - - /** - * Maximize the application window. - */ - void maximizeWindow() { - frame.setExtendedState(JFrame.MAXIMIZED_BOTH); - } - - /** - * Minimize the application window. - */ - void minimizeWindow() { - frame.setExtendedState(JFrame.ICONIFIED); - } - - /** - * Restore the default GUI layout. - */ - void restoreDefaultWindow() { - maximizeWindow(); - frame.restoreDefaults(); - } - - /** - * Remove the currently selected file from the data source list. - */ - void closeFile() { - if (!configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) { - DataSourceItem item = (DataSourceItem) frame.toolbarPanel.dataSourceComboBox.getSelectedItem(); - if (item.getPath().equals(configurationModel.getDataSourcePath())) { - frame.toolbarPanel.dataSourceComboBox.removeItem(frame.toolbarPanel.dataSourceComboBox.getSelectedItem()); - } - } - } - + /** * Save a screenshot to a file using a file chooser. */ - void saveScreenshot() { - JFileChooser fc = new JFileChooser(); + private void saveScreenshot() { + final JFileChooser fc = new JFileChooser(); fc.setAcceptAllFileFilterUsed(false); fc.setDialogTitle("Save Screenshot"); - FileNameExtensionFilter pngFilter = new FileNameExtensionFilter("png file (*.png)", "png"); - String format = pngFilter.getExtensions()[0]; + final FileNameExtensionFilter pngFilter = new FileNameExtensionFilter("png file (*.png)", "png"); + final String format = pngFilter.getExtensions()[0]; fc.addChoosableFileFilter(pngFilter); fc.setCurrentDirectory(new File(".")); - int r = fc.showSaveDialog(frame); - if (r == JFileChooser.APPROVE_OPTION) { + final int r = fc.showSaveDialog(this.frame); + if (r == JFileChooser.APPROVE_OPTION) { String fileName = fc.getSelectedFile().getPath(); if (!fileName.endsWith("." + format)) { fileName += "." + format; } - frame.repaint(); - Object lock = new Object(); - synchronized (lock) { - try { - lock.wait(500); - } catch (InterruptedException e) { - e.printStackTrace(); + /* + * final Object lock = new Object(); synchronized (lock) { try { lock.wait(500); } catch (final + * InterruptedException e) { e.printStackTrace(); } } + */ + writeScreenshot(fileName, format); + DialogUtil.showInfoDialog(this.frame, "Screenshot Saved", "Screenshot was saved to file" + '\n' + fileName); + LOGGER.info("saved screenshot to " + fileName); + } + } + + /** + * Save current settings to a file using a file chooser. + */ + private void saveSettings() { + final JFileChooser fc = new JFileChooser(); + fc.setDialogTitle("Save Configuration"); + fc.setCurrentDirectory(new File(".")); + final int r = fc.showSaveDialog(this.frame); + if (r == JFileChooser.APPROVE_OPTION) { + final File f = fc.getSelectedFile(); + this.configurationModel.getConfiguration().writeToFile(f); + LOGGER.info("saved configuration to file: " + f.getPath()); + DialogUtil.showInfoDialog(this.frame, "Settings Saved", "Settings were saved successfully."); + } + } + + /** + * Export a JTable's data to a comma-delimited text file using a file chooser. + * + * @param table the table to export + */ + private void saveTable(final JTable table) { + final JFileChooser fc = new JFileChooser(); + fc.setDialogTitle("Save Table to Text File"); + fc.setCurrentDirectory(new File(".")); + final int r = fc.showSaveDialog(this.frame); + if (r == JFileChooser.APPROVE_OPTION) { + final String fileName = fc.getSelectedFile().getPath(); + try { + TableExporter.export(table, fileName, ','); + LOGGER.info("saved table data to " + fileName); + DialogUtil.showInfoDialog(this.frame, "Table Data Saved", "The table was exported successfully."); + } catch (final IOException e) { + DialogUtil.showErrorDialog(this.frame, "Table Export Error", "The table export failed."); + LOGGER.warning("failed to save table data to " + fileName); + } + } + } + + /** + * Set the log level from the configuration model. + */ + private void setLogLevel() { + final Level newLevel = this.configurationModel.getLogLevel(); + if (LOGGER.getLevel() != newLevel) { + LOGGER.setLevel(newLevel); + LOGGER.log(Level.INFO, "Log Level was changed to <" + this.configurationModel.getLogLevel().toString() + + ">"); + } + } + + /** + * Setup AIDA plotting into the GUI components. + */ + private void setupAida() { + // Register the factory for displaying plots in tabs. + MonitoringAnalysisFactory.register(); + + // Set the root tab pane for displaying plots. + MonitoringPlotFactory.setRootPane(this.frame.getPlotPanel().getPlotPane()); + + // Setup the region listener to connect the plot info window. + MonitoringPlotFactory.setPlotterRegionListener(new PlotterRegionListener() { + @Override + public void regionSelected(final PlotterRegion region) { + if (region != null) { + MonitoringApplication.this.frame.getPlotInfoPanel().setCurrentRegion(region); } } - writeScreenshot(fileName, format); - DialogUtil.showInfoDialog(frame, "Screenshot Saved", "Screenshot was saved to file" + '\n' + fileName); - logger.info("saved screenshot to " + fileName); - } + }); + + // Perform global configuration of the JFreeChart back end. + AnalysisFactory.configure(); + } + + /** + * Setup the logger. + */ + private void setupLogger() { + LOGGER.setUseParentHandlers(false); + this.logHandler = new LogHandler(); + LOGGER.addHandler(this.logHandler); + this.streamHandler = new MonitoringApplicationStreamHandler(System.out); + LOGGER.addHandler(this.streamHandler); + for (final Handler handler : LOGGER.getHandlers()) { + handler.setLevel(DEFAULT_LEVEL); + } + LOGGER.setLevel(DEFAULT_LEVEL); + LOGGER.info("logging initialized"); + } + + /** + * Configure the system status monitor panel for a new job. + */ + private void setupSystemStatusMonitor() { + + // Clear the system status monitor table. + this.frame.getSystemStatusPanel().clear(); + + // Get the global registry of SystemStatus objects. + final SystemStatusRegistry registry = SystemStatusRegistry.getSystemStatusRegistery(); + + // Process the SystemStatus objects. + for (final SystemStatus systemStatus : registry.getSystemStatuses()) { + // This will add the status to the two tables. + this.frame.getSystemStatusPanel().addSystemStatus(systemStatus); + } + + LOGGER.info("system status monitor initialized successfully"); + } + + /** + * Show the settings dialog window. + */ + private void showSettingsDialog() { + this.frame.getSettingsDialog().setVisible(true); + } + + /** + * Start the AIDA server instance. + */ + private void startAIDAServer() { + if (this.configurationModel.hasValidProperty(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) { + this.server.setName(this.configurationModel.getAIDAServerName()); + } + final boolean started = this.server.start(); + if (started) { + this.frame.getApplicationMenu().startAIDAServer(); + LOGGER.info("AIDA server started at " + this.server.getName()); + DialogUtil + .showInfoDialog(this.frame, "AIDA Server Started", "The remote AIDA server started successfully."); + } else { + LOGGER.warning("AIDA server failed to start"); + DialogUtil.showErrorDialog(this.frame, "Failed to Start AIDA Server", + "The remote AIDA server failed to start."); + } + } + + /** + * Start a new monitoring session. + */ + private synchronized void startSession() { + + LOGGER.info("starting new session"); + + try { + + // Reset the plot panel and global AIDA state. + resetPlots(); + + // The system status registry is cleared here before any event processors + // which might create a SystemStatus are added to the event processing chain + // e.g. an LCSim Driver, etc. + SystemStatusRegistry.getSystemStatusRegistery().clear(); + + // List of extra composite record processors including the updater for the RunPanel. + final List<CompositeRecordProcessor> processors = new ArrayList<CompositeRecordProcessor>(); + processors.add(this.frame.getEventDashboard().new EventDashboardUpdater()); + + // Add Driver to update the trigger diagnostics tables. + final List<Driver> drivers = new ArrayList<Driver>(); + drivers.add(this.frame.getTriggerPanel().new TriggerDiagnosticGUIDriver()); + + // Add listener to push conditions changes to conditions panel. + final List<ConditionsListener> conditionsListeners = new ArrayList<ConditionsListener>(); + conditionsListeners.add(this.frame.getConditionsPanel().new ConditionsPanelListener()); + + // Instantiate the event processing wrapper. + this.processing = new EventProcessing(this, processors, drivers, conditionsListeners); + + // Connect to the ET system, if applicable. + this.processing.connect(); + + // Configure event processing from the global application settings, including setup of record loop. + LOGGER.info("setting up event processing on source " + this.configurationModel.getDataSourcePath() + + " with type " + this.configurationModel.getDataSourceType()); + this.processing.setup(this.configurationModel); + + // Setup the system status monitor table. + setupSystemStatusMonitor(); + + // Start the event processing thread. + this.processing.start(); + + LOGGER.info("new session successfully initialized"); + + } catch (final Exception e) { + + // Disconnect from the ET system. + this.processing.disconnect(); + + // Log the error that occurred and show a pop up dialog. + this.errorHandler + .setError(e) + .log() + .printStackTrace() + .showErrorDialog( + "There was an error while starting the session." + '\n' + "See the log for details.", + "Session Error"); + + LOGGER.severe("failed to start new session"); + } + } + + /** + * Stop the AIDA server instance. + */ + private void stopAIDAServer() { + this.server.disconnect(); + this.frame.getApplicationMenu().stopAIDAServer(); + LOGGER.info("AIDA server was stopped"); + DialogUtil.showInfoDialog(this.frame, "AIDA Server Stopped", "The AIDA server was stopped."); } /** * Save a screenshot to an output file. - * @param fileName The name of the output file. - */ - void writeScreenshot(String fileName, String format) { - BufferedImage image = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB); - frame.paint(image.getGraphics()); + * + * @param fileName the name of the output file + * @param format the output file format (must be accepted by <code>ImageIO</code>) + */ + private void writeScreenshot(final String fileName, final String format) { + this.frame.repaint(); + final BufferedImage image = new BufferedImage(this.frame.getWidth(), this.frame.getHeight(), + BufferedImage.TYPE_INT_RGB); + this.frame.paint(image.getGraphics()); try { ImageIO.write(image, format, new File(fileName)); - } catch (IOException e) { - errorHandler.setError(e).setMessage("Failed to save screenshot.").printStackTrace().log().showErrorDialog(); - } - } - - /** - * Set the log level from the configuration model. - */ - void setLogLevel() { - Level newLevel = configurationModel.getLogLevel(); - if (logger.getLevel() != newLevel) { - logger.setLevel(newLevel); - logger.log(Level.INFO, "Log Level was changed to <" + configurationModel.getLogLevel().toString() + ">"); - } - } - - /** - * Export a JTable's data to a comma-delimited text file using a file chooser. - */ - void saveTable(JTable table) { - JFileChooser fc = new JFileChooser(); - fc.setDialogTitle("Save Table to Text File"); - fc.setCurrentDirectory(new File(".")); - int r = fc.showSaveDialog(frame); - if (r == JFileChooser.APPROVE_OPTION) { - String fileName = fc.getSelectedFile().getPath(); - try { - TableExporter.export(table, fileName, ','); - logger.info("saved table data to " + fileName); - DialogUtil.showInfoDialog(frame, "Table Data Saved", "The table was exported successfully."); - } catch (IOException e) { - DialogUtil.showErrorDialog(frame, "Table Export Error", "The table export failed."); - logger.warning("failed to save table data to " + fileName); - } - } - } - - /** - * Save the log table to a file using a file chooser. - */ - void saveLogTable() { - saveTable(frame.logPanel.logTable); - } - - /** - * Redirect <code>System.out</code> and <code>System.err</code> to file chosen - * by a file chooser. - */ - void chooseLogFile() { - JFileChooser fc = new JFileChooser(); - fc.setAcceptAllFileFilterUsed(false); - fc.setDialogTitle("Save Log Messages to File"); - fc.setCurrentDirectory(new File(".")); - int r = fc.showSaveDialog(frame); - if (r == JFileChooser.APPROVE_OPTION) { - String fileName = fc.getSelectedFile().getPath(); - if (new File(fileName).exists()) { - DialogUtil.showErrorDialog(frame, "File Exists", "File already exists."); - } else { - logToFile(new File(fileName)); - } - } - } - - /** - * Redirect <code>System.out</code> and <code>System.err</code> to a file. - * @param file The output log file. - * @throws FileNotFoundException if the file does not exist. - */ - void logToFile(File file) { - try { - - // Create the output file stream. - PrintStream fileStream = new PrintStream(new FileOutputStream(file.getPath())); - System.setOut(fileStream); - System.setErr(fileStream); - - // Flush the current handler, but do NOT close here or System.out gets clobbered! - streamHandler.flush(); - - // Replace the current handler with one using the file stream. - logger.removeHandler(streamHandler); - streamHandler = new MonitoringApplicationStreamHandler(fileStream); - streamHandler.setLevel(logger.getLevel()); - logger.addHandler(streamHandler); - - // Set the properties on the model. - configurationModel.setLogFileName(file.getPath()); - configurationModel.setLogToFile(true); - - logger.info("Saving log messages to " + configurationModel.getLogFileName()); - DialogUtil.showInfoDialog(frame, "Logging to File", - "Log messages redirected to file" + '\n' + configurationModel.getLogFileName()); - - } catch (FileNotFoundException e) { - errorHandler.setError(e).log().showErrorDialog(); - } - } - - /** - * Send <code>System.out</code> and <code>System.err</code> back to the terminal, - * e.g. if they were previously sent to a file. - */ - void logToTerminal() { - - // Reset System.out and err back to original streams. - System.setOut(sysOut); - System.setErr(sysErr); - - // Flush and close the current handler, which is using a file stream. - streamHandler.flush(); - streamHandler.close(); - - // Replace the handler with the one printing to the terminal. - logger.removeHandler(streamHandler); - streamHandler = new MonitoringApplicationStreamHandler(System.out); - streamHandler.setLevel(logger.getLevel()); - logger.addHandler(streamHandler); - - logger.log(Level.INFO, "log messages redirected to terminal"); - - // Update the model to indicate logging to file has been disabled. - configurationModel.setLogToFile(false); - - DialogUtil.showInfoDialog(frame, "Log to Terminal", "Log messages will be sent to the terminal."); - } - - /** - * Start the AIDA server instance. - */ - void startAIDAServer() { - if (configurationModel.hasValidProperty(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) { - server.setName(configurationModel.getAIDAServerName()); - } - boolean started = server.start(); - if (started) { - frame.menu.startAIDAServer(); - logger.info("AIDA server started at " + server.getName()); - DialogUtil.showInfoDialog(frame, "AIDA Server Started", "The remote AIDA server started successfully."); - } else { - logger.warning("AIDA server failed to start"); - DialogUtil.showErrorDialog(frame, "Failed to Start AIDA Server", "The remote AIDA server failed to start."); - } - } - - /** - * Stop the AIDA server instance. - */ - void stopAIDAServer() { - server.disconnect(); - frame.menu.stopAIDAServer(); - logger.info("AIDA server was stopped"); - DialogUtil.showInfoDialog(frame, "AIDA Server Stopped", "The AIDA server was stopped."); - } - - /** - * Run the disconnection on a separate thread. - */ - void runDisconnectThread() { - new Thread() { - public void run() { - logger.fine("disconnect thread is running ..."); - connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTING); - MonitoringApplication.this.processing.stop(); - logger.fine("disconnect thread finished!"); - } - }.run(); - } -} + } catch (final IOException e) { + this.errorHandler.setError(e).setMessage("Failed to save screenshot.").printStackTrace().log() + .showErrorDialog(); + } + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java Tue Apr 21 14:48:39 2015 @@ -2,6 +2,7 @@ import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.Frame; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; @@ -12,132 +13,283 @@ /** * This class instantiates the primary GUI components of the monitoring application. - * - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ @SuppressWarnings("serial") -class MonitoringApplicationFrame extends JFrame { - - EventDashboard dashboardPanel; - PlotPanel plotPanel; - PlotInfoPanel plotInfoPanel; - LogPanel logPanel; - TriggerDiagnosticsPanel triggerPanel; - ConditionsPanel conditionsPanel; - SystemStatusPanel systemStatusPanel; - ToolbarPanel toolbarPanel; - MenuBar menu; - - JSplitPane mainSplitPane; - JSplitPane rightSplitPane; - JSplitPane leftSplitPane; - - SettingsDialog settingsDialog; - - static final Rectangle BOUNDS = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); - static final int PIXEL_WIDTH_MAX = (int) BOUNDS.getWidth(); - static final int PIXEL_HEIGHT_MAX = (int) BOUNDS.getHeight(); - - /** - * - * @param listener - */ - public MonitoringApplicationFrame( - MonitoringApplication application) { - +final class MonitoringApplicationFrame extends JFrame { + + /** + * The current graphics bounds. + */ + private static final Rectangle BOUNDS = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); + + /** + * The maximum height of a window in pixels. + */ + private static final int PIXEL_HEIGHT_MAX = (int) BOUNDS.getHeight(); + + /** + * The maximum width of a window in pixels. + */ + private static final int PIXEL_WIDTH_MAX = (int) BOUNDS.getWidth(); + + /** + * The conditions panel. + */ + private final ConditionsPanel conditionsPanel; + + /** + * The dashboard panel. + */ + private final EventDashboard dashboardPanel; + + /** + * The left split pane that divides the dashboard and the tabs. + */ + private final JSplitPane leftSplitPane; + + /** + * The log panel. + */ + private final LogPanel logPanel; + + /** + * The primary split pain dividing the left and right panels. + */ + private final JSplitPane mainSplitPane; + + /** + * The application's menu bar. + */ + private final MenuBar menu; + + /** + * The plot info panel. + */ + private final PlotInfoPanel plotInfoPanel; + + /** + * The plot panel. + */ + private final PlotPanel plotPanel; + + /** + * The right split pane showing plots and statistics. + */ + private final JSplitPane rightSplitPane; + + /** + * The settings dialog window. + */ + private final SettingsDialog settingsDialog; + + /** + * The system status panel which shows under the tabs. + */ + private final SystemStatusPanel systemStatusPanel; + + /** + * The toolbar panel with the buttons, data source and connection information. + */ + private final ToolbarPanel toolbarPanel; + + /** + * The trigger diagnostics panel. + */ + private final TriggerDiagnosticsPanel triggerPanel; + + /** + * Class constructor. + * + * @param application the associated application object + */ + public MonitoringApplicationFrame(final MonitoringApplication application) { + // Disable interaction until specifically enabled externally after initialization. - setEnabled(false); - + this.setEnabled(false); + // Create the content panel. - JPanel contentPanel = new JPanel(); - setContentPane(contentPanel); + final JPanel contentPanel = new JPanel(); + this.setContentPane(contentPanel); contentPanel.setLayout(new BorderLayout()); contentPanel.setOpaque(true); contentPanel.setPreferredSize(new Dimension(PIXEL_WIDTH_MAX, PIXEL_HEIGHT_MAX)); - + // Create the top panel. - toolbarPanel = new ToolbarPanel(application.configurationModel, application.connectionModel, application); - contentPanel.add(toolbarPanel, BorderLayout.NORTH); - + this.toolbarPanel = new ToolbarPanel(application.getConfigurationModel(), application.getConnectionModel(), + application); + contentPanel.add(this.toolbarPanel, BorderLayout.NORTH); + // Create the bottom panel. - JPanel bottomPanel = new JPanel(); + final JPanel bottomPanel = new JPanel(); bottomPanel.setLayout(new BorderLayout()); contentPanel.add(bottomPanel, BorderLayout.CENTER); - + // Create the left panel. - JPanel leftPanel = new JPanel(); + final JPanel leftPanel = new JPanel(); leftPanel.setLayout(new BorderLayout()); - + // Create the run dashboard. - dashboardPanel = new EventDashboard(application.runModel); + this.dashboardPanel = new EventDashboard(application.getRunModel()); // Create the tabbed pane for content in bottom of left panel such as log table and system monitor. - JTabbedPane tableTabbedPane = new JTabbedPane(); - + final JTabbedPane tableTabbedPane = new JTabbedPane(); + // Create the log table and add it to the tabs. - logPanel = new LogPanel(application.configurationModel, application); - tableTabbedPane.addTab("Log Messages", logPanel); - + this.logPanel = new LogPanel(application.getConfigurationModel(), application); + tableTabbedPane.addTab("Log Messages", this.logPanel); + // Create the system monitor. - //systemStatusTable = new SystemStatusTable(); - systemStatusPanel = new SystemStatusPanel(); - tableTabbedPane.addTab("System Status Monitor", systemStatusPanel); - + // systemStatusTable = new SystemStatusTable(); + this.systemStatusPanel = new SystemStatusPanel(); + tableTabbedPane.addTab("System Status Monitor", this.systemStatusPanel); + // Add the trigger diagnostics tables. - triggerPanel = new TriggerDiagnosticsPanel(); - tableTabbedPane.addTab("Trigger Diagnostics", triggerPanel); - + this.triggerPanel = new TriggerDiagnosticsPanel(); + tableTabbedPane.addTab("Trigger Diagnostics", this.triggerPanel); + // Add the conditions panel. - conditionsPanel = new ConditionsPanel(); - tableTabbedPane.addTab("Detector Conditions", conditionsPanel); - + this.conditionsPanel = new ConditionsPanel(); + tableTabbedPane.addTab("Detector Conditions", this.conditionsPanel); + // Vertical split pane in left panel. - leftSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, dashboardPanel, tableTabbedPane); - leftSplitPane.setDividerLocation(250); - leftPanel.add(leftSplitPane, BorderLayout.CENTER); - + this.leftSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, this.dashboardPanel, tableTabbedPane); + this.leftSplitPane.setDividerLocation(250); + leftPanel.add(this.leftSplitPane, BorderLayout.CENTER); + // Create the right panel. - JPanel rightPanel = new JPanel(); + final JPanel rightPanel = new JPanel(); rightPanel.setLayout(new BorderLayout()); - + // Create the plot info panel. - plotInfoPanel = new PlotInfoPanel(); - + this.plotInfoPanel = new PlotInfoPanel(); + // Create the plot panel. - plotPanel = new PlotPanel(); - plotInfoPanel.saveButton.addActionListener(plotPanel); - + this.plotPanel = new PlotPanel(); + this.plotInfoPanel.addActionListener(this.plotPanel); + // Create the right panel vertical split pane for displaying plots and their information and statistics. - rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, plotPanel, plotInfoPanel); - rightSplitPane.setDividerLocation(680); - rightPanel.add(rightSplitPane, BorderLayout.CENTER); - + this.rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, this.plotPanel, this.plotInfoPanel); + this.rightSplitPane.setDividerLocation(680); + rightPanel.add(this.rightSplitPane, BorderLayout.CENTER); + // Create the main horizontal split pane for dividing the left and right panels. - mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel); - mainSplitPane.setDividerLocation(600); - bottomPanel.add(mainSplitPane, BorderLayout.CENTER); - + this.mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel); + this.mainSplitPane.setDividerLocation(600); + bottomPanel.add(this.mainSplitPane, BorderLayout.CENTER); + // Create the menu bar. - menu = new MenuBar(application.configurationModel, application.connectionModel, application); - setJMenuBar(menu); - toolbarPanel.dataSourceComboBox.addActionListener(menu); - + this.menu = new MenuBar(application.getConfigurationModel(), application.getConnectionModel(), application); + this.setJMenuBar(this.menu); + this.toolbarPanel.getDataSourceComboBox().addActionListener(this.menu); + // Setup the settings dialog box (invisible until activated). - settingsDialog = new SettingsDialog(application.configurationModel, application); - - // Setup the frame now that all components have been added. - pack(); - setExtendedState(JFrame.MAXIMIZED_BOTH); - setVisible(true); - } - + this.settingsDialog = new SettingsDialog(application.getConfigurationModel(), application); + + // Setup the frame now that all components have been added. + this.pack(); + this.setExtendedState(Frame.MAXIMIZED_BOTH); + this.setVisible(true); + } + + /** + * Get the application menu. + * + * @return the application menu + */ + MenuBar getApplicationMenu() { + return this.menu; + } + + /** + * Get the panel showing conditions information. + * + * @return the conditions panel + */ + ConditionsPanel getConditionsPanel() { + return this.conditionsPanel; + } + + /** + * Get the panel for the dashboard. + * + * @return the dashboard panel + */ + EventDashboard getEventDashboard() { + return this.dashboardPanel; + } + + /** + * Get the panel that shows the log table and controls. + * + * @return the log panel + */ + LogPanel getLogPanel() { + return this.logPanel; + } + + /** + * Get the plot info panel that shows plot statistics. + * + * @return the plot info panel + */ + PlotInfoPanel getPlotInfoPanel() { + return this.plotInfoPanel; + } + + /** + * Get the plot panel for displaying AIDA plots. + * + * @return the plot panel + */ + PlotPanel getPlotPanel() { + return this.plotPanel; + } + + /** + * Get the settings dialog window. + * + * @return the settings dialog window + */ + SettingsDialog getSettingsDialog() { + return this.settingsDialog; + } + + /** + * Get the system status panel. + * + * @return the system status panel + */ + SystemStatusPanel getSystemStatusPanel() { + return this.systemStatusPanel; + } + + /** + * Get the toolbar panel with the buttons etc. + * + * @return the toolbar panel + */ + ToolbarPanel getToolbarPanel() { + return this.toolbarPanel; + } + + /** + * Get the trigger diagnostics panel. + * + * @return the trigger diagnostics panel + */ + TriggerDiagnosticsPanel getTriggerPanel() { + return this.triggerPanel; + } + /** * Restore default window settings. */ void restoreDefaults() { - setExtendedState(JFrame.MAXIMIZED_BOTH); - mainSplitPane.resetToPreferredSizes(); - leftSplitPane.resetToPreferredSizes(); - rightSplitPane.resetToPreferredSizes(); - } -} + this.setExtendedState(Frame.MAXIMIZED_BOTH); + this.mainSplitPane.resetToPreferredSizes(); + this.leftSplitPane.resetToPreferredSizes(); + this.rightSplitPane.resetToPreferredSizes(); + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java Tue Apr 21 14:48:39 2015 @@ -38,149 +38,284 @@ /** * <p> - * This is a GUI component for showing the statistics and other information about an AIDA plot - * when it is clicked on in the monitoring application. + * This is a GUI component for showing the statistics and other information about an AIDA plot when it is clicked on in + * the monitoring application. * <p> * The information in the table is updated dynamically via the <code>AIDAObserver</code> API on the AIDA object. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class PlotInfoPanel extends JPanel implements AIDAListener, ActionListener, FunctionListener { - - JComboBox<Object> plotComboBox; - JTable infoTable = new JTable(); - DefaultTableModel model; - JButton saveButton; - - PlotterRegion currentRegion; - Object currentObject; - - static final int MAX_ROWS = 13; - static final int MIN_WIDTH = 400; - static final int MIN_HEIGHT = 300; - static final String[] COLUMN_NAMES = { "Field", "Value" }; - static final String PLOT_SELECTED = "PlotSelected"; - - Timer timer = new Timer(); +@SuppressWarnings("serial") +final class PlotInfoPanel extends JPanel implements AIDAListener, ActionListener, FunctionListener, AddActionListener { + + /** + * The names of the two columns. + */ + private static final String[] COLUMN_NAMES = {"Field", "Value"}; + + /** + * The maximum number of rows in the table. + */ + private static final int MAX_ROWS = 13; + + /** + * Minimum height of panel in pixels. + */ + private static final int MIN_HEIGHT = 300; + + /** + * Minimum width of panel in pixels. + */ + private static final int MIN_WIDTH = 400; + + /** + * The currently selected AIDA object. + */ + private Object currentObject; + + /** + * The currently selected plotter region. + */ + private PlotterRegion currentRegion; + + /** + * The table showing plot statistics. + */ + private final JTable infoTable = new JTable(); + + /** + * The default table model. + */ + private DefaultTableModel model; + + /** + * The combo box for selecting the object from the region. + */ + private JComboBox<Object> plotComboBox; + + /** + * The button for saving plot graphics.. + */ + private JButton saveButton; + + /** + * The timer for updating the table. + */ + private final Timer timer = new Timer(); /** * Class constructor, which will setup the GUI components. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked"}) PlotInfoPanel() { - - setLayout(new FlowLayout(FlowLayout.CENTER)); - - JPanel leftPanel = new JPanel(); + + this.setLayout(new FlowLayout(FlowLayout.CENTER)); + + final JPanel leftPanel = new JPanel(); leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS)); leftPanel.setPreferredSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); - - Dimension filler = new Dimension(0, 10); - + + final Dimension filler = new Dimension(0, 10); + // Save button. - saveButton = new JButton("Save Plots ..."); - saveButton.setActionCommand(Commands.SAVE_SELECTED_PLOTS); - saveButton.setAlignmentX(CENTER_ALIGNMENT); - leftPanel.add(saveButton); - + this.saveButton = new JButton("Save Current Plot Tab ..."); + this.saveButton.setActionCommand(Commands.SAVE_SELECTED_PLOTS); + this.saveButton.setAlignmentX(CENTER_ALIGNMENT); + leftPanel.add(this.saveButton); + leftPanel.add(new Box.Filler(filler, filler, filler)); // Combo box for selecting plotted object. - plotComboBox = new JComboBox<Object>() { + this.plotComboBox = new JComboBox<Object>() { + @Override public Dimension getMaximumSize() { - Dimension max = super.getMaximumSize(); - max.height = getPreferredSize().height; + final Dimension max = super.getMaximumSize(); + max.height = this.getPreferredSize().height; return max; } }; - plotComboBox.setActionCommand(PLOT_SELECTED); - plotComboBox.setAlignmentX(CENTER_ALIGNMENT); - plotComboBox.setRenderer(new BasicComboBoxRenderer() { + this.plotComboBox.setActionCommand(Commands.PLOT_SELECTED); + this.plotComboBox.setAlignmentX(CENTER_ALIGNMENT); + this.plotComboBox.setRenderer(new BasicComboBoxRenderer() { + @Override @SuppressWarnings("rawtypes") - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + public Component getListCellRendererComponent(final JList list, final Object value, final int index, + final boolean isSelected, final boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value != null) { - String title = getObjectTitle(value); - setText(value.getClass().getSimpleName() + " - " + title); + final String title = PlotInfoPanel.this.getObjectTitle(value); + this.setText(value.getClass().getSimpleName() + " - " + title); } else { - setText("Click on a plot region ..."); + this.setText("Click on a plot region ..."); } return this; } }); - plotComboBox.addActionListener(this); - leftPanel.add(plotComboBox); - + this.plotComboBox.addActionListener(this); + leftPanel.add(this.plotComboBox); + leftPanel.add(new Box.Filler(filler, filler, filler)); - + // Table with plot info. - String data[][] = new String[0][0]; - model = new DefaultTableModel(data, COLUMN_NAMES); - model.setColumnIdentifiers(COLUMN_NAMES); - infoTable.setModel(model); - ((DefaultTableModel)infoTable.getModel()).setRowCount(MAX_ROWS); - infoTable.setAlignmentX(CENTER_ALIGNMENT); - leftPanel.add(infoTable); - - add(leftPanel); - } - - /** - * This method will be called when the backing AIDA object is updated and a state change is - * fired via the <code>AIDAObservable</code> API. The table is updated to reflect the new state - * of the object. - * @param evt The EventObject pointing to the backing AIDA object. + final String[][] data = new String[0][0]; + this.model = new DefaultTableModel(data, COLUMN_NAMES); + this.model.setColumnIdentifiers(COLUMN_NAMES); + this.infoTable.setModel(this.model); + ((DefaultTableModel) this.infoTable.getModel()).setRowCount(MAX_ROWS); + this.infoTable.setAlignmentX(CENTER_ALIGNMENT); + leftPanel.add(this.infoTable); + + this.add(leftPanel); + } + + /** + * Implementation of <code>actionPerformed</code> to handle the selection of a new object from the combo box. + * + * @param e the {@link java.awt.event.ActionEvent} to handle */ @Override - public void stateChanged(final EventObject evt) { - - // Make a timer task for running the update. - TimerTask task = new TimerTask() { - public void run() { - - // Is the state change from the current AIDAObservable? - if (evt.getSource() != currentObject) { - // Assume this means that a different AIDAObservable was selected in the GUI. - return; - } - - // Update the table values on the Swing EDT. - runUpdateTable(); - - // Set the observable to valid so subsequent state changes are received. - ((AIDAObservable) currentObject).setValid((AIDAListener) PlotInfoPanel.this); - } - }; - - /* - * Schedule the task to run in ~0.5 seconds. If the Runnable runs immediately, somehow the - * observable state gets permanently set to invalid and additional state changes will not be - * received! - */ - timer.schedule(task, 500); - } - - /** - * Implementation of <code>actionPerformed</code> to handle the selection of a new object from - * the combo box. + public void actionPerformed(final ActionEvent e) { + // Is there a new item selected in the combo box? + if (Commands.PLOT_SELECTED.equals(e.getActionCommand())) { + if (this.plotComboBox.getSelectedItem() != null) { + // Set the current object from the combo box value, to update the GUI state. + this.setCurrentObject(this.plotComboBox.getSelectedItem()); + } + } + } + + /** + * Assign an action listener to certain components. + * + * @param listener the action listener to add */ @Override - public void actionPerformed(ActionEvent e) { - // Is there a new item selected in the combo box? - if (PLOT_SELECTED.equals(e.getActionCommand())) { - if (plotComboBox.getSelectedItem() != null) { - // Set the current object from the combo box value, to update the GUI state. - setCurrentObject(plotComboBox.getSelectedItem()); - } - } - } - - /** - * Get the title of an AIDA object. Unfortunately there is no base type with this information, - * so it is read manually from each possible type. - * @param object The AIDA object. - * @return The title of the object from its title method or value of its toString method, if - * none exists. - */ - String getObjectTitle(Object object) { + public void addActionListener(final ActionListener listener) { + this.saveButton.addActionListener(listener); + } + + /** + * Add this object as an <code>AIDAListener</code> on the current <code>AIDAObservable</code>. + */ + private void addListener() { + if (this.currentObject instanceof AIDAObservable && !(this.currentObject instanceof FunctionDispatcher)) { + // Setup a listener on the current AIDA object. + final AIDAObservable observable = (AIDAObservable) this.currentObject; + observable.addListener(this); + observable.setValid(this); + observable.setConnected(true); + } else if (this.currentObject instanceof IFunction) { + if (this.currentObject instanceof FunctionDispatcher) { + ((FunctionDispatcher) this.currentObject).addFunctionListener(this); + } + } + } + + /** + * Add a row to the info table. + * + * @param field the field name + * @param value the field value + */ + private void addRow(final String field, final Object value) { + this.model.insertRow(this.infoTable.getRowCount(), new Object[] {field, value}); + } + + /** + * Add rows to the info table from the state of a 2D cloud. + * + * @param cloud the AIDA object + */ + private void addRows(final ICloud2D cloud) { + this.addRow("title", cloud.title()); + this.addRow("entries", cloud.entries()); + this.addRow("max entries", cloud.maxEntries()); + this.addRow("x lower edge", cloud.lowerEdgeX()); + this.addRow("x upper edge", cloud.upperEdgeX()); + this.addRow("y lower edge", cloud.lowerEdgeY()); + this.addRow("y upper edge", cloud.upperEdgeY()); + this.addRow("x mean", String.format("%.10f%n", cloud.meanX())); + this.addRow("y mean", String.format("%.10f%n", cloud.meanY())); + this.addRow("x rms", String.format("%.10f%n", cloud.rmsX())); + this.addRow("y rms", String.format("%.10f%n", cloud.rmsY())); + } + + /** + * Add rows to the info table from the state of a function. + * + * @param function the AIDA function object + */ + private void addRows(final IFunction function) { + this.addRow("title", function.title()); + + // Add generically the values of all function parameters. + for (final String parameter : function.parameterNames()) { + this.addRow(parameter, function.parameter(parameter)); + } + } + + /** + * Add rows to the info table from the state of a 1D histogram. + * + * @param histogram the AIDA object + */ + private void addRows(final IHistogram1D histogram) { + this.addRow("title", histogram.title()); + this.addRow("bins", histogram.axis().bins()); + this.addRow("entries", histogram.entries()); + this.addRow("mean", String.format("%.10f%n", histogram.mean())); + this.addRow("rms", String.format("%.10f%n", histogram.rms())); + this.addRow("sum bin heights", histogram.sumBinHeights()); + this.addRow("max bin height", histogram.maxBinHeight()); + this.addRow("overflow entries", histogram.binEntries(IAxis.OVERFLOW_BIN)); + this.addRow("underflow entries", histogram.binEntries(IAxis.UNDERFLOW_BIN)); + } + + /** + * Add rows to the info table from the state of a 2D histogram. + * + * @param histogram the AIDA object + */ + private void addRows(final IHistogram2D histogram) { + this.addRow("title", histogram.title()); + this.addRow("x bins", histogram.xAxis().bins()); + this.addRow("y bins", histogram.yAxis().bins()); + this.addRow("entries", histogram.entries()); + this.addRow("x mean", String.format("%.10f%n", histogram.meanX())); + this.addRow("y mean", String.format("%.10f%n", histogram.meanY())); + this.addRow("x rms", String.format("%.10f%n", histogram.rmsX())); + this.addRow("y rms", String.format("%.10f%n", histogram.rmsY())); + this.addRow("sum bin heights", histogram.sumBinHeights()); + this.addRow("max bin height", histogram.maxBinHeight()); + this.addRow("x overflow entries", histogram.binEntriesX(IAxis.OVERFLOW_BIN)); + this.addRow("y overflow entries", histogram.binEntriesY(IAxis.OVERFLOW_BIN)); + this.addRow("x underflow entries", histogram.binEntriesX(IAxis.UNDERFLOW_BIN)); + this.addRow("y underflow entries", histogram.binEntriesY(IAxis.UNDERFLOW_BIN)); + } + + /** + * Callback for updating from changed to <code>IFunction</code> object. + * + * @param event the change event (unused in this method) + */ + @Override + public void functionChanged(final FunctionChangedEvent event) { + try { + this.runUpdateTable(); + } catch (final Exception e) { + e.printStackTrace(); + } + } + + /** + * Get the title of an AIDA object. Unfortunately there is no base type with this information, so it is read + * manually from each possible type. + * + * @param object the AIDA object + * @return the title of the object from its title method or value of its <code>toString</code> method, if none + * exists + */ + private String getObjectTitle(final Object object) { if (object instanceof IBaseHistogram) { return ((IBaseHistogram) object).title(); } else if (object instanceof IDataPointSet) { @@ -193,226 +328,166 @@ } /** - * Set the current plotter region, which will rebuild the GUI accordingly. - * @param region The current plotter region. - */ - synchronized void setCurrentRegion(PlotterRegion region) { - if (region != currentRegion) { - currentRegion = region; - updateComboBox(); - setCurrentObject(plotComboBox.getSelectedItem()); - setupContentPane(); - } - } - - /** - * Configure the frame's content panel from current component settings. - */ - void setupContentPane() { - plotComboBox.setSize(plotComboBox.getPreferredSize()); - infoTable.setSize(infoTable.getPreferredSize()); - setVisible(true); - } - - /** - * Update the info table from the state of the current AIDA object. - */ - void updateTable() { - model.setRowCount(0); - if (currentObject instanceof IHistogram1D) { - addRows((IHistogram1D) currentObject); - } else if (currentObject instanceof IHistogram2D) { - addRows((IHistogram2D) currentObject); - } else if (currentObject instanceof ICloud2D) { - addRows((ICloud2D) currentObject); - } else if (currentObject instanceof ICloud1D) { - if (((ICloud1D) currentObject).isConverted()) { - addRows(((ICloud1D) currentObject).histogram()); - } - } else if (currentObject instanceof IFunction) { - addRows((IFunction) currentObject); - } - } - - /** - * Run the {@link #updateTable()} method on the Swing EDT. - */ - void runUpdateTable() { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - updateTable(); - } - }); - } - - /** - * Update the combo box contents with the plots from the current region. - */ - void updateComboBox() { - plotComboBox.removeAllItems(); - List<Object> objects = currentRegion.getPlottedObjects(); - for (Object object : objects) { - if (isValidObject(object)) { - plotComboBox.addItem(object); - } - } - } - - boolean isValidObject(Object object) { - if (object == null) + * Return <code>true</code> if the object is a valid AIDA object. + * + * @param object the object + * @return <code>true</code> if object is a valid AIDA object + */ + private boolean isValidObject(final Object object) { + if (object == null) { return false; + } if (object instanceof IBaseHistogram || object instanceof IFunction || object instanceof IDataPointSet) { return true; - } + } return false; } /** - * Add rows to the info table from the state of a 1D histogram. - * @param histogram The AIDA object. - */ - void addRows(IHistogram1D histogram) { - addRow("title", histogram.title()); - addRow("bins", histogram.axis().bins()); - addRow("entries", histogram.entries()); - addRow("mean", String.format("%.10f%n", histogram.mean())); - addRow("rms", String.format("%.10f%n", histogram.rms())); - addRow("sum bin heights", histogram.sumBinHeights()); - addRow("max bin height", histogram.maxBinHeight()); - addRow("overflow entries", histogram.binEntries(IAxis.OVERFLOW_BIN)); - addRow("underflow entries", histogram.binEntries(IAxis.UNDERFLOW_BIN)); - } - - /** - * Add rows to the info table from the state of a 2D histogram. - * @param histogram The AIDA object. - */ - void addRows(IHistogram2D histogram) { - addRow("title", histogram.title()); - addRow("x bins", histogram.xAxis().bins()); - addRow("y bins", histogram.yAxis().bins()); - addRow("entries", histogram.entries()); - addRow("x mean", String.format("%.10f%n", histogram.meanX())); - addRow("y mean", String.format("%.10f%n", histogram.meanY())); - addRow("x rms", String.format("%.10f%n", histogram.rmsX())); - addRow("y rms", String.format("%.10f%n", histogram.rmsY())); - addRow("sum bin heights", histogram.sumBinHeights()); - addRow("max bin height", histogram.maxBinHeight()); - addRow("x overflow entries", histogram.binEntriesX(IAxis.OVERFLOW_BIN)); - addRow("y overflow entries", histogram.binEntriesY(IAxis.OVERFLOW_BIN)); - addRow("x underflow entries", histogram.binEntriesX(IAxis.UNDERFLOW_BIN)); - addRow("y underflow entries", histogram.binEntriesY(IAxis.UNDERFLOW_BIN)); - } - - /** - * Add rows to the info table from the state of a 2D cloud. - * @param cloud The AIDA object. - */ - void addRows(ICloud2D cloud) { - addRow("title", cloud.title()); - addRow("entries", cloud.entries()); - addRow("max entries", cloud.maxEntries()); - addRow("x lower edge", cloud.lowerEdgeX()); - addRow("x upper edge", cloud.upperEdgeX()); - addRow("y lower edge", cloud.lowerEdgeY()); - addRow("y upper edge", cloud.upperEdgeY()); - addRow("x mean", String.format("%.10f%n", cloud.meanX())); - addRow("y mean", String.format("%.10f%n", cloud.meanY())); - addRow("x rms", String.format("%.10f%n", cloud.rmsX())); - addRow("y rms", String.format("%.10f%n", cloud.rmsY())); - } - - /** - * Add rows to the info table from the state of a 2D cloud. - * @param cloud The AIDA object. - */ - void addRows(IFunction function) { - addRow("title", function.title()); - - // Add generically the values of all function parameters. - for (String parameter : function.parameterNames()) { - addRow(parameter, function.parameter(parameter)); - } - } - - /** - * Add a row to the info table. - * @param field The field name. - * @param value The field value. - */ - void addRow(String field, Object value) { - model.insertRow(infoTable.getRowCount(), new Object[] { field, value }); - } - - /** - * Set the current AIDA object that backs this GUI, i.e. an IHistogram1D etc. - * @param object The backing AIDA object. - */ - synchronized void setCurrentObject(Object object) { - - if (object == null) + * Remove this as a listener on the current AIDA object. + */ + private void removeListener() { + if (this.currentObject != null) { + if (this.currentObject instanceof AIDAObservable && !(this.currentObject instanceof IFunction)) { + // Remove this object as an listener on the AIDA observable. + ((AIDAObservable) this.currentObject).removeListener(this); + } else if (this.currentObject instanceof FunctionDispatcher) { + // Remove this object as function listener. + ((FunctionDispatcher) this.currentObject).removeFunctionListener(this); + } + } + } + + /** + * Run the {@link #updateTable()} method on the Swing EDT. + */ + private void runUpdateTable() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + PlotInfoPanel.this.updateTable(); + } + }); + } + + /** + * Set the current AIDA object that backs this GUI, i.e. an IHistogram1D or other plot object etc. + * + * @param object the backing AIDA object + */ + private synchronized void setCurrentObject(final Object object) { + + if (object == null) { throw new IllegalArgumentException("The object arg is null!"); - - if (object == currentObject) + } + + if (object == this.currentObject) { return; + } // Remove the AIDAListener from the previous object. - removeListener(); + this.removeListener(); // Set the current object reference. - currentObject = object; + this.currentObject = object; // Update the table immediately with information from the current object. // We need to wait for this the first time, so we know the preferred size // of the table GUI component when resizing the content pane. - updateTable(); + this.updateTable(); // Add an AIDAListener to the AIDA object via the AIDAObservable API. - addListener(); - } - - /** - * Remove this as a listener on the current AIDA object. - */ - void removeListener() { - if (currentObject != null) { - if (currentObject instanceof AIDAObservable && !(currentObject instanceof IFunction)) { - // Remove this object as an listener on the AIDA observable. - ((AIDAObservable) currentObject).removeListener(this); - } else if (currentObject instanceof FunctionDispatcher) { - // Remove this object as function listener. - ((FunctionDispatcher)currentObject).removeFunctionListener(this); - } - } - } - - /** - * Add this object as an <code>AIDAListener</code> on the current <code>AIDAObservable</code>. - */ - void addListener() { - if (currentObject instanceof AIDAObservable && !(currentObject instanceof FunctionDispatcher)) { - // Setup a listener on the current AIDA object. - AIDAObservable observable = (AIDAObservable) currentObject; - observable.addListener(this); - observable.setValid(this); - observable.setConnected(true); - } else if (currentObject instanceof IFunction) { - if (currentObject instanceof FunctionDispatcher) { - ((FunctionDispatcher)currentObject).addFunctionListener(this); - } - } - } - - /** - * Callback for updating from changed to <code>IFunction</code> object. - * @param event The change event (unused in this method). + this.addListener(); + } + + /** + * Set the current plotter region, which will rebuild the GUI accordingly. + * + * @param region The current plotter region. + */ + synchronized void setCurrentRegion(final PlotterRegion region) { + if (region != this.currentRegion) { + this.currentRegion = region; + this.updateComboBox(); + this.setCurrentObject(this.plotComboBox.getSelectedItem()); + this.setupContentPane(); + } + } + + /** + * Configure the frame's content panel from current component settings. + */ + private void setupContentPane() { + this.plotComboBox.setSize(this.plotComboBox.getPreferredSize()); + this.infoTable.setSize(this.infoTable.getPreferredSize()); + this.setVisible(true); + } + + /** + * This method will be called when the backing AIDA object is updated and a state change is fired via the + * <code>AIDAObservable</code> API. The table is updated to reflect the new state of the object. + * + * @param evt the EventObject pointing to the backing AIDA object */ @Override - public void functionChanged(FunctionChangedEvent event) { - try { - runUpdateTable(); - } catch (Exception e) { - e.printStackTrace(); - } - } -} + public void stateChanged(final EventObject evt) { + + // Make a timer task for running the update. + final TimerTask task = new TimerTask() { + @Override + public void run() { + + // Is the state change from the current AIDAObservable? + if (evt.getSource() != PlotInfoPanel.this.currentObject) { + // Assume this means that a different AIDAObservable was selected in the GUI. + return; + } + + // Update the table values on the Swing EDT. + PlotInfoPanel.this.runUpdateTable(); + + // Set the observable to valid so subsequent state changes are received. + ((AIDAObservable) PlotInfoPanel.this.currentObject).setValid(PlotInfoPanel.this); + } + }; + + /* + * Schedule the task to run in ~0.5 seconds. If the Runnable runs immediately, somehow the observable state gets + * permanently set to invalid and additional state changes will not be received! + */ + this.timer.schedule(task, 500); + } + + /** + * Update the combo box contents with the plots from the current region. + */ + private void updateComboBox() { + this.plotComboBox.removeAllItems(); + final List<Object> objects = this.currentRegion.getPlottedObjects(); + for (final Object object : objects) { + if (this.isValidObject(object)) { + this.plotComboBox.addItem(object); + } + } + } + + /** + * Update the info table from the state of the current AIDA object. + */ + private void updateTable() { + this.model.setRowCount(0); + if (this.currentObject instanceof IHistogram1D) { + this.addRows((IHistogram1D) this.currentObject); + } else if (this.currentObject instanceof IHistogram2D) { + this.addRows((IHistogram2D) this.currentObject); + } else if (this.currentObject instanceof ICloud2D) { + this.addRows((ICloud2D) this.currentObject); + } else if (this.currentObject instanceof ICloud1D) { + if (((ICloud1D) this.currentObject).isConverted()) { + this.addRows(((ICloud1D) this.currentObject).histogram()); + } + } else if (this.currentObject instanceof IFunction) { + this.addRows((IFunction) this.currentObject); + } + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotPanel.java Tue Apr 21 14:48:39 2015 @@ -6,83 +6,130 @@ import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import javax.imageio.ImageIO; import javax.swing.JFileChooser; import javax.swing.JPanel; import javax.swing.JTabbedPane; +import javax.swing.filechooser.FileNameExtensionFilter; import org.hps.monitoring.application.util.DialogUtil; +import org.hps.monitoring.plotting.ExportPdf; import org.hps.monitoring.plotting.MonitoringPlotFactory; /** * This is the panel containing the tabs with the monitoring plots. - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class PlotPanel extends JPanel implements ActionListener { - - private JTabbedPane plotPane; - +@SuppressWarnings("serial") +final class PlotPanel extends JPanel implements ActionListener { + + /** + * The tabs containing the plots. + */ + private final JTabbedPane plotPane; + + /** + * Class constructor. + */ public PlotPanel() { - setLayout(new BorderLayout()); - plotPane = new JTabbedPane(); - plotPane.setPreferredSize(getPreferredSize()); - add(plotPane, BorderLayout.CENTER); - } - - JTabbedPane getPlotPane() { - return plotPane; + this.setLayout(new BorderLayout()); + this.plotPane = new JTabbedPane(); + this.plotPane.setPreferredSize(this.getPreferredSize()); + this.add(this.plotPane, BorderLayout.CENTER); } /** - * Get the indices of the current selected tabs. - * @return The indices of the current tabs. + * Handle an {@link java.awt.event.ActionEvent}. + * + * @param event the {@link java.awt.event.ActionEvent} to handle */ - int[] getSelectedTabs() { - int[] indices = new int[2]; - indices[0] = plotPane.getSelectedIndex(); - Component component = plotPane.getSelectedComponent(); - if (component instanceof JTabbedPane) { - indices[1] = ((JTabbedPane)component).getSelectedIndex(); - } - return indices; - } - - public void actionPerformed(ActionEvent event) { + @Override + public void actionPerformed(final ActionEvent event) { if (event.getActionCommand().equals(Commands.SAVE_SELECTED_PLOTS)) { - int[] indices = getSelectedTabs(); - IPlotter plotter = MonitoringPlotFactory.getPlotterRegistry().find(indices[0], indices[1]); + final int[] indices = this.getSelectedTabIndices(); + final IPlotter plotter = MonitoringPlotFactory.getPlotterRegistry().find(indices[0], indices[1]); if (plotter != null) { - savePlotter(plotter); + this.savePlotter(plotter); } else { DialogUtil.showErrorDialog(this, "Error Finding Plots", "No plots found in selected tab."); } } } - - static final String DEFAULT_FORMAT = "png"; - void savePlotter(IPlotter plotter) { - JFileChooser fc = new JFileChooser(); + + /** + * Get the tabbed pane with the plots. + * + * @return the tabbed pane with the plots + */ + JTabbedPane getPlotPane() { + return this.plotPane; + } + + /** + * Get the currently selected plot tab. + * + * @return the currently selected plot tab + */ + Component getSelectedTab() { + return ((JTabbedPane) this.plotPane.getSelectedComponent()).getSelectedComponent(); + } + + /** + * Get the indices of the current selected tabs. + * + * @return The indices of the current tabs. + */ + private int[] getSelectedTabIndices() { + final int[] indices = new int[2]; + indices[0] = this.plotPane.getSelectedIndex(); + final Component component = this.plotPane.getSelectedComponent(); + if (component instanceof JTabbedPane) { + indices[1] = ((JTabbedPane) component).getSelectedIndex(); + } + return indices; + } + + /** + * Remove all tabs from the plot pane. + */ + void reset() { + this.plotPane.removeAll(); + } + + /** + * Save the plotter from a tab to a graphics file. + * + * @param plotter the plotter to save + */ + private void savePlotter(final IPlotter plotter) { + final JFileChooser fc = new JFileChooser(); fc.setAcceptAllFileFilterUsed(false); fc.setDialogTitle("Save Plots - " + plotter.title()); fc.setCurrentDirectory(new File(".")); - int r = fc.showSaveDialog(this); - if (r == JFileChooser.APPROVE_OPTION) { + fc.setAcceptAllFileFilterUsed(false); + fc.setFileFilter(new FileNameExtensionFilter("PNG file", "png")); + fc.addChoosableFileFilter(new FileNameExtensionFilter("JPG file", "jpg")); + fc.addChoosableFileFilter(new FileNameExtensionFilter("GIF file", "gif")); + final int r = fc.showSaveDialog(this); + if (r == JFileChooser.APPROVE_OPTION) { String path = fc.getSelectedFile().getPath(); - if (path.lastIndexOf(".") == -1) { - path += "." + DEFAULT_FORMAT; + final FileNameExtensionFilter filter = (FileNameExtensionFilter) fc.getFileFilter(); + if (!path.endsWith("." + filter.getExtensions()[0])) { + path += "." + filter.getExtensions()[0]; } + final BufferedImage image = ExportPdf.getImage(this.getSelectedTab()); try { - plotter.writeToFile(path); - } catch (IOException e) { + ImageIO.write(image, filter.getExtensions()[0], new File(path)); + DialogUtil.showInfoDialog(this, "Plots Saved", "Plots from panel were saved to" + '\n' + path); + } catch (final IOException e) { e.printStackTrace(); DialogUtil.showErrorDialog(this, "Error Saving Plots", "There was an error saving the plots."); } - } + } } - - void reset() { - plotPane.removeAll(); - } -} +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsDialog.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsDialog.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsDialog.java Tue Apr 21 14:48:39 2015 @@ -9,35 +9,50 @@ import org.hps.monitoring.application.model.ConfigurationModel; /** - * The modal dialog for entering settings. It contains a <code>JPanel</code> with the different - * settings sub-tabs. + * The modal dialog for entering application settings. + * <p> + * It contains a <code>JPanel</code> with the different settings sub-tabs. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class SettingsDialog extends JDialog { +@SuppressWarnings("serial") +final class SettingsDialog extends JDialog { - final SettingsPanel settingsPanel; + /** + * The panel with the settings. + */ + private final SettingsPanel settingsPanel; - public SettingsDialog(ConfigurationModel configurationModel, ActionListener listener) { + /** + * Class constructor. + * + * @param configurationModel the configuration model with global settings + * @param listener the action listener assigned to certain components + */ + public SettingsDialog(final ConfigurationModel configurationModel, final ActionListener listener) { // Initialize the GUI panel. - settingsPanel = new SettingsPanel(this, configurationModel, listener); - + this.settingsPanel = new SettingsPanel(this, configurationModel, listener); + // Configure the frame. - setTitle("Settings"); - setContentPane(settingsPanel); - setResizable(false); - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - setModalityType(ModalityType.APPLICATION_MODAL); - pack(); + this.setTitle("Settings"); + this.setContentPane(this.settingsPanel); + this.setResizable(false); + this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + this.setModalityType(ModalityType.APPLICATION_MODAL); + this.pack(); // Add window listener for turning invisible when closing. - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - setVisible(false); + this.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(final WindowEvent e) { + SettingsDialog.this.setVisible(false); } - - public void windowOpened(WindowEvent event) { - SettingsDialog.this.setLocationRelativeTo(null); + + @Override + public void windowOpened(final WindowEvent event) { + SettingsDialog.this.setLocationRelativeTo(null); } - }); + }); } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsPanel.java Tue Apr 21 14:48:39 2015 @@ -16,54 +16,82 @@ /** * The container component with the tabs that have job and connection settings. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class SettingsPanel extends JPanel implements ActionListener { +@SuppressWarnings("serial") +final class SettingsPanel extends JPanel implements ActionListener { - JTabbedPane tabs; - JobSettingsPanel jobPanel; - ConnectionSettingsPanel connectionPanel; - static final String OKAY_COMMAND = "settingsOkay"; + /** + * The panel with connection settings. + */ + private final ConnectionSettingsPanel connectionPanel; - JDialog parent; + /** + * The panel with general job settings. + */ + private final JobSettingsPanel jobPanel; - SettingsPanel(JDialog parent, ConfigurationModel configurationModel, ActionListener listener) { + /** + * The parent dialog window. + */ + private final JDialog parent; + + /** + * The tabs with the sub-panels. + */ + private final JTabbedPane tabs; + + /** + * Class constructor. + * + * @param parent the parent dialog window + * @param configurationModel the global configuration model + * @param listener the action listener assigned to certain components + */ + SettingsPanel(final JDialog parent, final ConfigurationModel configurationModel, final ActionListener listener) { this.parent = parent; - - connectionPanel = new ConnectionSettingsPanel(); - jobPanel = new JobSettingsPanel(configurationModel); - + + this.connectionPanel = new ConnectionSettingsPanel(); + this.jobPanel = new JobSettingsPanel(configurationModel); + // Push configuration to sub-components. - connectionPanel.setConfigurationModel(configurationModel); - jobPanel.setConfigurationModel(configurationModel); - + this.connectionPanel.setConfigurationModel(configurationModel); + this.jobPanel.setConfigurationModel(configurationModel); + // Add ActionListener to sub-components. - connectionPanel.addActionListener(listener); - jobPanel.addActionListener(listener); - + this.connectionPanel.addActionListener(listener); + this.jobPanel.addActionListener(listener); + this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); - tabs = new JTabbedPane(); - tabs.addTab("Connection Settings", connectionPanel); - tabs.addTab("Job Settings", jobPanel); - add(tabs); + this.tabs = new JTabbedPane(); + this.tabs.addTab("Connection Settings", this.connectionPanel); + this.tabs.addTab("Job Settings", this.jobPanel); + this.add(this.tabs); - JButton okayButton = new JButton("Okay"); - okayButton.setActionCommand(OKAY_COMMAND); + final JButton okayButton = new JButton("Okay"); + okayButton.setActionCommand(Commands.SETTINGS_OKAY_COMMAND); okayButton.addActionListener(this); - add(Box.createRigidArea(new Dimension(1, 5))); - JPanel buttonsPanel = new JPanel(); + this.add(Box.createRigidArea(new Dimension(1, 5))); + final JPanel buttonsPanel = new JPanel(); buttonsPanel.add(okayButton); buttonsPanel.setLayout(new FlowLayout()); - add(buttonsPanel); - add(Box.createRigidArea(new Dimension(1, 5))); + this.add(buttonsPanel); + this.add(Box.createRigidArea(new Dimension(1, 5))); } + /** + * Handle action events. + * + * @param e the action event to handle + */ @Override - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals(OKAY_COMMAND)) { - parent.setVisible(false); + public void actionPerformed(final ActionEvent e) { + if (e.getActionCommand().equals(Commands.SETTINGS_OKAY_COMMAND)) { + this.parent.setVisible(false); } - } + } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java Tue Apr 21 14:48:39 2015 @@ -1,6 +1,3 @@ -/** - * - */ package org.hps.monitoring.application; import java.awt.Component; @@ -22,125 +19,190 @@ /** * This is a table that shows every system status change in a different row. - * - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -public class SystemStatusEventsTable extends JTable { - - SystemStatusEventsTableModel tableModel = new SystemStatusEventsTableModel(); - +@SuppressWarnings("serial") +final class SystemStatusEventsTable extends JTable { + + /** + * The model for the system status events table. + */ + static class SystemStatusEventsTableModel extends DefaultTableModel implements SystemStatusListener { + + /** + * The classes of the table columns. + */ + private final Class<?>[] columnClasses = {Date.class, Subsystem.class, SystemStatus.class, String.class, + String.class}; + + /** + * The names of the columns. + */ + private final String[] columnNames = {"Date", "Subsystem", "Status Code", "Description", "Message"}; + + /** + * The list of statuses shown in the table. + */ + private final List<SystemStatus> statuses = new ArrayList<SystemStatus>(); + + /** + * Class constructor. + */ + SystemStatusEventsTableModel() { + } + + /** + * Register the listener on this status. + * + * @param status the system status + */ + void addSystemStatus(final SystemStatus status) { + status.addListener(this); + } + + /** + * Clear all the records from the table. + */ + void clear() { + this.statuses.clear(); + this.setRowCount(0); + } + + /** + * Get the column class. + * + * @param columnIndex the column index + */ + @Override + public Class<?> getColumnClass(final int columnIndex) { + return this.columnClasses[columnIndex]; + } + + /** + * Get the column count. + * + * @return the column count + */ + @Override + public int getColumnCount() { + return this.columnNames.length; + } + + /** + * Get the column name. + * + * @param columnIndex the column index + */ + @Override + public String getColumnName(final int columnIndex) { + return this.columnNames[columnIndex]; + } + + /** + * Get the row count. + * + * @return the row count + */ + @Override + public int getRowCount() { + if (this.statuses != null) { + return this.statuses.size(); + } else { + return 0; + } + } + + /** + * Get a cell value from the table. + * + * @param rowIndex the row index + * @param columnIndex the column index + * @return the cell value at the rowIndex and columnIndex + */ + @Override + public Object getValueAt(final int rowIndex, final int columnIndex) { + final SystemStatus status = this.statuses.get(rowIndex); + switch (columnIndex) { + case 0: + return new Date(status.getLastChangedMillis()); + case 1: + return status.getSubsystem(); + case 2: + return status.getStatusCode(); + case 3: + return status.getDescription(); + case 4: + return status.getMessage(); + default: + return null; + } + } + + /** + * Update the table with status changes. + * + * @param status the system status + */ + @Override + public void statusChanged(final SystemStatus status) { + final SystemStatus newStatus = new SystemStatusImpl(status); + this.statuses.add(newStatus); + this.fireTableDataChanged(); + } + } + + /** + * The table model. + */ + private final SystemStatusEventsTableModel tableModel = new SystemStatusEventsTableModel(); + + /** + * Class constructor. + */ SystemStatusEventsTable() { - setModel(tableModel); - + this.setModel(this.tableModel); + // Date formatting. - getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() { + this.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() { final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS"); @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + public Component getTableCellRendererComponent(final JTable table, Object value, final boolean isSelected, + final boolean hasFocus, final int row, final int column) { if (value instanceof Date) { - value = dateFormat.format(value); + value = this.dateFormat.format(value); } return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); } }); - + // Rendering of system status cells using different background colors. - getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + this.getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { + public Component getTableCellRendererComponent(final JTable table, final Object value, + final boolean isSelected, final boolean hasFocus, final int row, final int col) { // Cells are by default rendered as a JLabel. - JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col); + final JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, + row, col); // Color code the cell by its status. - StatusCode statusCode = (StatusCode) value; + final StatusCode statusCode = (StatusCode) value; label.setBackground(statusCode.getColor()); return label; } }); } - - void registerListener() { + + /** + * Get the system status events table model. + * + * @return the system status events table model + */ + SystemStatusEventsTableModel getSystemStatusEventsTableModel() { + return this.tableModel; } - - static class SystemStatusEventsTableModel extends DefaultTableModel implements SystemStatusListener { - - List<SystemStatus> statuses = new ArrayList<SystemStatus>(); - - String[] columnNames = { "Date", "Subsystem", "Status Code", "Description", "Message" }; - Class<?>[] columnClasses = { Date.class, Subsystem.class, SystemStatus.class, String.class, String.class }; - - SystemStatusEventsTableModel() { - } - - @Override - public String getColumnName(int column) { - return columnNames[column]; - } - - @Override - public Class<?> getColumnClass(int column) { - return columnClasses[column]; - } - - /** - * Update the table with status changes. - * @param status The system status. - */ - @Override - public void statusChanged(SystemStatus status) { - SystemStatus newStatus = new SystemStatusImpl(status); - statuses.add(newStatus); - fireTableDataChanged(); - } - - /** - * Register the listener on this status. - * @param status The system status. - */ - void addSystemStatus(SystemStatus status) { - status.addListener(this); - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public int getRowCount() { - if (statuses != null) { - return statuses.size(); - } else { - return 0; - } - } - - @Override - public Object getValueAt(int row, int column) { - SystemStatus status = statuses.get(row); - switch (column) { - case 0: - return new Date(status.getLastChangedMillis()); - case 1: - return status.getSubsystem(); - case 2: - return status.getStatusCode(); - case 3: - return status.getDescription(); - case 4: - return status.getMessage(); - default: - return null; - } - } - - public void clear() { - this.statuses.clear(); - this.setRowCount(0); - } - } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java Tue Apr 21 14:48:39 2015 @@ -1,5 +1,5 @@ /** - * + * */ package org.hps.monitoring.application; @@ -13,39 +13,54 @@ import org.hps.monitoring.subsys.SystemStatus; /** - * This is a panel showing the two tables for viewing the system statuses, - * one showing the current state of all system status monitors and the other - * all system status change events. - * - * @author Jeremy McCormick <[log in to unmask]> + * This is a panel showing the two tables for viewing the system statuses, one showing the current state of all system + * status monitors and the other with all system status change events. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -public class SystemStatusPanel extends JPanel { - - SystemStatusTable statusTable = new SystemStatusTable(); - SystemStatusEventsTable eventsTable = new SystemStatusEventsTable(); - - SystemStatusPanel() { +@SuppressWarnings("serial") +final class SystemStatusPanel extends JPanel { + + /** + * The system status events table. + */ + private final SystemStatusEventsTable eventsTable = new SystemStatusEventsTable(); + + /** + * The system status table. + */ + private final SystemStatusTable statusTable = new SystemStatusTable(); + + /** + * Class constructor. + */ + SystemStatusPanel() { super(new BorderLayout()); - JSplitPane splitPane = new JSplitPane( - JSplitPane.VERTICAL_SPLIT, - new JScrollPane(statusTable), - new JScrollPane(eventsTable)); + final JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(this.statusTable), + new JScrollPane(this.eventsTable)); splitPane.setDividerLocation(50); - add(splitPane, - BorderLayout.CENTER); - } - - void addSystemStatus(SystemStatus status) { + this.add(splitPane, BorderLayout.CENTER); + } + + /** + * Add a system status. + * + * @param status the system status to add + */ + void addSystemStatus(final SystemStatus status) { // Register listeners of table models on this status. - statusTable.getTableModel().addSystemStatus(status); - eventsTable.tableModel.addSystemStatus(status); + this.statusTable.getTableModel().addSystemStatus(status); + this.eventsTable.getSystemStatusEventsTableModel().addSystemStatus(status); } - + + /** + * Clear all the table records. + */ void clear() { // Clear the system status monitor table. - statusTable.getTableModel().clear(); + this.statusTable.getTableModel().clear(); // Clear the system status events table. - ((SystemStatusEventsTableModel)eventsTable.getModel()).clear(); + ((SystemStatusEventsTableModel) this.eventsTable.getModel()).clear(); } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusTable.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusTable.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusTable.java Tue Apr 21 14:48:39 2015 @@ -17,102 +17,152 @@ /** * This table shows the current state of {@link org.hps.monitoring.subsys.SystemStatus} objects. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class SystemStatusTable extends JTable { - - SystemStatusTable() { - - setModel(new SystemStatusTableModel()); - - // Rendering of system status cells using different background colors. - getColumnModel().getColumn(SystemStatusTableModel.STATUS_COL).setCellRenderer(new DefaultTableCellRenderer() { - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { - - // Cells are by default rendered as a JLabel. - JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col); - - // Color code the cell by its status. - StatusCode statusCode = StatusCode.valueOf((String) value); - label.setBackground(statusCode.getColor()); - return label; - } - }); - - // Date formatting for last changed. - getColumnModel().getColumn(SystemStatusTableModel.LAST_CHANGED_COL).setCellRenderer(new DefaultTableCellRenderer() { - - final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS"); - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - if (value instanceof Date) { - value = dateFormat.format(value); - } - return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - } - }); - - // Button for clearing system statuses. - getColumnModel().getColumn(SystemStatusTableModel.RESET_COL).setCellRenderer(new ButtonRenderer("Clear")); - addMouseListener(new JTableButtonMouseListener(this)); - getColumn("Clearable").setWidth(0); - getColumn("Clearable").setMinWidth(0); - getColumn("Clearable").setMaxWidth(0); - - // Column widths. - getColumnModel().getColumn(SystemStatusTableModel.ACTIVE_COL).setPreferredWidth(8); - getColumnModel().getColumn(SystemStatusTableModel.STATUS_COL).setPreferredWidth(10); - getColumnModel().getColumn(SystemStatusTableModel.SYSTEM_COL).setPreferredWidth(10); - // TODO: Add default width setting for every column. - - setAutoCreateRowSorter(true); - } - - public SystemStatusTableModel getTableModel() { - return (SystemStatusTableModel) getModel(); - } +@SuppressWarnings("serial") +final class SystemStatusTable extends JTable { /** - * Renders a button if the status is clearable. + * Renders a button if the status is clear-able. */ private class ButtonRenderer extends JButton implements TableCellRenderer { - public ButtonRenderer(String label) { + /** + * Class constructor. + * + * @param label the label of the button + */ + public ButtonRenderer(final String label) { this.setText(label); } - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - boolean clearable = (Boolean) table.getModel().getValueAt(row, SystemStatusTableModel.CLEARABLE_COL); - if (clearable) + /** + * Get the renderer for the table cell. + * + * @param table the table + * @param value the object from the table cell + * @param isSelected <code>true</code> if cell is selected + * @param hasFocus <code>true</code> if cell has focus + * @param rowIndex the row index + * @param columnIndex the column index + */ + @Override + public Component getTableCellRendererComponent(final JTable table, final Object value, + final boolean isSelected, final boolean hasFocus, final int rowIndex, final int columnIndex) { + final boolean clearable = (Boolean) table.getModel().getValueAt(rowIndex, + SystemStatusTableModel.CLEARABLE_COLUMN_INDEX); + if (clearable) { return this; - else + } else { return null; + } } } /** - * Fires a mouse click event when the clear button is pressed, which in turn will activate the - * action event for the button. The <code>ActionListener</code> then sets the - * <code>StatusCode</code> to <code>CLEARED</code>. + * Fires a mouse click event when the clear button is pressed, which in turn will activate the action event for the + * button. The <code>ActionListener</code> then sets the <code>StatusCode</code> to <code>CLEARED</code>. */ private static class JTableButtonMouseListener extends MouseAdapter { + + /** + * The table. + */ private final JTable table; - public JTableButtonMouseListener(JTable table) { + /** + * Class constructor. + * + * @param table the table for the listener + */ + public JTableButtonMouseListener(final JTable table) { this.table = table; } - public void mouseClicked(MouseEvent e) { - int column = table.getColumnModel().getColumnIndexAtX(e.getX()); - int row = e.getY() / table.getRowHeight(); - if (row < table.getRowCount() && row >= 0 && column < table.getColumnCount() && column >= 0) { - Object value = table.getValueAt(row, column); + /** + * Implement mouse clicked action. + * + * @param e the mouse event + */ + @Override + public void mouseClicked(final MouseEvent e) { + final int column = this.table.getColumnModel().getColumnIndexAtX(e.getX()); + final int row = e.getY() / this.table.getRowHeight(); + if (row < this.table.getRowCount() && row >= 0 && column < this.table.getColumnCount() && column >= 0) { + final Object value = this.table.getValueAt(row, column); if (value instanceof JButton) { ((JButton) value).doClick(); } } } } -} + + /** + * Class constructor. + */ + SystemStatusTable() { + + this.setModel(new SystemStatusTableModel()); + + // Rendering of system status cells using different background colors. + this.getColumnModel().getColumn(SystemStatusTableModel.STATUS_COLUMN_INDEX) + .setCellRenderer(new DefaultTableCellRenderer() { + + @Override + public Component getTableCellRendererComponent(final JTable table, final Object value, + final boolean isSelected, final boolean hasFocus, final int row, final int col) { + + // Cells are by default rendered as a JLabel. + final JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, + hasFocus, row, col); + + // Color code the cell by its status. + final StatusCode statusCode = StatusCode.valueOf((String) value); + label.setBackground(statusCode.getColor()); + return label; + } + }); + + // Date formatting for last changed. + this.getColumnModel().getColumn(SystemStatusTableModel.LAST_CHANGED_COLUMN_INDEX) + .setCellRenderer(new DefaultTableCellRenderer() { + + final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS"); + + @Override + public Component getTableCellRendererComponent(final JTable table, Object value, + final boolean isSelected, final boolean hasFocus, final int row, final int column) { + if (value instanceof Date) { + value = this.dateFormat.format(value); + } + return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } + }); + + // Button for clearing system statuses. + this.getColumnModel().getColumn(SystemStatusTableModel.RESET_COLUMN_INDEX) + .setCellRenderer(new ButtonRenderer("Clear")); + this.addMouseListener(new JTableButtonMouseListener(this)); + this.getColumn("Clearable").setWidth(0); + this.getColumn("Clearable").setMinWidth(0); + this.getColumn("Clearable").setMaxWidth(0); + + // Column widths. + this.getColumnModel().getColumn(SystemStatusTableModel.ACTIVE_COLUMN_INDEX).setPreferredWidth(8); + this.getColumnModel().getColumn(SystemStatusTableModel.STATUS_COLUMN_INDEX).setPreferredWidth(10); + this.getColumnModel().getColumn(SystemStatusTableModel.SYSTEM_COLUMN_INDEX).setPreferredWidth(10); + // TODO: Add default width setting for every column. + + this.setAutoCreateRowSorter(true); + } + + /** + * Get the tqble model. + * + * @return the table model + */ + public SystemStatusTableModel getTableModel() { + return (SystemStatusTableModel) this.getModel(); + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java Tue Apr 21 14:48:39 2015 @@ -13,21 +13,37 @@ /** * A GUI component for the top-level toolbar of the monitoring app. - * - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -public class ToolbarPanel extends JPanel { +@SuppressWarnings("serial") +final class ToolbarPanel extends JPanel { - DataSourceComboBox dataSourceComboBox; - JPanel buttonsPanel; + /** + * The panel with the buttons. + */ + private final JPanel buttonsPanel; - ToolbarPanel(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel, ActionListener listener) { + /** + * The combo box with the list of data sources. + */ + private final DataSourceComboBox dataSourceComboBox; - setLayout(new FlowLayout(FlowLayout.LEFT)); - - JPanel containerPanel = new JPanel(); + /** + * Class constructor. + * + * @param configurationModel the configuration model for the application + * @param connectionModel the connection status model + * @param listener the action listener to assign to certain components + */ + ToolbarPanel(final ConfigurationModel configurationModel, final ConnectionStatusModel connectionModel, + final ActionListener listener) { + + this.setLayout(new FlowLayout(FlowLayout.LEFT)); + + final JPanel containerPanel = new JPanel(); containerPanel.setLayout(new GridBagLayout()); - + // Create the connection status panel. GridBagConstraints gbs = new GridBagConstraints(); gbs.anchor = GridBagConstraints.WEST; @@ -36,30 +52,38 @@ gbs.weightx = 0.5; gbs.fill = GridBagConstraints.BOTH; gbs.insets = new Insets(10, 0, 0, 10); - JPanel connectionPanel = new ConnectionStatusPanel(connectionModel); + final JPanel connectionPanel = new ConnectionStatusPanel(connectionModel); containerPanel.add(connectionPanel, gbs); // Create the buttons panel. - buttonsPanel = new EventButtonsPanel(connectionModel, listener); + this.buttonsPanel = new EventButtonsPanel(connectionModel, listener); gbs.anchor = GridBagConstraints.WEST; gbs.gridx = 1; gbs.gridy = 0; gbs.weightx = 0.5; gbs.fill = GridBagConstraints.BOTH; gbs.insets = new Insets(0, 0, 0, 10); - containerPanel.add(buttonsPanel, gbs); + containerPanel.add(this.buttonsPanel, gbs); // Add the data source combo box. - dataSourceComboBox = new DataSourceComboBox(configurationModel, connectionModel); + this.dataSourceComboBox = new DataSourceComboBox(configurationModel, connectionModel); gbs = new GridBagConstraints(); gbs.anchor = GridBagConstraints.WEST; gbs.gridx = 2; gbs.gridy = 0; gbs.weightx = 1.0; gbs.fill = GridBagConstraints.HORIZONTAL; - containerPanel.add(dataSourceComboBox, gbs); - - add(containerPanel); + containerPanel.add(this.dataSourceComboBox, gbs); + + this.add(containerPanel); } + /** + * Get the combo box with the data sources + * + * @return the combo box with the data sources + */ + DataSourceComboBox getDataSourceComboBox() { + return this.dataSourceComboBox; + } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java Tue Apr 21 14:48:39 2015 @@ -7,7 +7,7 @@ import javax.swing.JPanel; import javax.swing.JTabbedPane; -import org.hps.analysis.trigger.DiagSnapshot; +import org.hps.analysis.trigger.data.DiagnosticSnapshot; import org.hps.monitoring.trigger.ClusterTablePanel; import org.hps.monitoring.trigger.DiagnosticUpdatable; import org.hps.monitoring.trigger.EfficiencyTablePanel; @@ -18,63 +18,94 @@ /** * This is a panel containing the trigger diagnostics tables. - * - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class TriggerDiagnosticsPanel extends JPanel { +@SuppressWarnings("serial") +final class TriggerDiagnosticsPanel extends JPanel { - JTabbedPane tabs = new JTabbedPane(); - ClusterTablePanel clusterPanel = new ClusterTablePanel(); - SinglesTablePanel singlesPanel = new SinglesTablePanel(); - PairTablePanel pairsPanel = new PairTablePanel(); - EfficiencyTablePanel efficiencyPanel = new EfficiencyTablePanel(); - - List<DiagnosticUpdatable> updateList = new ArrayList<DiagnosticUpdatable>(); - - TriggerDiagnosticsPanel() { - setLayout(new BorderLayout()); - - tabs.addTab("Clusters", clusterPanel); - tabs.addTab("Singles", singlesPanel); - tabs.addTab("Pairs", pairsPanel); - tabs.addTab("Efficiency", efficiencyPanel); - - updateList.add(clusterPanel); - updateList.add(singlesPanel); - updateList.add(pairsPanel); - updateList.add(efficiencyPanel); - - add(tabs, BorderLayout.CENTER); - } - /** * Driver for updating the tables. */ class TriggerDiagnosticGUIDriver extends Driver { - // FIXME: Hard-coded collection name. + /** + * Default name of trigger diagnostics collection. + */ private String diagnosticCollectionName = "DiagnosticSnapshot"; - + @Override - public void process(EventHeader event) { + public void process(final EventHeader event) { // Updates are only performed if a diagnostic snapshot object // exists. Otherwise, do nothing. - if(event.hasCollection(DiagSnapshot.class, diagnosticCollectionName)) { + if (event.hasCollection(DiagnosticSnapshot.class, this.diagnosticCollectionName)) { // Get the snapshot collection. - List<DiagSnapshot> snapshotList = event.get(DiagSnapshot.class, diagnosticCollectionName); - - // Get the snapshot. There will only ever be one. - DiagSnapshot snapshot = snapshotList.get(0); - + final List<DiagnosticSnapshot> snapshotList = event.get(DiagnosticSnapshot.class, + this.diagnosticCollectionName); + // Update the GUI panels. - for (DiagnosticUpdatable update : updateList) { - update.updatePanel(snapshot); + for (final DiagnosticUpdatable update : TriggerDiagnosticsPanel.this.updateList) { + update.updatePanel(snapshotList.get(1), snapshotList.get(0)); } - } + } } - - void setDiagnosticCollectionName(String name) { - diagnosticCollectionName = name; + + /** + * Set the name of the trigger diagnostics collection. + * + * @param name the name of the trigger diagnostics collection + */ + void setDiagnosticCollectionName(final String name) { + this.diagnosticCollectionName = name; } - } + } + + /** + * The panel with cluster statistics. + */ + private final ClusterTablePanel clusterPanel = new ClusterTablePanel(); + + /** + * The panel with efficiency statistics. + */ + private final EfficiencyTablePanel efficiencyPanel = new EfficiencyTablePanel(); + + /** + * The panel with pairs statistics. + */ + private final PairTablePanel pairsPanel = new PairTablePanel(); + + /** + * The panel with singles statistics. + */ + private final SinglesTablePanel singlesPanel = new SinglesTablePanel(); + + /** + * The tabs containing the statistics panels. + */ + private final JTabbedPane tabs = new JTabbedPane(); + + /** + * The list of objects that can be updated with trigger diagnostics. + */ + private final List<DiagnosticUpdatable> updateList = new ArrayList<DiagnosticUpdatable>(); + + /** + * Class constructor. + */ + TriggerDiagnosticsPanel() { + this.setLayout(new BorderLayout()); + + this.tabs.addTab("Clusters", this.clusterPanel); + this.tabs.addTab("Singles", this.singlesPanel); + this.tabs.addTab("Pairs", this.pairsPanel); + this.tabs.addTab("Efficiency", this.efficiencyPanel); + + this.updateList.add(this.clusterPanel); + this.updateList.add(this.singlesPanel); + this.updateList.add(this.pairsPanel); + this.updateList.add(this.efficiencyPanel); + + this.add(this.tabs, BorderLayout.CENTER); + } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/AbstractModel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/AbstractModel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/AbstractModel.java Tue Apr 21 14:48:39 2015 @@ -10,97 +10,38 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import javassist.Modifier; +import org.lcsim.util.log.DefaultLogFormatter; +import org.lcsim.util.log.LogUtil; + /** * An abstract class which updates a set of listeners when there are property changes to a backing model. - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public abstract class AbstractModel { - protected PropertyChangeSupport propertyChangeSupport; - - public AbstractModel() { - propertyChangeSupport = new PropertyChangeSupport(this); - } - - public void addPropertyChangeListener(PropertyChangeListener listener) { - propertyChangeSupport.addPropertyChangeListener(listener); - } - - public void removePropertyChangeListener(PropertyChangeListener listener) { - propertyChangeSupport.removePropertyChangeListener(listener); - } - - protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { - propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); - } - - protected void firePropertyChange(PropertyChangeEvent evt) { - propertyChangeSupport.firePropertyChange(evt); - } - - abstract public String[] getPropertyNames(); - - void firePropertiesChanged(Collection<String> properties) { - propertyLoop: for (String property : properties) { - Method getMethod = null; - for (Method method : getClass().getMethods()) { - if (method.getName().equals("get" + property)) { - getMethod = method; - break; - } - } - //System.out.println(getMethod.getName()); - try { - Object value = null; - try { - value = getMethod.invoke(this, (Object[]) null); - //System.out.println(" value = " + value); - } catch (NullPointerException e) { - // This means there is no get method for the property which is a throwable error. - throw new RuntimeException("Property " + property + " is missing a get method.", e); - } catch (InvocationTargetException e) { - // Is the cause of the problem an illegal argument to the method? - if (e.getCause() instanceof IllegalArgumentException) { - // For this error, assume that the key itself is missing from the configuration which is a warning. - System.err.println("The key " + property + " is not set in the configuration."); - continue propertyLoop; - } else { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - if (value != null) { - firePropertyChange(property, value, value); - for (PropertyChangeListener listener : propertyChangeSupport.getPropertyChangeListeners()) { - // FIXME: For some reason calling the propertyChangeSupport methods directly here doesn't work! - listener.propertyChange(new PropertyChangeEvent(this, property, value, value)); - } - } - } catch (IllegalAccessException | IllegalArgumentException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - } - - public void fireModelChanged() { - firePropertiesChanged(Arrays.asList(getPropertyNames())); - } + /** + * Setup logging. + */ + private static final Logger LOGGER = LogUtil.create(AbstractModel.class.getName(), new DefaultLogFormatter(), + Level.INFO); /** - * This method will statically extract property names from a class, which in this package's conventions are statically declared, - * public strings that end with "_PROPERTY". - * - * @param type The class with the properties. - * @return The list of property names. + * This method will extract property names from a class, which in this package's conventions are statically + * declared, public strings that end with the sub-string "_PROPERTY". + * + * @param type the class with the properties settings + * @return the list of property names */ - protected static String[] getPropertyNames(Class<? extends AbstractModel> type) { - List<String> fields = new ArrayList<String>(); - for (Field field : type.getDeclaredFields()) { - int modifiers = field.getModifiers(); + protected static String[] getPropertyNames(final Class<? extends AbstractModel> type) { + final List<String> fields = new ArrayList<String>(); + for (final Field field : type.getDeclaredFields()) { + final int modifiers = field.getModifiers(); if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && field.getName().endsWith("_PROPERTY")) { try { fields.add((String) field.get(null)); @@ -111,4 +52,135 @@ } return fields.toArray(new String[] {}); } -} + + /** + * The property change support object. + */ + private final PropertyChangeSupport propertyChangeSupport; + + /** + * Class constructor. + */ + public AbstractModel() { + this.propertyChangeSupport = new PropertyChangeSupport(this); + } + + /** + * Add a property change listener. + * + * @param listener the property change listener + */ + public void addPropertyChangeListener(final PropertyChangeListener listener) { + this.propertyChangeSupport.addPropertyChangeListener(listener); + } + + /** + * Fire property change events. + */ + public void fireModelChanged() { + this.firePropertiesChanged(Arrays.asList(this.getPropertyNames())); + } + + /** + * Fire property change for a list of named properties. + * + * @param properties the list of property names + */ + void firePropertiesChanged(final Collection<String> properties) { + for (final String property : properties) { + + // Find the getter for this property. + Method getMethod = null; + for (final Method method : this.getClass().getMethods()) { + if (method.getName().equals("get" + property)) { + getMethod = method; + break; + } + } + + // Is there a valid get method for the property? + if (getMethod != null) { + LOGGER.fine("property: " + property + ", method: " + getMethod.getName()); + try { + Object value = null; + try { + value = getMethod.invoke(this, (Object[]) null); + } catch (final InvocationTargetException e) { + // Is the cause of the problem an illegal argument to the method? + if (e.getCause() instanceof IllegalArgumentException) { + // Property key is not in the configuration (this should not happen under normal + // circumstances). + LOGGER.log(Level.WARNING, "Property key missing from configuration: " + property, e); + continue; + } else { + // Something else went wrong, which we assume is a fatal error. + LOGGER.log(Level.SEVERE, "Error setting property: " + property, e); + throw new RuntimeException("Error setting property: " + property, e); + } + } + if (value != null) { + this.firePropertyChange(property, value, value); + for (final PropertyChangeListener listener : this.propertyChangeSupport + .getPropertyChangeListeners()) { + // FIXME: For some reason calling the propertyChangeSupport methods directly here doesn't + // work! + listener.propertyChange(new PropertyChangeEvent(this, property, value, value)); + } + } + } catch (IllegalAccessException | IllegalArgumentException e) { + // This should not usually happen. + LOGGER.log(Level.SEVERE, "Error setting property: " + property, e); + throw new RuntimeException("Error setting property: " + property, e); + } + } else { + // There was no getter found for the property which is a non-fatal warning. + LOGGER.log(Level.WARNING, "Unknown property in configuration: " + property); + } + } + } + + /** + * Fire a property change event. + * + * @param evt the property change event + */ + protected void firePropertyChange(final PropertyChangeEvent evt) { + this.propertyChangeSupport.firePropertyChange(evt); + } + + /** + * Fire a property change. + * + * @param propertyName the name of the property + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(final String propertyName, final Object oldValue, final Object newValue) { + this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Get the property change support object. + * + * @return the property change support object + */ + PropertyChangeSupport getPropertyChangeSupport() { + return this.propertyChangeSupport; + } + + /** + * Get the list of the property names for this model. + * + * @return the list of the property names for this model + */ + abstract public String[] getPropertyNames(); + + /** + * Remove a property change listener from the model. + * + * @param listener the property change listener to remove + */ + public void removePropertyChangeListener(final PropertyChangeListener listener) { + this.propertyChangeSupport.removePropertyChangeListener(listener); + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/Configuration.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/Configuration.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/Configuration.java Tue Apr 21 14:48:39 2015 @@ -9,210 +9,244 @@ import java.util.Set; /** - * This class provides a list of key, value pairs backed by a <code>Properties</code> object. The - * getter and setter methods for these values are not public, because the - * {@link org.hps.monitoring.application.model.ConfigurationModel} class should be used instead - * to get or set application configuration values. + * This class provides a list of key, value pairs backed by a <code>Properties</code> object. The getter and setter + * methods for these values are not public, because the {@link org.hps.monitoring.application.model.ConfigurationModel} + * class should be used instead to get or set application configuration values. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class Configuration { - Properties properties; - File file; - String resourcePath; - + /** + * The file containing the keys and values. + */ + private File file; + + /** + * The Java properties file. + */ + private Properties properties; + + /** + * The path to an embedded properties resource from a jar. + */ + private String resourcePath; + + /** + * Class constructor. + */ Configuration() { - properties = new Properties(); - } - - /** - * Load a configuration from a properties file. - * @param file The properties file. - */ - public Configuration(File file) { + this.properties = new Properties(); + } + + /** + * Class constructor. + * <p> + * Loads a configuration from a properties file. + * + * @param file the properties file + */ + public Configuration(final File file) { this.file = file; try { - properties = new Properties(); - properties.load(new FileInputStream(this.file)); - } catch (IOException e) { + this.properties = new Properties(); + this.properties.load(new FileInputStream(this.file)); + } catch (final IOException e) { throw new RuntimeException("Error parsing properties file.", e); } } /** + * Class constructor. + * <p> * Load a configuration from a resource path pointing to a properties file. - * @param resourcePath The resource path to the properties file. - */ - public Configuration(String resourcePath) { + * + * @param resourcePath the resource path to the properties file + */ + public Configuration(final String resourcePath) { this.resourcePath = resourcePath; - InputStream is = this.getClass().getResourceAsStream(this.resourcePath); - try { - properties = new Properties(); - properties.load(is); - } catch (IOException e) { + final InputStream is = this.getClass().getResourceAsStream(this.resourcePath); + try { + this.properties = new Properties(); + this.properties.load(is); + } catch (final IOException e) { throw new RuntimeException("Error parsing properties resource.", e); } } /** + * Check if the properties contains the key and if it has a non-null value. + * + * @param key the properties key + * @return <code>true</code> if properties key is valid + */ + boolean checkKey(final String key) { + return this.hasKey(key) && this.properties.getProperty(key) != null; + } + + /** + * Get a key value as a string. + * + * @param key the key to lookup + * @return the value or null if does not exist + */ + String get(final String key) { + if (this.checkKey(key)) { + // Return the key value for properties that are set. + return this.properties.getProperty(key); + } else { + // Return null for unset properties. + return null; + } + } + + /** + * Get a key value as a boolean. + * + * @param key the key to lookup + * @return the value or null if does not exist + */ + Boolean getBoolean(final String key) { + if (this.checkKey(key)) { + return Boolean.parseBoolean(this.properties.getProperty(key)); + } else { + return null; + } + } + + /** + * Get a key value as a double. + * + * @param key the key to lookup + * @return the value as a <code>Double</code> or <code>null</code> if does not exist + */ + Double getDouble(final String key) { + if (this.checkKey(key)) { + return Double.parseDouble(this.properties.getProperty(key)); + } else { + return null; + } + } + + /** * Get the file associated with this configuration or <code>null</code> if not set. - * @return The file associated with the configuration. + * + * @return the file associated with the configuration */ public File getFile() { - return file; - } - - /** - * Get the resource path associated with this configuration or <code>null</code> if not - * applicable. - * @return The resource path of this configuration. + return this.file; + } + + /** + * Get a key value as an integer. + * + * @param key the key to lookup + * @return the value as an <code>Integer</code> or <code>null</code> if does not exist + */ + Integer getInteger(final String key) { + if (this.checkKey(key)) { + return Integer.parseInt(this.properties.getProperty(key)); + } else { + return null; + } + } + + /** + * Get the property keys. + * + * @return the collection of property keys + */ + public Set<String> getKeys() { + return this.properties.stringPropertyNames(); + } + + /** + * Get a key value as a Long. + * + * @param key the key to lookup + * @return the key value as a <code>Long</code> + */ + Long getLong(final String key) { + if (this.checkKey(key)) { + return Long.parseLong(this.properties.getProperty(key)); + } else { + return null; + } + } + + /** + * Get the resource path associated with this configuration or <code>null</code> if not applicable. + * + * @return the resource path of this configuration */ public String getResourcePath() { - return resourcePath; - } - - /** - * True if configuration has value for the key. - * @param key The key. - * @return True if configuration has value for the key. - */ - boolean hasKey(String key) { - try { - return properties.containsKey(key); - } catch (java.lang.NullPointerException e) { + return this.resourcePath; + } + + /** + * Return <code>true</code> if configuration has value for the key. + * + * @param key the key + * @return <code>true</code> if configuration has value for the key + */ + boolean hasKey(final String key) { + try { + return this.properties.containsKey(key); + } catch (final java.lang.NullPointerException e) { return false; } } /** - * Get a key value as a string. - * @param key The key to lookup. - * @return The value or null if does not exist. - */ - String get(String key) { - if (checkKey(key)) { - // Return the key value for properties that are set. - return properties.getProperty(key); - } else { - // Return null for unset properties. - return null; - } - } - - /** - * Get a key value as a boolean. - * @param key The key to lookup. - * @return The value or null if does not exist. - */ - Boolean getBoolean(String key) { - if (checkKey(key)) { - return Boolean.parseBoolean(properties.getProperty(key)); - } else { - return null; - } - } - - /** - * Get a key value as a double. - * @param key The key to lookup. - * @return The value or null if does not exist. - */ - Double getDouble(String key) { - if (checkKey(key)) { - return Double.parseDouble(properties.getProperty(key)); - } else { - return null; - } - } - - /** - * Get a key value as an integer. - * @param key The key to lookup. - * @return The value or null if does not exist. - */ - Integer getInteger(String key) { - if (checkKey(key)) { - return Integer.parseInt(properties.getProperty(key)); - } else { - return null; - } - } - - /** - * Get a key value as a Long. - * @param key The key to lookup. - * @param key The value or null if does not exist. - * @return - */ - Long getLong(String key) { - if (checkKey(key)) { - return Long.parseLong(properties.getProperty(key)); - } else { - return null; - } + * Merge in values from another configuration into this one which will override properties that already exist with + * new values. + * + * @param configuration the configuration with the properties to merge + */ + void merge(final Configuration configuration) { + for (final String property : configuration.getKeys()) { + this.set(property, configuration.get(property)); + } + } + + /** + * Remove a configuration value. + * + * @param key the key of the value + */ + void remove(final String key) { + this.properties.remove(key); + } + + /** + * Set a configuration value. + * + * @param key the key for lookup + * @param value the value to assign to that key + */ + void set(final String key, final Object value) { + this.properties.put(key, String.valueOf(value)); + } + + /** + * Convert this object to a string by printing out its properties list. + */ + @Override + public String toString() { + return this.properties.toString(); } /** * Write this configuration to a file and set that file as the current one. + * * @param file The output file. */ - public void writeToFile(File file) { + public void writeToFile(final File file) { this.file = file; try { - properties.store(new FileOutputStream(this.file), null); - } catch (IOException e) { + this.properties.store(new FileOutputStream(this.file), null); + } catch (final IOException e) { throw new RuntimeException("Error saving properties file.", e); } } - - /** - * Check if the properties contains the key and if it has a non-null value. - * @param key The properties key. - * @return True if properties key is valid. - */ - boolean checkKey(String key) { - return hasKey(key) && properties.getProperty(key) != null; - } - - /** - * Set a configuration value. - * @param key The key for lookup. - * @param value The value to assign to that key. - */ - void set(String key, Object value) { - properties.put(key, String.valueOf(value)); - } - - /** - * Remove a configuration value. - * @param key The key of the value. - */ - void remove(String key) { - properties.remove(key); - } - - /** - * Convert this object to a string by printing out its properties list. - */ - public String toString() { - return properties.toString(); - } - - /** - * Get the property keys. - * @return The collection of property keys. - */ - public Set<String> getKeys() { - return properties.stringPropertyNames(); - } - - /** - * Merge in values from another configuration into this one which will override - * properties that already exist with new values. - * @param configuration The configuration with the properties to merge. - */ - void merge(Configuration configuration) { - for (String property : configuration.getKeys()) { - this.set(property, configuration.get(property)); - } - } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java Tue Apr 21 14:48:39 2015 @@ -9,497 +9,1072 @@ import org.jlab.coda.et.enums.Mode; /** - * A model of the global configuration parameters that can be used to automatically update the GUI - * from a configuration or push changes from GUI components into the current configuration. + * A model of the global configuration parameters that can be used to automatically update the GUI from a configuration + * or push changes from GUI components into the current configuration. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class ConfigurationModel extends AbstractModel { - Configuration configuration; - - // Job setting properties. + /** + * Name of AIDA server. + */ public static final String AIDA_SERVER_NAME_PROPERTY = "AIDAServerName"; + + /** + * ET blocking setting. + */ + public static final String BLOCKING_PROPERTY = "Blocking"; + + /** + * ET chunk size (number of events per ET <code>getEvents</code>). + */ + public static final String CHUNK_SIZE_PROPERTY = "ChunkSize"; + + /** + * Conditions tag. + */ public static final String CONDITIONS_TAG_PROPERTY = "ConditionsTag"; + + /** + * The list of all property names. + */ + static final String[] CONFIG_PROPERTIES = AbstractModel.getPropertyNames(ConfigurationModel.class); + + /** + * The data source path which is a file path if using a file source (EVIO or LCIO file. + */ + public static final String DATA_SOURCE_PATH_PROPERTY = "DataSourcePath"; + + /** + * The data source type (EVIO, LCIO or ET). + * + * @see org.hps.record.enums.DataSourceType + * @return the data source type + */ + public static final String DATA_SOURCE_TYPE_PROPERTY = "DataSourceType"; + + /** + * The detector alias which is pointing to a local compact.xml detector file. + */ + public static final String DETECTOR_ALIAS_PROPERTY = "DetectorAlias"; + + /** + * The name of a detector model to use from the jar file. + */ public static final String DETECTOR_NAME_PROPERTY = "DetectorName"; - public static final String DETECTOR_ALIAS_PROPERTY = "DetectorAlias"; + + /** + * Flag to enable disconnecting when an EVIO END event is received. + */ + public static final String DISCONNECT_ON_END_RUN_PROPERTY = "DisconnectOnEndRun"; + + /** + * Flag to enable disconnecting if an event processing error occurs. + */ public static final String DISCONNECT_ON_ERROR_PROPERTY = "DisconnectOnError"; - public static final String DISCONNECT_ON_END_RUN_PROPERTY = "DisconnectOnEndRun"; + + /** + * The name of the ET system which is generally a file on disk. + */ + public static final String ET_NAME_PROPERTY = "EtName"; + + /** + * The name of the event builder for converting from EVIO to LCIO events. + */ public static final String EVENT_BUILDER_PROPERTY = "EventBuilderClassName"; + + /** + * Flag to freeze conditions system after initialization. + */ public static final String FREEZE_CONDITIONS_PROPERTY = "FreezeConditions"; + + /** + * The ET host property (TCP/IP host name). + */ + public static final String HOST_PROPERTY = "Host"; + + /** + * The name of the output log file. + */ public static final String LOG_FILE_NAME_PROPERTY = "LogFileName"; + + /** + * The filter level for displaying records in the log table. + */ + public static final String LOG_LEVEL_FILTER_PROPERTY = "LogLevelFilter"; + + /** + * The global log level. + */ public static final String LOG_LEVEL_PROPERTY = "LogLevel"; - public static final String LOG_LEVEL_FILTER_PROPERTY = "LogLevelFilter"; + + /** + * Flag to log to a file. + */ public static final String LOG_TO_FILE_PROPERTY = "LogToFile"; + + /** + * Max events after which session will be automatically ended. + */ public static final String MAX_EVENTS_PROPERTY = "MaxEvents"; + + /** + * The maximum number of recent files (hard-coded to 10 to match 0-9 shortcut mnemonics). + */ + private static final int MAX_RECENT_FILES = 10; + + /** + * The ET TCP/IP port. + */ + public static final String PORT_PROPERTY = "Port"; + + /** + * The ET pre-scaling value which throttles event rate. + */ + public static final String PRESCALE_PROPERTY = "Prescale"; + + /** + * The processing stage(s) to execute (ET, EVIO or LCIO). + */ + public static final String PROCESSING_STAGE_PROPERTY = "ProcessingStage"; + + /** + * The ET queue size. + */ + public static final String QUEUE_SIZE_PROPERTY = "QueueSize"; + + /** + * The list of recent files. + */ public static final String RECENT_FILES_PROPERTY = "RecentFiles"; + + /** + * The ET station name. + */ + public static final String STATION_NAME_PROPERTY = "StationName"; + + /** + * The ET station position. + */ + public static final String STATION_POSITION_PROPERTY = "StationPosition"; + + /** + * The steering file. + */ + public static final String STEERING_FILE_PROPERTY = "SteeringFile"; + + /** + * The steering resource. + */ + public static final String STEERING_RESOURCE_PROPERTY = "SteeringResource"; + + /** + * The steering type (file or resource). + */ public static final String STEERING_TYPE_PROPERTY = "SteeringType"; - public static final String STEERING_FILE_PROPERTY = "SteeringFile"; - public static final String STEERING_RESOURCE_PROPERTY = "SteeringResource"; + + /** + * A user run number to use for initializing the conditions system. + */ public static final String USER_RUN_NUMBER_PROPERTY = "UserRunNumber"; - // Data source properties. - public static final String DATA_SOURCE_TYPE_PROPERTY = "DataSourceType"; - public static final String DATA_SOURCE_PATH_PROPERTY = "DataSourcePath"; - public static final String PROCESSING_STAGE_PROPERTY = "ProcessingStage"; - - // ET connection parameters. - public static final String ET_NAME_PROPERTY = "EtName"; - public static final String HOST_PROPERTY = "Host"; - public static final String PORT_PROPERTY = "Port"; - public static final String BLOCKING_PROPERTY = "Blocking"; + /** + * The verbose setting for the ET system. + */ public static final String VERBOSE_PROPERTY = "Verbose"; - public static final String STATION_NAME_PROPERTY = "StationName"; - public static final String CHUNK_SIZE_PROPERTY = "ChunkSize"; - public static final String QUEUE_SIZE_PROPERTY = "QueueSize"; - public static final String STATION_POSITION_PROPERTY = "StationPosition"; + + /** + * The ET wait mode. + */ public static final String WAIT_MODE_PROPERTY = "WaitMode"; + + /** + * The ET wait time (if using timed wait mode). + */ public static final String WAIT_TIME_PROPERTY = "WaitTime"; - public static final String PRESCALE_PROPERTY = "Prescale"; - - // Action command to get notified after configuration change is performed. - public static final String CONFIGURATION_CHANGED = "configurationChanged"; - - static final String[] CONFIG_PROPERTIES = AbstractModel.getPropertyNames(ConfigurationModel.class); - + + /** + * The underlying properties for the model. + */ + private Configuration configuration; + + /** + * Class constructor. + * <p> + * Create a new model without any initial property settings. + */ public ConfigurationModel() { this.configuration = new Configuration(); } - public ConfigurationModel(Configuration configuration) { + /** + * Class constructor. + * <p> + * Sets the properties from a configuration (file or resource). + * + * @param configuration the configuration containing property settings + */ + public ConfigurationModel(final Configuration configuration) { this.configuration = configuration; - fireModelChanged(); - } - - public void setConfiguration(Configuration configuration) { - this.configuration = configuration; - fireModelChanged(); - } - + this.fireModelChanged(); + } + + /** + * Add a single recent file. + * + * @param recentFile the recent file to add + */ + public void addRecentFile(final String recentFile) { + if (!this.configuration.checkKey(RECENT_FILES_PROPERTY)) { + this.configuration.set(RECENT_FILES_PROPERTY, recentFile); + this.firePropertyChange(RECENT_FILES_PROPERTY, null, recentFile); + } else { + final List<String> recentFilesList = this.getRecentFilesList(); + if (!recentFilesList.contains(recentFile)) { + if (this.getRecentFilesList().size() >= MAX_RECENT_FILES) { + // Bump the first file from the list if max recent files is exceeded (10 files). + recentFilesList.remove(0); + this.setRecentFilesList(recentFilesList); + } + final String oldValue = this.configuration.get(RECENT_FILES_PROPERTY); + final String recentFiles = oldValue + "\n" + recentFile; + this.configuration.set(RECENT_FILES_PROPERTY, recentFiles); + this.firePropertyChange(RECENT_FILES_PROPERTY, oldValue, recentFile); + } + } + + } + + /** + * Fire property change for all property keys. + */ + @Override + public void fireModelChanged() { + this.firePropertiesChanged(this.configuration.getKeys()); + } + + /** + * Get the AIDA server name. + * + * @return the AIDA server name + */ + public String getAIDAServerName() { + return this.configuration.get(AIDA_SERVER_NAME_PROPERTY); + } + + /** + * Get the ET blocking setting. + * + * @return the ET blocking setting + */ + public Boolean getBlocking() { + return this.configuration.getBoolean(BLOCKING_PROPERTY); + } + + /** + * Get the ET chunk size, which is the number of events that will be retrieved at once from the server. + * + * @return the ET chunk size + */ + public Integer getChunkSize() { + return this.configuration.getInteger(CHUNK_SIZE_PROPERTY); + } + + /** + * Get the conditions system tag. + * + * @return the conditions system tag + */ + public String getConditionsTag() { + return this.configuration.get(CONDITIONS_TAG_PROPERTY); + } + + /** + * Get the underlying configuration containing properties. + * + * @return the underlying configuration with properties settings + */ public Configuration getConfiguration() { return this.configuration; } - public Level getLogLevel() { - return Level.parse(configuration.get(LOG_LEVEL_PROPERTY)); - } - - public void setLogLevel(Level level) { - Level oldValue = getLogLevel(); - configuration.set(LOG_LEVEL_PROPERTY, level.getName()); - firePropertyChange(LOG_LEVEL_PROPERTY, oldValue, getLogLevel()); - } - - public Level getLogLevelFilter() { - return Level.parse(configuration.get(LOG_LEVEL_FILTER_PROPERTY)); - } - - public void setLogLevelFilter(Level level) { - Level oldValue = getLogLevelFilter(); - configuration.set(LOG_LEVEL_FILTER_PROPERTY, level.getName()); - firePropertyChange(LOG_LEVEL_FILTER_PROPERTY, oldValue, getLogLevelFilter()); - } - - public SteeringType getSteeringType() { - return SteeringType.valueOf(configuration.get(STEERING_TYPE_PROPERTY)); - } - - public void setSteeringType(SteeringType steeringType) { - SteeringType oldValue = getSteeringType(); - configuration.set(STEERING_TYPE_PROPERTY, steeringType.name()); - firePropertyChange(STEERING_TYPE_PROPERTY, oldValue, getSteeringType()); - } - - public String getSteeringFile() { - return configuration.get(STEERING_FILE_PROPERTY); - } - - public void setSteeringFile(String steeringFile) { - String oldValue = getSteeringFile(); - configuration.set(STEERING_FILE_PROPERTY, steeringFile); - firePropertyChange(STEERING_FILE_PROPERTY, oldValue, getSteeringFile()); - } - - public String getSteeringResource() { - return configuration.get(STEERING_RESOURCE_PROPERTY); - } - - public void setSteeringResource(String steeringResource) { - String oldValue = getSteeringResource(); - configuration.set(STEERING_RESOURCE_PROPERTY, steeringResource); - firePropertyChange(STEERING_RESOURCE_PROPERTY, oldValue, steeringResource); - } - - public String getDetectorName() { - return configuration.get(DETECTOR_NAME_PROPERTY); - } - - public void setDetectorName(String detectorName) { - String oldValue = getDetectorName(); - configuration.set(DETECTOR_NAME_PROPERTY, detectorName); - firePropertyChange(DETECTOR_NAME_PROPERTY, oldValue, getDetectorName()); - } - - public String getDetectorAlias() { - return configuration.get(DETECTOR_ALIAS_PROPERTY); - } - - public void setDetectorAlias(String detectorAlias) { - String oldValue = null; - if (hasPropertyKey(DETECTOR_ALIAS_PROPERTY)) { - oldValue = getDetectorAlias(); - } - configuration.set(DETECTOR_ALIAS_PROPERTY, detectorAlias); - firePropertyChange(DETECTOR_ALIAS_PROPERTY, oldValue, getDetectorAlias()); - } - - public String getEventBuilderClassName() { - return configuration.get(EVENT_BUILDER_PROPERTY); - } - - public void setEventBuilderClassName(String eventBuilderClassName) { - String oldValue = getEventBuilderClassName(); - configuration.set(EVENT_BUILDER_PROPERTY, eventBuilderClassName); - firePropertyChange(EVENT_BUILDER_PROPERTY, oldValue, getEventBuilderClassName()); - } - - public Boolean getLogToFile() { - return configuration.getBoolean(LOG_TO_FILE_PROPERTY); - } - - public void setLogToFile(Boolean logToFile) { - Boolean oldValue = getLogToFile(); - configuration.set(LOG_TO_FILE_PROPERTY, logToFile); - firePropertyChange(LOG_TO_FILE_PROPERTY, oldValue, getLogToFile()); - } - - public String getLogFileName() { - return configuration.get(LOG_FILE_NAME_PROPERTY); - } - - public void setLogFileName(String logFileName) { - String oldValue = getLogFileName(); - configuration.set(LOG_FILE_NAME_PROPERTY, logFileName); - firePropertyChange(LOG_FILE_NAME_PROPERTY, oldValue, getLogFileName()); - } - - public Boolean getDisconnectOnError() { - return configuration.getBoolean(DISCONNECT_ON_ERROR_PROPERTY); - } - - public void setDisconnectOnError(Boolean disconnectOnError) { - Boolean oldValue = getDisconnectOnError(); - configuration.set(DISCONNECT_ON_ERROR_PROPERTY, disconnectOnError); - firePropertyChange(DISCONNECT_ON_ERROR_PROPERTY, oldValue, getDisconnectOnError()); - } - - public Boolean getDisconnectOnEndRun() { - return configuration.getBoolean(DISCONNECT_ON_END_RUN_PROPERTY); - } - - public void setDisconnectOnEndRun(Boolean disconnectOnEndRun) { - Boolean oldValue = getDisconnectOnEndRun(); - configuration.set(DISCONNECT_ON_END_RUN_PROPERTY, disconnectOnEndRun); - firePropertyChange(DISCONNECT_ON_END_RUN_PROPERTY, oldValue, getDisconnectOnEndRun()); - } - + /** + * Get the data source path. + * + * @return the data source path + */ + public String getDataSourcePath() { + return this.configuration.get(DATA_SOURCE_PATH_PROPERTY); + } + + /** + * Get the data source type (EVIO, LCIO or ET). + * + * @return the data source type + */ public DataSourceType getDataSourceType() { - if (configuration.checkKey(DATA_SOURCE_TYPE_PROPERTY)) { - return DataSourceType.valueOf(configuration.get(DATA_SOURCE_TYPE_PROPERTY)); + if (this.configuration.checkKey(DATA_SOURCE_TYPE_PROPERTY)) { + return DataSourceType.valueOf(this.configuration.get(DATA_SOURCE_TYPE_PROPERTY)); } else { return null; } } - public void setDataSourceType(DataSourceType dataSourceType) { - DataSourceType oldValue = getDataSourceType(); - configuration.set(DATA_SOURCE_TYPE_PROPERTY, dataSourceType); - firePropertyChange(DATA_SOURCE_TYPE_PROPERTY, oldValue, getDataSourceType()); - } - - public String getDataSourcePath() { - return configuration.get(DATA_SOURCE_PATH_PROPERTY); - } - - public void setDataSourcePath(String dataSourcePath) { - String oldValue = getDataSourcePath(); - configuration.set(DATA_SOURCE_PATH_PROPERTY, dataSourcePath); - firePropertyChange(DATA_SOURCE_PATH_PROPERTY, oldValue, getDataSourcePath()); - } - - /* - public void setDataSource(String dataSource) { - setDataSourcePath(dataSource); - DataSourceType dst = DataSourceType.getDataSourceType(dataSource); - setDataSourceType(dst); - } - */ - + /** + * Get the detector alias which is a compact.xml file on disk. + * + * @return the detector alias + */ + public String getDetectorAlias() { + return this.configuration.get(DETECTOR_ALIAS_PROPERTY); + } + + /** + * Get the detector name. + * + * @return the detector name + */ + public String getDetectorName() { + return this.configuration.get(DETECTOR_NAME_PROPERTY); + } + + /** + * Get the disconnect on end run flag. + * + * @return the disconnect on end run flag + */ + public Boolean getDisconnectOnEndRun() { + return this.configuration.getBoolean(DISCONNECT_ON_END_RUN_PROPERTY); + } + + /** + * Get the disconnect on error flag. + * + * @return the disconnect on error flag + */ + public Boolean getDisconnectOnError() { + return this.configuration.getBoolean(DISCONNECT_ON_ERROR_PROPERTY); + } + + /** + * Get the ET system name. + * + * @return the ET system name + */ + public String getEtName() { + return this.configuration.get(ET_NAME_PROPERTY); + } + + /** + * Get the ET path from concatenating the ET system name, host and post (which is just used for the GUI). + * + * @return the ET path + */ + public String getEtPath() { + return this.getEtName() + "@" + this.getHost() + ":" + this.getPort(); + } + + /** + * Get the event builder class name. + * + * @return the event builder class name + */ + public String getEventBuilderClassName() { + return this.configuration.get(EVENT_BUILDER_PROPERTY); + } + + /** + * Get the freeze conditions setting which will cause conditions system to be frozen after initialization with the + * currently selected run number and detector name. + * + * @return the freeze conditions setting + */ + public Boolean getFreezeConditions() { + return this.configuration.getBoolean(FREEZE_CONDITIONS_PROPERTY); + } + + /** + * Get the ET host name. + * + * @return the ET host name + */ + public String getHost() { + return this.configuration.get(HOST_PROPERTY); + } + + /** + * Get the log file name. + * + * @return the log file name + */ + public String getLogFileName() { + return this.configuration.get(LOG_FILE_NAME_PROPERTY); + } + + /** + * Get the global log level. + * + * @return the global log level + */ + public Level getLogLevel() { + return Level.parse(this.configuration.get(LOG_LEVEL_PROPERTY)); + } + + /** + * Get the log level filter for displaying messages in the log table. + * + * @return the log level filter + */ + public Level getLogLevelFilter() { + return Level.parse(this.configuration.get(LOG_LEVEL_FILTER_PROPERTY)); + } + + /** + * Get the log to file setting which redirects monitoring application log messages from the console to a file. + * + * @return the log to file setting + */ + public Boolean getLogToFile() { + return this.configuration.getBoolean(LOG_TO_FILE_PROPERTY); + } + + /** + * Get the maximum number of events before disconnecting. + * + * @return the maximum number of events before disconnecting + */ + public Long getMaxEvents() { + return this.configuration.getLong(MAX_EVENTS_PROPERTY); + } + + /** + * Get the ET TCP/IP port value. + * + * @return the ET TCP/IP port value + */ + public Integer getPort() { + return this.configuration.getInteger(PORT_PROPERTY); + } + + /** + * Get the ET station prescale value. + * + * @return the ET station prescale value + */ + public Integer getPrescale() { + return this.configuration.getInteger(PRESCALE_PROPERTY); + } + + /** + * Get the processing stage. + * <p> + * Each level will execute the preceding ones, e.g. LCIO exectures EVIO, ET and LCIO event processing + * + * @return the processing stage to execute + */ public ProcessingStage getProcessingStage() { - if (configuration.get(PROCESSING_STAGE_PROPERTY) == null) + if (this.configuration.get(PROCESSING_STAGE_PROPERTY) == null) { throw new RuntimeException(PROCESSING_STAGE_PROPERTY + " is null!!!"); - return ProcessingStage.valueOf(configuration.get(PROCESSING_STAGE_PROPERTY)); - } - - public void setProcessingStage(ProcessingStage processingStage) { - ProcessingStage oldValue = getProcessingStage(); - configuration.set(PROCESSING_STAGE_PROPERTY, processingStage); - firePropertyChange(PROCESSING_STAGE_PROPERTY, oldValue, getProcessingStage()); - } - - public String getEtName() { - return configuration.get(ET_NAME_PROPERTY); - } - - public void setEtName(String etName) { - String oldValue = getEtName(); - configuration.set(ET_NAME_PROPERTY, etName); - firePropertyChange(ET_NAME_PROPERTY, oldValue, getEtName()); - } - - public String getHost() { - return configuration.get(HOST_PROPERTY); - } - - public void setHost(String host) { - String oldValue = getHost(); - configuration.set(HOST_PROPERTY, host); - firePropertyChange(HOST_PROPERTY, oldValue, getHost()); - } - - public Integer getPort() { - return configuration.getInteger(PORT_PROPERTY); - } - - public void setPort(Integer port) { - Integer oldValue = getPort(); - configuration.set(PORT_PROPERTY, port); - firePropertyChange(PORT_PROPERTY, oldValue, getPort()); - } - - public Boolean getBlocking() { - return configuration.getBoolean(BLOCKING_PROPERTY); - } - - public void setBlocking(Boolean blocking) { - Boolean oldValue = getBlocking(); - configuration.set(BLOCKING_PROPERTY, blocking); - firePropertyChange(BLOCKING_PROPERTY, oldValue, getBlocking()); - } - - public Boolean getVerbose() { - return configuration.getBoolean(VERBOSE_PROPERTY); - } - - public void setVerbose(Boolean verbose) { - Boolean oldValue = getVerbose(); - configuration.set(VERBOSE_PROPERTY, verbose); - firePropertyChange(VERBOSE_PROPERTY, oldValue, getVerbose()); - } - - public String getStationName() { - return configuration.get(STATION_NAME_PROPERTY); - } - - public void setStationName(String stationName) { - String oldValue = getStationName(); - configuration.set(STATION_NAME_PROPERTY, stationName); - firePropertyChange(STATION_NAME_PROPERTY, oldValue, getStationName()); - } - - public Integer getChunkSize() { - return configuration.getInteger(CHUNK_SIZE_PROPERTY); - } - - public void setChunkSize(Integer chunkSize) { - Integer oldValue = getChunkSize(); - configuration.set(CHUNK_SIZE_PROPERTY, chunkSize); - firePropertyChange(CHUNK_SIZE_PROPERTY, oldValue, getChunkSize()); - } - + } + return ProcessingStage.valueOf(this.configuration.get(PROCESSING_STAGE_PROPERTY)); + } + + /** + * Get the property names in the configuration. + * + * @return the property names in the configuration + */ + @Override + public String[] getPropertyNames() { + return CONFIG_PROPERTIES; + } + + /** + * Get the ET queue size. + * + * @return the ET queue size + */ public Integer getQueueSize() { - return configuration.getInteger(QUEUE_SIZE_PROPERTY); - } - - public void setQueueSize(Integer queueSize) { - Integer oldValue = getQueueSize(); - configuration.set(QUEUE_SIZE_PROPERTY, queueSize); - firePropertyChange(QUEUE_SIZE_PROPERTY, oldValue, getQueueSize()); - } - - public Integer getStationPosition() { - return configuration.getInteger(STATION_POSITION_PROPERTY); - } - - public void setStationPosition(Integer stationPosition) { - Integer oldValue = getStationPosition(); - configuration.set(STATION_POSITION_PROPERTY, stationPosition); - firePropertyChange(STATION_POSITION_PROPERTY, oldValue, getStationPosition()); - } - - public Mode getWaitMode() { - return Mode.valueOf(configuration.get(WAIT_MODE_PROPERTY)); - } - - public void setWaitMode(Mode waitMode) { - Mode oldValue = getWaitMode(); - configuration.set(WAIT_MODE_PROPERTY, waitMode.name()); - firePropertyChange(WAIT_MODE_PROPERTY, oldValue, getWaitMode()); - } - - public Integer getWaitTime() { - return configuration.getInteger(WAIT_TIME_PROPERTY); - } - - public void setWaitTime(Integer waitTime) { - Integer oldValue = getWaitTime(); - configuration.set(WAIT_TIME_PROPERTY, waitTime); - firePropertyChange(WAIT_TIME_PROPERTY, oldValue, getWaitTime()); - } - - public Integer getPrescale() { - return configuration.getInteger(PRESCALE_PROPERTY); - } - - public void setPrescale(Integer prescale) { - Integer oldValue = getPrescale(); - configuration.set(PRESCALE_PROPERTY, prescale); - firePropertyChange(PRESCALE_PROPERTY, oldValue, getPrescale()); - } - - public void setUserRunNumber(Integer userRunNumber) { - Integer oldValue = null; - if (hasPropertyKey(USER_RUN_NUMBER_PROPERTY)) { - oldValue = getUserRunNumber(); - } - configuration.set(USER_RUN_NUMBER_PROPERTY, userRunNumber); - firePropertyChange(USER_RUN_NUMBER_PROPERTY, oldValue, getUserRunNumber()); - } - - public Integer getUserRunNumber() { - return configuration.getInteger(USER_RUN_NUMBER_PROPERTY); - } - - public void setFreezeConditions(Boolean freezeConditions) { - Boolean oldValue = null; - if (hasPropertyKey(FREEZE_CONDITIONS_PROPERTY)) { - oldValue = getFreezeConditions(); - } - configuration.set(FREEZE_CONDITIONS_PROPERTY, freezeConditions); - firePropertyChange(FREEZE_CONDITIONS_PROPERTY, oldValue, freezeConditions); - } - - public Boolean getFreezeConditions() { - return configuration.getBoolean(FREEZE_CONDITIONS_PROPERTY); - } - - public void setMaxEvents(Long maxEvents) { - Long oldValue = getMaxEvents(); - configuration.set(MAX_EVENTS_PROPERTY, maxEvents); - firePropertyChange(MAX_EVENTS_PROPERTY, oldValue, getMaxEvents()); - } - - public Long getMaxEvents() { - return configuration.getLong(MAX_EVENTS_PROPERTY); - } - - public String getEtPath() { - return getEtName() + "@" + getHost() + ":" + getPort(); - } - - public void setConditionsTag(String conditionsTag) { - String oldValue = getConditionsTag(); - configuration.set(CONDITIONS_TAG_PROPERTY, conditionsTag); - firePropertyChange(CONDITIONS_TAG_PROPERTY, oldValue, getConditionsTag()); - } - - public String getConditionsTag() { - return configuration.get(CONDITIONS_TAG_PROPERTY); - } - - public void setAIDAServerName(String AIDAServerName) { - String oldValue = getAIDAServerName(); - configuration.set(AIDA_SERVER_NAME_PROPERTY, AIDAServerName); - firePropertyChange(AIDA_SERVER_NAME_PROPERTY, oldValue, getAIDAServerName()); - } - - public String getAIDAServerName() { - return configuration.get(AIDA_SERVER_NAME_PROPERTY); - } - + return this.configuration.getInteger(QUEUE_SIZE_PROPERTY); + } + + /** + * Get recent files as a string with paths separated by the '\n' string. + * + * @return the recent files as a delimited string + */ public String getRecentFiles() { - if (configuration.hasKey(RECENT_FILES_PROPERTY)) { - return configuration.get(RECENT_FILES_PROPERTY); + if (this.configuration.hasKey(RECENT_FILES_PROPERTY)) { + return this.configuration.get(RECENT_FILES_PROPERTY); } else { return null; - } - } - + } + } + + /** + * Get the recent files list. + * <p> + * This is actually just a copy from the property, so to set the recent file list call + * {@link #setRecentFiles(String)}. + * + * @return the recent files list + */ public List<String> getRecentFilesList() { - List<String> recentFilesList = new ArrayList<String>(); - if (configuration.hasKey(RECENT_FILES_PROPERTY)) { - for (String recentFile : configuration.get(RECENT_FILES_PROPERTY).split("\n")) { + final List<String> recentFilesList = new ArrayList<String>(); + if (this.configuration.hasKey(RECENT_FILES_PROPERTY)) { + for (final String recentFile : this.configuration.get(RECENT_FILES_PROPERTY).split("\n")) { recentFilesList.add(recentFile); } } return recentFilesList; } - - public void addRecentFile(String recentFile) { - if (!configuration.checkKey(RECENT_FILES_PROPERTY)) { - configuration.set(RECENT_FILES_PROPERTY, recentFile); - firePropertyChange(RECENT_FILES_PROPERTY, null, recentFile); - } else { - List<String> recentFilesList = getRecentFilesList(); - if (!recentFilesList.contains(recentFile)) { - if (getRecentFilesList().size() >= 10) { - throw new IllegalArgumentException("Maximum number of recent files reached."); - } - String oldValue = configuration.get(RECENT_FILES_PROPERTY); - String recentFiles = oldValue + "\n" + recentFile; - configuration.set(RECENT_FILES_PROPERTY, recentFiles); - firePropertyChange(RECENT_FILES_PROPERTY, oldValue, recentFile); + + /** + * Get the ET station name. + * + * @return the ET station name + */ + public String getStationName() { + return this.configuration.get(STATION_NAME_PROPERTY); + } + + /** + * Get the ET station position. + * + * @return the ET station position + */ + public Integer getStationPosition() { + return this.configuration.getInteger(STATION_POSITION_PROPERTY); + } + + /** + * Get the steering file location (if using a file on disk). + * + * @return the XML file steering path + */ + public String getSteeringFile() { + return this.configuration.get(STEERING_FILE_PROPERTY); + } + + /** + * Get the steering resource (if using a jar resource). + * + * @return the steering resource location + */ + public String getSteeringResource() { + return this.configuration.get(STEERING_RESOURCE_PROPERTY); + } + + /** + * Get whether the steering is a file or resource. + * + * @return whether the steering is a file or resource + */ + public SteeringType getSteeringType() { + return SteeringType.valueOf(this.configuration.get(STEERING_TYPE_PROPERTY)); + } + + /** + * Get the user run number for configuring the conditions system. + * + * @return the user run number for configuring the conditions system + */ + public Integer getUserRunNumber() { + return this.configuration.getInteger(USER_RUN_NUMBER_PROPERTY); + } + + /** + * Get the ET verbose flag. + * + * @return the ET verbose flag + */ + public Boolean getVerbose() { + return this.configuration.getBoolean(VERBOSE_PROPERTY); + } + + /** + * Get the ET wait mode. + * + * @return the ET wait mode + */ + public Mode getWaitMode() { + return Mode.valueOf(this.configuration.get(WAIT_MODE_PROPERTY)); + } + + /** + * Get the ET wait time. + * + * @return the ET wait time + */ + public Integer getWaitTime() { + return this.configuration.getInteger(WAIT_TIME_PROPERTY); + } + + /** + * Return <code>true</code> if the given property key exists. + * + * @param key the property key + * @return <code>true</code> if property key exists (still might be <code>null</code>) + */ + public boolean hasPropertyKey(final String key) { + return this.configuration.hasKey(key); + } + + /** + * Return <code>true</code> if the given property key exists and is non-null. + * + * @param key the property key + * @return <code>true</code> if the property key exists and is non-null + */ + public boolean hasValidProperty(final String key) { + return this.configuration.checkKey(key); + } + + /** + * Merge another properties configuration into this one. + * <p> + * Settings from the merged properties will override this one. + * + * @param configuration the properties configuration to merge in + */ + public void merge(final Configuration configuration) { + this.configuration.merge(configuration); + this.firePropertiesChanged(configuration.getKeys()); + } + + /** + * Remove the given property which should remove its key and value. + * + * @param property the property to remove + */ + public void remove(final String property) { + if (this.hasPropertyKey(property)) { + final Object oldValue = this.configuration.get(property); + if (oldValue != null) { + this.configuration.remove(property); + this.firePropertyChange(property, oldValue, null); } } - - } - - public void setRecentFiles(String recentFiles) { + } + + /** + * Set the name of the AIDA server. + * + * @param aidaServerName the name of the AIDA server + */ + public void setAIDAServerName(final String aidaServerName) { + final String oldValue = this.getAIDAServerName(); + this.configuration.set(AIDA_SERVER_NAME_PROPERTY, aidaServerName); + this.firePropertyChange(AIDA_SERVER_NAME_PROPERTY, oldValue, this.getAIDAServerName()); + } + + /** + * Set whether the ET station is blocking (generally this should not be set to <code>true</code>!) + * + * @param blocking <code>true</code> if station should be blocking + */ + public void setBlocking(final Boolean blocking) { + final Boolean oldValue = this.getBlocking(); + this.configuration.set(BLOCKING_PROPERTY, blocking); + this.firePropertyChange(BLOCKING_PROPERTY, oldValue, this.getBlocking()); + } + + /** + * The ET chunk size which is how many events should be returned at once in the array. + * + * @param chunkSize the ET chunk size + */ + public void setChunkSize(final Integer chunkSize) { + final Integer oldValue = this.getChunkSize(); + this.configuration.set(CHUNK_SIZE_PROPERTY, chunkSize); + this.firePropertyChange(CHUNK_SIZE_PROPERTY, oldValue, this.getChunkSize()); + } + + /** + * Set the conditions system tag. + * + * @param conditionsTag the conditions system tag + */ + public void setConditionsTag(final String conditionsTag) { + final String oldValue = this.getConditionsTag(); + this.configuration.set(CONDITIONS_TAG_PROPERTY, conditionsTag); + this.firePropertyChange(CONDITIONS_TAG_PROPERTY, oldValue, this.getConditionsTag()); + } + + /** + * Set a new configuration for the model which will fire property change events on all properties. + * + * @param configuration the configuration with properties for the model + */ + public void setConfiguration(final Configuration configuration) { + this.configuration = configuration; + this.fireModelChanged(); + } + + /** + * Set the data source path which should be a valid EVIO or LCIO file on an accessible disk. + * + * @param dataSourcePath the data source path + */ + public void setDataSourcePath(final String dataSourcePath) { + final String oldValue = this.getDataSourcePath(); + this.configuration.set(DATA_SOURCE_PATH_PROPERTY, dataSourcePath); + this.firePropertyChange(DATA_SOURCE_PATH_PROPERTY, oldValue, this.getDataSourcePath()); + } + + /** + * Set the data source type (EVIO, LCIO or ET). + * + * @param dataSourceType the data source type + */ + public void setDataSourceType(final DataSourceType dataSourceType) { + final DataSourceType oldValue = this.getDataSourceType(); + this.configuration.set(DATA_SOURCE_TYPE_PROPERTY, dataSourceType); + this.firePropertyChange(DATA_SOURCE_TYPE_PROPERTY, oldValue, this.getDataSourceType()); + } + + /** + * Set the detector alias which is an alternate file path to use for the detector model instead of the one from jar. + * + * @param detectorAlias the detector alias + */ + public void setDetectorAlias(final String detectorAlias) { String oldValue = null; - if (configuration.checkKey(RECENT_FILES_PROPERTY)) { - oldValue = configuration.get(RECENT_FILES_PROPERTY); + if (this.hasPropertyKey(DETECTOR_ALIAS_PROPERTY)) { + oldValue = this.getDetectorAlias(); } - configuration.set(RECENT_FILES_PROPERTY, recentFiles); - firePropertyChange(RECENT_FILES_PROPERTY, oldValue, configuration.get(RECENT_FILES_PROPERTY)); - } - - public void remove(String property) { - if (hasPropertyKey(property)) { - Object oldValue = configuration.get(property); - if (oldValue != null) { - configuration.remove(property); - firePropertyChange(property, oldValue, null); - } + this.configuration.set(DETECTOR_ALIAS_PROPERTY, detectorAlias); + this.firePropertyChange(DETECTOR_ALIAS_PROPERTY, oldValue, this.getDetectorAlias()); + } + + /** + * Set the detector to load from the detector model resources in the jar. + * <p> + * These are present in the jar according to the LCSim convention: + * + * <pre> + * ${DETECTOR_NAME}/detector.properties + * </pre> + * <p> + * where <code>detector.properties</code> has the name of the detector matching the directory name. + * + * @param detectorName the name of the detector name + */ + public void setDetectorName(final String detectorName) { + final String oldValue = this.getDetectorName(); + this.configuration.set(DETECTOR_NAME_PROPERTY, detectorName); + this.firePropertyChange(DETECTOR_NAME_PROPERTY, oldValue, this.getDetectorName()); + } + + /** + * Set to <code>true</code> to disconnect when an EVIO END event is received. + * + * @param disconnectOnEndRun <code>true</code> to disconnect when an EVIO END event is received + */ + public void setDisconnectOnEndRun(final Boolean disconnectOnEndRun) { + final Boolean oldValue = this.getDisconnectOnEndRun(); + this.configuration.set(DISCONNECT_ON_END_RUN_PROPERTY, disconnectOnEndRun); + this.firePropertyChange(DISCONNECT_ON_END_RUN_PROPERTY, oldValue, this.getDisconnectOnEndRun()); + } + + /** + * Set to <code>true<code> to disconnect if event processing errors occur. + * + * @param disconnectOnError set to <code>true</code> to disconnect if event processing errors occur + */ + public void setDisconnectOnError(final Boolean disconnectOnError) { + final Boolean oldValue = this.getDisconnectOnError(); + this.configuration.set(DISCONNECT_ON_ERROR_PROPERTY, disconnectOnError); + this.firePropertyChange(DISCONNECT_ON_ERROR_PROPERTY, oldValue, this.getDisconnectOnError()); + } + + /** + * Set the name of the ET system which is usually a file. + * <p> + * Setting this to a valid file on disk being used by the ET server to buffer events will result in event processing + * speedup. + * + * @param etName the name of the ET system (usually a path on disk used as an event buffer by an ET server) + */ + public void setEtName(final String etName) { + final String oldValue = this.getEtName(); + this.configuration.set(ET_NAME_PROPERTY, etName); + this.firePropertyChange(ET_NAME_PROPERTY, oldValue, this.getEtName()); + } + + /** + * Set the fully qualified class name of the {@link org.hps.record.LCSimEventBuilder} that should be used to build + * LCIO events from EVIO. + * + * @param eventBuilderClassName the fully qualified class name of the event builder + */ + public void setEventBuilderClassName(final String eventBuilderClassName) { + final String oldValue = this.getEventBuilderClassName(); + this.configuration.set(EVENT_BUILDER_PROPERTY, eventBuilderClassName); + this.firePropertyChange(EVENT_BUILDER_PROPERTY, oldValue, this.getEventBuilderClassName()); + } + + /** + * Set to <code>true</code> to freeze the conditions system after initialization if there is also a valid detector + * name and run number setting. + * + * @param freezeConditions <code>true</code> to freeze the conditions + */ + public void setFreezeConditions(final Boolean freezeConditions) { + Boolean oldValue = null; + if (this.hasPropertyKey(FREEZE_CONDITIONS_PROPERTY)) { + oldValue = this.getFreezeConditions(); } - } - - public boolean hasPropertyKey(String key) { - return configuration.hasKey(key); - } - - public boolean hasValidProperty(String key) { - return configuration.checkKey(key); - } - - @Override - public String[] getPropertyNames() { - return CONFIG_PROPERTIES; - } - - public void fireModelChanged() { - firePropertiesChanged(configuration.getKeys()); - } - - public void merge(Configuration configuration) { - this.configuration.merge(configuration); - this.firePropertiesChanged(configuration.getKeys()); + this.configuration.set(FREEZE_CONDITIONS_PROPERTY, freezeConditions); + this.firePropertyChange(FREEZE_CONDITIONS_PROPERTY, oldValue, freezeConditions); + } + + /** + * Set the ET TCP/IP host name of the server. + * + * @param host the host name + */ + public void setHost(final String host) { + final String oldValue = this.getHost(); + this.configuration.set(HOST_PROPERTY, host); + this.firePropertyChange(HOST_PROPERTY, oldValue, this.getHost()); + } + + /** + * Set the log file name if using file logging. + * + * @param logFileName the log file name + */ + public void setLogFileName(final String logFileName) { + final String oldValue = this.getLogFileName(); + this.configuration.set(LOG_FILE_NAME_PROPERTY, logFileName); + this.firePropertyChange(LOG_FILE_NAME_PROPERTY, oldValue, this.getLogFileName()); + } + + /** + * Set the global log level. + * + * @param level the global log level + */ + public void setLogLevel(final Level level) { + final Level oldValue = this.getLogLevel(); + this.configuration.set(LOG_LEVEL_PROPERTY, level.getName()); + this.firePropertyChange(LOG_LEVEL_PROPERTY, oldValue, this.getLogLevel()); + } + + /** + * Set log filter level for the log table. + * + * @param level the log filter level + */ + public void setLogLevelFilter(final Level level) { + final Level oldValue = this.getLogLevelFilter(); + this.configuration.set(LOG_LEVEL_FILTER_PROPERTY, level.getName()); + this.firePropertyChange(LOG_LEVEL_FILTER_PROPERTY, oldValue, this.getLogLevelFilter()); + } + + /** + * Set to <code>true</code> to send global messages to a file instead of the console. + * + * @param logToFile <code>true</code> to log to file + */ + public void setLogToFile(final Boolean logToFile) { + final Boolean oldValue = this.getLogToFile(); + this.configuration.set(LOG_TO_FILE_PROPERTY, logToFile); + this.firePropertyChange(LOG_TO_FILE_PROPERTY, oldValue, this.getLogToFile()); + } + + /** + * Set the maximum number of events to process before the session will automatically end. + * + * @param maxEvents the maximum number of events + */ + public void setMaxEvents(final Long maxEvents) { + final Long oldValue = this.getMaxEvents(); + this.configuration.set(MAX_EVENTS_PROPERTY, maxEvents); + this.firePropertyChange(MAX_EVENTS_PROPERTY, oldValue, this.getMaxEvents()); + } + + /** + * Set the TCP/IP port number of the ET server for the client connection. + * + * @param port the ET port number + */ + public void setPort(final Integer port) { + final Integer oldValue = this.getPort(); + this.configuration.set(PORT_PROPERTY, port); + this.firePropertyChange(PORT_PROPERTY, oldValue, this.getPort()); + } + + /** + * Set a prescale value for the ET station which will decrease the event rate. + * <p> + * A prescale of 2 would mean every 2nd event is processed, etc. + * + * @param prescale the ET station prescale value + */ + public void setPrescale(final Integer prescale) { + final Integer oldValue = this.getPrescale(); + this.configuration.set(PRESCALE_PROPERTY, prescale); + this.firePropertyChange(PRESCALE_PROPERTY, oldValue, this.getPrescale()); + } + + /** + * Set the processing stage which determines which event processing stages are executed. + * + * @param processingStage the processing stage to execute + */ + public void setProcessingStage(final String processingStage) { + final ProcessingStage oldValue = this.getProcessingStage(); + this.configuration.set(PROCESSING_STAGE_PROPERTY, ProcessingStage.valueOf(processingStage)); + this.firePropertyChange(PROCESSING_STAGE_PROPERTY, oldValue, this.getProcessingStage()); + } + + /** + * Set the ET queue size. + * + * @param queueSize the ET queue size + */ + public void setQueueSize(final Integer queueSize) { + final Integer oldValue = this.getQueueSize(); + this.configuration.set(QUEUE_SIZE_PROPERTY, queueSize); + this.firePropertyChange(QUEUE_SIZE_PROPERTY, oldValue, this.getQueueSize()); + } + + /** + * Set the recent files list, which is a list of "\n" delimited file paths. + * + * @param recentFiles the recent files list as a string + */ + public void setRecentFiles(final String recentFiles) { + String oldValue = null; + if (this.configuration.checkKey(RECENT_FILES_PROPERTY)) { + oldValue = this.configuration.get(RECENT_FILES_PROPERTY); + } + this.configuration.set(RECENT_FILES_PROPERTY, recentFiles); + this.firePropertyChange(RECENT_FILES_PROPERTY, oldValue, this.configuration.get(RECENT_FILES_PROPERTY)); + } + + /** + * Set the recent files list. + * <p> + * This method is not part of the public API and is only used internally. + * + * @param recentFilesList the recent files list + */ + private void setRecentFilesList(final List<String> recentFilesList) { + final StringBuffer sb = new StringBuffer(); + for (final String recentFile : recentFilesList) { + sb.append(recentFile + "\n"); + } + sb.setLength(sb.length() - 2); + this.configuration.set(RECENT_FILES_PROPERTY, sb.toString()); + } + + /** + * Set the ET station name. + * + * @param stationName the ET station name + */ + public void setStationName(final String stationName) { + final String oldValue = this.getStationName(); + this.configuration.set(STATION_NAME_PROPERTY, stationName); + this.firePropertyChange(STATION_NAME_PROPERTY, oldValue, this.getStationName()); + } + + /** + * Set the ET station position. + * + * @param stationPosition the ET station position + */ + public void setStationPosition(final Integer stationPosition) { + final Integer oldValue = this.getStationPosition(); + this.configuration.set(STATION_POSITION_PROPERTY, stationPosition); + this.firePropertyChange(STATION_POSITION_PROPERTY, oldValue, this.getStationPosition()); + } + + /** + * Set the steering file path. + * + * @param steeringFile the steering file path + */ + public void setSteeringFile(final String steeringFile) { + final String oldValue = this.getSteeringFile(); + this.configuration.set(STEERING_FILE_PROPERTY, steeringFile); + this.firePropertyChange(STEERING_FILE_PROPERTY, oldValue, this.getSteeringFile()); + } + + /** + * Set the steering file resource. + * + * @param steeringResource the steering file resource + */ + public void setSteeringResource(final String steeringResource) { + final String oldValue = this.getSteeringResource(); + this.configuration.set(STEERING_RESOURCE_PROPERTY, steeringResource); + this.firePropertyChange(STEERING_RESOURCE_PROPERTY, oldValue, steeringResource); + } + + /** + * Set the steering type (file or resource). + * + * @param steeringType the steering type + * @see SteeringType + */ + public void setSteeringType(final String steeringType) { + final SteeringType oldValue = this.getSteeringType(); + this.configuration.set(STEERING_TYPE_PROPERTY, SteeringType.valueOf(steeringType)); + this.firePropertyChange(STEERING_TYPE_PROPERTY, oldValue, this.getSteeringType()); + } + + /** + * Set a user run number which will be used to initialize the conditions system. + * <p> + * This should most likely be used with {@link #setFreezeConditions(Boolean)} or it is likely to be later overridden + * by run numbers from the data. + * + * @param userRunNumber the user run number + */ + public void setUserRunNumber(final Integer userRunNumber) { + Integer oldValue = null; + if (this.hasPropertyKey(USER_RUN_NUMBER_PROPERTY)) { + oldValue = this.getUserRunNumber(); + } + this.configuration.set(USER_RUN_NUMBER_PROPERTY, userRunNumber); + this.firePropertyChange(USER_RUN_NUMBER_PROPERTY, oldValue, this.getUserRunNumber()); + } + + /** + * Set verbose mode for the ET system. + * + * @param verbose the ET verbose flag + */ + public void setVerbose(final Boolean verbose) { + final Boolean oldValue = this.getVerbose(); + this.configuration.set(VERBOSE_PROPERTY, verbose); + this.firePropertyChange(VERBOSE_PROPERTY, oldValue, this.getVerbose()); + } + + /** + * Set the ET wait mode (timed, asynchronous or wait). + * + * @param waitMode the ET wait mode + */ + public void setWaitMode(final String waitMode) { + final Mode oldValue = this.getWaitMode(); + this.configuration.set(WAIT_MODE_PROPERTY, Mode.valueOf(waitMode)); + this.firePropertyChange(WAIT_MODE_PROPERTY, oldValue, this.getWaitMode()); + } + + /** + * Set the ET wait time, which is ignored if wait mode is not timed. + * + * @param waitTime the ET wait time + */ + public void setWaitTime(final Integer waitTime) { + final Integer oldValue = this.getWaitTime(); + this.configuration.set(WAIT_TIME_PROPERTY, waitTime); + this.firePropertyChange(WAIT_TIME_PROPERTY, oldValue, this.getWaitTime()); } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java Tue Apr 21 14:48:39 2015 @@ -3,23 +3,46 @@ import java.awt.Color; /** - * This is the status of the connection to the ET server from the monitoring client, - * and it includes a color that should be displayed in the GUI for the associated - * text. + * This is the status of the connection to the ET server from the monitoring client, and it includes a color that should + * be displayed in the GUI for the associated text. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public enum ConnectionStatus { + /** + * This is the state when the session is connected to event processing. + */ + CONNECTED(Color.GREEN), + /** + * This is the disconnected state when event processing is not occurring. + */ DISCONNECTED(Color.RED), - DISCONNECTING(Color.YELLOW), - CONNECTED(Color.GREEN); - - Color color; - - ConnectionStatus(Color color) { + /** + * This is the state when the session is being torn down. + */ + DISCONNECTING(Color.YELLOW); + + /** + * The color that should be displayed in the GUI component for this state. + */ + private Color color; + + /** + * Class constructor. + * + * @param color the color to display for this state + */ + private ConnectionStatus(final Color color) { this.color = color; } - + + /** + * Get the color to display for this state. + * + * @return the color to display for this state + */ public Color getColor() { - return color; + return this.color; } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java Tue Apr 21 14:48:39 2015 @@ -4,62 +4,117 @@ import java.beans.PropertyChangeListener; /** - * This model updates listeners when the connection status changes from disconnected - * to connected or vice versa. It will also notify when the event processing is - * paused. - * - * @author Jeremy McCormick <[log in to unmask]> + * This model updates listeners when the connection status changes from disconnected to connected or vice versa. It will + * also notify listeners when the event processing has been paused. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class ConnectionStatusModel extends AbstractModel { - + + /** + * The connection status property. + */ public static final String CONNECTION_STATUS_PROPERTY = "ConnectionStatus"; + + /** + * The paused property. + */ public static final String PAUSED_PROPERTY = "Paused"; - - static final String[] propertyNames = new String[] { - CONNECTION_STATUS_PROPERTY, - PAUSED_PROPERTY - }; - ConnectionStatus connectionStatus = ConnectionStatus.DISCONNECTED; - boolean paused = false; - + /** + * The property names of this class. + */ + private static final String[] PROPERTY_NAMES = new String[] {CONNECTION_STATUS_PROPERTY, PAUSED_PROPERTY}; + + /** + * The current connection status. + */ + private ConnectionStatus connectionStatus = ConnectionStatus.DISCONNECTED; + + /** + * Flag which is <code>true</code> when event processing is in the paused state. + */ + private boolean paused = false; + + /** + * Get the current connection status. + * + * @return the current connection status + */ + public ConnectionStatus getConnectionStatus() { + return this.connectionStatus; + } + + /** + * Return <code>true</code> if the event processing is currently paused. + * + * @return <code>true</code> if event processing is currently paused + */ + public boolean getPaused() { + return this.paused; + } + + /** + * Get the property names for this class. + * + * @return the property names for this class + */ + @Override public String[] getPropertyNames() { - return propertyNames; + return PROPERTY_NAMES; } - - public ConnectionStatus getConnectionStatus() { - return connectionStatus; + + /** + * Return <code>true</code> if the status is <code>CONNECTED</code>. + * + * @return <code>true</code> if status is <code>CONNECTED</code> + */ + public boolean isConnected() { + return this.connectionStatus == ConnectionStatus.CONNECTED; } - - public void setConnectionStatus(ConnectionStatus connectionStatus) { - ConnectionStatus oldValue = connectionStatus; + + /** + * Return <code>true</code> if the status is <code>DISCONNECTED</code>. + * + * @return <code>true</code> if the status is <code>DISCONNECTED</code> + */ + public boolean isDisconnected() { + return this.connectionStatus == ConnectionStatus.DISCONNECTED; + } + + /** + * Return <code>true</code> if the status is <code>DISCONNECTING</code>. + * + * @return <code>true</code> if the status is <code>DISCONNECTING</code> + */ + public boolean isDisconnecting() { + return this.connectionStatus == ConnectionStatus.DISCONNECTING; + } + + /** + * Set the connection status. + * + * @param connectionStatus the new connection status + */ + public void setConnectionStatus(final ConnectionStatus connectionStatus) { + final ConnectionStatus oldValue = connectionStatus; this.connectionStatus = connectionStatus; - for (PropertyChangeListener listener : propertyChangeSupport.getPropertyChangeListeners()) { - listener.propertyChange(new PropertyChangeEvent(this, CONNECTION_STATUS_PROPERTY, oldValue, this.connectionStatus)); + for (final PropertyChangeListener listener : this.getPropertyChangeSupport().getPropertyChangeListeners()) { + listener.propertyChange(new PropertyChangeEvent(this, CONNECTION_STATUS_PROPERTY, oldValue, + this.connectionStatus)); } - } - - public boolean getPaused() { - return paused; } - - public void setPaused(boolean paused) { - boolean oldValue = this.paused; + + /** + * Set to <code>true</code> if status is paused. + * + * @param paused <code>true</code> if status is paused + */ + public void setPaused(final boolean paused) { + final boolean oldValue = this.paused; this.paused = paused; - for (PropertyChangeListener listener : propertyChangeSupport.getPropertyChangeListeners()) { + for (final PropertyChangeListener listener : this.getPropertyChangeSupport().getPropertyChangeListeners()) { listener.propertyChange(new PropertyChangeEvent(this, PAUSED_PROPERTY, oldValue, this.paused)); } } - - public boolean isConnected() { - return this.connectionStatus == ConnectionStatus.CONNECTED; - } - - public boolean isDisconnected() { - return this.connectionStatus == ConnectionStatus.DISCONNECTED; - } - - public boolean isDisconnecting() { - return this.connectionStatus == ConnectionStatus.DISCONNECTING; - } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java Tue Apr 21 14:48:39 2015 @@ -2,18 +2,22 @@ /** * Mix-in interface for classes that have an associated {@link ConfigurationModel}. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public interface HasConfigurationModel { /** - * Set the ConfigurationModel of the object. - * @param configurationModel The ConfigurationModel. + * Get the current {@link ConfigurationModel} of the object. + * + * @return the associated {@link ConfigurationModel} + */ + ConfigurationModel getConfigurationModel(); + + /** + * Set the {@link ConfigurationModel} of the object. + * + * @param configurationModel the new {@link ConfigurationModel} */ void setConfigurationModel(ConfigurationModel configurationModel); - - /** - * Get the current ConfigurationModel of the object. - * @return The ConfigurationModel. - */ - ConfigurationModel getConfigurationModel(); } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/RunModel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/RunModel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/RunModel.java Tue Apr 21 14:48:39 2015 @@ -4,117 +4,258 @@ /** * Backing model for run information that shows in the {@link org.hps.monitoring.application.EventDashboard}. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class RunModel extends AbstractModel { - public final static String RUN_NUMBER_PROPERTY = "RunNumber"; - public final static String START_DATE_PROPERTY = "StartDate"; - public final static String END_DATE_PROPERTY = "EndDate"; - public final static String RUN_LENGTH_PROPERTY = "RunLength"; // set at end, in seconds - public final static String TOTAL_EVENTS_PROPERTY = "TotalEvents"; // only set at end - public final static String EVENTS_RECEIVED_PROPERTY = "EventsReceived"; // events received so far - public final static String ELAPSED_TIME_PROPERTY = "ElapsedTime"; // updated on the fly, in seconds - public final static String DATA_RECEIVED_PROPERTY = "DataReceived"; // updated on the fly, in bytes - public final static String EVENT_NUMBER_PROPERTY = "EventNumber"; // current event number - public final static String DATA_RATE_PROPERTY = "DataRate"; // data rate in megabytes per second - public final static String EVENT_RATE_PROPERTY = "EventRate"; // event rate per second - - static final String[] RUN_PROPERTIES = AbstractModel.getPropertyNames(RunModel.class); - - Integer runNumber; - Date startDate; - Date endDate; - Integer runLength; - Integer totalEvents; - Integer eventsReceived; - Integer elapsedTime; - Double dataReceived; - Integer eventNumber; - Double dataRate; - Double eventRate; - + /** + * The data rate in megabytes per second. + */ + public static final String DATA_RATE_PROPERTY = "DataRate"; + + /** + * The amount of data received in bytes since the last timer tick. + */ + public static final String DATA_RECEIVED_PROPERTY = "DataReceived"; + + /** + * The total elapsed time in the session. + */ + public static final String ELAPSED_TIME_PROPERTY = "ElapsedTime"; + + /** + * The end date of the run which comes from the EVIO END record. + */ + public static final String END_DATE_PROPERTY = "EndDate"; + + /** + * The event number currently being processed which usually comes from the EVIO or LCIO records. + */ + public static final String EVENT_NUMBER_PROPERTY = "EventNumber"; + + /** + * The event rate in Hertz. + */ + public static final String EVENT_RATE_PROPERTY = "EventRate"; + + /** + * The total number of events received in the session. + */ + public static final String EVENTS_RECEIVED_PROPERTY = "EventsReceived"; + + /** + * The total length of the run which is set from the EVIO END record. + */ + public static final String RUN_LENGTH_PROPERTY = "RunLength"; + + /** + * The run number which comes from the EVIO control data. + */ + public static final String RUN_NUMBER_PROPERTY = "RunNumber"; + + /** + * The properties of this model. + */ + private static final String[] RUN_PROPERTIES = AbstractModel.getPropertyNames(RunModel.class); + + /** + * The start date of the run which comes from the EVIO PRESTART event. + */ + public static final String START_DATE_PROPERTY = "StartDate"; + + /** + * The total events in the run which comes from the EVIO END event. + */ + public static final String TOTAL_EVENTS_PROPERTY = "TotalEvents"; + + /** + * The data rate in MB/s. + */ + private Double dataRate; + + /** + * The data received in bytes. + */ + private Double dataReceived; + + /** + * The elapsed time in seconds. + */ + private Integer elapsedTime; + + /** + * The end date of the run. + */ + private Date endDate; + + /** + * The current event number. + */ + private Integer eventNumber; + + /** + * The event rate in Hertz. + */ + private Double eventRate; + + /** + * The number of events received. + */ + private Integer eventsReceived; + + /** + * The length of the run. + */ + private Integer runLength; + + /** + * The run number. + */ + private Integer runNumber; + + /** + * The run start date. + */ + private Date startDate; + + /** + * The total events received in the run. + */ + private Integer totalEvents; + + /** + * Add data received in bytes. + * + * @param addDataReceived the amount of data received in bytes + */ + public void addDataReceived(final double addDataReceived) { + this.setDataReceived(this.dataReceived + addDataReceived); + } + + /** + * Compute the run length from the start and end date and set its value in the GUI. + */ + public void computeRunLength() { + if (this.startDate != null && this.endDate != null) { + final long elapsedMillis = this.endDate.getTime() - this.startDate.getTime(); + final int elapsedSeconds = (int) (elapsedMillis / 1000.); + this.setRunLength(elapsedSeconds); + } + } + + /** + * Get the data rate in MB/s. + * + * @return the data rate in MB/s + */ + public double getDataRate() { + return this.dataRate; + } + + /** + * Get the data received in bytes. + * + * @return the data received in bytes + */ + public double getDataReceived() { + return this.dataReceived; + } + + /** + * Get the elapsed time in seconds. + * + * @return the elapsed time in seconds + */ + public int getElapsedTime() { + return this.elapsedTime; + } + + /** + * Get the run end date. + * + * @return the run end date + */ + public Date getEndDate() { + return this.endDate; + } + + /** + * Get the current event number. + * + * @return the current event number + */ + public int getEventNumber() { + return this.eventNumber; + } + + /** + * Get the event rate in Hertz. + * + * @return the event rate in Hertz + */ + public double getEventRate() { + return this.eventRate; + } + + /** + * Get the number of events received in the session. + * + * @return the number of events received + */ + public int getEventsReceived() { + return this.eventsReceived; + } + + /** + * Get the property names for this model. + * + * @return the property names for this model + */ + @Override public String[] getPropertyNames() { return RUN_PROPERTIES; } - public void setRunNumber(int runNumber) { - Integer oldValue = this.runNumber; - this.runNumber = runNumber; - this.firePropertyChange(RUN_NUMBER_PROPERTY, oldValue, this.runNumber); - } - - public void setStartDate(Date startDate) { - Date oldValue = this.startDate; - this.startDate = startDate; - this.firePropertyChange(START_DATE_PROPERTY, oldValue, this.startDate); - } - - public void setEndDate(Date endDate) { - Date oldValue = this.endDate; - this.endDate = endDate; - this.firePropertyChange(END_DATE_PROPERTY, oldValue, this.endDate); - } - - public void setRunLength(int runLength) { - Integer oldValue = this.runLength; - this.runLength = runLength; - this.firePropertyChange(RUN_LENGTH_PROPERTY, oldValue, this.runLength); - } - - public void computeRunLength() { - if (startDate != null && endDate != null) { - long elapsedMillis = endDate.getTime() - startDate.getTime(); - int elapsedSeconds = (int) ((double) elapsedMillis / 1000.); - this.setRunLength(elapsedSeconds); - } - } - - public void setTotalEvents(int totalEvents) { - Integer oldValue = this.totalEvents; - this.totalEvents = totalEvents; - this.firePropertyChange(TOTAL_EVENTS_PROPERTY, oldValue, this.totalEvents); - } - - public void setEventsReceived(int eventsReceived) { - Integer oldValue = this.eventsReceived; - this.eventsReceived = eventsReceived; - this.firePropertyChange(EVENTS_RECEIVED_PROPERTY, oldValue, this.eventsReceived); - } - - public void setElapsedTime(int elapsedTime) { - Integer oldValue = this.elapsedTime; - this.elapsedTime = elapsedTime; - this.firePropertyChange(ELAPSED_TIME_PROPERTY, oldValue, this.elapsedTime); - } - - public void setDataReceived(double dataReceived) { - Double oldValue = this.dataReceived; - this.dataReceived = dataReceived; - this.firePropertyChange(DATA_RECEIVED_PROPERTY, oldValue, this.dataReceived); - } - - public void addDataReceived(double addDataReceived) { - this.setDataReceived(dataReceived + addDataReceived); - } - - public void setEventNumber(int eventNumber) { - Integer oldValue = this.eventNumber; - this.eventNumber = eventNumber; - this.firePropertyChange(EVENT_NUMBER_PROPERTY, oldValue, this.eventNumber); - } - - public void setDataRate(double dataRate) { - Double oldValue = this.dataRate; - this.dataRate = dataRate; - this.firePropertyChange(DATA_RATE_PROPERTY, oldValue, this.dataRate); - } - - public void setEventRate(double eventRate) { - Double oldValue = this.eventRate; - this.eventRate = eventRate; - this.firePropertyChange(EVENT_RATE_PROPERTY, oldValue, this.eventRate); - } - + /** + * Get the run length in seconds. + * + * @return the run length in seconds + */ + public int getRunLength() { + return this.runLength; + } + + /** + * Get the run number. + * + * @return the run number + */ + public int getRunNumber() { + return this.runNumber; + } + + /** + * Get the start date. + * + * @return the start date + */ + public Date getStartDate() { + return this.startDate; + } + + /** + * Get the total events in the run. + * + * @return the total events in the run + */ + public int getTotalEvents() { + return this.totalEvents; + } + + /** + * Reset the model for new run. + */ public void reset() { setDataReceived(0); setElapsedTime(0); @@ -125,4 +266,125 @@ setStartDate(null); setTotalEvents(0); } -} + + /** + * Set the data rate in MB/s. + * + * @param dataRate the data rate in MB/s + */ + public void setDataRate(final double dataRate) { + final Double oldValue = this.dataRate; + this.dataRate = dataRate; + this.firePropertyChange(DATA_RATE_PROPERTY, oldValue, this.dataRate); + } + + /** + * Set the data received in bytes. + * + * @param dataReceived the data received in bytes + */ + public void setDataReceived(final double dataReceived) { + final Double oldValue = this.dataReceived; + this.dataReceived = dataReceived; + this.firePropertyChange(DATA_RECEIVED_PROPERTY, oldValue, this.dataReceived); + } + + /** + * Set the elapsed time in seconds. + * + * @param elapsedTime the elapsed time in seconds + */ + public void setElapsedTime(final int elapsedTime) { + final Integer oldValue = this.elapsedTime; + this.elapsedTime = elapsedTime; + this.firePropertyChange(ELAPSED_TIME_PROPERTY, oldValue, this.elapsedTime); + } + + /** + * Set the run end date. + * + * @param endDate the run end date + */ + public void setEndDate(final Date endDate) { + final Date oldValue = this.endDate; + this.endDate = endDate; + this.firePropertyChange(END_DATE_PROPERTY, oldValue, this.endDate); + } + + /** + * Set the current event number. + * + * @param eventNumber the current event number + */ + public void setEventNumber(final int eventNumber) { + final Integer oldValue = this.eventNumber; + this.eventNumber = eventNumber; + this.firePropertyChange(EVENT_NUMBER_PROPERTY, oldValue, this.eventNumber); + } + + /** + * Set the event rate in Hertz. + * + * @param eventRate the event rate in Hertz + */ + public void setEventRate(final double eventRate) { + final Double oldValue = this.eventRate; + this.eventRate = eventRate; + this.firePropertyChange(EVENT_RATE_PROPERTY, oldValue, this.eventRate); + } + + /** + * Set the number of events received. + * + * @param eventsReceived the number of events received + */ + public void setEventsReceived(final int eventsReceived) { + final Integer oldValue = this.eventsReceived; + this.eventsReceived = eventsReceived; + this.firePropertyChange(EVENTS_RECEIVED_PROPERTY, oldValue, this.eventsReceived); + } + + /** + * Set the length of the run in seconds. + * + * @param runLength the length of the run in seconds + */ + public void setRunLength(final int runLength) { + final Integer oldValue = this.runLength; + this.runLength = runLength; + this.firePropertyChange(RUN_LENGTH_PROPERTY, oldValue, this.runLength); + } + + /** + * Set the run number. + * + * @param runNumber the run number + */ + public void setRunNumber(final int runNumber) { + final Integer oldValue = this.runNumber; + this.runNumber = runNumber; + this.firePropertyChange(RUN_NUMBER_PROPERTY, oldValue, this.runNumber); + } + + /** + * Set the start date. + * + * @param startDate the start date + */ + public void setStartDate(final Date startDate) { + final Date oldValue = this.startDate; + this.startDate = startDate; + this.firePropertyChange(START_DATE_PROPERTY, oldValue, this.startDate); + } + + /** + * Set the total number of events in the run. + * + * @param totalEvents the total number of events in the run + */ + public void setTotalEvents(final int totalEvents) { + final Integer oldValue = this.totalEvents; + this.totalEvents = totalEvents; + this.firePropertyChange(TOTAL_EVENTS_PROPERTY, oldValue, this.totalEvents); + } +} Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SteeringType.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SteeringType.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SteeringType.java Tue Apr 21 14:48:39 2015 @@ -2,8 +2,16 @@ /** * The type of steering to use for event processing. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public enum SteeringType { - RESOURCE, - FILE; + /** + * Steering from local file on disk. + */ + FILE, + /** + * Steering from resource in jar file. + */ + RESOURCE; } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java Tue Apr 21 14:48:39 2015 @@ -2,7 +2,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -16,74 +15,164 @@ /** * A <code>JTableModel</code> that has a list of {@link org.hps.monitoring.subsys.SystemStatus} objects. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ +@SuppressWarnings("serial") public final class SystemStatusTableModel extends AbstractTableModel implements SystemStatusListener { - public static final int RESET_COL = 0; - public static final int ACTIVE_COL = 1; - public static final int STATUS_COL = 2; - public static final int SYSTEM_COL = 3; - public static final int DESCRIPTION_COL = 4; - public static final int MESSAGE_COL = 5; - public static final int LAST_CHANGED_COL = 6; - public static final int CLEARABLE_COL = 7; - - static final String[] columnNames = { "Reset", "Active", "Status", "System", "Description", "Message", "Last Changed", "Clearable" }; - - List<SystemStatus> statuses = new ArrayList<SystemStatus>(); - final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS"); - - public void addSystemStatus(SystemStatus status) { - statuses.add(status); + /** + * Active field column index. + */ + public static final int ACTIVE_COLUMN_INDEX = 1; + + /** + * Clearable field column index. + */ + public static final int CLEARABLE_COLUMN_INDEX = 7; + + /** + * The names of the columns. + */ + private static final String[] COLUMN_NAMES = {"Reset", "Active", "Status", "System", "Description", "Message", + "Last Changed", "Clearable"}; + + /** + * Description column index. + */ + public static final int DESCRIPTION_COLUMN_INDEX = 4; + + /** + * Last changed field column index. + */ + public static final int LAST_CHANGED_COLUMN_INDEX = 6; + + /** + * Message field column index. + */ + public static final int MESSAGE_COLUMN_INDEX = 5; + + /** + * Reset field column index. + */ + public static final int RESET_COLUMN_INDEX = 0; + + /** + * Status field column index. + */ + public static final int STATUS_COLUMN_INDEX = 2; + + /** + * System field column index. + */ + public static final int SYSTEM_COLUMN_INDEX = 3; + + /** + * The list of system status objects that back the model. + */ + private final List<SystemStatus> statuses = new ArrayList<SystemStatus>(); + + /** + * Add a system status to the model. + * + * @param status the system status to add to the model + */ + public void addSystemStatus(final SystemStatus status) { + this.statuses.add(status); status.addListener(this); fireTableDataChanged(); } + /** + * Clear all the data in the model. + */ + public void clear() { + this.statuses.clear(); + fireTableDataChanged(); + } + + /** + * Get the class of the column. + * + * @param columnIndex the index of the column + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public Class getColumnClass(final int columnIndex) { + switch (columnIndex) { + case ACTIVE_COLUMN_INDEX: + return Boolean.class; + case LAST_CHANGED_COLUMN_INDEX: + return Date.class; + default: + return String.class; + } + } + + /** + * Get the column count. + * + * @return the column count + */ + @Override + public int getColumnCount() { + return COLUMN_NAMES.length; + } + + /** + * Get the column name. + * + * @param columnIndex the column index + */ + @Override + public String getColumnName(final int columnIndex) { + return COLUMN_NAMES[columnIndex]; + } + + /** + * Get the row count. + * + * @return the row count + */ @Override public int getRowCount() { - return statuses.size(); - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public String getColumnName(int col) { - return columnNames[col]; - } - + return this.statuses.size(); + } + + /** + * Get a table cell value. + * + * @param rowIndex the row index + * @param columnIndex the column index + */ @Override public Object getValueAt(final int rowIndex, final int columnIndex) { - SystemStatus status = statuses.get(rowIndex); + final SystemStatus status = this.statuses.get(rowIndex); switch (columnIndex) { - case ACTIVE_COL: + case ACTIVE_COLUMN_INDEX: return status.isActive(); - case STATUS_COL: + case STATUS_COLUMN_INDEX: return status.getStatusCode().name(); - case SYSTEM_COL: + case SYSTEM_COLUMN_INDEX: return status.getSubsystem().name(); - case DESCRIPTION_COL: + case DESCRIPTION_COLUMN_INDEX: return status.getDescription(); - case MESSAGE_COL: + case MESSAGE_COLUMN_INDEX: return status.getMessage(); - case LAST_CHANGED_COL: + case LAST_CHANGED_COLUMN_INDEX: return new Date(status.getLastChangedMillis()); - case RESET_COL: - // If the status is clearable, then it has a button that can be used to - // manually set the state to CLEARED. If the status is not clearable, + case RESET_COLUMN_INDEX: + // If the status is clear-able, then the cell has a button which can be used to + // manually set the state to CLEARED. If the status cannot be cleared, // then nothing is rendered in this cell. if (status.isClearable()) { final JButton button = new JButton(); button.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - SystemStatus status = statuses.get(rowIndex); - // Only clearable statuses can have this state set. Check for this - // just to be safe, even though no button is available for non-clearable - // statuses. + @Override + public void actionPerformed(final ActionEvent e) { + final SystemStatus status = SystemStatusTableModel.this.statuses.get(rowIndex); if (status.isClearable()) { - StatusCode oldStatusCode = status.getStatusCode(); + final StatusCode oldStatusCode = status.getStatusCode(); status.setStatus(StatusCode.CLEARED, "Cleared from " + oldStatusCode.name() + " state."); } } @@ -92,48 +181,45 @@ } else { return null; } - case CLEARABLE_COL: + case CLEARABLE_COLUMN_INDEX: return status.isClearable(); default: return null; } } - @Override - public Class getColumnClass(int column) { - switch (column) { - case ACTIVE_COL: - return Boolean.class; - case LAST_CHANGED_COL: - return Date.class; - default: - return String.class; + /** + * Return <code>true</code> if cell is editable. + * + * @return <code>true</code> if cell is editable + */ + @Override + public boolean isCellEditable(final int rowIndex, final int columnIndex) { + return columnIndex == ACTIVE_COLUMN_INDEX; + } + + /** + * Set the table cell value. + * + * @param value the new value + * @param rowIndex the row index + * @param columnIndex the column index + */ + @Override + public void setValueAt(final Object value, final int rowIndex, final int columnIndex) { + if (columnIndex == ACTIVE_COLUMN_INDEX) { + this.statuses.get(rowIndex).setActive((Boolean) value); } } - @Override - public boolean isCellEditable(int row, int col) { - if (col == ACTIVE_COL) - return true; - else - return false; - } - - @Override - public void statusChanged(SystemStatus status) { - int rowNumber = statuses.indexOf(status); + /** + * Notify of system status changed. + * + * @param status the system status that changed + */ + @Override + public void statusChanged(final SystemStatus status) { + final int rowNumber = this.statuses.indexOf(status); fireTableRowsUpdated(rowNumber, rowNumber); } - - public void clear() { - statuses.clear(); - fireTableDataChanged(); - } - - @Override - public void setValueAt(Object value, int row, int col) { - if (col == ACTIVE_COL) { - statuses.get(row).setActive((Boolean) value); - } - } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/package-info.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/package-info.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/package-info.java Tue Apr 21 14:48:39 2015 @@ -1,22 +1,20 @@ /** - * The Monitoring Application is a flexible framework for monitoring the - * event processing chain of the HPS experiment. It implements the conversion - * of ET byte buffers to EVIO and then the building of LCIO events from the - * raw EVIO data. - * <p> - * It provides three primary GUI components: + * The Monitoring Application is a flexible framework for monitoring the event processing chain of the HPS experiment in + * an online environment. It implements the conversion of ET byte buffers to EVIO and then the building of LCIO events + * from the raw EVIO data. + * <p> + * It provides three primary GUI components: * <ul> * <li>run dashboard showing basic information about data received</li> - * <li>system status monitor that can monitor the status of specific subsystems</li> + * <li>tab panel showing various information panels</li> * <li>plotting window that displays any plots generated through the AIDA API</li> * </ul> * <p> - * The FreeHep framework is used extensively for the record processing. Every part - * of the event processing chain uses the - * <a href="http://java.freehep.org/freehep-record/">freehep-record</a> - * module to manage the flow of records and activate any processors that are listening - * on the record loops. + * The FreeHep framework is used extensively for the record processing. Every part of the event processing chain uses + * the <a href="http://java.freehep.org/freehep-record/">freehep-record</a> module to manage the flow of records and + * activate any processors that are listening on the record loops. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> + */ +package org.hps.monitoring.application; - * @author Jeremy McCormick <[log in to unmask]> - */ -package org.hps.monitoring.application; Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/AIDAServer.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/AIDAServer.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/AIDAServer.java Tue Apr 21 14:48:39 2015 @@ -11,69 +11,90 @@ /** * AIDA RMI server wrapper. - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -public class AIDAServer { - - RmiServerImpl server; - String name; - boolean connected = false; - +public final class AIDAServer { + /** - * Class constructor. - * @param name The name of the AIDA server. + * Connected flag. */ - public AIDAServer(String name) { + private boolean connected = false; + + /** + * The name of the server. + */ + private String name; + + /** + * The RMI server object. + */ + private RmiServerImpl server; + + /** + * Class constructor. + * + * @param name the name of the AIDA server + */ + public AIDAServer(final String name) { this.name = name; } - + + /** + * Return <code>true</code> if connected. + * + * @return <code>true</code> if connected to server + */ + public boolean connected() { + return this.connected; + } + + /** + * Close the server down by disconnecting it. + */ + public void disconnect() { + this.server.disconnect(); + this.connected = false; + } + + /** + * Get the server name as a string. + * + * @return the server name + */ + public String getName() { + try { + return InetAddress.getLocalHost().getCanonicalHostName() + this.server.getBindName() + ":" + + RmiRemoteUtils.port; + } catch (final Exception e) { + e.printStackTrace(); + } + return null; + } + /** * Set the name that will be used for the path part of the URL. + * * @param name The server's name. */ - public void setName(String name) { + public void setName(final String name) { this.name = name; } /** * Start the remote AIDA server. - * @return True if server started successfully; false if an error occurred during initialization. + * + * @return <code>true</code> if server started successfully; false if an error occurred during initialization. */ public boolean start() { - RemoteServer treeServer = new RemoteServer((IDevTree) AIDA.defaultInstance().tree()); + final RemoteServer treeServer = new RemoteServer((IDevTree) AIDA.defaultInstance().tree()); try { - server = new RmiServerImpl(treeServer, "/" + name); - connected = true; + this.server = new RmiServerImpl(treeServer, "/" + this.name); + this.connected = true; + } catch (final Exception e) { + e.printStackTrace(); + this.connected = false; } - catch (Exception e) { - e.printStackTrace(); - connected = false; - } - return connected; - } - - /** - * Close the server down by disconnecting it. - */ - public void disconnect() { - server.disconnect(); - connected = false; - } - - /** - * True if connected. - * @return True if connected to server. - */ - public boolean connected() { - return connected; - } - - public String getName() { - try { - return InetAddress.getLocalHost().getCanonicalHostName() + server.getBindName() + ":" + RmiRemoteUtils.port; - } catch (Exception e) { - e.printStackTrace(); - } - return null; + return this.connected; } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/DialogUtil.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/DialogUtil.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/DialogUtil.java Tue Apr 21 14:48:39 2015 @@ -7,27 +7,102 @@ import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; +/** + * This is a set of utility methods for creating Swing dialog windows. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> + */ public final class DialogUtil { /** - * - * @param parentComponent - * @param title - * @param message - * @return + * Show a confirmation dialog. + * + * @param parent the parent component + * @param message the message + * @param title the title of the dialog + * @return the result from the user's dialog selection */ - public static JDialog showStatusDialog(final Component parentComponent, String title, String message) { - final JOptionPane optionPane = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[] {}, null); + public static int showConfirmationDialog(final Component parent, final String title, final String message) { + final Object[] options = { "Yes", "No", "Cancel" }; + final int result = JOptionPane.showOptionDialog(parent, message, title, JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, options[2]); + return result; + } + + /** + * Show an error dialog. + * + * @param component the parent component + * @param error the error message + * @param title the title of the dialog + */ + public static void showErrorDialog(final Component component, final String title, final String message) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(component, message, title, JOptionPane.ERROR_MESSAGE); + } + }; + SwingUtilities.invokeLater(runnable); + } + + /** + * Show an error dialog with an associated thrown object. + * + * @param component the parent component + * @param error the <code>Throwable</code> error + * @param title the title of the dialog + */ + public static void showErrorDialog(final Component component, final Throwable error, final String title) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(component, error.getMessage(), title, JOptionPane.ERROR_MESSAGE); + } + }; + SwingUtilities.invokeLater(runnable); + } + + /** + * Show an information dialog. + * + * @param component the parent component + * @param title the title of the dialog + * @param message the message + */ + public static void showInfoDialog(final Component component, final String title, final String message) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(component, message, title, JOptionPane.INFORMATION_MESSAGE); + } + }; + SwingUtilities.invokeLater(runnable); + } + + /** + * Show a status dialog which will block GUI interaction. + * + * @param parentComponent the parent component + * @param title the title of the dialog + * @param message the message + * @return the dialog window component + */ + public static JDialog showStatusDialog(final Component parentComponent, final String title, final String message) { + final JOptionPane optionPane = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE, + JOptionPane.DEFAULT_OPTION, null, new Object[] {}, null); final JDialog dialog = new JDialog(); dialog.setContentPane(optionPane); dialog.setTitle(title); dialog.setAlwaysOnTop(true); dialog.setLocationRelativeTo(null); - dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); dialog.pack(); dialog.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { + @Override + public void windowClosing(final WindowEvent e) { dialog.setVisible(false); dialog.dispose(); parentComponent.setEnabled(true); @@ -40,68 +115,9 @@ } /** - * - * @param component - * @param error - * @param title + * Do not allow class instantiation. */ - public static void showErrorDialog(final Component component, final Throwable error, final String title) { - final Runnable runnable = new Runnable() { - public void run() { - JOptionPane.showMessageDialog(component, error.getMessage(), title, JOptionPane.ERROR_MESSAGE); - } - }; - SwingUtilities.invokeLater(runnable); - } - - /** - * - * @param component - * @param error - * @param title - */ - public static void showErrorDialog(final Component component, final String title, final String message) { - final Runnable runnable = new Runnable() { - public void run() { - JOptionPane.showMessageDialog(component, message, title, JOptionPane.ERROR_MESSAGE); - } - }; - SwingUtilities.invokeLater(runnable); - } - - /** - * - * @param component - * @param title - * @param message - */ - public static void showInfoDialog(final Component component, final String title, final String message) { - final Runnable runnable = new Runnable() { - public void run() { - JOptionPane.showMessageDialog(component, message, title, JOptionPane.INFORMATION_MESSAGE); - } - }; - SwingUtilities.invokeLater(runnable); - } - - /** - * - * @param parent - * @param message - * @param title - * @return - */ - public static int showConfirmationDialog(final Component parent, final String title, final String message) { - Object[] options = { "Yes", "No", "Cancel" }; - int result = JOptionPane.showOptionDialog( - parent, - message, - title, - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE, - null, - options, - options[2]); - return result; + private DialogUtil() { + throw new UnsupportedOperationException("Do not instantiate this class."); } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java Tue Apr 21 14:48:39 2015 @@ -8,10 +8,9 @@ import javax.swing.SwingUtilities; /** + * An error handling class which is able to do any of the following, depending on how the users wants to handle the + * error. * <p> - * An error handling class which is able to do any of the following, depending on how the users - * wants to handle the error. - * </p> * <ul> * <li>Print a message</li> * <li>Print the stack trace</li> @@ -20,97 +19,130 @@ * <li>Raise an exception</li> * <li>Exit the application</li> * </ul> - * </p> It mostly uses the "builder" pattern so that the various handling methods can be easily - * chained, where appropriate. Some methods are not available for chaining when it doesn't make - * sense. </p> + * <p> + * It mostly uses the "builder" pattern so that the various handling methods can be easily chained, where appropriate. + * Some methods are not available for chaining when it doesn't make sense. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class ErrorHandler { - Logger logger; - Component component; - Throwable error; - String message; + /** + * The component used for showing dialog windows. + */ + private final Component component; /** - * Constructor. + * The thrown error. + */ + private Throwable error; + + /** + * A logger for reporting error messages. + */ + private final Logger logger; + + /** + * The error message. + */ + private String message; + + /** + * Class constructor. + * * @param component The GUI component to which this object is assigned. * @param logger The logger to which messages will be written. */ - public ErrorHandler(Component component, Logger logger) { + public ErrorHandler(final Component component, final Logger logger) { this.logger = logger; this.component = component; } /** - * Set the error that occurred. This should always be called first in a method chain. - * @param error The error which is a <code>Throwable</code>. + * Exit the application. + * <p> + * This is not a chain-able method for obvious reasons. + */ + public void exit() { + System.err.println("Fatal error. Application will exit."); + System.exit(1); + } + + /** + * Log the error message to the <code>Logger</code>. + * + * @return this object + */ + public ErrorHandler log() { + this.logger.log(Level.SEVERE, this.message, this.error); + return this; + } + + /** + * Print the error message to System.err. + * * @return This object. */ - public ErrorHandler setError(Throwable error) { + public ErrorHandler printMessage() { + System.err.println(this.message); + return this; + } + + /** + * Print the full stack trace of the error to System.err. + * + * @return this object + */ + public ErrorHandler printStackTrace() { + this.error.printStackTrace(); + return this; + } + + /** + * Immediately re-throw the error as a <code>RuntimeException</code>. + * <p> + * Additional methods cannot be chained to this as they would not be executed. + */ + public void raiseException() { + throw new RuntimeException(this.message, this.error); + } + + /** + * Set the error that occurred. + * <p> + * This should always be called first when method chaining. + * + * @param error the error which is any type of <code>Throwable</code> + * @return this object + */ + public ErrorHandler setError(final Throwable error) { this.error = error; this.message = error.getMessage(); return this; } /** - * Set the error message if it differs from the exception's message. - * @param message The erro message. - * @return This object. + * Set the error message, if it differs from the exception's message. + * + * @param message the error message + * @return this object */ - public ErrorHandler setMessage(String message) { + public ErrorHandler setMessage(final String message) { this.message = message; return this; } /** - * Print the full stack trace of the error to System.err. - * @return This object. - */ - public ErrorHandler printStackTrace() { - error.printStackTrace(); - return this; - } - - /** - * Print the error message to System.err. - * @return This object. - */ - public ErrorHandler printMessage() { - System.err.println(message); - return this; - } - - /** - * Log the error message to the <code>Logger</code>. - * @return This object. - */ - public ErrorHandler log() { - logger.log(Level.SEVERE, message, error); - return this; - } - - /** * Show an error dialog with the message. - * @return This object. + * + * @return this object */ public ErrorHandler showErrorDialog() { final Runnable runnable = new Runnable() { + @Override public void run() { - JOptionPane.showMessageDialog(component, error.getMessage(), "Application Error", JOptionPane.ERROR_MESSAGE); - } - }; - SwingUtilities.invokeLater(runnable); - return this; - } - - /** - * Show an error dialog with a custom message and title. - * @return This object. - */ - public ErrorHandler showErrorDialog(final String message, final String title) { - final Runnable runnable = new Runnable() { - public void run() { - JOptionPane.showMessageDialog(component, message, title, JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(ErrorHandler.this.component, ErrorHandler.this.error.getMessage(), + "Application Error", JOptionPane.ERROR_MESSAGE); } }; SwingUtilities.invokeLater(runnable); @@ -118,18 +150,20 @@ } /** - * Rethrow the error as a <code>RuntimeException</code>. Additional methods cannot be chained to - * this as they would not be executed. + * Show an error dialog with a custom message and title. + * + * @param message the error message + * @param title the title of the dialog window + * @return this object */ - public void raiseException() { - throw new RuntimeException(message, error); - } - - /** - * Exit the application. This is not chainable for obvious reasons. - */ - public void exit() { - System.err.println("Fatal error. Application will exit."); - System.exit(1); + public ErrorHandler showErrorDialog(final String message, final String title) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(ErrorHandler.this.component, message, title, JOptionPane.ERROR_MESSAGE); + } + }; + SwingUtilities.invokeLater(runnable); + return this; } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java Tue Apr 21 14:48:39 2015 @@ -6,28 +6,39 @@ import org.hps.record.et.EtConnection; import org.jlab.coda.et.EtConstants; +/** + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> + */ public final class EtSystemUtil { - private EtSystemUtil() { + /** + * Create an {@link org.hps.record.et.EtConnection} from the settings in a + * {@link org.hps.monitoring.application.model.ConfigurationModel}. + * + * @param config the {@link org.hps.monitoring.application.model.ConfigurationModel} with the connection settings + * @return the new {@link org.hps.record.et.EtConnection} + */ + public static EtConnection createEtConnection(final ConfigurationModel config) { + return EtConnection.createConnection(config.getEtName(), config.getHost(), config.getPort(), + config.getBlocking(), config.getQueueSize(), config.getPrescale(), config.getStationName(), + config.getStationPosition(), config.getWaitMode(), config.getWaitTime(), config.getChunkSize()); } - - public static EtConnection createEtConnection(ConfigurationModel config) { - return EtConnection.createConnection(config.getEtName(), - config.getHost(), - config.getPort(), - config.getBlocking(), - config.getQueueSize(), - config.getPrescale(), - config.getStationName(), - config.getStationPosition(), - config.getWaitMode(), - config.getWaitTime(), - config.getChunkSize()); + + /** + * Create an event selection array (with size 6). + * + * @return the event selection array + */ + public static int[] createSelectArray() { + final int select[] = new int[EtConstants.stationSelectInts]; + Arrays.fill(select, -1); + return select; } - - public static int[] createSelectArray() { - int select[] = new int[EtConstants.stationSelectInts]; - Arrays.fill(select, -1); - return select; - } + + /** + * Do not allow class instantiation. + */ + private EtSystemUtil() { + throw new UnsupportedOperationException("Do not instantiate this class."); + } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java Tue Apr 21 14:48:39 2015 @@ -5,24 +5,39 @@ import javax.swing.filechooser.FileFilter; /** - * This is a simple file filter that will accept files with ".evio" anywhere in their name. + * This is a file filter that will accept files with ".evio" anywhere in their name. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class EvioFileFilter extends FileFilter { - public EvioFileFilter() { + /** + * Class constructor. + */ + public EvioFileFilter() { } - + + /** + * Return <code>true</code> if path should be accepted. + * + * @return <code>true</code> to accept the path + */ @Override - public boolean accept(File pathname) { - if (pathname.getName().contains(".evio") || pathname.isDirectory()) { + public boolean accept(final File path) { + if (path.getName().contains(".evio") || path.isDirectory()) { return true; } else { return false; } } - + + /** + * Get the description of the file filter. + * + * @return the description of the file filter + */ @Override public String getDescription() { return "EVIO files"; - } + } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java Tue Apr 21 14:48:39 2015 @@ -19,106 +19,120 @@ import org.reflections.Reflections; /** - * - * @author Jeremy McCormick <[log in to unmask]> + * This is a set of utility methods for getting jar resources at runtime. * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class ResourceUtil { - private ResourceUtil() { - } - - /** - * Get the files with extension 'lcsim' from all loaded jar files. - * @param packageName The package name for filtering the resources. - * @return A list of embedded steering file resources. - */ - public static String[] findSteeringResources(String packageName) { - List<String> resources = new ArrayList<String>(); - URL url = ResourceUtil.class.getResource("ResourceUtil.class"); - String scheme = url.getProtocol(); - if (!"jar".equals(scheme)) { - throw new RuntimeException("Unsupported URL protocol: " + url.getProtocol()); - } - try { - JarURLConnection con = (JarURLConnection) url.openConnection(); - JarFile archive = con.getJarFile(); - Enumeration<JarEntry> entries = archive.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - if (entry.getName().endsWith(".lcsim") && entry.getName().contains(packageName)) { - resources.add(entry.getName()); - } - } - archive.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - java.util.Collections.sort(resources); - String[] arr = new String[resources.size()]; - for (int i = 0; i < arr.length; i++) { - arr[i] = resources.get(i); - } - return arr; - } - - /** - * Find all classes that implement {@link org.hps.record.LCSimEventBuilder} and return - * a list of their canonical names. - * @return The list of classes implementing LCSimEventBuilder. - */ - public static String[] findEventBuilderClassNames() { - Reflections reflections = new Reflections("org.hps"); - Set<Class<? extends LCSimEventBuilder>> subTypes = reflections.getSubTypesOf(LCSimEventBuilder.class); - Set<String> classNames = new HashSet<String>(); - for (Class<? extends LCSimEventBuilder> type : subTypes) { - classNames.add(type.getCanonicalName()); - } - return classNames.toArray(new String[classNames.size()]); - } - /** * Find a list of available detector names. - * Only those detectors that have names starting with "HPS" in their - * detector.properties files will be returned. - * @return The list of available detector names. + * <p> + * Only those detectors that have names starting with "HPS" in their <code>detector.properties</code> files will be + * returned. + * + * @return the list of available HPS detector names */ public static String[] findDetectorNames() { - ClassLoader classLoader = ResourceUtil.class.getClassLoader(); - List<String> detectorNames = new ArrayList<String>(); - URL url = ResourceUtil.class.getResource("ResourceUtil.class"); - String protocol = url.getProtocol(); + final ClassLoader classLoader = ResourceUtil.class.getClassLoader(); + final List<String> detectorNames = new ArrayList<String>(); + final URL url = ResourceUtil.class.getResource("ResourceUtil.class"); + final String protocol = url.getProtocol(); if (!"jar".equals(protocol)) { throw new RuntimeException("Unsupported URL protocol: " + url.getProtocol()); } try { - JarURLConnection con = (JarURLConnection) url.openConnection(); - JarFile archive = con.getJarFile(); - Enumeration<JarEntry> entries = archive.entries(); + final JarURLConnection con = (JarURLConnection) url.openConnection(); + final JarFile archive = con.getJarFile(); + final Enumeration<JarEntry> entries = archive.entries(); while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); + final JarEntry entry = entries.nextElement(); if (entry.getName().endsWith("detector.properties")) { - InputStream inputStream = classLoader.getResourceAsStream(entry.getName()); + final InputStream inputStream = classLoader.getResourceAsStream(entry.getName()); if (inputStream == null) { throw new RuntimeException("Failed to load jar entry: " + entry.getName()); } - Properties properties = new Properties(); + final Properties properties = new Properties(); properties.load(inputStream); - String detectorName = properties.getProperty("name"); + final String detectorName = properties.getProperty("name"); if (detectorName.startsWith("HPS")) { detectorNames.add(detectorName); } } } archive.close(); - } catch (IOException e) { + } catch (final IOException e) { throw new RuntimeException(e); } Collections.sort(detectorNames); return detectorNames.toArray(new String[detectorNames.size()]); - } - + } + + /** + * Find all classes that implement {@link org.hps.record.LCSimEventBuilder} and return a list of their canonical + * names. + * + * @return the list of fully qualified class names that implement LCSimEventBuilder + */ + public static String[] findEventBuilderClassNames() { + final Reflections reflections = new Reflections("org.hps"); + final Set<Class<? extends LCSimEventBuilder>> subTypes = reflections.getSubTypesOf(LCSimEventBuilder.class); + final Set<String> classNames = new HashSet<String>(); + for (final Class<? extends LCSimEventBuilder> type : subTypes) { + classNames.add(type.getCanonicalName()); + } + return classNames.toArray(new String[classNames.size()]); + } + + /** + * Get all of the files with the extension "lcsim" which are in a certain package. + * + * @param packageName the package name for filtering the list of resources + * @return a list of embedded steering file resources + */ + public static String[] findSteeringResources(final String packageName) { + final List<String> resources = new ArrayList<String>(); + final URL url = ResourceUtil.class.getResource("ResourceUtil.class"); + final String scheme = url.getProtocol(); + if (!"jar".equals(scheme)) { + throw new RuntimeException("Unsupported URL protocol: " + url.getProtocol()); + } + try { + final JarURLConnection con = (JarURLConnection) url.openConnection(); + final JarFile archive = con.getJarFile(); + final Enumeration<JarEntry> entries = archive.entries(); + while (entries.hasMoreElements()) { + final JarEntry entry = entries.nextElement(); + if (entry.getName().endsWith(".lcsim") && entry.getName().contains(packageName)) { + resources.add(entry.getName()); + } + } + archive.close(); + } catch (final IOException e) { + throw new RuntimeException(e); + } + java.util.Collections.sort(resources); + final String[] arr = new String[resources.size()]; + for (int i = 0; i < arr.length; i++) { + arr[i] = resources.get(i); + } + return arr; + } + + /** + * Get the list of available conditions tags from the conditions system. + * + * @return the list of available conditions tags + */ + // FIXME: This method probably does not belong in this class. public static String[] getConditionsTags() { return DatabaseConditionsManager.getInstance().getTags().toArray(new String[] {}); } + + /** + * Do not allow class instantiation. + */ + private ResourceUtil() { + throw new UnsupportedOperationException("Do not instantiate this class."); + } } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java Tue Apr 21 14:48:39 2015 @@ -15,20 +15,32 @@ import org.lcsim.event.base.BaseLCSimEvent; /** - * This is an ET event processor that will load DAQ configuration into the global manager - * from EVIO physics SYNC events, which have an event type in which bits 6 and 7 are set to 1. - * - * @author Jeremy McCormick <[log in to unmask]> - * + * This is an ET event processor that will load DAQ configuration into the global manager from EVIO physics SYNC events, + * which have an event type in which bits 6 and 7 are set to 1. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> * @see org.hps.recon.ecal.daqconfig.ConfigurationManager * @see org.hps.recon.ecal.daqconfig.EvioDAQParser */ -public class SyncEventProcessor extends EtEventProcessor { +// FIXME: This class is currently unused. +public final class SyncEventProcessor extends EtEventProcessor { + /** + * The name of the trigger configuration collection. + */ private static final String TRIGGER_CONFIG = "TriggerConfig"; - TriggerConfigEvioReader configReader = new TriggerConfigEvioReader(); - public void process(EtEvent event) { + /** + * The trigger configuration reader. + */ + private final TriggerConfigEvioReader configReader = new TriggerConfigEvioReader(); + + /** + * Process an ET event and if there is a trigger configuration present, parse it and update the configuration in the + * global manager. + */ + @Override + public void process(final EtEvent event) { EvioEvent evioEvent = null; try { evioEvent = new EvioReader(event.getDataBuffer()).parseNextEvent(); @@ -37,20 +49,20 @@ } try { // Create a dummy LCIO event to satisfy the configuration reader's interface. - BaseLCSimEvent dummyLcsimEvent = - new BaseLCSimEvent(EvioEventUtilities.getRunNumber(evioEvent), evioEvent.getEventNumber(), "DUMMY", 0, false); - + final BaseLCSimEvent dummyLcsimEvent = new BaseLCSimEvent(EvioEventUtilities.getRunNumber(evioEvent), + evioEvent.getEventNumber(), "DUMMY", 0, false); + // Create the DAQ configuration object in the LCIO event. - configReader.getDAQConfig(evioEvent, dummyLcsimEvent); - + this.configReader.getDAQConfig(evioEvent, dummyLcsimEvent); + // Update the global configuration if a configuration was created. if (dummyLcsimEvent.hasCollection(EvioDAQParser.class, TRIGGER_CONFIG)) { - List<EvioDAQParser> configList = dummyLcsimEvent.get(EvioDAQParser.class, TRIGGER_CONFIG); + final List<EvioDAQParser> configList = dummyLcsimEvent.get(EvioDAQParser.class, TRIGGER_CONFIG); if (!configList.isEmpty()) { ConfigurationManager.updateConfiguration(configList.get(0)); } } - } catch (Exception e) { + } catch (final Exception e) { System.err.println("Failed to load DAQ config from sync event ..."); e.printStackTrace(); } Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/TableExporter.java ============================================================================= --- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/TableExporter.java (original) +++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/TableExporter.java Tue Apr 21 14:48:39 2015 @@ -9,54 +9,60 @@ /** * This is a utility for exporting a JTable's model data to a text file. - * Non-numeric fields are all contained in double quotes. - * - * @author Jeremy McCormick <[log in to unmask]> + * <p> + * Non-numeric fields such as strings are delimited by double quotes. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class TableExporter { - - private TableExporter() { - } - + /** * Export the given table to a text file. - * @param table The JTable component. - * @param path The output file path. - * @param fieldDelimiter The field delimiter to use. - * @throws IOException if there are errors writing the file. + * + * @param table the JTable component + * @param path the output file path + * @param fieldDelimiter the field delimiter to use + * @throws IOException if there are errors writing the file */ - public static void export(JTable table, String path, char fieldDelimiter) throws IOException { - - StringBuffer buffer = new StringBuffer(); - TableModel model = table.getModel(); - int rowCount = model.getRowCount(); - int columnCount = model.getColumnCount(); - + public static void export(final JTable table, final String path, final char fieldDelimiter) throws IOException { + + final StringBuffer buffer = new StringBuffer(); + final TableModel model = table.getModel(); + final int rowCount = model.getRowCount(); + final int columnCount = model.getColumnCount(); + // Column headers. for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { buffer.append("\"" + model.getColumnName(columnIndex) + "\"" + fieldDelimiter); - } + } buffer.setLength(buffer.length() - 1); buffer.append('\n'); - + // Row data. for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) { for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { - Object value = model.getValueAt(rowIndex, columnIndex); + final Object value = model.getValueAt(rowIndex, columnIndex); if (Number.class.isAssignableFrom(model.getColumnClass(columnIndex))) { buffer.append(value); } else { buffer.append("\"" + value + "\"" + fieldDelimiter); } - } + } buffer.setLength(buffer.length() - 1); buffer.append('\n'); } - + // Write string buffer to file. - BufferedWriter out = new BufferedWriter(new FileWriter(path)); + final BufferedWriter out = new BufferedWriter(new FileWriter(path)); out.write(buffer.toString()); out.flush(); out.close(); - } + } + + /** + * Do not allow class instantiation. + */ + private TableExporter() { + throw new UnsupportedOperationException("Do not instantiate this class."); + } }