package edu.hawaii.ics.yucheng; import java.io.PrintStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Properties; /** * An immutable class that contains the configuration information of a node. * * @author Cheng Jade * @assignment ICS 421 Project * @date Feb 29, 2010 * @bugs None */ public final class ConfigurationNode { /** The driver name used for the database connection. */ public final String driver; /** The host name URI for the database server. */ public final String hostname; /** A name used for identifying the thread responsible for this instance. */ public final String name; /** The password for the database connection. */ public final String password; /** The user name for the database connection. */ public final String username; /** * Initializes a new instance of the ConfigurationNode class. * * @param name * The name used for identifying the thread responsible for this * instance. * @param driver * The driver name used for the database connection. * @param hostname * The host name URI for the database server. * @param username * The user name for the database connection. * @param password * The password for the database connection. * * @throws NullPointerException * @throws ProgramException * Thrown if any parameter is null. */ public ConfigurationNode(final String name, final String driver, final String hostname, final String username, final String password) throws ProgramException { // Check if any parameter is null, and throw exception in that case. if (null == name) throw new NullPointerException("name"); if (null == driver) throw new NullPointerException("driver"); if (null == hostname) throw new NullPointerException("hostname"); if (null == username) throw new NullPointerException("username"); if (null == password) throw new NullPointerException("password"); // Assign the parameter values to the class fields. this.name = name; this.driver = driver; this.hostname = hostname; this.username = username; this.password = password; } /** * Initializes a new instance of the ConfigurationNode class. * * @param properties * A properties object that the configuration node will be loaded * from. * @param name * The name used for identifying the thread responsible for this * instance. * * @throws NullPointerException * @throws ProgramException * Thrown if the reading properties goes wrong. */ public ConfigurationNode(final Properties properties, final String name) throws ProgramException { // Read the corresponding lines from the properties object, and use the // values as the parameters to call the other constructor, which assigns // the class fields to those values. this(name, read(properties, name, "driver"), read(properties, name, "hostname"), read(properties, name, "username"), read(properties, name, "passwd")); } /** * Creates a key and looks up a value in the properties object. The value is * returned if it is found; otherwise, an exception is thrown. * * @return The key word to search for in the properties file. * * @throws NullPointerException * @throws ProgramException * Thrown if the key is not found in the properties object. */ private static String read(final Properties properties, final String prefix, final String name) throws ProgramException { assert null != name; // Check if the properties and prefix are not nulls. if (null == properties) throw new NullPointerException("properties"); if (null == prefix) throw new NullPointerException("prefix"); // Create the key to search for according to the prefix and name. final String key = prefix + "." + name; // Search for the key and return the corresponding value. final String value = properties.getProperty(key); if (null == value) throw new ProgramException("Property '" + key + "' not found in configuration file."); return value; } /** * Logs a message to a specified output stream. * * @param stream * The output stream, e.g. System.out. * * @param message * The message to log. */ public void log(final PrintStream stream, final String message) { assert null != stream; stream.println("[" + this.hostname + "]: " + message); } public ArrayList<ConfigurationNode> getNodesFromCatalog(final String tableName) throws ProgramException { final ArrayList<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>(); // connect the catalog and retrieve the nodes. try { this.runStatement(new StatementRunner() { public void run(final Statement statement) throws ProgramException, SQLException { final ResultSet set = statement.executeQuery("SELECT * FROM DTABLES WHERE TNAME = '" + tableName + "' OR TNAME = " + "UCASE('" + tableName + "')"); while (set.next()) { final String driver = set.getString("NODEDRIVER").trim(); final String url = set.getString("NODEURL").trim(); final String user = set.getString("NODEUSER").trim(); final String password = set.getString("NODEPASSWD").trim(); final String name = "node" + set.getString("NODEID").trim(); nodes.add(new ConfigurationNode(name, driver, url, user, password)); } } }); } catch (final Exception e) { throw new ProgramException(e.getMessage(), e); } return nodes; } /** * Creates a new statement and executes it through the specified statement * runner. * * @param runner * The statement runner. * * @throws NullPointerException * @throws ProgramException * Thrown if there is an error executing the statement. */ public void runStatement(final StatementRunner runner) throws ProgramException { if (null == runner) throw new NullPointerException("runner"); // Open the connection. try { final Connection connection = this.getConnection(); // Create the statement object. try { final Statement statement = connection.createStatement(); try { // Execute the statement. runner.run(statement); } finally { // Always close the statement. statement.close(); } } finally { // Always close the connection. connection.close(); } } catch (final SQLException e) { // Wrap and re-throw SQL exceptions. throw new ProgramException(e); } } /** * Returns a readable version of the contents of the Configuration Node. * * @return A readable version of the contents of the Configuration Node. */ @Override public String toString() { final StringBuilder builder = new StringBuilder(); builder.append(" Name: "); builder.append(this.name); builder.append("\n Driver: "); builder.append(this.driver); builder.append("\n Hostname: "); builder.append(this.hostname); builder.append("\n Username: "); builder.append(this.username); builder.append("\n Password: "); builder.append(this.password); return builder.toString(); } /** * Checks the DBMS driver is available. * * @throws ProgramException * Thrown if the DBMS driver is not available. */ private void checkDriver() throws ProgramException { // Create an instance of the driver if possible. try { Class.forName(this.driver).newInstance(); return; } catch (final InstantiationException e) { System.out.println("InstantiationException"); } catch (final IllegalAccessException e) { System.out.println("IllegalAccessException"); } catch (final ClassNotFoundException e) { System.out.println("ClassNotFoundException: " + e.getMessage()); } // In any other case, throw an exception indicating the failure. throw new ProgramException("Cannot load driver '" + this.driver + "'."); } /** * Gets a connection to the DBMS database. * * @throws ProgramException * Thrown if the connection cannot be made. */ private Connection getConnection() throws ProgramException { // First, check the driver is available. this.checkDriver(); // Next, create and return a new connection based on the instance data. try { return DriverManager.getConnection(this.hostname, this.username, this.password); } catch (final SQLException e) { // Wrap and re-throw SQL exceptions. final String message = "Cannot connect to '" + this.hostname + "'."; throw new ProgramException(message, e); } } /** * The entry point for a test for this class. * * @param args * The command line arguments (not used). */ public static void main(final String[] args) { // Declare, initialize, and print a ConfigurationNode object. try { System.out.println(new ConfigurationNode("a", "b", "c", "d", "e")); } catch (final ProgramException e) { System.err.println(e.getMessage()); System.exit(1); return; } // Exit cleanly while debugging from Eclipse. System.exit(0); } }