Print

Print


Author: [log in to unmask]
Date: Wed Jan 28 11:05:12 2015
New Revision: 1997

Log:
Add support for setting max records.  Includes other minor fixes and improvements.  HPSJAVA-253

Modified:
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/JobSettingsPanel.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/MonitoringApplication.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/RunPanel.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/AbstractModel.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/Configuration.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/ConfigurationModel.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/RunModel.java
    java/trunk/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/JobSettingsPanel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/JobSettingsPanel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/JobSettingsPanel.java	Wed Jan 28 11:05:12 2015
@@ -31,7 +31,6 @@
 import javax.swing.JFileChooser;
 import javax.swing.JTextField;
 import javax.swing.filechooser.FileFilter;
-import javax.swing.filechooser.FileNameExtensionFilter;
 
 import org.hps.monitoring.enums.SteeringType;
 import org.hps.monitoring.gui.model.ConfigurationModel;
@@ -56,6 +55,7 @@
     private JComboBox<String> eventBuilderComboBox;
     private JTextField userRunNumberField;
     private JCheckBox freezeConditionsCheckBox;    
+    private JTextField maxEventsField;
     private JCheckBox disconnectOnErrorCheckBox;
     private JCheckBox disconnectOnEndRunCheckBox;
     private JTextField aidaSaveFileNameField;
@@ -128,6 +128,11 @@
         freezeConditionsCheckBox = addCheckBox("Freeze detector conditions", false, true);
         freezeConditionsCheckBox.addActionListener(this);
         freezeConditionsCheckBox.setActionCommand(FREEZE_CONDITIONS_CHANGED);
+        
+        maxEventsField = addField("Max Events", "-1", 10, false);
+        maxEventsField.addPropertyChangeListener("value", this);
+        maxEventsField.setEnabled(true);
+        maxEventsField.setEditable(true);
         
         eventBuilderComboBox = addComboBox("LCSim Event Builder", this.findEventBuilderClassNames());
         eventBuilderComboBox.setSize(24, eventBuilderComboBox.getPreferredSize().height);
@@ -319,7 +324,7 @@
         } else if (DETECTOR_NAME_CHANGED.equals(e.getActionCommand())) {
             configurationModel.setDetectorName((String) detectorNameComboBox.getSelectedItem());
         } else if (FREEZE_CONDITIONS_CHANGED.equals(e.getActionCommand())) {
-            if (configurationModel.hasPropertyValue(USER_RUN_NUMBER_PROPERTY) && configurationModel.getUserRunNumber() != null) {
+            if (configurationModel.hasPropertyKey(USER_RUN_NUMBER_PROPERTY) && configurationModel.getUserRunNumber() != null) {
                 configurationModel.setFreezeConditions(freezeConditionsCheckBox.isSelected());
             } else {
                 throw new IllegalArgumentException("Conditions system may only be frozen if there is a valid user run number.");
@@ -371,6 +376,9 @@
                     throw new IllegalArgumentException("The value " + evt.getNewValue() + " is not a valid run number.");
                 }                            
             }
+        } else if (source == maxEventsField) {
+            configurationModel.setMaxEvents(Long.parseLong(maxEventsField.getText()));
+            System.out.println("setMaxEvents - " + configurationModel.getMaxEvents());
         }
     }
 
@@ -429,6 +437,10 @@
                 if (value != null) {
                     freezeConditionsCheckBox.setSelected((Boolean) value);
                 }
+            } else if (evt.getPropertyName().equals(MAX_EVENTS_PROPERTY)) {
+                if (value != null) {
+                    maxEventsField.setText(value.toString());
+                }
             }
         }
     }

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/MonitoringApplication.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/MonitoringApplication.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/MonitoringApplication.java	Wed Jan 28 11:05:12 2015
@@ -87,7 +87,6 @@
 /**
  * This class is the implementation of the GUI for the Monitoring Application.
  */
