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");
}
}
}