Skip to content
Snippets Groups Projects
UploadReferenceTablesAction.java 7.78 KiB
Newer Older
  • Learn to ignore specific revisions
  • HMoss's avatar
    HMoss committed
    package edu.ncsu.csc.itrust.action;
    
    import java.io.BufferedInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Scanner;
    
    import edu.ncsu.csc.itrust.beans.CDCStatsBean;
    import edu.ncsu.csc.itrust.dao.DAOFactory;
    import edu.ncsu.csc.itrust.dao.mysql.CDCBmiStatsDAO;
    import edu.ncsu.csc.itrust.dao.mysql.CDCHeadCircStatsDAO;
    import edu.ncsu.csc.itrust.dao.mysql.CDCHeightStatsDAO;
    import edu.ncsu.csc.itrust.dao.mysql.CDCStatsDAO;
    import edu.ncsu.csc.itrust.dao.mysql.CDCWeightStatsDAO;
    import edu.ncsu.csc.itrust.exception.DBException;
    
    /**
     * UploadReferenceTablesAction is an action class that is used for uploading reference tables. It reads 
     * in csv files and parses and loads them to a specified reference table. Contains methods for storing 
     * csv files for weight, height, bmi, and head circumference statistics. Each store method also verifies 
     * whether the passed in file is correctly formatted.
     *
     */
    public class UploadReferenceTablesAction {
    	/**
    	 * Regex pattern to match the header format of a CDC health stats csv. Checks that header contains 
    	 * at least sex, age, L, M, and S fields
    	 */
    	private static final String headerFormat = "Sex,Agemos,L,M,S.*";
    	/**
    	 * Regex pattern to match each row of data in a CDC health stats csv. Checks that header contains at 
    	 * least sex, age, L, M, and S fields
    	 */
    	private static final String statsDataFormat = "\\d,\\d+\\.?\\d?(,-?\\d+\\.\\d+){3}(,-?\\d+\\.\\d+)*";
    	
    	private CDCWeightStatsDAO weightStatsDAO;
    	private CDCHeightStatsDAO heightStatsDAO;
    	private CDCHeadCircStatsDAO headCircStatsDAO;
    	private CDCBmiStatsDAO bmiStatsDAO;
    	
    	/**
    	 * Constructor for UploadReferenceTablesAction. Reads in DAOFactory and initializes 
    	 * CDCStatsDAO fields with the factory.
    	 * @param factory the DAOfactory to use for database transactions
    	 */
    	public UploadReferenceTablesAction(DAOFactory factory) {
    		weightStatsDAO = new CDCWeightStatsDAO(factory);
    		heightStatsDAO = new CDCHeightStatsDAO(factory);
    		headCircStatsDAO = new CDCHeadCircStatsDAO(factory);
    		bmiStatsDAO = new CDCBmiStatsDAO(factory);
    	}
    	
    	/**
    	 * Parses a CSV file and stores the statistics for average patient weights
    	 * @param weightCSV InputStream object with weight statistics csv file
    	 * @return true if data is stored correctly in the database.
    	 * 		   false if csv file is of the incorrect format and cannot be stored
    	 */
    	public boolean storeWeightStats(InputStream weightCSV) {
    		return storeCDCStats(weightCSV, weightStatsDAO);
    	}
    	
    	/**
    	 * Parses a CSV file and stores the statistics for average patient heights/lengths
    	 * @param heightCSV InputStream object with height statistics csv file
    	 * @return true if data is stored correctly in the database.
    	 * 		   false if csv file is of the incorrect format and cannot be stored
    	 */
    	public boolean storeHeightStats(InputStream heightCSV) {
    		return storeCDCStats(heightCSV, heightStatsDAO);
    	}
    	
    	/**
    	 * Parses a CSV file and stores the statistics for average patient head circumferences
    	 * @param  @param headCircCSV InputStream object with head circumference statistics csv file
    	 * @return true if data is stored correctly in the database.
    	 * 		   false if csv file is of the incorrect format and cannot be stored
    	 */
    	public boolean storeHeadCircStats(InputStream headCircCSV) {
    		return storeCDCStats(headCircCSV, headCircStatsDAO);
    	}
    	
    	/**
    	 * Parses a CSV file and stores the statistics for average patient BMIs
    	 * @param bmiCSV InputStream object with bmi statistics csv file
    	 * @return true if data is stored correctly in the database.
    	 * 		   false if csv file is of the incorrect format and cannot be stored
    	 */
    	public boolean storeBMIStats(InputStream bmiCSV) {
    		return storeCDCStats(bmiCSV, bmiStatsDAO);
    	}
    	
    	/**
    	 * Parses a csv file and sends it to the CDCStatsDAO that is passed in to store the data. 
    	 * First verifies whether the csv file is formatted correctly. If the file is of the correct
    	 * format then the file is parsed and passed into the specified CDCStatsDAO for storing.
    	 * @param healthStatsCSV InputStream with the csv file containing the health statistics to 
    	 * store in the database
    	 * @param dao the CDCStatsDAO to use to store the data from the csv file
    	 * @return true if data is stored correctly in the database.
    	 * 		   false if csv file is of the incorrect format and cannot be stored
    	 */
    	@SuppressWarnings("resource")
    	private boolean storeCDCStats(InputStream healthStatsCSV, CDCStatsDAO dao) {
    		BufferedInputStream csvFile = new BufferedInputStream(healthStatsCSV);
    		try {
    			csvFile.mark(csvFile.available() + 1);
    			//If the csv file cannot be verified, close the InputStream and return false
    			if (!verifyCDCStatsCSV(csvFile)) {
    				csvFile.close();
    				return false;
    			}
    			csvFile.reset();
    		} catch (IOException e) {
    			return false;
    		}
    		
    		//Create scanner to read each line of data in the csv
    		Scanner csvScanner = new Scanner(csvFile, "UTF-8");
    		//Scanner to parse through each row of data
    		Scanner rowScanner = null;
    		//String for saving a row of data
    		String row = "";
    		
    		//Scan and throw away the header line.
    		csvScanner.nextLine();
    		
    		//CDCStatsBean for storing health metric statistics taken from the csv file
    		CDCStatsBean statsBean = null;
    		
    		try {
    			while (csvScanner.hasNextLine()) {
    				//Create new CDCStatsBean for storing a new row of data
    				statsBean = new CDCStatsBean();
    				
    				//Read a row of data
    				row = csvScanner.nextLine();
    				
    				//Read the next row if row is a header
    				if (row.matches(headerFormat))
    					continue;
    				
    				//Create scanner to parse each row by using commas as the delimiter
    				rowScanner = new Scanner(row).useDelimiter(",");
    				//Get the sex field
    				statsBean.setSex(rowScanner.nextInt());
    				//Get the age field
    				statsBean.setAge(rowScanner.nextFloat());
    				//Get the L field
    				statsBean.setL(rowScanner.nextDouble());
    				//Get the M field
    				statsBean.setM(rowScanner.nextDouble());
    				//Get the S field
    				statsBean.setS(rowScanner.nextDouble());
    				
    				//Insert CDCStatsBean into the database
    				dao.storeStats(statsBean);
    			}
    		} catch (DBException e) {
    			//If there is a DBException close the InputStream and 
    			//return false since not all the data has been added correctly
    			try {
    				healthStatsCSV.close();
    			} catch (IOException e1) {
    				//Still return false if I/O error occurs
    			}
    			return false;
    		}
    		
    		return true;	
    	}
    	
    	/**
    	 * Verifies that a health stats csv file is of the correct format. Checks that the header is formatted
    	 * correctly, and then checks that each data row contains only integers, doubles, and commas
    	 * @param healthStatsCSV InputStream with the csv file whose format needs to be checked
    	 * @return true if the csv file is correctly formatted. false otherwise.
    	 */
    	@SuppressWarnings("resource")
    	private boolean verifyCDCStatsCSV(InputStream healthStatsCSV) {
    		//Create scanner to read each line of data in the csv
    		Scanner csvScanner = new Scanner(healthStatsCSV, "UTF-8");
    		//String for holding a line of data from the CSV file
    		String line = "";
    		
    		//Read the header line
    		if (csvScanner.hasNextLine()) {
    			line = csvScanner.nextLine();
    		} else {
    			csvScanner.close();
    			//If the csv file does not contain a line, the csv file is incorrect
    			return false;
    		}
    		//If the header line is incorrectly formatted then the csv file is incorrect
    		if (!line.matches(headerFormat)) {
    			csvScanner.close();
    			return false;
    		}
    		
    		//Verify that each consecutive line follows correct formatting
    		while (csvScanner.hasNextLine()) {
    			line = csvScanner.nextLine();
    			//If none of the lines match a data line format nor a header line
    			//format then the csv file is incorrect
    			if (!line.matches(statsDataFormat) && !line.matches(headerFormat)) {
    				csvScanner.close();
    				return false;
    			}
    		}
    		
    		//The csv file passes the verification process it is deemed correct
    		return true;
    	}
    }