-// TODO: Move GUI/window functionality to a new class. (This one is too big!)
 public final class MonitoringApplication extends ApplicationWindow implements ActionListener, SystemStatusListener, PropertyChangeListener {
 
     // Top-level Swing components.
@@ -128,7 +127,7 @@
     private static Logger logger;
     private Handler logHandler;
     private DefaultTableModel logTableModel;
-    static final String[] logTableColumns = { "Date", "Message", "Level" };
+    static final String[] logTableColumns = { "Date", "Level", "Message" };
     private JTable logTable;
     private static Level DEFAULT_LOG_LEVEL = Level.INFO;
 
@@ -536,7 +535,7 @@
         saveLayoutItem.setActionCommand(SAVE_LAYOUT);
         saveLayoutItem.addActionListener(this);
         saveLayoutItem.setToolTipText("Include current GUI layout when saving settings.");
-        if (configurationModel.hasPropertyValue(ConfigurationModel.SAVE_LAYOUT_PROPERTY)) {
+        if (configurationModel.hasPropertyKey(ConfigurationModel.SAVE_LAYOUT_PROPERTY)) {
             saveLayoutItem.setSelected(configurationModel.getSaveLayout());
         }
         saveLayoutItem.addPropertyChangeListener(this); 
@@ -1135,7 +1134,7 @@
                 DatabaseConditionsManager conditionsManager = DatabaseConditionsManager.getInstance();
                 logger.config("setting user run number " + userRunNumber + " with detector " + detectorName);
                 conditionsManager.setDetector(configurationModel.getDetectorName(), userRunNumber);
-                if (configurationModel.hasPropertyValue(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) {
+                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 from monitoring app");
                     conditionsManager.freeze();
@@ -1326,21 +1325,25 @@
 
         CompositeLoopConfiguration loopConfig = new CompositeLoopConfiguration().setStopOnEndRun(configurationModel.getDisconnectOnEndRun()).setStopOnErrors(configurationModel.getDisconnectOnError()).setDataSourceType(configurationModel.getDataSourceType()).setProcessingStage(configurationModel.getProcessingStage()).setEtConnection(connection).setFilePath(configurationModel.getDataSourcePath()).setLCSimEventBuilder(eventBuilder).setDetectorName(configurationModel.getDetectorName());
 
+        long maxEvents = configurationModel.getMaxEvents();
+        System.out.println("setupCompositeLoop - max events " + maxEvents);
+        if (maxEvents > 0L) {
+            System.out.println("setupCompositeLoop - setting max events to " + maxEvents);
+            loopConfig.setMaxRecords(maxEvents);
+        }
+        
         // Add all Drivers from the pre-configured JobManager.
         for (Driver driver : jobManager.getDriverExecList()) {
             loopConfig.add(driver);
         }
 
-        // DEBUG: Turn these off while doing other stuff!!!!
         // Using ET server?
         if (usingEtServer()) {
 
             // ET system monitor.
-            // FIXME: Make whether this is run or not configurable through the JobPanel.
             loopConfig.add(new EtSystemMonitor());
 
             // ET system strip charts.
-            // FIXME: Make whether this is run or not configurable through the JobPanel.
             loopConfig.add(new EtSystemStripCharts());
         }
 
@@ -1506,7 +1509,7 @@
                 // Interrupt the thread which should cause it to stop.
                 sessionWatchdogThread.interrupt();
                 try {
-                    // This should always work once the thread is interupted.
+                    // This should always work once the thread is interrupted.
                     sessionWatchdogThread.join();
                 } catch (InterruptedException e) {
                     // This should never happen.
@@ -1539,8 +1542,7 @@
 
             } catch (InterruptedException e) {
                 // This probably just means that the disconnect button was pushed, and this thread
-                // should
-                // no longer monitor the event processing.
+                // should no longer monitor the event processing.
                 e.printStackTrace();
             }
         }
@@ -1604,7 +1606,7 @@
     }
 
     private void updateLayoutConfiguration() {
-        if (configurationModel.hasPropertyValue(SAVE_LAYOUT_PROPERTY)) {
+        if (configurationModel.hasPropertyKey(SAVE_LAYOUT_PROPERTY)) {
             // Should the GUI config be saved?
             if (configurationModel.getSaveLayout()) {
                 // Push the current GUI settings into the configuration.
@@ -1698,10 +1700,10 @@
     }
 
     /**
-     * This is a thread to validate the current input file. This must be done on a seperate thread,
+     * This is a thread to validate the current input file. This must be done on a separate thread,
      * because EVIO files may take a long time to be completely read in using the EvioReader. Also,
      * since the request for file validation comes on the EDT thread, the task must be put onto a
-     * seperate thread so that actionPerformed() may exit and not block the EDT from updating the
+     * different thread so that actionPerformed() may exit and not block the EDT from updating the
      * GUI.
      */
     class FileValidationThread extends Thread {

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/RunPanel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/RunPanel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/RunPanel.java	Wed Jan 28 11:05:12 2015
@@ -29,7 +29,6 @@
  * Dashboard for displaying information about the current run.
  * @author Jeremy McCormick <[log in to unmask]>
  */
-// TODO: Add event sequence number from CompositeRecord.
 class RunPanel extends JPanel implements PropertyChangeListener {
 
     FieldPanel runNumberField = new FieldPanel("Run Number", "", 10, false);
@@ -46,7 +45,7 @@
 
     RunModel model;
     
-    NumberFormat formatter = new DecimalFormat("#0.00"); 
+    static final NumberFormat formatter = new DecimalFormat("#0.00"); 
 
     RunPanel(RunModel model) {
         this.model = model;
@@ -82,6 +81,45 @@
         int eventNumber;
         int runNumber = -1;
         long jobStartMillis;
+        long lastTickMillis = 0;
+        static final long millis = 1000;
+        
+        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);
+                */
+                
+                model.setElapsedTime(elapsedTime);
+                model.setEventsReceived(totalEvents);
+                model.setDataRate(megaBytesReceived / tickLengthSeconds);
+                model.addDataReceived(megaBytesReceived);
+                model.setEventNumber(eventNumber);
+                model.setEventRate(eventsReceived / tickLengthSeconds);
+                
+                eventsReceived = 0;
+                bytesReceived = 0;
+                eventNumber = 0;  
+                
+                lastTickMillis = System.currentTimeMillis();
+                
+                // System.out.println();
+            }        
+        }
         
         @Override
         public void startJob() {
@@ -90,46 +128,31 @@
             
             // Start the timer to update GUI components about once per second.
             timer = new Timer("RunModelUpdaterTimer");
-            TimerTask task = new TimerTask() {                                                                 
-                public void run() {                     
-                    final int elapsedTime = (int) ((System.currentTimeMillis() - jobStartMillis) / 1000);
-                    double megaBytesReceived = bytesReceived / 1000000;
-                    totalEvents += eventsReceived;
-                    
-                    model.setElapsedTime(elapsedTime);
-                    model.setEventsReceived(totalEvents);
-                    model.setDataRate(megaBytesReceived);
-                    model.addDataReceived(megaBytesReceived);
-                    model.setEventNumber(eventNumber);
-                    model.setEventRate(eventsReceived);
-                    eventsReceived = 0;
-                    bytesReceived = 0;
-                    eventNumber = 0;  
-                }
-            };
-            timer.scheduleAtFixedRate(task, 0, 1000);          
+            lastTickMillis = System.currentTimeMillis();
+            timer.scheduleAtFixedRate(new RunTimerTask(), 0, 1000);
         }
 
         @Override
-        public void process(CompositeRecord event) {
-            ++eventsReceived;
+        public void process(CompositeRecord event) {            
             if (event.getEvioEvent() != null) {
                 EvioEvent evioEvent = event.getEvioEvent();
                 bytesReceived += evioEvent.getTotalBytes();
-                eventNumber = evioEvent.getEventNumber();
                 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 {                    
+                } else if (EvioEventUtilities.isPhysicsEvent(evioEvent)) {                    
                     // Check for run info in head bank.
                     checkHeadBank(evioEvent);
+                    eventNumber = evioEvent.getEventNumber();
+                    eventsReceived += 1;
                 }
             } else if (event.getEtEvent() != null) {
                 bytesReceived += event.getEtEvent().getData().length;
                 eventNumber = event.getEtEvent().getId();
+                eventsReceived += 1;
             } else if (event.getLcioEvent() != null) {
                 EventHeader lcioEvent = event.getLcioEvent();
                 eventNumber = lcioEvent.getEventNumber();
@@ -137,11 +160,13 @@
                     runNumber = lcioEvent.getRunNumber();
                     startRun(lcioEvent);
                 }
+                eventsReceived += 1;
             }                    
         }
 
         /**
-         * @param evioEvent
+         * 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);
@@ -150,7 +175,7 @@
                 if (headBankRun != runNumber) {
                     runNumber = headBankRun;
                     model.setRunNumber(headBankRun);
-                    model.setStartDate(new Date(headBank.getIntData()[3]));
+                    model.setStartDate(new Date(headBank.getIntData()[3] * 1000));
                 }
             }
         }
@@ -176,22 +201,26 @@
             if (data != null) {
                 int seconds = data[0];
                 runNumber = data[1];
-                long startMillis = ((long) seconds) * 1000;
-
+                
                 // Update the GUI.
                 model.setRunNumber(runNumber);
-                model.setStartDate(new Date(startMillis));
+                model.setStartDate(new Date(seconds * 1000));
             }
         }
         
         private void startRun(EventHeader lcioEvent) {
             model.setRunNumber(lcioEvent.getRunNumber());
-            model.setStartDate(new Date(lcioEvent.getTimeStamp() / 1000));
+            long seconds = lcioEvent.getTimeStamp() / 1000000000;
+            model.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);
         }
     }
     

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/AbstractModel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/AbstractModel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/AbstractModel.java	Wed Jan 28 11:05:12 2015
@@ -3,8 +3,13 @@
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
+import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import javassist.Modifier;
 
 /**
  * An abstract class which updates a set of listeners when there are property changes to a backing model.
@@ -90,4 +95,29 @@
             }
         }
     }
+    
+    /**
+     * 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[]{});
+    }
 }

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/Configuration.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/Configuration.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/Configuration.java	Wed Jan 28 11:05:12 2015
@@ -129,6 +129,20 @@
             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.

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/ConfigurationModel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/ConfigurationModel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/ConfigurationModel.java	Wed Jan 28 11:05:12 2015
@@ -1,7 +1,10 @@
 package org.hps.monitoring.gui.model;
 
 import java.io.File;
+import java.lang.reflect.Field;
 import java.util.logging.Level;
+
+import javassist.Modifier;
 
 import org.hps.monitoring.enums.SteeringType;
 import org.hps.record.enums.DataSourceType;
@@ -12,9 +15,8 @@
  * 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.
  */
-// TODO: Should set methods check if new value is equal to old and then ignore if so?
 // FIXME: When the set methods are called, e.g. from GUI updates, this triggers
-// a property change event that pushes the values back to the GUI again.
+//        a property change event that pushes the values back to the GUI again.
 // FIXME: Should check if property exists in set methods before retrieving old value for all set methods.
 public final class ConfigurationModel extends AbstractModel {
 
@@ -32,6 +34,7 @@
     public static final String LOG_FILE_NAME_PROPERTY = "LogFileName";
     public static final String LOG_LEVEL_PROPERTY = "LogLevel";
     public static final String LOG_TO_FILE_PROPERTY = "LogToFile";
+    public static final String MAX_EVENTS_PROPERTY = "MaxEvents";
     public static final String MONITORING_APPLICATION_LAYOUT_PROPERTY = "MonitoringApplicationLayout";
     public static final String PLOT_FRAME_LAYOUT_PROPERTY = "PlotFrameLayout";
     public static final String SAVE_LAYOUT_PROPERTY = "SaveLayout";
@@ -59,56 +62,9 @@
     public static final String WAIT_MODE_PROPERTY = "WaitMode";
     public static final String WAIT_TIME_PROPERTY = "WaitTime";
     public static final String PRESCALE_PROPERTY = "Prescale";
-
-    // These key values are primarily used to figure out what properties need to be persisted when
-    // writing to a text file.
-    // FIXME: This could probably be replaced with introspection on this class of "_PROPERTY" variables.
-    static final String[] CONFIG_PROPERTIES = new String[] {
-
-            // Job settings
-            AIDA_AUTO_SAVE_PROPERTY, 
-            AIDA_FILE_NAME_PROPERTY, 
-            DETECTOR_NAME_PROPERTY, 
-            DETECTOR_ALIAS_PROPERTY,
-            DISCONNECT_ON_ERROR_PROPERTY, 
-            DISCONNECT_ON_END_RUN_PROPERTY, 
-            EVENT_BUILDER_PROPERTY,
-            FREEZE_CONDITIONS_PROPERTY,
-            LOG_FILE_NAME_PROPERTY, 
-            LOG_LEVEL_PROPERTY, 
-            LOG_TO_FILE_PROPERTY, 
-            STEERING_FILE_PROPERTY, 
-            STEERING_RESOURCE_PROPERTY, 
-            STEERING_TYPE_PROPERTY,
-            USER_RUN_NUMBER_PROPERTY,
-
-            // Data source
-            DATA_SOURCE_TYPE_PROPERTY, 
-            DATA_SOURCE_PATH_PROPERTY, 
-            PROCESSING_STAGE_PROPERTY,
-
-            // ET parameters
-            ET_NAME_PROPERTY, 
-            HOST_PROPERTY, 
-            PORT_PROPERTY, 
-            BLOCKING_PROPERTY, 
-            VERBOSE_PROPERTY, 
-            STATION_NAME_PROPERTY, 
-            CHUNK_SIZE_PROPERTY, 
-            QUEUE_SIZE_PROPERTY, 
-            STATION_POSITION_PROPERTY, 
-            WAIT_MODE_PROPERTY, 
-            WAIT_TIME_PROPERTY, 
-            PRESCALE_PROPERTY,
-
-            // GUI layout
-            SAVE_LAYOUT_PROPERTY, 
-            MONITORING_APPLICATION_LAYOUT_PROPERTY, 
-            PLOT_FRAME_LAYOUT_PROPERTY, 
-            SYSTEM_STATUS_FRAME_LAYOUT_PROPERTY };
-
-    String detectorName;
-
+   
+    static final String[] CONFIG_PROPERTIES = AbstractModel.getPropertyNames(ConfigurationModel.class);
+        
     public ConfigurationModel() {
         this.config = new Configuration();
     }
@@ -185,7 +141,7 @@
     
     public void setDetectorAlias(String detectorAlias) {
         String oldValue = null;
-        if (hasPropertyValue(DETECTOR_ALIAS_PROPERTY)) {
+        if (hasPropertyKey(DETECTOR_ALIAS_PROPERTY)) {
             oldValue = getDetectorAlias();
         }
         config.set(DETECTOR_ALIAS_PROPERTY, detectorAlias);
@@ -208,7 +164,7 @@
     }
 
     public void setLogToFile(boolean logToFile) {
-        boolean oldValue = getLogToFile();
+        Boolean oldValue = getLogToFile();
         config.set(LOG_TO_FILE_PROPERTY, logToFile);
         firePropertyChange(LOG_TO_FILE_PROPERTY, oldValue, getLogToFile());
     }
@@ -228,7 +184,7 @@
     }
 
     public void setAidaAutoSave(boolean aidaAutoSave) {
-        boolean oldValue = getAidaAutoSave();
+        Boolean oldValue = getAidaAutoSave();
         config.set(AIDA_AUTO_SAVE_PROPERTY, aidaAutoSave);
         firePropertyChange(AIDA_AUTO_SAVE_PROPERTY, oldValue, aidaAutoSave);
     }
@@ -248,7 +204,7 @@
     }
 
     public void setDisconnectOnError(boolean disconnectOnError) {
-        boolean oldValue = getDisconnectOnError();
+        Boolean oldValue = getDisconnectOnError();
         config.set(DISCONNECT_ON_ERROR_PROPERTY, disconnectOnError);
         firePropertyChange(DISCONNECT_ON_ERROR_PROPERTY, oldValue, getDisconnectOnError());
     }
@@ -258,7 +214,7 @@
     }
 
     public void setDisconnectOnEndRun(boolean disconnectOnEndRun) {
-        boolean oldValue = getDisconnectOnEndRun();
+        Boolean oldValue = getDisconnectOnEndRun();
         config.set(DISCONNECT_ON_END_RUN_PROPERTY, disconnectOnEndRun);
         firePropertyChange(DISCONNECT_ON_END_RUN_PROPERTY, oldValue, getDisconnectOnEndRun());
     }
@@ -320,7 +276,7 @@
     }
 
     public void setPort(int port) {
-        int oldValue = getPort();
+        Integer oldValue = getPort();
         config.set(PORT_PROPERTY, port);
         firePropertyChange(PORT_PROPERTY, oldValue, getPort());
     }
@@ -330,7 +286,7 @@
     }
 
     public void setBlocking(boolean blocking) {
-        boolean oldValue = getBlocking();
+        Boolean oldValue = getBlocking();
         config.set(BLOCKING_PROPERTY, blocking);
         firePropertyChange(BLOCKING_PROPERTY, oldValue, getBlocking());
     }
@@ -340,7 +296,7 @@
     }
 
     public void setVerbose(boolean verbose) {
-        boolean oldValue = getVerbose();
+        Boolean oldValue = getVerbose();
         config.set(VERBOSE_PROPERTY, verbose);
         firePropertyChange(VERBOSE_PROPERTY, oldValue, getVerbose());
     }
@@ -360,7 +316,7 @@
     }
 
     public void setChunkSize(int chunkSize) {
-        int oldValue = getChunkSize();
+        Integer oldValue = getChunkSize();
         config.set(CHUNK_SIZE_PROPERTY, chunkSize);
         firePropertyChange(CHUNK_SIZE_PROPERTY, oldValue, getChunkSize());
     }
