Print

Print


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;
+    	}
+    }    
 }