Print

Print


Author: [log in to unmask]
Date: Fri Sep  4 12:59:35 2015
New Revision: 3524

Log:
Merge in conditions branch to trunk.  HPSJAVA-517

Added:
    java/trunk/conditions/src/main/java/org/hps/conditions/api/ConditionsTag.java
      - copied unchanged from r3393, java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/ConditionsTag.java
    java/trunk/conditions/src/main/java/org/hps/conditions/database/ConditionsTagConverter.java
      - copied unchanged from r3393, java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/database/ConditionsTagConverter.java
    java/trunk/conditions/src/test/java/org/hps/conditions/api/ConditionsTagTest.java
      - copied, changed from r3393, java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/api/ConditionsTagTest.java
Modified:
    java/trunk/conditions/   (props changed)
    java/trunk/conditions/pom.xml
    java/trunk/conditions/src/main/java/org/hps/conditions/ConditionsDriver.java
    java/trunk/conditions/src/main/java/org/hps/conditions/api/ConditionsRecord.java
    java/trunk/conditions/src/main/java/org/hps/conditions/api/TableMetaData.java
    java/trunk/conditions/src/main/java/org/hps/conditions/cli/AbstractCommand.java
    java/trunk/conditions/src/main/java/org/hps/conditions/cli/AddCommand.java
    java/trunk/conditions/src/main/java/org/hps/conditions/cli/CommandLineTool.java
    java/trunk/conditions/src/main/java/org/hps/conditions/cli/TagCommand.java
    java/trunk/conditions/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java
    java/trunk/conditions/src/main/java/org/hps/conditions/run/RunSpreadsheet.java
    java/trunk/conditions/src/test/java/org/hps/conditions/EngRunConditionsTest.java
    java/trunk/evio/src/main/java/org/hps/evio/EvioToLcio.java

Modified: java/trunk/conditions/pom.xml
 =============================================================================
--- java/trunk/conditions/pom.xml	(original)
+++ java/trunk/conditions/pom.xml	Fri Sep  4 12:59:35 2015
@@ -32,12 +32,14 @@
                         <exclude>org/hps/conditions/svt/SvtDetectorSetupTest.java</exclude> 
                         <exclude>org/hps/conditions/svt/SvtConfigurationTest.java</exclude>
                         <exclude>org/hps/conditions/svt/SvtDaqMappingTest.java</exclude>
+                        <exclude>org/hps/conditions/svt/TestRunSvtBadChannelsTest.java</exclude>
                         <exclude>org/hps/conditions/svt/TestRunSvtConditionsConverterTest.java</exclude>
                         <exclude>org/hps/conditions/svt/TestRunSvtDaqMappingTest.java</exclude>
                         <exclude>org/hps/conditions/beam/BeamConditionsTest.java</exclude>
                         <exclude>org/hps/conditions/ecal/EcalHardwareConditionsTest.java</exclude>
                         <exclude>org/hps/conditions/database/CollectionIdTest.java</exclude>
                         <exclude>org/hps/conditions/svt/SvtTimingConstantsTest.java</exclude>
+                        <exclude>org/hps/conditions/api/ConditionsTagTest.java</exclude>
                         <exclude>org/hps/conditions/dummy/**.java</exclude>
                     </excludes>
                 </configuration>

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/ConditionsDriver.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/ConditionsDriver.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/ConditionsDriver.java	Fri Sep  4 12:59:35 2015
@@ -75,7 +75,7 @@
 
         if (this.tag != null) {
             // Set a tag for filtering ConditionsRecord objects.
-            conditionsManager.setTag(this.tag);
+            conditionsManager.addTag(this.tag);
         }
         if (this.detectorName != null) {
             // The manager can only be initialized here if there is a user supplied detector name.

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/api/ConditionsRecord.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/api/ConditionsRecord.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/api/ConditionsRecord.java	Fri Sep  4 12:59:35 2015
@@ -358,9 +358,11 @@
     /**
      * Get the string tag associated with these conditions.
      *
+     * @deprecated Use the {@link ConditionsTag} class instead.
      * @return The string tag.
      */
     @Field(names = {"tag"})
+    @Deprecated
     public String getTag() {
         return this.getFieldValue("tag");
     }

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/api/TableMetaData.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/api/TableMetaData.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/api/TableMetaData.java	Fri Sep  4 12:59:35 2015
@@ -262,9 +262,16 @@
         buff.append('\n');
         return buff.toString();
     }
