package uk.org.ury.database; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import uk.org.ury.config.ConfigReader; import uk.org.ury.database.exceptions.ConnectionFailureException; import uk.org.ury.database.exceptions.MissingCredentialsException; /** * A database connection manager that connects to the URY databases using * suitably privileged accounts, and handles the processing of SQL queries. * * @author Matt Windsor * @author Nathan Lasseter * */ public class DatabaseDriver { /* The JDBC path used to connect to the URY database. */ private String DATABASE_PATH = "jdbc:postgresql://"; /* The database connection. */ private Connection conn; /** * Construct a new DatabaseDriver with the given user class. * * @param config * The config with login details. * * @param type * The user class to log in to the database with. * * @throws IllegalArgumentException * if the user class is not supported (this should not happen). * * @throws MissingCredentialsException * if the user class login credentials could not be loaded. * * @throws ConnectionFailureException * if the database backend failed to connect to the database * server. */ public DatabaseDriver(ConfigReader config, UserClass type) throws MissingCredentialsException, ConnectionFailureException { try { connect(config, type); } catch (SQLException e) { throw new ConnectionFailureException(e.getMessage()); } } /** * Connect to the URY database. * * @param config * The config to use for the connection. * @param type * The access level of the connection * * @throws SQLException * if the database connection failed. */ private void connect(ConfigReader config, UserClass type) throws SQLException { if (config == null) throw new IllegalArgumentException("Supplied null config."); if (config.getDatabase().getHost() == null) throw new IllegalArgumentException("config has no associated host."); if (config.getDatabase().getDb() == null) throw new IllegalArgumentException( "config has no associated database."); DATABASE_PATH = DATABASE_PATH + config.getDatabase().getHost() + "/" + config.getDatabase().getDb(); if (type == UserClass.READ_ONLY) { if (config.getRoAuth().getUser() == null) throw new IllegalArgumentException( "config has no associated username."); if (config.getRoAuth().getPass() == null) throw new IllegalArgumentException( "config has no associated password."); conn = DriverManager.getConnection(DATABASE_PATH, config .getRoAuth().getUser(), config.getRoAuth().getPass()); } else if (type == UserClass.READ_WRITE) { if (config.getRwAuth().getUser() == null) throw new IllegalArgumentException( "config has no associated username."); if (config.getRwAuth().getPass() == null) throw new IllegalArgumentException( "config has no associated password."); conn = DriverManager.getConnection(DATABASE_PATH, config .getRwAuth().getUser(), config.getRwAuth().getPass()); } } /** * Execute an unprepared SQL statement with no arguments. * * @param sql * The SQL statement to execute. * @param fetchSize * The maximum number of query rows to return. * * @return the JDBC results set. * * @throws SQLException * if a SQL error occurs. */ public ResultSet executeQuery(String sql, int fetchSize) throws SQLException { Statement st = conn.createStatement(); st.setFetchSize(fetchSize); return st.executeQuery(sql); } /** * Perform a SQL statement with arguments. * * This accepts an array of parameter objects, which must each either be * String or Integer objects. The objects will be used sequentially to fill * in '?' placeholders in the query text. * * @param sql * The SQL statement to execute. * @param params * A list of parameter objects. * @param fetchSize * The maximum number of query rows to return. * * @return the set of results from the query. * * @throws IllegalArgumentException * if any of the parameters is unsupported by the database as a * statement parameter. * * @throws SQLException * if a SQL error occurs. */ public ResultSet executeQuery(String sql, Object[] params, int fetchSize) throws SQLException { PreparedStatement st = conn.prepareStatement(sql); st.setFetchSize(fetchSize); for (int i = 0; i < params.length; i++) if (params[i] instanceof String) st.setString(i + 1, (String) params[i]); else if (params[i] instanceof Integer) st.setInt(i + 1, (Integer) params[i]); else throw new IllegalArgumentException("Unsupported parameter #" + (i + 1)); return st.executeQuery(); } }