@@ -370,7 +326,7 @@
     }
 
     public void setQueueSize(int queueSize) {
-        int oldValue = getQueueSize();
+        Integer oldValue = getQueueSize();
         config.set(QUEUE_SIZE_PROPERTY, queueSize);
         firePropertyChange(QUEUE_SIZE_PROPERTY, oldValue, getQueueSize());
     }
@@ -380,7 +336,7 @@
     }
 
     public void setStationPosition(int stationPosition) {
-        int oldValue = getStationPosition();
+        Integer oldValue = getStationPosition();
         config.set(STATION_POSITION_PROPERTY, stationPosition);
         firePropertyChange(STATION_POSITION_PROPERTY, oldValue, getStationPosition());
     }
@@ -400,7 +356,7 @@
     }
 
     public void setWaitTime(int waitTime) {
-        int oldValue = getWaitTime();
+        Integer oldValue = getWaitTime();
         config.set(WAIT_TIME_PROPERTY, waitTime);
         firePropertyChange(WAIT_TIME_PROPERTY, oldValue, getWaitTime());
     }
@@ -410,14 +366,14 @@
     }
 
     public void setPrescale(int prescale) {
-        int oldValue = getPrescale();
+        Integer oldValue = getPrescale();
         config.set(PRESCALE_PROPERTY, prescale);
         firePropertyChange(PRESCALE_PROPERTY, oldValue, getPrescale());
     }
     
     public void setUserRunNumber(Integer userRunNumber) {
         Integer oldValue = null;
-        if (hasPropertyValue(USER_RUN_NUMBER_PROPERTY)) {
+        if (hasPropertyKey(USER_RUN_NUMBER_PROPERTY)) {
             oldValue = getUserRunNumber();
         }
         config.set(USER_RUN_NUMBER_PROPERTY, userRunNumber);
@@ -430,7 +386,7 @@
     
     public void setFreezeConditions(boolean freezeConditions) {
         Boolean oldValue = null;
-        if (hasPropertyValue(FREEZE_CONDITIONS_PROPERTY)) {
+        if (hasPropertyKey(FREEZE_CONDITIONS_PROPERTY)) {
             oldValue = getFreezeConditions();
         }
         config.set(FREEZE_CONDITIONS_PROPERTY, freezeConditions);
@@ -446,7 +402,7 @@
     }
 
     public void setSaveLayout(boolean saveLayout) {
-        boolean oldValue = getSaveLayout();
+        Boolean oldValue = getSaveLayout();
         config.set(SAVE_LAYOUT_PROPERTY, saveLayout);
         firePropertyChange(SAVE_LAYOUT_PROPERTY, oldValue, getSaveLayout());
     }
@@ -479,6 +435,17 @@
         String oldValue = getPlotFrameLayout();
         config.set(PLOT_FRAME_LAYOUT_PROPERTY, layout);
         firePropertyChange(PLOT_FRAME_LAYOUT_PROPERTY, oldValue, getPlotFrameLayout());
+    }
+    
+    public void setMaxEvents(long maxEvents) {
+        //System.out.println("ConfigurationModel.setMaxEvents - " + maxEvents);
+        Long oldValue = getMaxEvents();
+        config.set(MAX_EVENTS_PROPERTY, maxEvents);
+        firePropertyChange(MAX_EVENTS_PROPERTY, oldValue, getMaxEvents());
+    }
+    
+    public Long getMaxEvents() {
+        return config.getLong(MAX_EVENTS_PROPERTY);
     }
 
     public void remove(String property) {
@@ -489,7 +456,7 @@
         }
     }
     
-    public boolean hasPropertyValue(String key) {
+    public boolean hasPropertyKey(String key) {
         return config.hasKey(key);
     }
     

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/RunModel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/RunModel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/model/RunModel.java	Wed Jan 28 11:05:12 2015
@@ -19,19 +19,8 @@
     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[] properties = new String[] { 
-        RUN_NUMBER_PROPERTY, 
-        START_DATE_PROPERTY, 
-        END_DATE_PROPERTY, 
-        RUN_LENGTH_PROPERTY, 
-        TOTAL_EVENTS_PROPERTY, 
-        ELAPSED_TIME_PROPERTY, 
-        DATA_RECEIVED_PROPERTY, 
-        EVENT_NUMBER_PROPERTY, 
-        DATA_RATE_PROPERTY,
-        EVENT_RATE_PROPERTY
-    };
-
+    static final String[] RUN_PROPERTIES = AbstractModel.getPropertyNames(RunModel.class);
+    
     Integer runNumber;
     Date startDate;
     Date endDate;
@@ -45,11 +34,11 @@
     Double eventRate;
 
     public String[] getPropertyNames() {
-        return properties;
+        return RUN_PROPERTIES;
     }
 
     public void setRunNumber(int runNumber) {
-        int oldValue = this.runNumber;
+        Integer oldValue = this.runNumber;
         this.runNumber = runNumber;
         this.firePropertyChange(RUN_NUMBER_PROPERTY, oldValue, this.runNumber);
     }
@@ -67,7 +56,7 @@
     }
 
     public void setRunLength(int runLength) {
-        int oldValue = this.runLength;
+        Integer oldValue = this.runLength;
         this.runLength = runLength;
         this.firePropertyChange(RUN_LENGTH_PROPERTY, oldValue, this.runLength);
     }
@@ -81,29 +70,25 @@
     }
 
     public void setTotalEvents(int totalEvents) {
-        int oldValue = this.totalEvents;
+        Integer oldValue = this.totalEvents;
         this.totalEvents = totalEvents;
         this.firePropertyChange(TOTAL_EVENTS_PROPERTY, oldValue, this.totalEvents);
     }
 
     public void setEventsReceived(int eventsReceived) {
-        int oldValue = this.eventsReceived;
+        Integer oldValue = this.eventsReceived;
         this.eventsReceived = eventsReceived;
         this.firePropertyChange(EVENTS_RECEIVED_PROPERTY, oldValue, this.eventsReceived);
     }
 