-
-    // TODO: add methods for getting SQL strings for PreparedStatements; can be setup once at initialization time for
-    // each table
+    
+    /**
+     * Method for removing a field that was found using the automatic introspection methods.
+     */
+    void removeField(String fieldName) {
+        fieldNames.remove(fieldName);
+        fieldTypes.remove(fieldName);
+    }
+
+    // TODO: add methods for getting SQL strings for PreparedStatements; can be setup once at initialization time for each table
     // String getSelectStatement();
     // String getInsertStatement();
     // String getUpdateStatement();

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/cli/AbstractCommand.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/cli/AbstractCommand.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/cli/AbstractCommand.java	Fri Sep  4 12:59:35 2015
@@ -6,6 +6,7 @@
 import org.apache.commons.cli.ParseException;
 import org.apache.commons.cli.Parser;
 import org.apache.commons.cli.PosixParser;
+import org.hps.conditions.database.DatabaseConditionsManager;
 
 /**
  * This is the API that sub-commands such as 'load' or 'print' must implement in the conditions command line interface.
@@ -108,4 +109,12 @@
         final HelpFormatter help = new HelpFormatter();
         help.printHelp(this.getName(), this.getOptions());
     }
+    
+    /**
+     * Convenience method for getting the conditions manager.
+     * @return the conditions manager
+     */
+    public DatabaseConditionsManager getManager() {
+        return DatabaseConditionsManager.getInstance();
+    }
 }

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/cli/AddCommand.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/cli/AddCommand.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/cli/AddCommand.java	Fri Sep  4 12:59:35 2015
@@ -41,7 +41,6 @@
         OPTIONS.getOption("t").setRequired(true);
         OPTIONS.addOption("c", true, "collection ID (required)");
         OPTIONS.getOption("c").setRequired(true);
-        OPTIONS.addOption("T", true, "tag value (optional)");
         OPTIONS.addOption("u", true, "user name (optional)");
         OPTIONS.addOption("m", true, "notes about this conditions set (optional)");
     }
@@ -67,7 +66,7 @@
      * @return the new conditions record
      */
     private ConditionsRecord createConditionsRecord(final int runStart, final int runEnd, final String tableName,
-            final String name, final int collectionId, final String createdBy, final String tag, final String notes) {
+            final String name, final int collectionId, final String createdBy, final String notes) {
         final ConditionsRecord conditionsRecord = new ConditionsRecord();
         final FieldValuesMap fieldValues = new FieldValuesMap();
         fieldValues.setValue("run_start", runStart);
@@ -76,9 +75,6 @@
         fieldValues.setValue("name", name);
         fieldValues.setValue("collection_id", collectionId);
         fieldValues.setValue("created_by", createdBy);
-        if (tag != null) {
-            fieldValues.setValue("tag", tag);
-        }
         if (notes != null) {
             fieldValues.setValue("notes", notes);
         }
@@ -134,12 +130,6 @@
             createdBy = commandLine.getOptionValue("u");
         }
 
