Author: [log in to unmask] Date: Thu Apr 9 19:22:57 2015 New Revision: 2671 Log: Code cleanup in monitoring-app module. Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/AddActionListener.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/DatePanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventDashboard.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/FieldPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsDialog.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ToolbarPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/AbstractModel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/Configuration.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/SteeringType.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/package-info.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/AIDAServer.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/DialogUtil.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/TableExporter.java Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java Thu Apr 9 19:22:57 2015 @@ -16,6 +16,7 @@ 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; @@ -23,6 +24,8 @@ /** * 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> */ @SuppressWarnings("serial") abstract class AbstractFieldsPanel extends JPanel implements PropertyChangeListener, HasConfigurationModel, @@ -83,18 +86,14 @@ * @return <code>true</code> if property change event should be accepted */ boolean accept(final PropertyChangeEvent evt) { - if (evt.getPropertyName().equals("ancestor")) { - return false; - } else { - return true; - } + 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. + * @param listener the AcitonListener to add */ @Override public void addActionListener(final ActionListener listener) { @@ -124,10 +123,10 @@ /** * 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. + * @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) { @@ -157,10 +156,10 @@ /** * 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. + * @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, @@ -173,9 +172,9 @@ /** * 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. + * @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 String[] values) { @@ -186,7 +185,7 @@ c.insets = this.insets; c.anchor = GridBagConstraints.WEST; final JLabel waitModeLabel = new JLabel(name); - waitModeLabel.setHorizontalAlignment(JLabel.LEFT); + waitModeLabel.setHorizontalAlignment(SwingConstants.LEFT); this.add(waitModeLabel, c); c = new GridBagConstraints(); @@ -206,9 +205,9 @@ /** * 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. + * @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) { @@ -220,7 +219,7 @@ c.insets = this.insets; c.anchor = GridBagConstraints.WEST; final JLabel waitModeLabel = new JLabel(name + ":"); - waitModeLabel.setHorizontalAlignment(JLabel.LEFT); + waitModeLabel.setHorizontalAlignment(SwingConstants.LEFT); this.add(waitModeLabel, c); ++this.currentGridY; @@ -242,8 +241,8 @@ /** * Add a labeled JComponent to the panel. * - * @param name The label text. - * @param component The component to add. + * @param name the label text + * @param component the component to add */ void addComponent(final String name, final JComponent component) { @@ -270,9 +269,9 @@ /** * Add a field. * - * @param name The name of the field. - * @param size The size of the field. - * @return The JTextField component. + * @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); @@ -281,10 +280,10 @@ /** * 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. + * @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); @@ -293,11 +292,11 @@ /** * 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. + * @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) { @@ -317,7 +316,7 @@ // JFormattedTextField field = new JFormattedTextField(value, size); final JFormattedTextField field = new JFormattedTextField(value); field.setColumns(size); - field.setHorizontalAlignment(JTextField.RIGHT); + field.setHorizontalAlignment(SwingConstants.RIGHT); field.setEditable(editable); field.setBackground(Color.WHITE); this.add(field, c); @@ -330,12 +329,12 @@ /** * 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. + * @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) { @@ -345,9 +344,9 @@ } /** - * Get the configuration model for this component. - * - * @return the configuration model for the component + * 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 ConfigurationModel getConfigurationModel() { Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/AddActionListener.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/AddActionListener.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/AddActionListener.java Thu Apr 9 19:22:57 2015 @@ -4,13 +4,14 @@ /** * Mixin interface for components which can be assigned an external <code>ActionListener</code>. - * - * @author Jeremy McCormick <[log in to unmask]> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ interface AddActionListener { /** * Assign an <code>ActionListener</code> to this component which will assign to appropriate child components. + * * @param listener the <code>ActionListener</code> to assign to this component */ void addActionListener(ActionListener listener); Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java Thu Apr 9 19:22:57 2015 @@ -1,8 +1,8 @@ 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 ActionEvents in the MonitoringApplication. A few commands handled only by + * sub-components are not listed here. * * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java Thu Apr 9 19:22:57 2015 @@ -10,10 +10,10 @@ /** * 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 { /** * The {@link org.hps.conditions.api.ConditionsObjectCollection} for the model. Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsPanel.java Thu Apr 9 19:22:57 2015 @@ -28,15 +28,21 @@ /** * The component for showing conditions tables in the monitoring app. * - * @author Jeremy McCormick <[log in to unmask]> + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -public class ConditionsPanel extends JPanel { +@SuppressWarnings("serial") +public 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(final ConditionsEvent event) { @@ -65,12 +71,24 @@ } } + /** + * 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()); @@ -81,7 +99,7 @@ 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(model)); + ConditionsPanel.this.conditionsTable.setRowSorter(new TableRowSorter<TableModel>(model)); ConditionsPanel.this.conditionsTable.revalidate(); } }); @@ -90,8 +108,8 @@ final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, this.conditionsList, new JScrollPane( this.conditionsTable)); - splitPane.setResizeWeight(0.6); + // splitPane.setResizeWeight(0.6); this.add(splitPane); } -} +} Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java Thu Apr 9 19:22:57 2015 @@ -15,8 +15,11 @@ /** * Connection settings panel. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -class ConnectionSettingsPanel extends AbstractFieldsPanel { +@SuppressWarnings("serial") +final class ConnectionSettingsPanel extends AbstractFieldsPanel { /** * Updates the GUI from changes in the ConfigurationModel. @@ -58,20 +61,69 @@ } } - static final String[] waitModes = { Mode.SLEEP.name(), Mode.TIMED.name(), Mode.ASYNC.name() }; + /** + * 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; /** @@ -112,7 +164,7 @@ this.stationPositionField = this.addField("Station Position", 3); this.stationPositionField.addPropertyChangeListener("value", this); - this.waitModeComboBox = this.addComboBox("Wait Mode", waitModes); + this.waitModeComboBox = this.addComboBox("Wait Mode", WAIT_MODES); this.waitModeComboBox.setActionCommand(Commands.WAIT_MODE_CHANGED); this.waitModeComboBox.addActionListener(this); @@ -125,6 +177,8 @@ /** * Used to update the ConfigurationModel from GUI components. + * + * @param e the <code>ActionEvent</code> to handle */ @Override public void actionPerformed(final ActionEvent e) { @@ -139,8 +193,8 @@ /** * Enable or disable the connection panel GUI elements. - * - * @param e Set to true for enabled; false to disable. + * + * @param e <code>true</code> to enable the components in the panel */ void enableConnectionPanel(final boolean e) { this.etNameField.setEnabled(e); @@ -192,6 +246,10 @@ } } + /** + * Set configuration model (using <code>super</code> method) and add a property change listener for connection + * settings. + */ @Override public void setConfigurationModel(final ConfigurationModel model) { super.setConfigurationModel(model); @@ -199,4 +257,4 @@ // This listener updates the GUI from changes in the configuration. this.getConfigurationModel().addPropertyChangeListener(new ConnectionSettingsChangeListener()); } -} +} Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java Thu Apr 9 19:22:57 2015 @@ -11,59 +11,81 @@ 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 { +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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java Thu Apr 9 19:22:57 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/DatePanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/DatePanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/DatePanel.java Thu Apr 9 19:22:57 2015 @@ -6,32 +6,71 @@ /** * A small JPanel 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java Thu Apr 9 19:22:57 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,24 @@ 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 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 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. + */ @Override public void propertyChange(final PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) { @@ -72,35 +137,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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventDashboard.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventDashboard.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventDashboard.java Thu Apr 9 19:22:57 2015 @@ -20,248 +20,400 @@ 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(); - + + @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); - } - } - - /** - * Update the GUI from changes to the backing RunModel object. + EventDashboard.this.runModel.setRunNumber(this.runNumber); + EventDashboard.this.runModel.setStartDate(new Date(seconds * MILLIS)); + } + } + } + + /** + * 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. + */ + FieldPanel dataRateField = new FieldPanel("Data Rate [MB/s]", "", 12, false); + + /** + * Field for showing the total data received in MB. + */ + FieldPanel dataReceivedField = new FieldPanel("Data Received [MB]", "", 14, false); + + /** + * Field for showing the elapsed job time in seconds. + */ + FieldPanel elapsedTimeField = new FieldPanel("Elapsed Time [sec]", "", 14, false); + + /** + * Field for showing the end date. + */ + DatePanel endDateField = new DatePanel("Run End", "", 14, false); + + /** + * Field for showing the current event number. + */ + FieldPanel eventNumberField = new FieldPanel("Event Number", "", 14, false); + + /** + * Field showing the event rate in Hertz. + */ + FieldPanel eventRateField = new FieldPanel("Event Rate [Hz]", "", 14, false); + + /** + * Field for showing the total number of events received. + */ + FieldPanel eventsReceivedField = new FieldPanel("Events Received", "", 14, false); + + /** + * Field for showing the length of the run in seconds. + */ + FieldPanel lengthField = new FieldPanel("Run Length [sec]", "", 12, false); + + /** + * The backing model with run and event information. + */ + RunModel runModel; + + /** + * Field for showing the run number. + */ + FieldPanel runNumberField = new FieldPanel("Run Number", "", 10, false); + + /** + * Field for showing the start date. + */ + DatePanel startDateField = new DatePanel("Run Start", "", 14, false); + + /** + * Field for showing the total events in the run. + */ + FieldPanel totalEventsField = new FieldPanel("Total Events in Run", "", 14, false); + + /** + * Class constructor which will build the GUI components. + */ + public EventDashboard() { + build(); + } + + /** + * 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)); + } + } + + /** + * Set the backing {@link org.hps.monitoring.application.model.RunModel} of the component. + * + * @param runModel the backing {@link org.hps.monitoring.application.model.RunModel} of the component + */ + public void setModel(final RunModel runModel) { + this.runModel = runModel; + } +} Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java Thu Apr 9 19:22:57 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,73 +38,404 @@ 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 is used internally to organize 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 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 conditions change. + * + * @param application the current monitoring application + * @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 (usingEtServer()) { + // Create a connection to the ET server. + try { + this.logger.fine("connecting to ET system ..."); + + // Create the main ET system connection. + 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 (usingEtServer()) { + 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 to the processing watchdog thread. + * <p> + * This will happen if there is a user requested disconnect from pushing the disconnect 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 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); @@ -118,37 +444,41 @@ } /** - * @param configurationModel - */ - void setupLcsim(ConfigurationModel configurationModel) { - MonitoringApplication.logger.info("setting up lcsim"); + * 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. @@ -156,7 +486,7 @@ 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); } else if (steeringType.equals(SteeringType.FILE)) { @@ -164,143 +494,157 @@ } // Set conditions tag. - if (configurationModel.hasValidProperty(ConfigurationModel.CONDITIONS_TAG_PROPERTY) && !configurationModel.getConditionsTag().equals("")) { - logger.config("conditions tag is set to " + configurationModel.getConditionsTag()); + 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 configuration model. + 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()); 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. @@ -308,398 +652,92 @@ // Wake up all ET stations to unblock the system and make sure secondary stations are detached. if (usingEtServer()) { - wakeUpEtStations(); - } - + 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"); + this.logger.fine("sending STOP command to loop ..."); + this.sessionState.loop.execute(Command.STOP); + this.logger.fine("loop got command STOP"); // Cleanup the event processing thread since it was told to stop now. try { - logger.fine("waiting for event processing thread to end ..."); - sessionState.processingThread.join(); - logger.fine("event processing thread ended"); - } catch (InterruptedException e) { + this.logger.fine("waiting for event processing thread to end ..."); + this.sessionState.processingThread.join(); + this.logger.fine("event processing thread ended"); + } 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(); - + // 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 ..."); + * 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) { - } - } - // 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/FieldPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/FieldPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/FieldPanel.java Thu Apr 9 19:22:57 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java Thu Apr 9 19:22:57 2015 @@ -28,29 +28,41 @@ import org.jdom.input.SAXBuilder; /** - * This is the GUI panel for setting job parameters. It is connected to the global configuration via a + * 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 { +@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) { - if (pathname.getName().equals("compact.xml")) { - return true; - } else { - return false; - } - } - + 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"; @@ -61,6 +73,10 @@ * 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. + */ @Override public void propertyChange(final PropertyChangeEvent evt) { if (evt.getSource() instanceof ConfigurationModel) { @@ -121,37 +137,110 @@ } } - // The available LogLevel settings as an array of strings. + /** + * 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. - static final String STEERING_PACKAGE = "org/hps/steering/monitoring/"; + 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<?> steeringTypeComboBox; + /** + * Field for setting a user run number for conditions system activation. + */ private final JTextField userRunNumberField; /** * Class constructor. - */ + * + * @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); @@ -248,6 +337,11 @@ 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 void actionPerformed(final ActionEvent event) { try { @@ -300,7 +394,9 @@ } /** - * Attaches the ActionListener from the main app to specific GUI components in this class. + * 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) { @@ -309,25 +405,25 @@ } /** - * Parse the lcsim steering file to see if it appears to be valid. + * 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. - * @throws JDOMException if the XML is not 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 (!rootNode.getName().equals("lcsim")) { - throw new IOException("Not an LCSim XML file: " + file.getPath()); + 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. */ - void chooseCompactFile() { + private void chooseCompactFile() { final JFileChooser fc = new JFileChooser(); fc.setDialogTitle("Choose a Compact XML File"); fc.setCurrentDirectory(new File(".")); @@ -340,9 +436,9 @@ } /** - * Choose an lcsim steering file. - */ - void chooseSteeringFile() { + * Choose an LCSim steering file. + */ + private void chooseSteeringFile() { final JFileChooser fc = new JFileChooser(); fc.setDialogTitle("Choose an LCSim Steering File"); fc.setCurrentDirectory(new File(".")); @@ -418,9 +514,17 @@ } } + /** + * 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(final ConfigurationModel model) { super.setConfigurationModel(model); model.addPropertyChangeListener(new JobSettingsChangeListener()); } -} +} Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java Thu Apr 9 19:22:57 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java Thu Apr 9 19:22:57 2015 @@ -15,46 +15,66 @@ /** * 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{ +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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java Thu Apr 9 19:22:57 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java Thu Apr 9 19:22:57 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java Thu Apr 9 19:22:57 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("Recent Files"); - 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java Thu Apr 9 19:22:57 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; @@ -29,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; @@ -60,217 +59,308 @@ 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() { + + /** + * Not used. + * + * @param e + */ @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(); } + /** + * Not used. + * + * @param e + */ @Override - public void windowIconified(WindowEvent e) { + public void windowClosing(final WindowEvent e) { } + /** + * Not used. + * + * @param e + */ @Override - public void windowDeiconified(WindowEvent e) { + public void windowDeactivated(final WindowEvent e) { } + /** + * Not used. + * + * @param e + */ @Override - public void windowActivated(WindowEvent e) { + public void windowDeiconified(final WindowEvent e) { } + /** + * Not used. + * + * @param e + */ @Override - public void windowDeactivated(WindowEvent e) { + public void windowIconified(final WindowEvent e) { + } + + /** + * Not used. + * + * @param 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)) { @@ -279,20 +369,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(); @@ -321,562 +411,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 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) { - + 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 property change event. + */ + @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, getRunData()); + 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."); } } } - - /** - * Get a list of run data for writing to a PDF. - * @return The list of run data from the model. - */ - List<String> getRunData() { - List<String> data = new ArrayList<String>(); - data.add("Created: " + new Date()); - data.add("Run Number: " + runModel.getRunNumber()); - data.add("Started: " + runModel.getStartDate()); - data.add("Ended: " + runModel.getEndDate()); - data.add("Length: " + runModel.getRunLength() + " seconds"); - data.add("Total Events: " + runModel.getTotalEvents()); - data.add("Elapsed Time: " + runModel.getElapsedTime()); - data.add("Events Processed: " + runModel.getEventsReceived()); - return data; - } - - /** - * 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java Thu Apr 9 19:22:57 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); - + // Create the content panel. - JPanel contentPanel = new JPanel(); + final JPanel contentPanel = new JPanel(); 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.saveButton.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); + 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. + this.settingsDialog = new SettingsDialog(application.getConfigurationModel(), application); + + // Setup the frame now that all components have been added. pack(); - setExtendedState(JFrame.MAXIMIZED_BOTH); - setVisible(true); - } - + setExtendedState(Frame.MAXIMIZED_BOTH); + 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(); - } -} + setExtendedState(Frame.MAXIMIZED_BOTH); + this.mainSplitPane.resetToPreferredSizes(); + this.leftSplitPane.resetToPreferredSizes(); + this.rightSplitPane.resetToPreferredSizes(); + } +} Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java Thu Apr 9 19:22:57 2015 @@ -38,26 +38,28 @@ /** * <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; +final class PlotInfoPanel extends JPanel implements AIDAListener, ActionListener, FunctionListener { + + static final String[] COLUMN_NAMES = { "Field", "Value" }; + static final int MAX_ROWS = 13; + static final int MIN_HEIGHT = 300; + static final int MIN_WIDTH = 400; + + static final String PLOT_SELECTED = "PlotSelected"; + Object currentObject; + + PlotterRegion currentRegion; JTable infoTable = new JTable(); DefaultTableModel model; + JComboBox<Object> plotComboBox; 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(); @@ -66,39 +68,42 @@ */ @SuppressWarnings("unchecked") PlotInfoPanel() { - + setLayout(new FlowLayout(FlowLayout.CENTER)); - JPanel leftPanel = new JPanel(); + 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 Current Plot Tab ..."); - 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(); + final Dimension max = super.getMaximumSize(); max.height = getPreferredSize().height; return max; } }; - plotComboBox.setActionCommand(PLOT_SELECTED); - plotComboBox.setAlignmentX(CENTER_ALIGNMENT); - plotComboBox.setRenderer(new BasicComboBoxRenderer() { + this.plotComboBox.setActionCommand(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); + final String title = getObjectTitle(value); setText(value.getClass().getSimpleName() + " - " + title); } else { setText("Click on a plot region ..."); @@ -106,172 +111,103 @@ 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); - + 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); + 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. + * Implementation of <code>actionPerformed</code> to handle the selection of a new object from the combo box. */ @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. - */ - @Override - public void actionPerformed(ActionEvent e) { + public void actionPerformed(final ActionEvent e) { // Is there a new item selected in the combo box? if (PLOT_SELECTED.equals(e.getActionCommand())) { - if (plotComboBox.getSelectedItem() != null) { + if (this.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) { - if (object instanceof IBaseHistogram) { - return ((IBaseHistogram) object).title(); - } else if (object instanceof IDataPointSet) { - return ((IDataPointSet) object).title(); - } else if (object instanceof IFunction) { - return ((IFunction) object).title(); - } else { - return object.toString(); - } - } - - /** - * 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 false; - if (object instanceof IBaseHistogram || object instanceof IFunction || object instanceof IDataPointSet) { - return true; - } - return false; + setCurrentObject(this.plotComboBox.getSelectedItem()); + } + } + } + + /** + * Add this object as an <code>AIDAListener</code> on the current <code>AIDAObservable</code>. + */ + 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. + */ + 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. + */ + void addRows(final 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(final IFunction function) { + addRow("title", function.title()); + + // Add generically the values of all function parameters. + for (final String parameter : function.parameterNames()) { + addRow(parameter, function.parameter(parameter)); + } } /** * Add rows to the info table from the state of a 1D histogram. + * * @param histogram The AIDA object. */ - void addRows(IHistogram1D histogram) { + void addRows(final IHistogram1D histogram) { addRow("title", histogram.title()); addRow("bins", histogram.axis().bins()); addRow("entries", histogram.entries()); @@ -285,9 +221,10 @@ /** * Add rows to the info table from the state of a 2D histogram. + * * @param histogram The AIDA object. */ - void addRows(IHistogram2D histogram) { + void addRows(final IHistogram2D histogram) { addRow("title", histogram.title()); addRow("x bins", histogram.xAxis().bins()); addRow("y bins", histogram.yAxis().bins()); @@ -305,62 +242,95 @@ } /** - * 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 }); + * 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 { + 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 toString method, if none exists. + */ + String getObjectTitle(final Object object) { + if (object instanceof IBaseHistogram) { + return ((IBaseHistogram) object).title(); + } else if (object instanceof IDataPointSet) { + return ((IDataPointSet) object).title(); + } else if (object instanceof IFunction) { + return ((IFunction) object).title(); + } else { + return object.toString(); + } + } + + boolean isValidObject(final Object object) { + if (object == null) { + return false; + } + if (object instanceof IBaseHistogram || object instanceof IFunction || object instanceof IDataPointSet) { + return true; + } + return false; + } + + /** + * Remove this as a listener on the current AIDA object. + */ + 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. + */ + void runUpdateTable() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + updateTable(); + } + }); } /** * 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) + 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(); // 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 @@ -372,47 +342,93 @@ } /** - * 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). + * 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; + updateComboBox(); + setCurrentObject(this.plotComboBox.getSelectedItem()); + setupContentPane(); + } + } + + /** + * Configure the frame's content panel from current component settings. + */ + void setupContentPane() { + this.plotComboBox.setSize(this.plotComboBox.getPreferredSize()); + this.infoTable.setSize(this.infoTable.getPreferredSize()); + 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. + 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. + */ + void updateComboBox() { + this.plotComboBox.removeAllItems(); + final List<Object> objects = this.currentRegion.getPlottedObjects(); + for (final Object object : objects) { + if (isValidObject(object)) { + this.plotComboBox.addItem(object); + } + } + } + + /** + * Update the info table from the state of the current AIDA object. + */ + void updateTable() { + this.model.setRowCount(0); + if (this.currentObject instanceof IHistogram1D) { + addRows((IHistogram1D) this.currentObject); + } else if (this.currentObject instanceof IHistogram2D) { + addRows((IHistogram2D) this.currentObject); + } else if (this.currentObject instanceof ICloud2D) { + addRows((ICloud2D) this.currentObject); + } else if (this.currentObject instanceof ICloud1D) { + if (((ICloud1D) this.currentObject).isConverted()) { + addRows(((ICloud1D) this.currentObject).histogram()); + } + } else if (this.currentObject instanceof IFunction) { + addRows((IFunction) this.currentObject); } } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java Thu Apr 9 19:22:57 2015 @@ -1,7 +1,6 @@ package org.hps.monitoring.application; import hep.aida.IPlotter; -import hep.aida.jfree.plotter.Plotter; import java.awt.BorderLayout; import java.awt.Component; @@ -23,45 +22,25 @@ /** * 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; - +final class PlotPanel extends JPanel implements ActionListener { + + private final JTabbedPane plotPane; + public PlotPanel() { setLayout(new BorderLayout()); - plotPane = new JTabbedPane(); - plotPane.setPreferredSize(getPreferredSize()); - add(plotPane, BorderLayout.CENTER); - } - - JTabbedPane getPlotPane() { - return plotPane; + this.plotPane = new JTabbedPane(); + this.plotPane.setPreferredSize(getPreferredSize()); + add(this.plotPane, BorderLayout.CENTER); } - /** - * Get the indices of the current selected tabs. - * @return The indices of the current tabs. - */ - int[] getSelectedTabIndices() { - int[] indices = new int[2]; - indices[0] = plotPane.getSelectedIndex(); - Component component = plotPane.getSelectedComponent(); - if (component instanceof JTabbedPane) { - indices[1] = ((JTabbedPane)component).getSelectedIndex(); - } - return indices; - } - - Component getSelectedTab() { - return ((JTabbedPane) plotPane.getSelectedComponent()).getSelectedComponent(); - } - - public void actionPerformed(ActionEvent event) { + @Override + public void actionPerformed(final ActionEvent event) { if (event.getActionCommand().equals(Commands.SAVE_SELECTED_PLOTS)) { - int[] indices = getSelectedTabIndices(); - IPlotter plotter = MonitoringPlotFactory.getPlotterRegistry().find(indices[0], indices[1]); + final int[] indices = getSelectedTabIndices(); + final IPlotter plotter = MonitoringPlotFactory.getPlotterRegistry().find(indices[0], indices[1]); if (plotter != null) { savePlotter(plotter); } else { @@ -69,9 +48,36 @@ } } } - - void savePlotter(IPlotter plotter) { - JFileChooser fc = new JFileChooser(); + + JTabbedPane getPlotPane() { + return this.plotPane; + } + + Component getSelectedTab() { + return ((JTabbedPane) this.plotPane.getSelectedComponent()).getSelectedComponent(); + } + + /** + * Get the indices of the current selected tabs. + * + * @return The indices of the current tabs. + */ + 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; + } + + void reset() { + this.plotPane.removeAll(); + } + + void savePlotter(final IPlotter plotter) { + final JFileChooser fc = new JFileChooser(); fc.setAcceptAllFileFilterUsed(false); fc.setDialogTitle("Save Plots - " + plotter.title()); fc.setCurrentDirectory(new File(".")); @@ -79,25 +85,21 @@ fc.setFileFilter(new FileNameExtensionFilter("PNG file", "png")); fc.addChoosableFileFilter(new FileNameExtensionFilter("JPG file", "jpg")); fc.addChoosableFileFilter(new FileNameExtensionFilter("GIF file", "gif")); - int r = fc.showSaveDialog(this); - if (r == JFileChooser.APPROVE_OPTION) { + final int r = fc.showSaveDialog(this); + if (r == JFileChooser.APPROVE_OPTION) { String path = fc.getSelectedFile().getPath(); - FileNameExtensionFilter filter = (FileNameExtensionFilter) fc.getFileFilter(); + final FileNameExtensionFilter filter = (FileNameExtensionFilter) fc.getFileFilter(); if (!path.endsWith("." + filter.getExtensions()[0])) { path += "." + filter.getExtensions()[0]; } - BufferedImage image = ExportPdf.getImage(getSelectedTab()); + final BufferedImage image = ExportPdf.getImage(getSelectedTab()); try { ImageIO.write(image, filter.getExtensions()[0], new File(path)); DialogUtil.showInfoDialog(this, "Plots Saved", "Plots from panel were saved to" + '\n' + path); - } catch (IOException e) { + } 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsDialog.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsDialog.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsDialog.java Thu Apr 9 19:22:57 2015 @@ -9,21 +9,22 @@ 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 settings. 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 { +final class SettingsDialog extends JDialog { final SettingsPanel settingsPanel; - public SettingsDialog(ConfigurationModel configurationModel, ActionListener listener) { + 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); + setContentPane(this.settingsPanel); setResizable(false); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); setModalityType(ModalityType.APPLICATION_MODAL); @@ -31,13 +32,15 @@ // Add window listener for turning invisible when closing. addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { + @Override + public void windowClosing(final WindowEvent e) { setVisible(false); } - - public void windowOpened(WindowEvent event) { - SettingsDialog.this.setLocationRelativeTo(null); + + @Override + public void windowOpened(final WindowEvent event) { + SettingsDialog.this.setLocationRelativeTo(null); } - }); + }); } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java Thu Apr 9 19:22:57 2015 @@ -16,44 +16,46 @@ /** * 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 { +final class SettingsPanel extends JPanel implements ActionListener { + + static final String OKAY_COMMAND = "settingsOkay"; + ConnectionSettingsPanel connectionPanel; + JobSettingsPanel jobPanel; + JDialog parent; JTabbedPane tabs; - JobSettingsPanel jobPanel; - ConnectionSettingsPanel connectionPanel; - static final String OKAY_COMMAND = "settingsOkay"; - JDialog parent; - - SettingsPanel(JDialog parent, ConfigurationModel configurationModel, ActionListener listener) { + 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); + add(this.tabs); - JButton okayButton = new JButton("Okay"); + final JButton okayButton = new JButton("Okay"); okayButton.setActionCommand(OKAY_COMMAND); okayButton.addActionListener(this); add(Box.createRigidArea(new Dimension(1, 5))); - JPanel buttonsPanel = new JPanel(); + final JPanel buttonsPanel = new JPanel(); buttonsPanel.add(okayButton); buttonsPanel.setLayout(new FlowLayout()); add(buttonsPanel); @@ -61,9 +63,9 @@ } @Override - public void actionPerformed(ActionEvent e) { + public void actionPerformed(final ActionEvent e) { if (e.getActionCommand().equals(OKAY_COMMAND)) { - parent.setVisible(false); + this.parent.setVisible(false); } - } + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java Thu Apr 9 19:22:57 2015 @@ -1,5 +1,5 @@ /** - * + * */ package org.hps.monitoring.application; @@ -22,125 +22,130 @@ /** * 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 { - +final class SystemStatusEventsTable extends JTable { + + static class SystemStatusEventsTableModel extends DefaultTableModel implements SystemStatusListener { + + Class<?>[] columnClasses = { Date.class, Subsystem.class, SystemStatus.class, String.class, String.class }; + + String[] columnNames = { "Date", "Subsystem", "Status Code", "Description", "Message" }; + List<SystemStatus> statuses = new ArrayList<SystemStatus>(); + + SystemStatusEventsTableModel() { + } + + /** + * Register the listener on this status. + * + * @param status The system status. + */ + void addSystemStatus(final SystemStatus status) { + status.addListener(this); + } + + public void clear() { + this.statuses.clear(); + this.setRowCount(0); + } + + @Override + public Class<?> getColumnClass(final int column) { + return this.columnClasses[column]; + } + + @Override + public int getColumnCount() { + return this.columnNames.length; + } + + @Override + public String getColumnName(final int column) { + return this.columnNames[column]; + } + + @Override + public int getRowCount() { + if (this.statuses != null) { + return this.statuses.size(); + } else { + return 0; + } + } + + @Override + public Object getValueAt(final int row, final int column) { + final SystemStatus status = this.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; + } + } + + /** + * 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); + fireTableDataChanged(); + } + } + SystemStatusEventsTableModel tableModel = new SystemStatusEventsTableModel(); - + SystemStatusEventsTable() { - setModel(tableModel); - + setModel(this.tableModel); + // Date formatting. 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() { @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() { } - - 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java Thu Apr 9 19:22:57 2015 @@ -1,5 +1,5 @@ /** - * + * */ package org.hps.monitoring.application; @@ -13,39 +13,35 @@ 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 all system status change events. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ -public class SystemStatusPanel extends JPanel { - +final class SystemStatusPanel extends JPanel { + + SystemStatusEventsTable eventsTable = new SystemStatusEventsTable(); SystemStatusTable statusTable = new SystemStatusTable(); - SystemStatusEventsTable eventsTable = new SystemStatusEventsTable(); - - SystemStatusPanel() { + + 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) { + add(splitPane, BorderLayout.CENTER); + } + + 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.tableModel.addSystemStatus(status); } - + 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java Thu Apr 9 19:22:57 2015 @@ -17,8 +17,55 @@ /** * 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 { +final class SystemStatusTable extends JTable { + + /** + * Renders a button if the status is clearable. + */ + private class ButtonRenderer extends JButton implements TableCellRenderer { + + public ButtonRenderer(final String label) { + this.setText(label); + } + + @Override + public Component getTableCellRendererComponent(final JTable table, final Object value, + final boolean isSelected, final boolean hasFocus, final int row, final int column) { + final boolean clearable = (Boolean) table.getModel().getValueAt(row, SystemStatusTableModel.CLEARABLE_COL); + if (clearable) { + return this; + } 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>. + */ + private static class JTableButtonMouseListener extends MouseAdapter { + private final JTable table; + + public JTableButtonMouseListener(final JTable table) { + this.table = table; + } + + @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(); + } + } + } + } SystemStatusTable() { @@ -28,31 +75,35 @@ getColumnModel().getColumn(SystemStatusTableModel.STATUS_COL).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.valueOf((String) value); + final 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() { + getColumnModel().getColumn(SystemStatusTableModel.LAST_CHANGED_COL).setCellRenderer( + new DefaultTableCellRenderer() { - final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS"); + 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); - } - }); + @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. getColumnModel().getColumn(SystemStatusTableModel.RESET_COL).setCellRenderer(new ButtonRenderer("Clear")); @@ -73,46 +124,4 @@ public SystemStatusTableModel getTableModel() { return (SystemStatusTableModel) getModel(); } - - /** - * Renders a button if the status is clearable. - */ - private class ButtonRenderer extends JButton implements TableCellRenderer { - - public ButtonRenderer(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) - return this; - 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>. - */ - private static class JTableButtonMouseListener extends MouseAdapter { - private final JTable table; - - public JTableButtonMouseListener(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); - if (value instanceof JButton) { - ((JButton) value).doClick(); - } - } - } - } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ToolbarPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ToolbarPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ToolbarPanel.java Thu Apr 9 19:22:57 2015 @@ -13,21 +13,22 @@ /** * 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 { +final class ToolbarPanel extends JPanel { - DataSourceComboBox dataSourceComboBox; - JPanel buttonsPanel; + private final JPanel buttonsPanel; + private final DataSourceComboBox dataSourceComboBox; - ToolbarPanel(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel, ActionListener listener) { + ToolbarPanel(final ConfigurationModel configurationModel, final ConnectionStatusModel connectionModel, + final ActionListener listener) { setLayout(new FlowLayout(FlowLayout.LEFT)); - - JPanel containerPanel = new JPanel(); + + final JPanel containerPanel = new JPanel(); containerPanel.setLayout(new GridBagLayout()); - + // Create the connection status panel. GridBagConstraints gbs = new GridBagConstraints(); gbs.anchor = GridBagConstraints.WEST; @@ -36,30 +37,34 @@ 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); - + containerPanel.add(this.dataSourceComboBox, gbs); + add(containerPanel); } + DataSourceComboBox getDataSourceComboBox() { + return this.dataSourceComboBox; + } + } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java Thu Apr 9 19:22:57 2015 @@ -18,36 +18,12 @@ /** * 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> */ @SuppressWarnings("serial") -class TriggerDiagnosticsPanel extends JPanel { +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. */ @@ -55,24 +31,50 @@ // FIXME: Hard-coded collection name. 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(DiagnosticSnapshot.class, diagnosticCollectionName)) { + if (event.hasCollection(DiagnosticSnapshot.class, this.diagnosticCollectionName)) { // Get the snapshot collection. - List<DiagnosticSnapshot> snapshotList = event.get(DiagnosticSnapshot.class, diagnosticCollectionName); - + final List<DiagnosticSnapshot> snapshotList = event.get(DiagnosticSnapshot.class, + this.diagnosticCollectionName); + // Update the GUI panels. - for (DiagnosticUpdatable update : updateList) { + for (final DiagnosticUpdatable update : TriggerDiagnosticsPanel.this.updateList) { update.updatePanel(snapshotList.get(1), snapshotList.get(0)); } - } + } } - - void setDiagnosticCollectionName(String name) { - diagnosticCollectionName = name; + + void setDiagnosticCollectionName(final String name) { + this.diagnosticCollectionName = name; } - } + } + + ClusterTablePanel clusterPanel = new ClusterTablePanel(); + EfficiencyTablePanel efficiencyPanel = new EfficiencyTablePanel(); + PairTablePanel pairsPanel = new PairTablePanel(); + SinglesTablePanel singlesPanel = new SinglesTablePanel(); + + JTabbedPane tabs = new JTabbedPane(); + + List<DiagnosticUpdatable> updateList = new ArrayList<DiagnosticUpdatable>(); + + TriggerDiagnosticsPanel() { + 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); + + add(this.tabs, BorderLayout.CENTER); + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/AbstractModel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/AbstractModel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/AbstractModel.java Thu Apr 9 19:22:57 2015 @@ -15,56 +15,70 @@ /** * 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 { + + /** + * 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. + */ + 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)); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + return fields.toArray(new String[] {}); + } protected PropertyChangeSupport propertyChangeSupport; public AbstractModel() { - propertyChangeSupport = new PropertyChangeSupport(this); + this.propertyChangeSupport = new PropertyChangeSupport(this); } - public void addPropertyChangeListener(PropertyChangeListener listener) { - propertyChangeSupport.addPropertyChangeListener(listener); + public void addPropertyChangeListener(final PropertyChangeListener listener) { + this.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); + public void fireModelChanged() { + firePropertiesChanged(Arrays.asList(getPropertyNames())); } - protected void firePropertyChange(PropertyChangeEvent evt) { - propertyChangeSupport.firePropertyChange(evt); - } - - abstract public String[] getPropertyNames(); - - void firePropertiesChanged(Collection<String> properties) { - propertyLoop: for (String property : properties) { + void firePropertiesChanged(final Collection<String> properties) { + propertyLoop: for (final String property : properties) { Method getMethod = null; - for (Method method : getClass().getMethods()) { + for (final Method method : getClass().getMethods()) { if (method.getName().equals("get" + property)) { getMethod = method; break; } } - //System.out.println(getMethod.getName()); + // System.out.println(getMethod.getName()); try { Object value = null; try { value = getMethod.invoke(this, (Object[]) null); - //System.out.println(" value = " + value); - } catch (NullPointerException e) { + // System.out.println(" value = " + value); + } catch (final 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) { + } catch (final 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. + // 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 { @@ -74,7 +88,8 @@ } if (value != null) { firePropertyChange(property, value, value); - for (PropertyChangeListener listener : propertyChangeSupport.getPropertyChangeListeners()) { + 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)); } @@ -85,30 +100,18 @@ } } } - - public void fireModelChanged() { - firePropertiesChanged(Arrays.asList(getPropertyNames())); + + protected void firePropertyChange(final PropertyChangeEvent evt) { + this.propertyChangeSupport.firePropertyChange(evt); } - /** - * 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. - */ - protected static String[] getPropertyNames(Class<? extends AbstractModel> type) { - List<String> fields = new ArrayList<String>(); - for (Field field : type.getDeclaredFields()) { - int modifiers = field.getModifiers(); - if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && field.getName().endsWith("_PROPERTY")) { - try { - fields.add((String) field.get(null)); - } catch (IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - return fields.toArray(new String[] {}); + protected void firePropertyChange(final String propertyName, final Object oldValue, final Object newValue) { + this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + abstract public String[] getPropertyNames(); + + public void removePropertyChangeListener(final PropertyChangeListener listener) { + this.propertyChangeSupport.removePropertyChangeListener(listener); } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/Configuration.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/Configuration.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/Configuration.java Thu Apr 9 19:22:57 2015 @@ -9,210 +9,227 @@ 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 { + File file; Properties properties; - File file; String resourcePath; Configuration() { - properties = new Properties(); + this.properties = new Properties(); } /** * Load a configuration from a properties file. + * * @param file The properties file. */ - public Configuration(File 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); } } /** * 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) { + 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 True if properties key is valid. + */ + boolean checkKey(final String key) { + return 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 (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 (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 or null if does not exist. + */ + Double getDouble(final String key) { + if (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. */ public File getFile() { - return file; - } - - /** - * Get the resource path associated with this configuration or <code>null</code> if not - * applicable. + return this.file; + } + + /** + * Get a key value as an integer. + * + * @param key The key to lookup. + * @return The value or null if does not exist. + */ + Integer getInteger(final String key) { + if (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. + * @param key The value or null if does not exist. + * @return + */ + Long getLong(final String key) { + if (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; + return this.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) { + 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; - } - } - - /** - * Write this configuration to a file and set that file as the current one. - * @param file The output file. - */ - public void writeToFile(File file) { - this.file = file; - try { - properties.store(new FileOutputStream(this.file), null); - } catch (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; + * 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(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); + 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 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)); + 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(final File file) { + this.file = file; + try { + this.properties.store(new FileOutputStream(this.file), null); + } catch (final IOException e) { + throw new RuntimeException("Error saving properties file.", e); } } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java Thu Apr 9 19:22:57 2015 @@ -9,497 +9,505 @@ 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. public static final String AIDA_SERVER_NAME_PROPERTY = "AIDAServerName"; + + public static final String BLOCKING_PROPERTY = "Blocking"; + + public static final String CHUNK_SIZE_PROPERTY = "ChunkSize"; public static final String CONDITIONS_TAG_PROPERTY = "ConditionsTag"; + static final String[] CONFIG_PROPERTIES = AbstractModel.getPropertyNames(ConfigurationModel.class); + public static final String CONFIGURATION_CHANGED = "configurationChanged"; + public static final String DATA_SOURCE_PATH_PROPERTY = "DataSourcePath"; + public static final String DATA_SOURCE_TYPE_PROPERTY = "DataSourceType"; + public static final String DETECTOR_ALIAS_PROPERTY = "DetectorAlias"; public static final String DETECTOR_NAME_PROPERTY = "DetectorName"; - public static final String DETECTOR_ALIAS_PROPERTY = "DetectorAlias"; + public static final String DISCONNECT_ON_END_RUN_PROPERTY = "DisconnectOnEndRun"; public static final String DISCONNECT_ON_ERROR_PROPERTY = "DisconnectOnError"; - public static final String DISCONNECT_ON_END_RUN_PROPERTY = "DisconnectOnEndRun"; + public static final String ET_NAME_PROPERTY = "EtName"; public static final String EVENT_BUILDER_PROPERTY = "EventBuilderClassName"; public static final String FREEZE_CONDITIONS_PROPERTY = "FreezeConditions"; + public static final String HOST_PROPERTY = "Host"; public static final String LOG_FILE_NAME_PROPERTY = "LogFileName"; + public static final String LOG_LEVEL_FILTER_PROPERTY = "LogLevelFilter"; public static final String LOG_LEVEL_PROPERTY = "LogLevel"; - public static final String LOG_LEVEL_FILTER_PROPERTY = "LogLevelFilter"; public static final String LOG_TO_FILE_PROPERTY = "LogToFile"; public static final String MAX_EVENTS_PROPERTY = "MaxEvents"; + private static final int MAX_RECENT_FILES = 10; + public static final String PORT_PROPERTY = "Port"; + public static final String PRESCALE_PROPERTY = "Prescale"; + public static final String PROCESSING_STAGE_PROPERTY = "ProcessingStage"; + public static final String QUEUE_SIZE_PROPERTY = "QueueSize"; public static final String RECENT_FILES_PROPERTY = "RecentFiles"; - public static final String STEERING_TYPE_PROPERTY = "SteeringType"; + public static final String STATION_NAME_PROPERTY = "StationName"; + public static final String STATION_POSITION_PROPERTY = "StationPosition"; public static final String STEERING_FILE_PROPERTY = "SteeringFile"; public static final String STEERING_RESOURCE_PROPERTY = "SteeringResource"; + public static final String STEERING_TYPE_PROPERTY = "SteeringType"; 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"; 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"; public static final String WAIT_MODE_PROPERTY = "WaitMode"; 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); + + Configuration configuration; public ConfigurationModel() { this.configuration = new Configuration(); } - public ConfigurationModel(Configuration configuration) { + public ConfigurationModel(final Configuration configuration) { this.configuration = configuration; fireModelChanged(); } - - public void setConfiguration(Configuration configuration) { + + public void addRecentFile(final String recentFile) { + if (!this.configuration.checkKey(RECENT_FILES_PROPERTY)) { + this.configuration.set(RECENT_FILES_PROPERTY, recentFile); + firePropertyChange(RECENT_FILES_PROPERTY, null, recentFile); + } else { + final List<String> recentFilesList = getRecentFilesList(); + if (!recentFilesList.contains(recentFile)) { + if (getRecentFilesList().size() >= MAX_RECENT_FILES) { + // Bump the first file from the list if max recent files is exceeded (10 files). + recentFilesList.remove(0); + setRecentFilesList(recentFilesList); + } + final String oldValue = this.configuration.get(RECENT_FILES_PROPERTY); + final String recentFiles = oldValue + "\n" + recentFile; + this.configuration.set(RECENT_FILES_PROPERTY, recentFiles); + firePropertyChange(RECENT_FILES_PROPERTY, oldValue, recentFile); + } + } + + } + + @Override + public void fireModelChanged() { + firePropertiesChanged(this.configuration.getKeys()); + } + + public String getAIDAServerName() { + return this.configuration.get(AIDA_SERVER_NAME_PROPERTY); + } + + public Boolean getBlocking() { + return this.configuration.getBoolean(BLOCKING_PROPERTY); + } + + public Integer getChunkSize() { + return this.configuration.getInteger(CHUNK_SIZE_PROPERTY); + } + + public String getConditionsTag() { + return this.configuration.get(CONDITIONS_TAG_PROPERTY); + } + + public Configuration getConfiguration() { + return this.configuration; + } + + public String getDataSourcePath() { + return this.configuration.get(DATA_SOURCE_PATH_PROPERTY); + } + + public DataSourceType getDataSourceType() { + if (this.configuration.checkKey(DATA_SOURCE_TYPE_PROPERTY)) { + return DataSourceType.valueOf(this.configuration.get(DATA_SOURCE_TYPE_PROPERTY)); + } else { + return null; + } + } + + public String getDetectorAlias() { + return this.configuration.get(DETECTOR_ALIAS_PROPERTY); + } + + public String getDetectorName() { + return this.configuration.get(DETECTOR_NAME_PROPERTY); + } + + public Boolean getDisconnectOnEndRun() { + return this.configuration.getBoolean(DISCONNECT_ON_END_RUN_PROPERTY); + } + + public Boolean getDisconnectOnError() { + return this.configuration.getBoolean(DISCONNECT_ON_ERROR_PROPERTY); + } + + public String getEtName() { + return this.configuration.get(ET_NAME_PROPERTY); + } + + public String getEtPath() { + return getEtName() + "@" + getHost() + ":" + getPort(); + } + + public String getEventBuilderClassName() { + return this.configuration.get(EVENT_BUILDER_PROPERTY); + } + + public Boolean getFreezeConditions() { + return this.configuration.getBoolean(FREEZE_CONDITIONS_PROPERTY); + } + + public String getHost() { + return this.configuration.get(HOST_PROPERTY); + } + + public String getLogFileName() { + return this.configuration.get(LOG_FILE_NAME_PROPERTY); + } + + public Level getLogLevel() { + return Level.parse(this.configuration.get(LOG_LEVEL_PROPERTY)); + } + + public Level getLogLevelFilter() { + return Level.parse(this.configuration.get(LOG_LEVEL_FILTER_PROPERTY)); + } + + public Boolean getLogToFile() { + return this.configuration.getBoolean(LOG_TO_FILE_PROPERTY); + } + + public Long getMaxEvents() { + return this.configuration.getLong(MAX_EVENTS_PROPERTY); + } + + public Integer getPort() { + return this.configuration.getInteger(PORT_PROPERTY); + } + + public Integer getPrescale() { + return this.configuration.getInteger(PRESCALE_PROPERTY); + } + + public ProcessingStage getProcessingStage() { + if (this.configuration.get(PROCESSING_STAGE_PROPERTY) == null) { + throw new RuntimeException(PROCESSING_STAGE_PROPERTY + " is null!!!"); + } + return ProcessingStage.valueOf(this.configuration.get(PROCESSING_STAGE_PROPERTY)); + } + + @Override + public String[] getPropertyNames() { + return CONFIG_PROPERTIES; + } + + public Integer getQueueSize() { + return this.configuration.getInteger(QUEUE_SIZE_PROPERTY); + } + + public String getRecentFiles() { + if (this.configuration.hasKey(RECENT_FILES_PROPERTY)) { + return this.configuration.get(RECENT_FILES_PROPERTY); + } else { + return null; + } + } + + public List<String> getRecentFilesList() { + 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 setDataSource(String dataSource) { setDataSourcePath(dataSource); DataSourceType dst = + * DataSourceType.getDataSourceType(dataSource); setDataSourceType(dst); } + */ + + public String getStationName() { + return this.configuration.get(STATION_NAME_PROPERTY); + } + + public Integer getStationPosition() { + return this.configuration.getInteger(STATION_POSITION_PROPERTY); + } + + public String getSteeringFile() { + return this.configuration.get(STEERING_FILE_PROPERTY); + } + + public String getSteeringResource() { + return this.configuration.get(STEERING_RESOURCE_PROPERTY); + } + + public SteeringType getSteeringType() { + return SteeringType.valueOf(this.configuration.get(STEERING_TYPE_PROPERTY)); + } + + public Integer getUserRunNumber() { + return this.configuration.getInteger(USER_RUN_NUMBER_PROPERTY); + } + + public Boolean getVerbose() { + return this.configuration.getBoolean(VERBOSE_PROPERTY); + } + + public Mode getWaitMode() { + return Mode.valueOf(this.configuration.get(WAIT_MODE_PROPERTY)); + } + + public Integer getWaitTime() { + return this.configuration.getInteger(WAIT_TIME_PROPERTY); + } + + public boolean hasPropertyKey(final String key) { + return this.configuration.hasKey(key); + } + + public boolean hasValidProperty(final String key) { + return this.configuration.checkKey(key); + } + + public void merge(final Configuration configuration) { + this.configuration.merge(configuration); + this.firePropertiesChanged(configuration.getKeys()); + } + + public void remove(final String property) { + if (hasPropertyKey(property)) { + final Object oldValue = this.configuration.get(property); + if (oldValue != null) { + this.configuration.remove(property); + firePropertyChange(property, oldValue, null); + } + } + } + + public void setAIDAServerName(final String AIDAServerName) { + final String oldValue = getAIDAServerName(); + this.configuration.set(AIDA_SERVER_NAME_PROPERTY, AIDAServerName); + firePropertyChange(AIDA_SERVER_NAME_PROPERTY, oldValue, getAIDAServerName()); + } + + public void setBlocking(final Boolean blocking) { + final Boolean oldValue = getBlocking(); + this.configuration.set(BLOCKING_PROPERTY, blocking); + firePropertyChange(BLOCKING_PROPERTY, oldValue, getBlocking()); + } + + public void setChunkSize(final Integer chunkSize) { + final Integer oldValue = getChunkSize(); + this.configuration.set(CHUNK_SIZE_PROPERTY, chunkSize); + firePropertyChange(CHUNK_SIZE_PROPERTY, oldValue, getChunkSize()); + } + + public void setConditionsTag(final String conditionsTag) { + final String oldValue = getConditionsTag(); + this.configuration.set(CONDITIONS_TAG_PROPERTY, conditionsTag); + firePropertyChange(CONDITIONS_TAG_PROPERTY, oldValue, getConditionsTag()); + } + + public void setConfiguration(final Configuration configuration) { this.configuration = configuration; fireModelChanged(); } - - 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) { + + public void setDataSourcePath(final String dataSourcePath) { + final String oldValue = getDataSourcePath(); + this.configuration.set(DATA_SOURCE_PATH_PROPERTY, dataSourcePath); + firePropertyChange(DATA_SOURCE_PATH_PROPERTY, oldValue, getDataSourcePath()); + } + + public void setDataSourceType(final DataSourceType dataSourceType) { + final DataSourceType oldValue = getDataSourceType(); + this.configuration.set(DATA_SOURCE_TYPE_PROPERTY, dataSourceType); + firePropertyChange(DATA_SOURCE_TYPE_PROPERTY, oldValue, getDataSourceType()); + } + + public void setDetectorAlias(final String detectorAlias) { String oldValue = null; if (hasPropertyKey(DETECTOR_ALIAS_PROPERTY)) { oldValue = getDetectorAlias(); } - configuration.set(DETECTOR_ALIAS_PROPERTY, detectorAlias); + this.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); + public void setDetectorName(final String detectorName) { + final String oldValue = getDetectorName(); + this.configuration.set(DETECTOR_NAME_PROPERTY, detectorName); + firePropertyChange(DETECTOR_NAME_PROPERTY, oldValue, getDetectorName()); + } + + public void setDisconnectOnEndRun(final Boolean disconnectOnEndRun) { + final Boolean oldValue = getDisconnectOnEndRun(); + this.configuration.set(DISCONNECT_ON_END_RUN_PROPERTY, disconnectOnEndRun); + firePropertyChange(DISCONNECT_ON_END_RUN_PROPERTY, oldValue, getDisconnectOnEndRun()); + } + + public void setDisconnectOnError(final Boolean disconnectOnError) { + final Boolean oldValue = getDisconnectOnError(); + this.configuration.set(DISCONNECT_ON_ERROR_PROPERTY, disconnectOnError); + firePropertyChange(DISCONNECT_ON_ERROR_PROPERTY, oldValue, getDisconnectOnError()); + } + + public void setEtName(final String etName) { + final String oldValue = getEtName(); + this.configuration.set(ET_NAME_PROPERTY, etName); + firePropertyChange(ET_NAME_PROPERTY, oldValue, getEtName()); + } + + public void setEventBuilderClassName(final String eventBuilderClassName) { + final String oldValue = getEventBuilderClassName(); + this.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); + public void setFreezeConditions(final Boolean freezeConditions) { + Boolean oldValue = null; + if (hasPropertyKey(FREEZE_CONDITIONS_PROPERTY)) { + oldValue = getFreezeConditions(); + } + this.configuration.set(FREEZE_CONDITIONS_PROPERTY, freezeConditions); + firePropertyChange(FREEZE_CONDITIONS_PROPERTY, oldValue, freezeConditions); + } + + public void setHost(final String host) { + final String oldValue = getHost(); + this.configuration.set(HOST_PROPERTY, host); + firePropertyChange(HOST_PROPERTY, oldValue, getHost()); + } + + public void setLogFileName(final String logFileName) { + final String oldValue = getLogFileName(); + this.configuration.set(LOG_FILE_NAME_PROPERTY, logFileName); + firePropertyChange(LOG_FILE_NAME_PROPERTY, oldValue, getLogFileName()); + } + + public void setLogLevel(final Level level) { + final Level oldValue = getLogLevel(); + this.configuration.set(LOG_LEVEL_PROPERTY, level.getName()); + firePropertyChange(LOG_LEVEL_PROPERTY, oldValue, getLogLevel()); + } + + public void setLogLevelFilter(final Level level) { + final Level oldValue = getLogLevelFilter(); + this.configuration.set(LOG_LEVEL_FILTER_PROPERTY, level.getName()); + firePropertyChange(LOG_LEVEL_FILTER_PROPERTY, oldValue, getLogLevelFilter()); + } + + public void setLogToFile(final Boolean logToFile) { + final Boolean oldValue = getLogToFile(); + this.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()); - } - - public DataSourceType getDataSourceType() { - if (configuration.checkKey(DATA_SOURCE_TYPE_PROPERTY)) { - return DataSourceType.valueOf(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); - } - */ - - public ProcessingStage getProcessingStage() { - if (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); + public void setMaxEvents(final Long maxEvents) { + final Long oldValue = getMaxEvents(); + this.configuration.set(MAX_EVENTS_PROPERTY, maxEvents); + firePropertyChange(MAX_EVENTS_PROPERTY, oldValue, getMaxEvents()); + } + + public void setPort(final Integer port) { + final Integer oldValue = getPort(); + this.configuration.set(PORT_PROPERTY, port); + firePropertyChange(PORT_PROPERTY, oldValue, getPort()); + } + + public void setPrescale(final Integer prescale) { + final Integer oldValue = getPrescale(); + this.configuration.set(PRESCALE_PROPERTY, prescale); + firePropertyChange(PRESCALE_PROPERTY, oldValue, getPrescale()); + } + + public void setProcessingStage(final ProcessingStage processingStage) { + final ProcessingStage oldValue = getProcessingStage(); + this.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); + public void setQueueSize(final Integer queueSize) { + final Integer oldValue = getQueueSize(); + this.configuration.set(QUEUE_SIZE_PROPERTY, queueSize); + firePropertyChange(QUEUE_SIZE_PROPERTY, oldValue, getQueueSize()); + } + + 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); + firePropertyChange(RECENT_FILES_PROPERTY, oldValue, this.configuration.get(RECENT_FILES_PROPERTY)); + } + + 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()); + } + + public void setStationName(final String stationName) { + final String oldValue = getStationName(); + this.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()); - } - - 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); + public void setStationPosition(final Integer stationPosition) { + final Integer oldValue = getStationPosition(); + this.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) { + public void setSteeringFile(final String steeringFile) { + final String oldValue = getSteeringFile(); + this.configuration.set(STEERING_FILE_PROPERTY, steeringFile); + firePropertyChange(STEERING_FILE_PROPERTY, oldValue, getSteeringFile()); + } + + public void setSteeringResource(final String steeringResource) { + final String oldValue = getSteeringResource(); + this.configuration.set(STEERING_RESOURCE_PROPERTY, steeringResource); + firePropertyChange(STEERING_RESOURCE_PROPERTY, oldValue, steeringResource); + } + + public void setSteeringType(final SteeringType steeringType) { + final SteeringType oldValue = getSteeringType(); + this.configuration.set(STEERING_TYPE_PROPERTY, steeringType.name()); + firePropertyChange(STEERING_TYPE_PROPERTY, oldValue, getSteeringType()); + } + + public void setUserRunNumber(final Integer userRunNumber) { Integer oldValue = null; if (hasPropertyKey(USER_RUN_NUMBER_PROPERTY)) { oldValue = getUserRunNumber(); } - configuration.set(USER_RUN_NUMBER_PROPERTY, userRunNumber); + this.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); - } - - public String getRecentFiles() { - if (configuration.hasKey(RECENT_FILES_PROPERTY)) { - return configuration.get(RECENT_FILES_PROPERTY); - } else { - return null; - } - } - - 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")) { - 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); - } - } - - } - - public void setRecentFiles(String recentFiles) { - String oldValue = null; - if (configuration.checkKey(RECENT_FILES_PROPERTY)) { - oldValue = configuration.get(RECENT_FILES_PROPERTY); - } - 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); - } - } - } - - 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()); + public void setVerbose(final Boolean verbose) { + final Boolean oldValue = getVerbose(); + this.configuration.set(VERBOSE_PROPERTY, verbose); + firePropertyChange(VERBOSE_PROPERTY, oldValue, getVerbose()); + } + + public void setWaitMode(final Mode waitMode) { + final Mode oldValue = getWaitMode(); + this.configuration.set(WAIT_MODE_PROPERTY, waitMode.name()); + firePropertyChange(WAIT_MODE_PROPERTY, oldValue, getWaitMode()); + } + + public void setWaitTime(final Integer waitTime) { + final Integer oldValue = getWaitTime(); + this.configuration.set(WAIT_TIME_PROPERTY, waitTime); + firePropertyChange(WAIT_TIME_PROPERTY, oldValue, getWaitTime()); } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java Thu Apr 9 19:22:57 2015 @@ -3,23 +3,22 @@ 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 { - DISCONNECTED(Color.RED), - DISCONNECTING(Color.YELLOW), - CONNECTED(Color.GREEN); - - Color color; - - ConnectionStatus(Color color) { + CONNECTED(Color.GREEN), DISCONNECTED(Color.RED), DISCONNECTING(Color.YELLOW); + + Color color; + + ConnectionStatus(final Color color) { this.color = color; } - + public Color getColor() { - return color; + return this.color; } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java Thu Apr 9 19:22:57 2015 @@ -4,62 +4,60 @@ 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 when the event processing is paused. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class ConnectionStatusModel extends AbstractModel { - + public static final String CONNECTION_STATUS_PROPERTY = "ConnectionStatus"; public static final String PAUSED_PROPERTY = "Paused"; - - static final String[] propertyNames = new String[] { - CONNECTION_STATUS_PROPERTY, - PAUSED_PROPERTY - }; + + static final String[] propertyNames = new String[] { CONNECTION_STATUS_PROPERTY, PAUSED_PROPERTY }; ConnectionStatus connectionStatus = ConnectionStatus.DISCONNECTED; boolean paused = false; - + + public ConnectionStatus getConnectionStatus() { + return this.connectionStatus; + } + + public boolean getPaused() { + return this.paused; + } + + @Override public String[] getPropertyNames() { return propertyNames; } - - public ConnectionStatus getConnectionStatus() { - return connectionStatus; + + public boolean isConnected() { + return this.connectionStatus == ConnectionStatus.CONNECTED; } - - public void setConnectionStatus(ConnectionStatus connectionStatus) { - ConnectionStatus oldValue = connectionStatus; + + public boolean isDisconnected() { + return this.connectionStatus == ConnectionStatus.DISCONNECTED; + } + + public boolean isDisconnecting() { + return this.connectionStatus == ConnectionStatus.DISCONNECTING; + } + + 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.propertyChangeSupport.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; + + public void setPaused(final boolean paused) { + final boolean oldValue = this.paused; this.paused = paused; - for (PropertyChangeListener listener : propertyChangeSupport.getPropertyChangeListeners()) { + for (final PropertyChangeListener listener : this.propertyChangeSupport.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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java Thu Apr 9 19:22:57 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 { /** + * Get the current ConfigurationModel of the object. + * + * @return The ConfigurationModel. + */ + ConfigurationModel getConfigurationModel(); + + /** * Set the ConfigurationModel of the object. + * * @param configurationModel The ConfigurationModel. */ void setConfigurationModel(ConfigurationModel configurationModel); - - /** - * Get the current ConfigurationModel of the object. - * @return The ConfigurationModel. - */ - ConfigurationModel getConfigurationModel(); } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java Thu Apr 9 19:22:57 2015 @@ -4,161 +4,98 @@ /** * 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 DATA_RATE_PROPERTY = "DataRate"; // data rate in megabytes per second + public final static String DATA_RECEIVED_PROPERTY = "DataReceived"; // updated on the fly, in bytes + public final static String ELAPSED_TIME_PROPERTY = "ElapsedTime"; // updated on the fly, in seconds + public final static String END_DATE_PROPERTY = "EndDate"; + public final static String EVENT_NUMBER_PROPERTY = "EventNumber"; // current event number + public final static String EVENT_RATE_PROPERTY = "EventRate"; // event rate per second + public final static String EVENTS_RECEIVED_PROPERTY = "EventsReceived"; // events received so far + public final static String RUN_LENGTH_PROPERTY = "RunLength"; // set at end, in seconds public final static String RUN_NUMBER_PROPERTY = "RunNumber"; + static final String[] RUN_PROPERTIES = AbstractModel.getPropertyNames(RunModel.class); 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); - + Double dataRate; + Double dataReceived; + Integer elapsedTime; + Date endDate; + Integer eventNumber; + Double eventRate; + Integer eventsReceived; + Integer runLength; Integer runNumber; Date startDate; - Date endDate; - Integer runLength; Integer totalEvents; - Integer eventsReceived; - Integer elapsedTime; - Double dataReceived; - Integer eventNumber; - Double dataRate; - Double eventRate; + public void addDataReceived(final double addDataReceived) { + this.setDataReceived(this.dataReceived + addDataReceived); + } + + 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); + } + } + + public double getDataRate() { + return this.dataRate; + } + + public double getDataReceived() { + return this.dataReceived; + } + + public int getElapsedTime() { + return this.elapsedTime; + } + + public Date getEndDate() { + return this.endDate; + } + + public int getEventNumber() { + return this.eventNumber; + } + + public double getEventRate() { + return this.eventRate; + } + + public int getEventsReceived() { + return this.eventsReceived; + } + + @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 int getRunLength() { + return this.runLength; } - + public int getRunNumber() { return this.runNumber; } - public void setStartDate(Date startDate) { - Date oldValue = this.startDate; - this.startDate = startDate; - this.firePropertyChange(START_DATE_PROPERTY, oldValue, this.startDate); - } - public Date getStartDate() { - return startDate; + return this.startDate; } - public void setEndDate(Date endDate) { - Date oldValue = this.endDate; - this.endDate = endDate; - this.firePropertyChange(END_DATE_PROPERTY, oldValue, this.endDate); - } - - public Date getEndDate() { - return endDate; + public int getTotalEvents() { + return this.totalEvents; } - public void setRunLength(int runLength) { - Integer oldValue = this.runLength; - this.runLength = runLength; - this.firePropertyChange(RUN_LENGTH_PROPERTY, oldValue, this.runLength); - } - - public int getRunLength() { - return 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 int getTotalEvents() { - return totalEvents; - } - - public void setEventsReceived(int eventsReceived) { - Integer oldValue = this.eventsReceived; - this.eventsReceived = eventsReceived; - this.firePropertyChange(EVENTS_RECEIVED_PROPERTY, oldValue, this.eventsReceived); - } - - public int getEventsReceived() { - return eventsReceived; - } - - public void setElapsedTime(int elapsedTime) { - Integer oldValue = this.elapsedTime; - this.elapsedTime = elapsedTime; - this.firePropertyChange(ELAPSED_TIME_PROPERTY, oldValue, this.elapsedTime); - } - - public int getElapsedTime() { - return elapsedTime; - } - - public void setDataReceived(double dataReceived) { - Double oldValue = this.dataReceived; - this.dataReceived = dataReceived; - this.firePropertyChange(DATA_RECEIVED_PROPERTY, oldValue, this.dataReceived); - } - - public double getDataReceived() { - return 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 int getEventNumber() { - return eventNumber; - } - - public void setDataRate(double dataRate) { - Double oldValue = this.dataRate; - this.dataRate = dataRate; - this.firePropertyChange(DATA_RATE_PROPERTY, oldValue, this.dataRate); - } - - public double getDataRate() { - return dataRate; - } - - public void setEventRate(double eventRate) { - Double oldValue = this.eventRate; - this.eventRate = eventRate; - this.firePropertyChange(EVENT_RATE_PROPERTY, oldValue, this.eventRate); - } - - public double getEventRate() { - return eventRate; - } - public void reset() { setDataReceived(0); setElapsedTime(0); @@ -168,5 +105,71 @@ setRunNumber(0); setStartDate(null); setTotalEvents(0); - } + } + + public void setDataRate(final double dataRate) { + final Double oldValue = this.dataRate; + this.dataRate = dataRate; + this.firePropertyChange(DATA_RATE_PROPERTY, oldValue, this.dataRate); + } + + public void setDataReceived(final double dataReceived) { + final Double oldValue = this.dataReceived; + this.dataReceived = dataReceived; + this.firePropertyChange(DATA_RECEIVED_PROPERTY, oldValue, this.dataReceived); + } + + public void setElapsedTime(final int elapsedTime) { + final Integer oldValue = this.elapsedTime; + this.elapsedTime = elapsedTime; + this.firePropertyChange(ELAPSED_TIME_PROPERTY, oldValue, this.elapsedTime); + } + + public void setEndDate(final Date endDate) { + final Date oldValue = this.endDate; + this.endDate = endDate; + this.firePropertyChange(END_DATE_PROPERTY, oldValue, this.endDate); + } + + public void setEventNumber(final int eventNumber) { + final Integer oldValue = this.eventNumber; + this.eventNumber = eventNumber; + this.firePropertyChange(EVENT_NUMBER_PROPERTY, oldValue, this.eventNumber); + } + + public void setEventRate(final double eventRate) { + final Double oldValue = this.eventRate; + this.eventRate = eventRate; + this.firePropertyChange(EVENT_RATE_PROPERTY, oldValue, this.eventRate); + } + + public void setEventsReceived(final int eventsReceived) { + final Integer oldValue = this.eventsReceived; + this.eventsReceived = eventsReceived; + this.firePropertyChange(EVENTS_RECEIVED_PROPERTY, oldValue, this.eventsReceived); + } + + public void setRunLength(final int runLength) { + final Integer oldValue = this.runLength; + this.runLength = runLength; + this.firePropertyChange(RUN_LENGTH_PROPERTY, oldValue, this.runLength); + } + + public void setRunNumber(final int runNumber) { + final Integer oldValue = this.runNumber; + this.runNumber = runNumber; + this.firePropertyChange(RUN_NUMBER_PROPERTY, oldValue, this.runNumber); + } + + public void setStartDate(final Date startDate) { + final Date oldValue = this.startDate; + this.startDate = startDate; + this.firePropertyChange(START_DATE_PROPERTY, oldValue, this.startDate); + } + + public void setTotalEvents(final int totalEvents) { + final Integer oldValue = this.totalEvents; + this.totalEvents = totalEvents; + this.firePropertyChange(TOTAL_EVENTS_PROPERTY, oldValue, this.totalEvents); + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/SteeringType.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/SteeringType.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/SteeringType.java Thu Apr 9 19:22:57 2015 @@ -2,8 +2,9 @@ /** * 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; + FILE, RESOURCE; } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java Thu Apr 9 19:22:57 2015 @@ -16,32 +16,47 @@ /** * 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> */ public final class SystemStatusTableModel extends AbstractTableModel implements SystemStatusListener { + public static final int ACTIVE_COL = 1; + public static final int CLEARABLE_COL = 7; + static final String[] columnNames = { "Reset", "Active", "Status", "System", "Description", "Message", + "Last Changed", "Clearable" }; + public static final int DESCRIPTION_COL = 4; + public static final int LAST_CHANGED_COL = 6; + public static final int MESSAGE_COL = 5; 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" }; + final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS"); + List<SystemStatus> statuses = new ArrayList<SystemStatus>(); - 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); + public void addSystemStatus(final SystemStatus status) { + this.statuses.add(status); status.addListener(this); fireTableDataChanged(); } + public void clear() { + this.statuses.clear(); + fireTableDataChanged(); + } + @Override - public int getRowCount() { - return statuses.size(); + public Class getColumnClass(final int column) { + switch (column) { + case ACTIVE_COL: + return Boolean.class; + case LAST_CHANGED_COL: + return Date.class; + default: + return String.class; + } } @Override @@ -50,13 +65,18 @@ } @Override - public String getColumnName(int col) { + public String getColumnName(final int col) { return columnNames[col]; } @Override + public int getRowCount() { + return this.statuses.size(); + } + + @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: return status.isActive(); @@ -77,13 +97,14 @@ if (status.isClearable()) { final JButton button = new JButton(); button.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - SystemStatus status = statuses.get(rowIndex); + @Override + public void actionPerformed(final ActionEvent e) { + final SystemStatus status = SystemStatusTableModel.this.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. if (status.isClearable()) { - StatusCode oldStatusCode = status.getStatusCode(); + final StatusCode oldStatusCode = status.getStatusCode(); status.setStatus(StatusCode.CLEARED, "Cleared from " + oldStatusCode.name() + " state."); } } @@ -100,40 +121,24 @@ } @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; + public boolean isCellEditable(final int row, final int col) { + if (col == ACTIVE_COL) { + return true; + } else { + return false; } } @Override - public boolean isCellEditable(int row, int col) { - if (col == ACTIVE_COL) - return true; - else - return false; + public void setValueAt(final Object value, final int row, final int col) { + if (col == ACTIVE_COL) { + this.statuses.get(row).setActive((Boolean) value); + } } @Override - public void statusChanged(SystemStatus status) { - int rowNumber = statuses.indexOf(status); + 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/package-info.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/package-info.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/package-info.java Thu Apr 9 19:22:57 2015 @@ -1,22 +1,19 @@ /** - * 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. - - * @author Jeremy McCormick <[log in to unmask]> + * 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; Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/AIDAServer.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/AIDAServer.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/AIDAServer.java Thu Apr 9 19:22:57 2015 @@ -11,69 +11,74 @@ /** * 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 { - + + boolean connected = false; + String name; RmiServerImpl server; - String name; - boolean connected = false; - + /** - * Class constructor. + * Class constructor. + * * @param name The name of the AIDA server. */ - public AIDAServer(String name) { + public AIDAServer(final String name) { this.name = name; } - + + /** + * True if connected. + * + * @return True 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; + } + + 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. */ 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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/DialogUtil.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/DialogUtil.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/DialogUtil.java Thu Apr 9 19:22:57 2015 @@ -7,27 +7,90 @@ import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; +/** + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> + */ public final class DialogUtil { /** - * + * @param parent + * @param message + * @param title + * @return + */ + 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; + } + + /** + * @param component + * @param error + * @param title + */ + 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); + } + + /** + * @param component + * @param error + * @param title + */ + 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); + } + + /** + * @param component + * @param title + * @param 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); + } + + /** * @param parentComponent * @param title * @param message * @return */ - 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 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); @@ -38,70 +101,4 @@ dialog.setVisible(true); return dialog; } - - /** - * - * @param component - * @param error - * @param title - */ - 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; - } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java Thu Apr 9 19:22:57 2015 @@ -9,8 +9,8 @@ /** * <p> - * An error handling class which is able to do any of the following, depending on how the users - * wants to handle the error. + * 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> @@ -20,109 +20,27 @@ * <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. </p> + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> */ public final class ErrorHandler { - Logger logger; Component component; Throwable error; + Logger logger; String message; /** * 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>. - * @return This object. - */ - public ErrorHandler setError(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. - */ - public ErrorHandler setMessage(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. - */ - public ErrorHandler showErrorDialog() { - final Runnable runnable = new Runnable() { - 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); - } - }; - SwingUtilities.invokeLater(runnable); - return this; - } - - /** - * Rethrow the error as a <code>RuntimeException</code>. Additional methods cannot be chained to - * this as they would not be executed. - */ - public void raiseException() { - throw new RuntimeException(message, error); } /** @@ -132,4 +50,98 @@ 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 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; + } + + /** + * Rethrow the error as a <code>RuntimeException</code>. 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. This should always be called first in a method chain. + * + * @param error The error which is a <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. + */ + public ErrorHandler setMessage(final String message) { + this.message = message; + return this; + } + + /** + * Show an error dialog with the message. + * + * @return This object. + */ + public ErrorHandler showErrorDialog() { + final Runnable runnable = new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(ErrorHandler.this.component, ErrorHandler.this.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() { + @Override + public void run() { + JOptionPane.showMessageDialog(ErrorHandler.this.component, message, title, JOptionPane.ERROR_MESSAGE); + } + }; + SwingUtilities.invokeLater(runnable); + return this; + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java Thu Apr 9 19:22:57 2015 @@ -6,28 +6,23 @@ 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() { + 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()); + + 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; - } + + private EtSystemUtil() { + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java Thu Apr 9 19:22:57 2015 @@ -5,24 +5,26 @@ import javax.swing.filechooser.FileFilter; /** - * This is a simple file filter that will accept files with ".evio" anywhere in their name. + * This is a simple 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() { + public EvioFileFilter() { } - + @Override - public boolean accept(File pathname) { + public boolean accept(final File pathname) { if (pathname.getName().contains(".evio") || pathname.isDirectory()) { return true; } else { return false; } } - + @Override public String getDescription() { return "EVIO files"; - } + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java Thu Apr 9 19:22:57 2015 @@ -19,106 +19,106 @@ import org.reflections.Reflections; /** - * - * @author Jeremy McCormick <[log in to unmask]> - * + * @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 + * 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. */ 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 classes implementing 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 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(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; + } + public static String[] getConditionsTags() { return DatabaseConditionsManager.getInstance().getTags().toArray(new String[] {}); } + + private ResourceUtil() { + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java Thu Apr 9 19:22:57 2015 @@ -15,11 +15,10 @@ 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 */ @@ -28,7 +27,8 @@ private static final String TRIGGER_CONFIG = "TriggerConfig"; TriggerConfigEvioReader configReader = new TriggerConfigEvioReader(); - public void process(EtEvent event) { + @Override + public void process(final EtEvent event) { EvioEvent evioEvent = null; try { evioEvent = new EvioReader(event.getDataBuffer()).parseNextEvent(); @@ -37,20 +37,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/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/TableExporter.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/TableExporter.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/TableExporter.java Thu Apr 9 19:22:57 2015 @@ -8,55 +8,56 @@ import javax.swing.table.TableModel; /** - * 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]> + * 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 <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. */ - 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(); - } + } + + private TableExporter() { + } }