Author: [log in to unmask] Date: Fri Jul 17 16:51:55 2015 New Revision: 3266 Log: Minor changes to crawler and run db API. Modified: java/trunk/record-util/src/main/java/org/hps/record/evio/crawler/Crawler.java java/trunk/record-util/src/main/java/org/hps/record/evio/crawler/CrawlerConfig.java java/trunk/record-util/src/main/java/org/hps/record/run/EpicsDataReader.java java/trunk/record-util/src/main/java/org/hps/record/run/RunManager.java Modified: java/trunk/record-util/src/main/java/org/hps/record/evio/crawler/Crawler.java ============================================================================= --- java/trunk/record-util/src/main/java/org/hps/record/evio/crawler/Crawler.java (original) +++ java/trunk/record-util/src/main/java/org/hps/record/evio/crawler/Crawler.java Fri Jul 17 16:51:55 2015 @@ -378,6 +378,7 @@ LOGGER.config("added date filter with time stamp " + config.timestamp()); } + // Is the accept run list not empty? (Empty means accept all runs.) if (!config.acceptRuns().isEmpty()) { // List of run numbers to accept. visitor.addFilter(new RunFilter(config.acceptRuns())); Modified: java/trunk/record-util/src/main/java/org/hps/record/evio/crawler/CrawlerConfig.java ============================================================================= --- java/trunk/record-util/src/main/java/org/hps/record/evio/crawler/CrawlerConfig.java (original) +++ java/trunk/record-util/src/main/java/org/hps/record/evio/crawler/CrawlerConfig.java Fri Jul 17 16:51:55 2015 @@ -5,6 +5,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -26,9 +27,10 @@ private static final SimpleDateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** - * A list of run numbers to accept in the job. - */ - private Set<Integer> acceptRuns; + * A list of run numbers to accept in the job; this default will probably get overridden but it is here to avoid + * null pointer exceptions. An empty list is assumed to mean "accept all runs" e.g. no run number filtering. + */ + private Set<Integer> acceptRuns = new LinkedHashSet<Integer>(); /** * <code>true</code> if database updates are allowed meaning existing records can be deleted and replaced. @@ -244,8 +246,9 @@ * * @param maxDepth the max depth */ - void setMaxDepth(final Integer maxDepth) { + CrawlerConfig setMaxDepth(final Integer maxDepth) { this.maxDepth = maxDepth; + return this; } /** Modified: java/trunk/record-util/src/main/java/org/hps/record/run/EpicsDataReader.java ============================================================================= --- java/trunk/record-util/src/main/java/org/hps/record/run/EpicsDataReader.java (original) +++ java/trunk/record-util/src/main/java/org/hps/record/run/EpicsDataReader.java Fri Jul 17 16:51:55 2015 @@ -7,7 +7,7 @@ import org.hps.record.epics.EpicsData; /** - * Convert run database records from the <i>run_epics</i> table in to a {@link EpicsData} object. + * Convert run database records from the <i>run_epics</i> table into a {@link EpicsData} object. * * @author Jeremy McCormick, SLAC */ Modified: java/trunk/record-util/src/main/java/org/hps/record/run/RunManager.java ============================================================================= --- java/trunk/record-util/src/main/java/org/hps/record/run/RunManager.java (original) +++ java/trunk/record-util/src/main/java/org/hps/record/run/RunManager.java Fri Jul 17 16:51:55 2015 @@ -1,27 +1,37 @@ package org.hps.record.run; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; +import org.hps.conditions.database.ConnectionParameters; import org.lcsim.conditions.ConditionsEvent; import org.lcsim.conditions.ConditionsListener; import org.lcsim.util.log.DefaultLogFormatter; import org.lcsim.util.log.LogUtil; /** - * Manages access to the run database and creates a {@link RunSummary} object from the data for a specific run. + * Manages read-only access to the run database and creates a {@link RunSummary} object from the data for a specific + * run. * <p> - * This class can also convert database records into {@link org.hps.record.epics.EpicsData}, - * {@link org.hps.record.scalers.ScalerData}, and {@link org.hps.record.evio.crawler.EvioFileList} using their - * {@link AbstractRunDatabaseReader} implementation classes. + * This class converts database records into {@link RunSummary}, {@link org.hps.record.epics.EpicsData}, + * {@link org.hps.record.scalers.ScalerData}, and {@link org.hps.record.evio.crawler.EvioFileList} objects using their + * corresponding {@link AbstractRunDatabaseReader} implementation classes. * * @author Jeremy McCormick, SLAC */ public final class RunManager implements ConditionsListener { /** + * The default connection parameters for read-only access to the run database using the standard 'hpsuser' account. + */ + private static ConnectionParameters DEFAULT_CONNECTION_PARAMETERS = new ConnectionParameters("hpsuser", + "darkphoton", "hps_run_db", "hpsdb.jlab.org"); + + /** * The singleton instance of the RunManager. */ private static RunManager INSTANCE; @@ -32,9 +42,9 @@ private static Logger LOGGER = LogUtil.create(RunManager.class, new DefaultLogFormatter(), Level.ALL); /** - * Get the instance of the {@link RunManager}. - * - * @return the instance of the {@link RunManager}. + * Get the global instance of the {@link RunManager}. + * + * @return the global instance of the {@link RunManager} */ public static RunManager getRunManager() { if (INSTANCE == null) { @@ -44,11 +54,16 @@ } /** - * The database connection. + * The active database connection. */ private Connection connection; /** + * The database connection parameters, initially set to the default parameters. + */ + private ConnectionParameters connectionParameters = DEFAULT_CONNECTION_PARAMETERS; + + /** * The run number; the -1 value indicates that this has not been set externally yet. */ private int run = -1; @@ -58,18 +73,18 @@ */ private RunSummary runSummary = null; + /** + * Load new run information when conditions have changed. + */ @Override - public void conditionsChanged(final ConditionsEvent conditionsEvent) { - final int newRun = conditionsEvent.getConditionsManager().getRun(); - LOGGER.info("initializing for run " + newRun + " ..."); - this.setRun(newRun); - LOGGER.info("done initializing for run " + this.getRun()); + public synchronized void conditionsChanged(final ConditionsEvent conditionsEvent) { + this.setRun(conditionsEvent.getConditionsManager().getRun()); } /** * Get the database connection. * - * @return the database connection + * @return the database connection or <code>null</code> if it is not set */ Connection getConnection() { return this.connection; @@ -97,28 +112,29 @@ * Read information from the run database and create a {@link RunSummary} from it. */ private void readRun() { - // Load main RunSummary object. + + // Read main RunSummary object but not objects that it references. final RunSummaryReader runSummaryReader = new RunSummaryReader(); runSummaryReader.setRun(this.getRun()); runSummaryReader.setConnection(this.getConnection()); runSummaryReader.read(); this.setRunSummary(runSummaryReader.getData()); - // Set EpicsData on RunSummary. + // Read EpicsData and set on RunSummary. final EpicsDataReader epicsDataReader = new EpicsDataReader(); epicsDataReader.setRun(this.getRun()); epicsDataReader.setConnection(this.getConnection()); epicsDataReader.read(); this.getRunSummary().setEpicsData(epicsDataReader.getData()); - // Set ScalerData on RunSummary. + // Read ScalerData and set on RunSummary. final ScalerDataReader scalerDataReader = new ScalerDataReader(); scalerDataReader.setRun(this.getRun()); scalerDataReader.setConnection(this.getConnection()); scalerDataReader.read(); this.getRunSummary().setScalerData(scalerDataReader.getData()); - // Set ScalerData on RunSummary. + // Read ScalerData and set on RunSummary. final EvioFileListReader evioFileListReader = new EvioFileListReader(); evioFileListReader.setRun(this.getRun()); evioFileListReader.setConnection(this.getConnection()); @@ -127,38 +143,83 @@ } /** - * Set the database connection. - * - * @param connection the database connection - */ - public void setConnection(final Connection connection) { - this.connection = connection; + * Check if the current run number exists in the run database. + * + * @return <code>true</code> if run exists + */ + private boolean runExists() throws SQLException { + PreparedStatement statement = null; + boolean exists = false; + try { + statement = connection.prepareStatement("SELECT run FROM runs where run = ?"); + statement.setInt(1, this.run); + final ResultSet resultSet = statement.executeQuery(); + exists = resultSet.next(); + } finally { + if (statement != null) { + try { + statement.close(); + } catch (final SQLException e) { + e.printStackTrace(); + } + } + } + return exists; + } + + /** + * Set the database connection parameters. + */ + public void setConnectionParameters(final ConnectionParameters connectionParameters) { + this.connectionParameters = connectionParameters; } /** * Set the run number. + * <p> + * This is public in order for the class to be usable without the conditions system but it should not be called + * within a standard lcsim job as it resets the global state of the RunManager. * * @param run the run number */ - public void setRun(final int run) { - - // Check status of database connection (must be open). + public synchronized void setRun(final int run) { + + if (run < 0) { + throw new IllegalArgumentException("invalid run number: " + run); + } + try { - if (this.connection.isClosed()) { - throw new IllegalStateException("The connection is closed."); + + // Setup the database connection. + if (this.connection == null || this.connection.isClosed()) { + this.connection = connectionParameters.createConnection(); } + + // Set the current run number. + this.run = run; + + // Does the current run exist in the database? + if (this.runExists()) { + LOGGER.info("run record found in hps_run_db for " + run); + try { + // Read the records from the database and convert into Java objects. + this.readRun(); + } catch (final Exception e) { + // There was some unknown error when reading in the run records. + LOGGER.log(Level.SEVERE, "Error reading from run database for run: " + run, e); + throw new RuntimeException(e); + } + } else { + // Run is not in the database. + LOGGER.warning("run database record does not exist for run " + run); + } + + // Close the database connection. + this.connection.close(); + } catch (final SQLException e) { throw new RuntimeException(e); } - - this.run = run; - - try { - // Read the run records from the database and convert into Java objects. - this.readRun(); - } catch (final Exception e) { - LOGGER.log(Level.SEVERE, "Error reading from run database for run: " + run, e); - } } /**