-        // Tag to assign (optional).
-        String tag = null;
-        if (commandLine.hasOption("T")) {
-            tag = commandLine.getOptionValue("T");
-        }
-
         // Notes (optional).
         String notes = null;
         if (commandLine.hasOption("m")) {
@@ -148,7 +138,7 @@
 
         // Create the conditions record to insert.
         final ConditionsRecord conditionsRecord = this.createConditionsRecord(runStart, runEnd, tableName, name,
-                collectionId, createdBy, tag, notes);
+                collectionId, createdBy, notes);
         LOGGER.info("inserting conditions record ..." + '\n' + conditionsRecord);
         try {
             boolean createdConnection = false;

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/cli/CommandLineTool.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/cli/CommandLineTool.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/cli/CommandLineTool.java	Fri Sep  4 12:59:35 2015
@@ -202,7 +202,7 @@
         // User specified tag of conditions records.
         if (commandLine.hasOption("t")) {
             final String tag = commandLine.getOptionValue("t");
-            this.conditionsManager.setTag(tag);
+            this.conditionsManager.addTag(tag);
             LOGGER.config("using tag " + tag);
         }
 

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/cli/TagCommand.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/cli/TagCommand.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/cli/TagCommand.java	Fri Sep  4 12:59:35 2015
@@ -1,9 +1,9 @@
 package org.hps.conditions.cli;
 
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -12,54 +12,81 @@
 import org.apache.commons.cli.Options;
 import org.hps.conditions.api.ConditionsObjectException;
 import org.hps.conditions.api.ConditionsRecord;
-import org.hps.conditions.api.TableRegistry;
 import org.hps.conditions.api.ConditionsRecord.ConditionsRecordCollection;
+import org.hps.conditions.api.ConditionsTag;
+import org.hps.conditions.api.ConditionsTag.ConditionsTagCollection;
 import org.hps.conditions.api.DatabaseObjectException;
 import org.hps.conditions.api.TableMetaData;
-import org.hps.conditions.database.DatabaseConditionsManager;
-import org.lcsim.conditions.ConditionsManager.ConditionsNotFoundException;
+import org.hps.conditions.api.TableRegistry;
+import org.hps.conditions.database.MultipleCollectionsAction;
+import org.lcsim.util.log.DefaultLogFormatter;
 import org.lcsim.util.log.LogUtil;
 
 /**
  * Create a conditions system tag.
+ * <p>
+ * The tag groups together conditions records from the <i>conditions</i> database table with a run validity range that 
+ * is between a specified starting and ending run.
+ * <p>
+ * Tagging will not disambiguate overlapping conditions, which is done at run-time based on the current run number.
  *
  * @author Jeremy McCormick, SLAC
  */
-public class TagCommand extends AbstractCommand {
-
-    /**
-     * The default detector name (dummy detector).
-     */
-    private static final String DETECTOR_NAME = "HPS-dummy-detector";
-
-    /**
-     * Setup logger.
-     */
-    private static final Logger LOGGER = LogUtil.create(TagCommand.class);
-
+final class TagCommand extends AbstractCommand {
+
+    /**
+     * Setup the logger.
+     */
+    private static final Logger LOGGER = LogUtil.create(TagCommand.class, new DefaultLogFormatter(), Level.ALL);
+    
     /**
      * Defines command options.
      */
     private static Options OPTIONS = new Options();
 
     /**
-     * Define command options.
+     * Define all command options.
      */
     static {
         OPTIONS.addOption(new Option("h", false, "Show help for tag command"));
-        OPTIONS.addOption(new Option("r", true, "List of run numbers to scan (at least one must be provided)"));
-        OPTIONS.getOption("r").setArgs(Option.UNLIMITED_VALUES);
-        OPTIONS.getOption("r").setRequired(true);
-        OPTIONS.addOption(new Option("t", true, "The new conditions tag"));
+        OPTIONS.addOption(new Option("t", true, "Conditions tag name"));
+        OPTIONS.addOption(new Option("s", true, "Starting run number (required)"));
+        OPTIONS.getOption("s").setRequired(true);
+        OPTIONS.addOption(new Option("e", true, "Ending run number (default is unlimited)"));
         OPTIONS.getOption("t").setRequired(true);
-        OPTIONS.addOption(new Option("f", false, "Don't prompt before making tag (careful!)"));
+        OPTIONS.addOption(new Option("m", true,
+                "MultipleCollectionsAction to use for disambiguation (default is LAST_CREATED)"));
+        OPTIONS.addOption(new Option("d", false, "Don't prompt before making tag (be careful!)"));
     }
 
     /**
      * Class constructor.
      */
     TagCommand() {
-        super("tag", "Tag a set of collections by copying their conditions records", OPTIONS);
+        super("tag", "Tag a set of conditions records to group them together", OPTIONS);
+    }
+
+    /**
+     * Create the collection with the records for creating a new conditions "tag".
+     *
+     * @param tagConditionsRecordCollection the tag record collection
+     * @param tagName the tag name
+     * @return the tag record collection
+     */
+    private ConditionsTagCollection createConditionsTagCollection(
+            final ConditionsRecordCollection tagConditionsRecordCollection, final String tagName) {
+        final ConditionsTagCollection conditionsTagCollection = new ConditionsTagCollection();
+        conditionsTagCollection.setConnection(this.getManager().getConnection());
+        conditionsTagCollection.setTableMetaData(TableRegistry.getTableRegistry().findByTableName("conditions_tags"));
+        for (final ConditionsRecord conditionsRecord : tagConditionsRecordCollection) {
+            final ConditionsTag conditionsTag = new ConditionsTag(conditionsRecord.getRowId(), tagName);
+            try {
+                conditionsTagCollection.add(conditionsTag);
+            } catch (final ConditionsObjectException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return conditionsTagCollection;
     }
 
     /**
@@ -70,108 +97,154 @@
 
         final CommandLine commandLine = this.parse(arguments);
 
-        final Set<Integer> runNumbers = new LinkedHashSet<Integer>();
-        if (commandLine.getOptionValues("r") == null) {
-            throw new RuntimeException("Missing -r argument with list of run numbers.");
-        }
-        for (final String value : commandLine.getOptionValues("r")) {
-            runNumbers.add(Integer.parseInt(value));
-        }
-        if (runNumbers.size() == 0) {
-            throw new RuntimeException("At least one run number must be provided with the -r switch.");
-        }
-
-        final String newTag;
+        // New tag name.
+        final String tagName;
         if (commandLine.hasOption("t")) {
-            newTag = commandLine.getOptionValue("t");
+            tagName = commandLine.getOptionValue("t");
+            LOGGER.info("tag name set to " + tagName);
         } else {
             throw new RuntimeException("Missing required -t argument with the tag name.");
         }
 
-        boolean dontPrompt = false;
-        if (commandLine.hasOption("f")) {
-            dontPrompt = true;
-        }
-
-        final ConditionsRecordCollection tagRecords = new ConditionsRecordCollection();
-        final Set<Integer> addedIds = new HashSet<Integer>();
-
-        final DatabaseConditionsManager manager = DatabaseConditionsManager.getInstance();
-        manager.setXmlConfig("/org/hps/conditions/config/conditions_database_no_svt.xml");
-        manager.setLogLevel(Level.ALL);
-
-        // Scan through all the runs between the start and end run, inclusive.
-        for (final Integer run : runNumbers) {
-            try {
-                // Setup the conditions manager with the run number.
-                manager.setDetector(TagCommand.DETECTOR_NAME, run);
-            } catch (final ConditionsNotFoundException e) {
-                throw new RuntimeException(e);
-            }
-
-            // The unique conditions keys from this run.
-            final Set<String> keys = manager.getConditionsRecords().getConditionsKeys();
-
-            // Scan through all the unique keys.
-            for (final String key : keys) {
-
-                // Get the table meta data for the key.
-                final TableMetaData tableMetaData = manager.findTableMetaData(key);
-
-                // Get the ConditionsRecord from the collection.
-                final ConditionsRecordCollection records = manager.findConditionsRecords(key);
-                records.sortByUpdated();
-                final ConditionsRecord record = records.get(records.size() - 1);
-
-                manager.getCachedConditions(tableMetaData.getCollectionClass(), tableMetaData.getTableName())
-                        .getCachedData();
-
-                // Is this record already part of the new tag?
-                if (!addedIds.contains(record.getRowId())) {
-                    // Create a new record copied from the old one.
-                    final ConditionsRecord newRecord = new ConditionsRecord(record);
-
-                    // Set the tag value.
-                    newRecord.setFieldValue("tag", newTag);
-
-                    // Add the record to the tag.
-                    try {
-                        tagRecords.add(newRecord);
-                    } catch (final ConditionsObjectException e) {
-                        throw new RuntimeException(e);
-                    }
-
-                    // Flag the record's ID as used so it is only added once.
-                    addedIds.add(record.getRowId());
-                }
-            }
-        }
-
-        // Print out all the records that were found.
-        LOGGER.info("found ConditionsRecords for tag " + newTag + " ...");
-        for (final ConditionsRecord record : tagRecords) {
-            LOGGER.info(record.toString());
-        }
-
-        // Prompt user to verify with console input.
-        boolean makeTag = true;
-        if (!dontPrompt) {
-            LOGGER.info("Create conditions tag " + newTag + " in database?  (Y/N)");
+        // Starting run number (required).
+        int runStart = -1;
+        if (commandLine.hasOption("s")) {
+            runStart = Integer.parseInt(commandLine.getOptionValue("s"));
+            LOGGER.config("run start set to " + runStart);
+        } else {
+            throw new RuntimeException("missing require -s argument with starting run number");
+        }
+
+        // Ending run number (max integer is default).
+        int runEnd = Integer.MAX_VALUE;
+        if (commandLine.hasOption("e")) {
+            runEnd = Integer.parseInt(commandLine.getOptionValue("e"));
+            LOGGER.config("run end set to " + runEnd);
+        }
+
+        // Run end must be greater than or equal to run start.
+        if (runEnd < runStart) {
+            throw new IllegalArgumentException("runEnd < runStart");
+        }
+
+        // Action for disambiguating overlapping collections (default is to use the most recent creation date).
+        MultipleCollectionsAction multipleCollectionsAction = MultipleCollectionsAction.LAST_CREATED;
+        if (commandLine.hasOption("m")) {
+            multipleCollectionsAction = MultipleCollectionsAction
+                    .valueOf(commandLine.getOptionValue("m").toUpperCase());
+        }
+        LOGGER.config("multiple collections action set tco " + multipleCollectionsAction);
+
+        // Whether to prompt before tagging (default is yes).
+        boolean promptBeforeTagging = true;
+        if (commandLine.hasOption("d")) {
+            promptBeforeTagging = false;
+        }
+        LOGGER.config("prompt before tagging: " + promptBeforeTagging);
+
+        // Conditions system configuration.
+        this.getManager().setXmlConfig("/org/hps/conditions/config/conditions_database_no_svt.xml");
+        this.getManager().setLogLevel(Level.ALL);
+
+        // Find all the applicable conditions records by their run number ranges.
+        ConditionsRecordCollection tagConditionsRecordCollection = this.findConditionsRecords(runStart, runEnd);
+
+        LOGGER.info("found " + tagConditionsRecordCollection.size() + " conditions records for the tag");
+
+        // Build the collection of tag records to insert into the database.
+        final ConditionsTagCollection conditionsTagCollection = this.createConditionsTagCollection(
+                tagConditionsRecordCollection, tagName);
+
+        LOGGER.info("created " + conditionsTagCollection.size() + " tag records ..." + '\n' + conditionsTagCollection);
+
+        LOGGER.getHandlers()[0].flush();
+
+        // Prompt user to verify tag creation.
+        boolean createTag = true;
+        if (promptBeforeTagging) {
+            System.out.println("Create conditions tag '" + tagName + "' in the database?  (Y/N)");
             final String line = System.console().readLine();
             if (!line.equals("Y")) {
-                makeTag = false;
-            }
-        }
-
-        // Create the tag in the database if user verified or force option was present.
-        if (makeTag) {
+                createTag = false;
+            }
+        }
+
+        // Create the tag.
+        if (createTag) {
             try {
-                tagRecords.setConnection(manager.getConnection());
-                tagRecords.setTableMetaData(TableRegistry.getTableRegistry().findByTableName("conditions"));
-                tagRecords.insert();
+                LOGGER.info("creating tag " + tagName + " in the database ...");
+                conditionsTagCollection.insert();
             } catch (DatabaseObjectException | SQLException e) {
                 throw new RuntimeException(e);
             }
-        }
+        } else {
+            LOGGER.warning("user aborted tag operation!");
+        }
+
+        LOGGER.info("done!");
+    }
+   
+    /**
+     * Find all the conditions records that are applicable for the given run range.
+     * <p>
+     * Overlapping run numbers in conditions with the same key are not disambiguated.
+     * This must be done in the user's job at runtime; usually the most recently created 
+     * conditions record will be used if multiple one's are applicable to the current run.
+     *
+     * @param runStart the start run
+     * @param runEnd the end run (must be greater than or equal to <code>runStart</code>)
+     * @return the conditions records that fall in the run range
+     */
+    private ConditionsRecordCollection findConditionsRecords(final int runStart, final int runEnd) {
+        if (runStart > runEnd) {
+            throw new IllegalArgumentException("runStart > runEnd");
+        }
+        if (runStart < 0) {
+            throw new IllegalArgumentException("invalid runStart: " + runStart);
+        }
+        if (runEnd < 0) {
+            throw new IllegalArgumentException("invalid runEnd: " + runEnd);
+        }
+        final Connection connection = this.getManager().getConnection();
+        final ConditionsRecordCollection conditionsRecordCollection = new ConditionsRecordCollection();
+        final TableMetaData tableMetaData = TableRegistry.getTableRegistry().findByTableName("conditions");
+        PreparedStatement statement = null;
+        try {
+            /*
+             * SQL statement handles 3 cases: 
+             * 1) condition's run_start in range 
+             * 2) condition's run_end in range 
+             * 3) condition's run_start and run_end enclose the range
+             */
+            statement = connection
+                    .prepareStatement("SELECT id FROM conditions WHERE (run_start >= ? and run_start <= ?) or (run_end >= ? and run_end <= ?)"
+                            + " or (run_start <= ? and run_end >= ?)");
+            statement.setInt(1, runStart);
+            statement.setInt(2, runEnd);
+            statement.setInt(3, runStart);
+            statement.setInt(4, runEnd);
+            statement.setInt(5, runStart);
+            statement.setInt(6, runEnd);
+
+            final ResultSet resultSet = statement.executeQuery();
+            while (resultSet.next()) {
+                final ConditionsRecord record = new ConditionsRecord();
+                record.setConnection(connection);
+                record.setTableMetaData(tableMetaData);
+                record.select(resultSet.getInt(1));
+                conditionsRecordCollection.add(record);
+            }
+        } catch (DatabaseObjectException | ConditionsObjectException | SQLException e) {
+            throw new RuntimeException(e);
+        } finally {
+            try {
+                if (statement != null) {
+                    statement.close();
+                }
+            } catch (final SQLException e) {
+                e.printStackTrace();
+            }
+        }
+        return conditionsRecordCollection;
     }
 }

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java	Fri Sep  4 12:59:35 2015
@@ -12,6 +12,7 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -21,10 +22,9 @@
 import org.hps.conditions.api.AbstractConditionsObjectConverter;
 import org.hps.conditions.api.ConditionsObject;
 import org.hps.conditions.api.ConditionsObjectCollection;
-import org.hps.conditions.api.ConditionsObjectException;
-import org.hps.conditions.api.ConditionsRecord;
 import org.hps.conditions.api.ConditionsRecord.ConditionsRecordCollection;
 import org.hps.conditions.api.ConditionsSeries;
+import org.hps.conditions.api.ConditionsTag.ConditionsTagCollection;
 import org.hps.conditions.api.TableMetaData;
 import org.hps.conditions.api.TableRegistry;
 import org.hps.conditions.ecal.EcalConditions;
@@ -64,7 +64,12 @@
     /**
      * Name of system property that can be used to specify custom database connection parameters.
      */
-    private static final String CONNECTION_PROPERTY = "org.hps.conditions.connection.file";
+    private static final String CONNECTION_PROPERTY_FILE = "org.hps.conditions.connection.file";
+    
+    /**
+     * Connection property resource.
+     */
+    private static final String CONNECTION_PROPERTY_RESOURCE = "org.hps.conditions.connection.resource";
 
     /**
      * The default XML config.
@@ -255,22 +260,47 @@
     private final TableRegistry tableRegistry = TableRegistry.getTableRegistry();
 
     /**
-     * The currently active conditions tag.
-     */
-    private String tag = null;
-
+     * The currently active conditions tag (empty collection means no tag is active).
+     */
+    private ConditionsTagCollection conditionsTagCollection = new ConditionsTagCollection();
+    
+    /**
+     * The current set of conditions for the run.
+     */
+    private ConditionsRecordCollection conditionsRecordCollection = null;
+    
+    /**
+     * The currently applied conditions tags.
+     */
+    private Set<String> tags = new HashSet<String>();
+    
     /**
      * Class constructor. Calling this will automatically register this manager as the global default.
      */
     private DatabaseConditionsManager() {
+        
+        // Register detector conditions converter.
         this.registerConditionsConverter(new DetectorConditionsConverter());
-        this.setupConnectionFromSystemProperty();
+        
+        // Setup connection from system property pointing to a file, if it was set.
+        this.setupConnectionSystemPropertyFile();
+        
+        // Setup connection from system property pointing to a resource, if it was set.
+        this.setupConnectionSystemPropertyResource();
+        
+        // Register default conditions manager.
         ConditionsManager.setDefaultConditionsManager(this);
+        
+        // Set run to invalid number.
         this.setRun(-1);
+        
+        // Register conditions converters.
         for (final AbstractConditionsObjectConverter converter : this.converters.values()) {
             // logger.fine("registering converter for " + converter.getType());
             this.registerConditionsConverter(converter);
         }
+        
+        // Add the SVT detector setup object as a listener.
         this.addConditionsListener(this.svtSetup);
     }
 
@@ -378,27 +408,7 @@
      * @return the set of matching conditions records
      */
     public ConditionsRecordCollection findConditionsRecords(final String name) {
-        final ConditionsRecordCollection runConditionsRecords = this.getCachedConditions(
-                ConditionsRecordCollection.class, "conditions").getCachedData();
-        logger.fine("searching for conditions with name " + name + " in " + runConditionsRecords.size() + " records");
-        final ConditionsRecordCollection foundConditionsRecords = new ConditionsRecordCollection();
-        for (final ConditionsRecord record : runConditionsRecords) {
-            if (record.getName().equals(name)) {
-                if (this.matchesTag(record)) {
-                    try {
-                        foundConditionsRecords.add(record);
-                    } catch (final ConditionsObjectException e) {
-                        throw new RuntimeException(e);
-                    }
-                    logger.finer("found matching conditions record " + record.getRowId());
-                } else {
-                    logger.finer("conditions record " + record.getRowId() + " rejected from non-matching tag "
-                            + record.getTag());
-                }
-            }
-        }
-        logger.fine("found " + foundConditionsRecords.size() + " conditions records matching tag " + this.tag);
-        return foundConditionsRecords;
+        return getConditionsRecords().findByKey(name);
     }
 
     /**
@@ -479,31 +489,30 @@
         collection.setCollectionId(collectionId);
         return collectionId;
     }
-
-    /**
-     * Get a list of all the {@link ConditionsRecord} objects.
-     *
-     * @return the list of all the {@link ConditionsRecord} objects
-     */
-    // FIXME: This should use a cache that is created during initialization, rather than look these up every time.
+    
+    /**
+     * Get the list of conditions records for the run, filtered by the current set of active tags.
+     * 
+     * @return the list of conditions records for the run
+     */
     public ConditionsRecordCollection getConditionsRecords() {
-        logger.finer("getting conditions records ...");
-        final ConditionsRecordCollection conditionsRecords = new ConditionsRecordCollection();
-        for (final TableMetaData tableMetaData : this.tableRegistry.values()) {
-            try {
-                final ConditionsRecordCollection foundConditionsRecords = this.findConditionsRecords(tableMetaData
-                        .getKey());
-                logger.finer("found " + foundConditionsRecords.size() + " collections with name "
-                        + tableMetaData.getKey());
-                conditionsRecords.addAll(foundConditionsRecords);
-            } catch (final Exception e) {
-                e.printStackTrace();
-                logger.warning(e.getMessage());
-            }
-        }
-        logger.finer("found " + conditionsRecords + " conditions records");
-        logger.getHandlers()[0].flush();
-        return conditionsRecords;
+        if (this.run == -1 || this.detectorName == null) {
+            throw new IllegalStateException("Conditions system is not initialized.");
+        } 
+        // If the collection is null then the new conditions records need to be retrieved from the database.
+        if (this.conditionsRecordCollection == null) {
+            
+            // Get the collection of conditions that are applicable for the current run.
+            this.conditionsRecordCollection =  
+                    this.getCachedConditions(ConditionsRecordCollection.class, "conditions").getCachedData();
+            
+            // If there is one or more tags enabled then filter the collection by the tag names.
+            if (this.conditionsTagCollection.size() > 0) {
+                this.conditionsRecordCollection = 
+                        this.conditionsTagCollection.filter(this.conditionsRecordCollection);
+            }
+        }
+        return this.conditionsRecordCollection;
     }
 
     /**
@@ -671,11 +680,14 @@
 
         // Open the database connection.
         this.openConnection();
-
+        
+        // Reset the conditions records to trigger a re-caching.
+        this.conditionsRecordCollection = null;
+        
         // Call the super class's setDetector method to construct the detector object and activate conditions listeners.
         logger.fine("activating default conditions manager");
         super.setDetector(detectorName, runNumber);
-
+        
         // Should all conditions sets be cached?
         if (this.cacheAllConditions) {
             // Cache the conditions sets of all registered converters.
@@ -807,24 +819,11 @@
     }
 
     /**
-     * Return <code>true</code> if the conditions record matches the current tag
-     *
-     * @param record the conditions record
-     * @return <code>true</code> if conditions record matches the currently used tag
-     */
-    private boolean matchesTag(final ConditionsRecord record) {
-        if (this.tag == null) {
-            // If there is no tag set then all records pass.
-            return true;
-        }
-        final String recordTag = record.getTag();
-        if (recordTag == null) {
-            // If there is a tag set but the record has no tag, it is rejected.
-            return false;
-        }
-        return this.tag.equals(recordTag);
-    }
-
+     * Create a new collection with the given type.
+     * 
+     * @param collectionType the collection type
+     * @return the new collection
+     */
     public <CollectionType extends ConditionsObjectCollection<?>> CollectionType newCollection(
             final Class<CollectionType> collectionType) {
         final List<TableMetaData> tableMetaDataList = TableRegistry.getTableRegistry().findByCollectionType(
@@ -845,6 +844,13 @@
         return collection;
     }
 
+    /**
+     * Create a new collection with the given type and table name.
+     * 
+     * @param collectionType the collection type
+     * @param tableName the table name
+     * @return the new collection
+     */
     public <CollectionType extends ConditionsObjectCollection<?>> CollectionType newCollection(
             final Class<CollectionType> collectionType, final String tableName) {
         final TableMetaData tableMetaData = TableRegistry.getTableRegistry().findByTableName(tableName);
@@ -1040,31 +1046,69 @@
     }
 
     /**
-     * Set a tag used to filter the accessible conditions records
+     * Add a tag used to filter the accessible conditions records.
+     * <p>
+     * Multiple tags are OR'd together.
      *
      * @param tag the tag value used to filter returned conditions records
      */
-    public void setTag(final String tag) {
-        this.tag = tag;
-        logger.info("using conditions tag: " + tag);
+    public void addTag(final String tag) {
+        if (!this.tags.contains(tag)) {
+            logger.info("adding tag " + tag);
+            ConditionsTagCollection addConditionsTagCollection = this.getCachedConditions(ConditionsTagCollection.class, tag).getCachedData();
+            logger.info("adding conditions tag " + tag + " with " + conditionsTagCollection.size() + " records");
+            this.conditionsTagCollection.addAll(addConditionsTagCollection);                    
+        } else {
+            logger.warning("tag " + tag + " is already added");
+        }
+    }
+    
+    /**
+     * Add one or more tags for filtering records.
+     * 
+     * @param tags the <code>Set</code> of tags to add
+     */
+    public void addTags(final Set<String> tags) {
+        for (String tag : tags) {
+            this.addTag(tag);
+        }
+    }
+    
+    /**
+     * Clear the tags used to filter the {@link org.hps.conditons.api.ConditionsRecord}s.
+     */
+    public void clearTags() {
+        this.tags.clear();
+        this.conditionsTagCollection.clear();
     }
 
     /**
      * Setup the database connection from a file specified by a Java system property setting. This could be overridden
      * by subsequent API calls to {@link #setConnectionProperties(File)} or {@link #setConnectionResource(String)}.
      */
-    private void setupConnectionFromSystemProperty() {
-        final String systemPropertiesConnectionPath = (String) System.getProperties().get(CONNECTION_PROPERTY);
+    private void setupConnectionSystemPropertyFile() {
+        final String systemPropertiesConnectionPath = (String) System.getProperties().get(CONNECTION_PROPERTY_FILE);
         if (systemPropertiesConnectionPath != null) {
             final File f = new File(systemPropertiesConnectionPath);
             if (!f.exists()) {
-                throw new RuntimeException("Connection properties file from " + CONNECTION_PROPERTY
+                throw new RuntimeException("Connection properties file from " + CONNECTION_PROPERTY_FILE
                         + " does not exist.");
             }
             this.setConnectionProperties(f);
-            logger.info("connection setup from system property " + CONNECTION_PROPERTY + " = "
+            logger.info("connection setup from system property " + CONNECTION_PROPERTY_FILE + " = "
                     + systemPropertiesConnectionPath);
-        }
+        }                              
+    }
+    
+    /**
+     * Setup the database connection from a file specified by a Java system property setting. This could be overridden
+     * by subsequent API calls to {@link #setConnectionProperties(File)} or {@link #setConnectionResource(String)}.
+     */
+    private void setupConnectionSystemPropertyResource() {
+        final String systemPropertiesConnectionResource = (String) System.getProperties().get(CONNECTION_PROPERTY_RESOURCE);
+        if (systemPropertiesConnectionResource != null) {
+            this.setConnectionResource(systemPropertiesConnectionResource);
+        } 
     }
 
     /**

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/run/RunSpreadsheet.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/run/RunSpreadsheet.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/run/RunSpreadsheet.java	Fri Sep  4 12:59:35 2015
@@ -7,11 +7,9 @@
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Locale;
 import java.util.TimeZone;
 
 import org.apache.commons.csv.CSVFormat;

Modified: java/trunk/conditions/src/test/java/org/hps/conditions/EngRunConditionsTest.java
 =============================================================================
--- java/trunk/conditions/src/test/java/org/hps/conditions/EngRunConditionsTest.java	(original)
+++ java/trunk/conditions/src/test/java/org/hps/conditions/EngRunConditionsTest.java	Fri Sep  4 12:59:35 2015
@@ -220,7 +220,7 @@
 
         final DatabaseConditionsManager manager = DatabaseConditionsManager.getInstance();
         DatabaseConditionsManager.getLogger().setLevel(Level.ALL);
-        manager.setTag("pass0");
+        manager.addTag("pass0");
         manager.setXmlConfig("/org/hps/conditions/config/conditions_database_engrun.xml");
 
         final FileCache cache = new FileCache();

Copied: java/trunk/conditions/src/test/java/org/hps/conditions/api/ConditionsTagTest.java (from r3393, java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/api/ConditionsTagTest.java)
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/api/ConditionsTagTest.java	(original)
+++ java/trunk/conditions/src/test/java/org/hps/conditions/api/ConditionsTagTest.java	Fri Sep  4 12:59:35 2015
@@ -73,14 +73,15 @@
         for (int run : RUNS) {
             MANAGER.setDetector("HPS-conditions-test", run);
             ConditionsRecordCollection conditionsRecordCollection = MANAGER.getConditionsRecords();
-            System.out.println("run " + run + " has " + conditionsRecordCollection.size());
+            System.out.println("run " + run + " has " + conditionsRecordCollection.size() + " conditions records");
             System.out.println(conditionsRecordCollection);
             for (int i = 0; i < CONDITIONS.length; i++) {
                 try {
                     BaseConditionsObjectCollection<?> conditionsObjectCollection = 
                             BaseConditionsObjectCollection.class.cast(
                                     MANAGER.getCachedConditions(TYPES[i], CONDITIONS[i]).getCachedData());
-                System.out.println("got collection " + conditionsObjectCollection.getTableMetaData().getTableName() 
+                System.out.println("got collection " + conditionsObjectCollection.getTableMetaData().getTableName() + ":" 
+                        + conditionsObjectCollection.getCollectionId()
                         + " with type " + conditionsObjectCollection.getTableMetaData().getCollectionClass().getName() 
                         + " and " + conditionsObjectCollection.size() + " objects");
                 } catch (Exception e) {

Modified: java/trunk/evio/src/main/java/org/hps/evio/EvioToLcio.java
 =============================================================================
--- java/trunk/evio/src/main/java/org/hps/evio/EvioToLcio.java	(original)
+++ java/trunk/evio/src/main/java/org/hps/evio/EvioToLcio.java	Fri Sep  4 12:59:35 2015
@@ -404,10 +404,13 @@
             LOGGER.config("User set run number to " + runNumber + " with command option.");
         }
 
-        // Set the conditions system tag.
+        // Add conditions system tag filters.
         if (cl.hasOption("t")) {
-            final String tag = cl.getOptionValue("t");
-            DatabaseConditionsManager.getInstance().setTag(tag);
+            final String[] tags = cl.getOptionValues("t");
+            for (String tag : tags) {
+                LOGGER.config("adding conditions tag " + tag);
+                DatabaseConditionsManager.getInstance().addTag(tag);
+            }
         }
 
         // Is there a run number from the command line options?