ConfigurationNode.java

package edu.hawaii.ics.yucheng;

import java.io.PrintStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * An immutable class that contains the configuration information of a node.
 * 
 * @author     Cheng Jade
 * @assignment ICS 421 Assignment 2-1
 * @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);
    }

    /**
     * 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("    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);
    }
}
Valid HTML 4.01 Valid CSS