-    public void incrementEventsReceived() {
-        this.setEventsReceived(eventsReceived + 1);
-    }
-
     public void setElapsedTime(int elapsedTime) {
-        int oldValue = this.elapsedTime;
+        Integer oldValue = this.elapsedTime;
         this.elapsedTime = elapsedTime;
         this.firePropertyChange(ELAPSED_TIME_PROPERTY, oldValue, this.elapsedTime);
     }
 
     public void setDataReceived(double dataReceived) {
-        double oldValue = this.dataReceived;
+        Double oldValue = this.dataReceived;
         this.dataReceived = dataReceived;
         this.firePropertyChange(DATA_RECEIVED_PROPERTY, oldValue, this.dataReceived);
     }
@@ -113,19 +98,19 @@
     }
 
     public void setEventNumber(int eventNumber) {
-        int oldValue = this.eventNumber;
+        Integer oldValue = this.eventNumber;
         this.eventNumber = eventNumber;
         this.firePropertyChange(EVENT_NUMBER_PROPERTY, oldValue, this.eventNumber);
     }
     
     public void setDataRate(double dataRate) {
-        double oldValue = this.dataRate;
+        Double oldValue = this.dataRate;
         this.dataRate = dataRate;
         this.firePropertyChange(DATA_RATE_PROPERTY, oldValue, this.dataRate);
     }
         
     public void setEventRate(double eventRate) {
-        double oldValue = this.eventRate;
+        Double oldValue = this.eventRate;
         this.eventRate = eventRate;
         this.firePropertyChange(EVENT_RATE_PROPERTY, oldValue, this.eventRate);
     }

Modified: java/trunk/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop
 =============================================================================
--- java/trunk/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop	(original)
+++ java/trunk/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop	Wed Jan 28 11:05:12 2015
@@ -11,6 +11,7 @@
 #LogFileName=
 LogLevel=ALL
 LogToFile=false
+MaxEvents=-1
 #SteeringFile=
 SteeringResource=org/hps/steering/monitoring/DummyMonitoring.lcsim
 SteeringType=RESOURCE
@@ -33,4 +34,6 @@
 StationName=MY_STATION
 Verbose=false
 WaitMode=TIMED
-WaitTime=1000000000
+WaitTime=1000000000
+
+SaveLayout=false;