package edu.hawaii.ics.yucheng; import java.io.FileNotFoundException; import java.io.FileReader; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Scanner; /** * The main routine of this project. */ public class DistributedDB { public static void main(String[] args) { assert null != args; // Print usage information, if wrong number of arguments were used. if (args.length != 2) { final String name = DistributedDB.class.getSimpleName(); System.err.println("Usage: java " + name + " <cofig> <SQLOrCSV>"); System.err.println(" <cofig> path to a configuration file"); System.err.println(" <SQLOrCSV> path to a SQL or CSV file"); System.exit(1); return; } // parse the SQL or CSV file and obtain the runner that executes proper // functionality, either execute the SQL statements or up load CSVs. try { final SharedConfiguration sharedConfig = new SharedConfiguration(args[0]); final ArrayList<String> sqlsOrCSV; if (sharedConfig.type == ConfigurationType.loadCSV) sqlsOrCSV = rawCSV(args[1]); else sqlsOrCSV = new SQLList(args[1]); Runnable runner = sharedConfig.getRunnable(sqlsOrCSV); runner.run(); } catch (final Exception e) { System.err.println("failed processing due to: " + e.getMessage()); System.exit(1); } } /** * reads a CSV file line after line and return a list of strings, which will * be parsed later. */ private static ArrayList<String> rawCSV(final String path) throws ProgramException { ArrayList<String> result = new ArrayList<String>(); try { final Scanner scanner = new Scanner(new FileReader(path)); try { while (scanner.hasNextLine()) result.add(scanner.nextLine()); return result; } finally { scanner.close(); } } catch (FileNotFoundException e) { throw new ProgramException("failed in rawCSV ", e); } } /** * Returns true if a specified table exists in a database. * * @param connection * The DBMS connection. * * @param tableName * The name of the table. * * @return True indicates the table exists. * * @throws ProgramException * Thrown if there is an error checking the meta-data of the * DBMS connection. */ public static boolean tableExists( final Connection connection, final String tableName) throws ProgramException { assert null != connection; assert null != tableName; try { // Get the tables matching the specified name. Check both lower and // upper case table names. final DatabaseMetaData meta = connection.getMetaData(); ResultSet set = meta.getTables( null, null, tableName, null); try { if (set.next()) return true; set = meta.getTables( null, null, tableName.toUpperCase(), null); return set.next(); } finally { set.close(); } } catch (final SQLException e) { throw new ProgramException(e); } } /** * Surrounds a specified string with single quotes. * * @param text * Some text to quote. * * @return The quoted text. */ public static String quote(final String text) { assert null != text; return "'" + text + "'"; } /** * Parses a command and returns the table name for the command, or null if * there is none. * * @param command * The SQL command. * * @return The table name within the command. */ public static String tableName(final String command) { assert null != command; // Search for the word TABLE. int index; final String upperCommand = command.toUpperCase(); if (-1 == (index = upperCommand.indexOf("TABLE") + 5)) return null; // Remove whitespace around the remaining portion of the command. String result = command.substring(index).trim(); // Look for the first occurrence of a special character. If a '.' is // encountered, remove this portion of the text, which is most likely // the schema. index = 0; while (index < result.length()) { final char ch = result.charAt(index); if (ch == '.') { result = result.substring(index + 1); index = 0; continue; } if (!Character.isLetterOrDigit(result.charAt(index))) break; index++; } // The remaining portion is the table name. result = result.substring(0, index); return result.length() == 0 ? null : result; } /** * Returns true if a specified command is of a specified type. * * @param command * The DDL command, e.g. "CREATE TABLE ...". * @param type * The command type, e.g. "CREATE". */ public static boolean isCommandType( final String command, final String type) { assert null != command; assert null != type; return command.toUpperCase().startsWith(type.toUpperCase()); } /** * Joins the thread and checks for errors. In the case of an error, a * warning is displayed, but no exception is thrown. */ public static void join(Thread thread, ConfigurationNode node) { try { thread.join(); } catch (final InterruptedException e) { node.log(System.err, "Failed to respond"); } } }