Author: [log in to unmask]
Date: Mon Apr 27 18:27:46 2015
New Revision: 2837
Log:
Rewrite the load command.
Modified:
java/branches/HPSJAVA-488/conditions/src/main/java/org/hps/conditions/cli/LoadCommand.java
Modified: java/branches/HPSJAVA-488/conditions/src/main/java/org/hps/conditions/cli/LoadCommand.java
=============================================================================
--- java/branches/HPSJAVA-488/conditions/src/main/java/org/hps/conditions/cli/LoadCommand.java (original)
+++ java/branches/HPSJAVA-488/conditions/src/main/java/org/hps/conditions/cli/LoadCommand.java Mon Apr 27 18:27:46 2015
@@ -2,20 +2,29 @@
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
+import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
+import org.hps.conditions.api.BaseConditionsObjectCollection;
+import org.hps.conditions.api.ConditionsObject;
+import org.hps.conditions.api.ConditionsObjectCollection;
+import org.hps.conditions.api.ConditionsObjectException;
+import org.hps.conditions.api.DatabaseObjectException;
+import org.hps.conditions.api.TableMetaData;
import org.hps.conditions.database.DatabaseConditionsManager;
-import org.hps.conditions.database.QueryBuilder;
import org.lcsim.util.log.LogUtil;
+import org.lcsim.util.log.MessageOnlyLogFormatter;
/**
* This is a sub-command to add conditions data using an input text file. The file should be ASCII text that is tab or
@@ -34,10 +43,15 @@
*/
final class LoadCommand extends AbstractCommand {
- /**
- * Setup logger.
- */
- private static final Logger LOGGER = LogUtil.create(LoadCommand.class);
+ /**
+ * The default separator for making tokens from input data.
+ */
+ private static final String DEFAULT_FIELD_SEPARATOR = " \t";
+
+ /**
+ * Setup the logger.
+ */
+ private static final Logger LOGGER = LogUtil.create(LoadCommand.class, new MessageOnlyLogFormatter(), Level.ALL);
/**
* Define command options.
@@ -45,20 +59,23 @@
private static final Options OPTIONS = new Options();
static {
OPTIONS.addOption(new Option("h", false, "print help for load command"));
- OPTIONS.addOption(new Option("t", true, "name of the target table in the database"));
- OPTIONS.addOption(new Option("f", true, "input data file"));
- OPTIONS.addOption(new Option("d", true, "description of collection data"));
+ OPTIONS.addOption(new Option("t", true, "name of the target table (required)"));
+ OPTIONS.getOption("t").setRequired(true);
+ OPTIONS.addOption(new Option("f", true, "input data file path (required)"));
+ OPTIONS.getOption("f").setRequired(true);
+ OPTIONS.addOption(new Option("d", true, "description of the collection for log"));
+ OPTIONS.addOption(new Option("s", true, "field seperator string (default is tabs or spaces)"));
}
/**
* Class constructor.
*/
LoadCommand() {
- super("load", "Load a set of conditions into the database from a text file", OPTIONS);
- }
-
- /**
- * Execute the 'load' command with the given arguments.
+ super("load", "Create a new conditions collection in the database from an input text file", OPTIONS);
+ }
+
+ /**
+ * Execute the <i>load</i> command with the given arguments.
*
* @param arguments the command arguments
*/
@@ -87,65 +104,158 @@
openedConnection = conditionsManager.openConnection();
}
- String collectionDescription = null;
+ String description = null;
if (commandLine.hasOption("d")) {
- collectionDescription = commandLine.getOptionValue("d");
- }
-
- int collectionId;
- try {
- collectionId = conditionsManager.addCollection(tableName,
- "loaded with command line client by " + System.getProperty("user.name"), collectionDescription);
- } catch (final SQLException e) {
- throw new RuntimeException("Error getting new collection ID.", e);
- }
-
- final List<String> columnNames = new ArrayList<String>();
- final List<List<String>> rows = new ArrayList<List<String>>();
- this.parseFile(fileName, columnNames, rows);
-
- final String insertSql = QueryBuilder.buildInsert(tableName, collectionId, columnNames, rows);
- LOGGER.info(insertSql);
-
- // FIXME: This call should go through an object API like ConditionsObjectCollection.insert rather than the
- // manager directly.
- final List<Integer> ids = conditionsManager.updateQuery(insertSql);
- LOGGER.info("Inserted " + ids.size() + " new rows into table " + tableName + " with collection_id "
- + collectionId);
+ description = commandLine.getOptionValue("d");
+ }
+
+ String separator = DEFAULT_FIELD_SEPARATOR;
+ if (commandLine.hasOption("s")) {
+ separator = commandLine.getOptionValue("s");
+ LOGGER.info("using separator character <" + separator + ">");
+ }
+
+ TableMetaData tableMetaData = conditionsManager.findTableMetaData(tableName);
+ BaseConditionsObjectCollection<ConditionsObject> newCollection = null;
+ try {
+ // Create a new collection. We don't use the specific type here because that won't work later when adding objects to it.
+ newCollection = new BaseConditionsObjectCollection<ConditionsObject>(conditionsManager.getConnection(), tableMetaData);
+ } catch (SQLException | DatabaseObjectException e) {
+ throw new RuntimeException("Error creating new collection.", e);
+ }
+
+ LOGGER.info("getting new collection ID ...");
+
+ try {
+ conditionsManager.getCollectionId(newCollection, description);
+ } catch (SQLException e) {
+ throw new RuntimeException("Error getting collection ID.", e);
+ }
+
+ LOGGER.info("collection was assigned ID " + newCollection.getCollectionId());
+
+ LOGGER.info("parsing input file " + fileName + " ...");
+ this.parseFile(fileName, newCollection, separator);
+ LOGGER.info("Done parsing input file!");
+
+ try {
+ LOGGER.info("Inserting collection ...");
+ newCollection.insert();
+ LOGGER.info("Done inserting collection!");
+ } catch (SQLException | DatabaseObjectException e) {
+ throw new RuntimeException("Error getting collection ID.", e);
+ }
+
conditionsManager.closeConnection(openedConnection);
}
-
- /**
- * Parse an input text file and add column names and row data to the input lists.
+
+ /**
+ * Parse an input text file and create conditions objects from its row data.
*
* @param fileName the name of the text file
- * @param columnNames the list of columns (modified by this method)
- * @param rows the list of rows (modified by this method)
- */
- private final void parseFile(final String fileName, final List<String> columnNames, final List<List<String>> rows) {
- final File inputFile = new File(fileName);
+ * @param collection the collection into which objects will be inserted
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private final void parseFile(final String fileName, final ConditionsObjectCollection collection, final String seperator) {
+
BufferedReader reader = null;
- try {
+
+ try {
+ final File inputFile = new File(fileName);
reader = new BufferedReader(new FileReader(inputFile));
+
+ LOGGER.info("reading in header line ...");
+
+ // Read in the header line with column names.
final String headerLine = reader.readLine();
+ LOGGER.info("got header line: " + headerLine);
if (headerLine == null) {
throw new IllegalArgumentException("The file is empty.");
}
- StringTokenizer tokenizer = new StringTokenizer(headerLine, " \t");
+ StringTokenizer tokenizer = new StringTokenizer(headerLine, seperator);
+ List<String> columnNames = new ArrayList<String>();
while (tokenizer.hasMoreTokens()) {
- columnNames.add(tokenizer.nextToken().trim());
- }
+ String columnName = tokenizer.nextToken().trim();
+ LOGGER.info("read column name: " + columnName);
+ columnNames.add(columnName);
+ }
+ if (columnNames.isEmpty()) {
+ throw new RuntimeException("No column names found in file.");
+ }
+
+ // Get table info.
+ TableMetaData tableMetaData = collection.getTableMetaData();
+ Class<? extends ConditionsObject> objectClass = tableMetaData.getObjectClass();
+
+ // Get the field names from the table info.
+ List<String> fieldNames = new ArrayList<String>(Arrays.asList(tableMetaData.getFieldNames()));
+ fieldNames.remove("collection_id");
+
+ // Check that the column names which were read in from the header row are valid.
+ for (String columnName : columnNames) {
+ LOGGER.info("checking column: " + columnName);
+ if (!fieldNames.contains(columnName)) {
+ throw new RuntimeException("Unknown column name: " + columnName);
+ }
+ }
+
+ // Read lines from the file.
String line = null;
+ int lineNumber = 1;
while ((line = reader.readLine()) != null) {
+
+ LOGGER.info("reading line " + lineNumber);
+
+ // Create a new conditions object for the row.
+ ConditionsObject object;
+ try {
+ object = objectClass.newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new RuntimeException("Error creating new object.", e);
+ }
+
+ // Parse the line.
tokenizer = new StringTokenizer(line, " \t");
- final List<String> row = new ArrayList<String>();
- while (tokenizer.hasMoreTokens()) {
- row.add(tokenizer.nextToken().trim());
+ int tokens = tokenizer.countTokens();
+
+ // Check that the number of data items is correct.
+ if (tokens != columnNames.size()) {
+ throw new RuntimeException("Row " + lineNumber + " has wrong number of data items.");
}
- rows.add(row);
- }
- } catch (final Exception e) {
- throw new RuntimeException(e);
+
+ // Iterate over the tokens.
+ for (int i = 0; i < tokens; i++) {
+
+ LOGGER.info("proc token " + i);
+
+ // Get the column name.
+ String columnName = columnNames.get(i);
+
+ // Get the column type.
+ Class<?> columnType = tableMetaData.getFieldType(columnName);
+
+ // Get the value of the cell.
+ String value = tokenizer.nextToken();
+
+ LOGGER.info("columnName: " + columnName);
+ LOGGER.info("columnType: " + columnType.getName());
+ LOGGER.info("value: " + value);
+
+ // Convert the value to a specific type and set the value on the object.
+ object.setFieldValue(columnNames.get(i), convertValue(columnType, value));
+
+ // Add the object to the collection.
+ LOGGER.info("adding conditions object: " + object);
+ collection.add(object);
+ }
+ ++lineNumber;
+ }
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException("The input file does not exist.", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Error reading from the file.", e);
+ } catch (ConditionsObjectException e) {
+ throw new RuntimeException("Error adding object to collection.", e);
} finally {
if (reader != null) {
try {
@@ -153,7 +263,28 @@
} catch (final IOException e) {
e.printStackTrace();
}
- }
- }
- }
+ }
+ }
+ }
+
+ /**
+ * Convert from a raw string into a specific type.
+ *
+ * @param type the target type
+ * @param value the raw value
+ * @return the value converter to the given type
+ */
+ Object convertValue(Class<?> type, String value) {
+ if (Integer.class.equals(type)) {
+ return Integer.parseInt(value);
+ } else if (Double.class.equals(type)) {
+ return Double.parseDouble(value);
+ } else if (Float.class.equals(type)) {
+ return Float.parseFloat(value);
+ } else if (Boolean.class.equals(type)) {
+ return Boolean.parseBoolean(value);
+ } else {
+ return value;
+ }
+ }
}
|