aboutsummaryrefslogtreecommitdiff
path: root/src/uk/org/ury/backend/database
diff options
context:
space:
mode:
authorMatt Windsor <mattwindsor@btinternet.com>2011-03-21 21:54:31 +0000
committerMatt Windsor <mattwindsor@btinternet.com>2011-03-21 21:54:31 +0000
commitdf7d7981b56a4560c95ea7e9b194080e93398ecf (patch)
treeb3ae4f02d23ae1f7f4951c776ee8d91b0047dd6f /src/uk/org/ury/backend/database
parent2d073129857a42ab4195cd433c8be152e357033f (diff)
GREAT PACKAGE RESHUFFLE: Everything is now organised into frontend, backend and common (to frontend and backend) packages. Things may have been broken. Doc refresh.
Diffstat (limited to 'src/uk/org/ury/backend/database')
-rw-r--r--src/uk/org/ury/backend/database/DatabaseDriver.java166
-rw-r--r--src/uk/org/ury/backend/database/DatabaseItem.java80
-rw-r--r--src/uk/org/ury/backend/database/UserClass.java38
-rw-r--r--src/uk/org/ury/backend/database/exceptions/ConnectionFailureException.java44
-rw-r--r--src/uk/org/ury/backend/database/exceptions/MissingCredentialsException.java52
-rw-r--r--src/uk/org/ury/backend/database/exceptions/MissingPropertyException.java47
-rw-r--r--src/uk/org/ury/backend/database/exceptions/QueryFailureException.java45
-rw-r--r--src/uk/org/ury/backend/database/exceptions/package.html11
-rw-r--r--src/uk/org/ury/backend/database/package.html15
9 files changed, 498 insertions, 0 deletions
diff --git a/src/uk/org/ury/backend/database/DatabaseDriver.java b/src/uk/org/ury/backend/database/DatabaseDriver.java
new file mode 100644
index 0000000..5cd9b98
--- /dev/null
+++ b/src/uk/org/ury/backend/database/DatabaseDriver.java
@@ -0,0 +1,166 @@
+package uk.org.ury.backend.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.backend.config.ConfigReader;
+import uk.org.ury.backend.database.exceptions.ConnectionFailureException;
+import uk.org.ury.backend.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();
+ }
+}
diff --git a/src/uk/org/ury/backend/database/DatabaseItem.java b/src/uk/org/ury/backend/database/DatabaseItem.java
new file mode 100644
index 0000000..b25e9f2
--- /dev/null
+++ b/src/uk/org/ury/backend/database/DatabaseItem.java
@@ -0,0 +1,80 @@
+package uk.org.ury.backend.database;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import uk.org.ury.backend.database.exceptions.MissingPropertyException;
+
+/**
+ * An abstract class presenting a template for objects serving as a data
+ * structure for collections of properties retrieved from a SQL database.
+ *
+ * @param E
+ * The enumeration type used as the property list.
+ *
+ * @param T
+ * The type of datum stored for each property.
+ *
+ * @author Matt Windsor
+ */
+public abstract class DatabaseItem<E, T> {
+ private Map<E, T> properties;
+
+ /**
+ * Construct a new item from an existing list of properties.
+ *
+ * @param properties
+ * The map of properties that the new item will inherit.
+ */
+ public DatabaseItem(Map<E, T> properties) {
+ this.properties = properties;
+ }
+
+ /**
+ * Check whether a property has been set in the item.
+ *
+ * @return true if the property has been set; false otherwise.
+ */
+
+ public boolean has(E property) {
+ return properties.containsKey(property);
+ }
+
+ /**
+ * Query this item for a property.
+ *
+ * @param property
+ * The property to query.
+ *
+ * @return The property, if it exists.
+ *
+ * @throws MissingPropertyException
+ * if the property does not exist.
+ */
+ public T get(E property) throws MissingPropertyException {
+ if (properties.containsKey(property))
+ return properties.get(property);
+ else
+ throw new MissingPropertyException(property.toString());
+ }
+
+ /**
+ * Retrieve a map of string representations of the properties.
+ *
+ * This relies on E and T having meaningful toString methods.
+ *
+ * @return a list of lines representing the response.
+ */
+ public Map<String, String> asResponse() {
+ // TODO: Fan out implementation details into separate class
+ Map<String, String> response = new HashMap<String, String>();
+
+ for (E property : properties.keySet()) {
+ if (properties.get(property) != null)
+ response.put(property.toString(), properties.get(property)
+ .toString());
+ }
+
+ return response;
+ }
+}
diff --git a/src/uk/org/ury/backend/database/UserClass.java b/src/uk/org/ury/backend/database/UserClass.java
new file mode 100644
index 0000000..1cd39fc
--- /dev/null
+++ b/src/uk/org/ury/backend/database/UserClass.java
@@ -0,0 +1,38 @@
+/**
+ *
+ */
+package uk.org.ury.backend.database;
+
+/**
+ * The various user classes of the database driver.
+ *
+ * These refer to various users in the database proper, and thus grant various
+ * levels of permission to the program.
+ *
+ * Please use the least privileged user class that works. For most cases,
+ * READ_ONLY should work perfectly.
+ *
+ * @author Matt Windsor
+ *
+ */
+
+public enum UserClass {
+ // Constant configName
+ READ_ONLY ("read_only"),
+ READ_WRITE ("read_write");
+
+ /**
+ * The name of the tag in the configuration file that contains the
+ * credentials for this user class.
+ */
+ public String configName;
+
+ /**
+ * Constructs a new UserClass.
+ *
+ * @param configName The name of the user class in the config.
+ */
+ private UserClass(String configName) {
+ this.configName = configName;
+ }
+}
diff --git a/src/uk/org/ury/backend/database/exceptions/ConnectionFailureException.java b/src/uk/org/ury/backend/database/exceptions/ConnectionFailureException.java
new file mode 100644
index 0000000..393f3ce
--- /dev/null
+++ b/src/uk/org/ury/backend/database/exceptions/ConnectionFailureException.java
@@ -0,0 +1,44 @@
+/**
+ *
+ */
+package uk.org.ury.backend.database.exceptions;
+
+/**
+ * Exception thrown when the database backend fails to connect to
+ * the database server, in absence of a more specific exception.
+ *
+ * @author Matt Windsor
+ */
+
+public class ConnectionFailureException extends Exception
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7353531873142099828L;
+
+
+/**
+ * Construct a new ConnectionFailureException with a
+ * default reason.
+ */
+
+ public
+ ConnectionFailureException ()
+ {
+ super ("Connection failure.");
+ }
+
+
+ /**
+ * Construct a new ConnectionFailureException.
+ *
+ * @param reason The explanation for the exception.
+ */
+
+ public
+ ConnectionFailureException (String reason)
+ {
+ super (reason);
+ }
+}
diff --git a/src/uk/org/ury/backend/database/exceptions/MissingCredentialsException.java b/src/uk/org/ury/backend/database/exceptions/MissingCredentialsException.java
new file mode 100644
index 0000000..4c73683
--- /dev/null
+++ b/src/uk/org/ury/backend/database/exceptions/MissingCredentialsException.java
@@ -0,0 +1,52 @@
+/**
+ *
+ */
+package uk.org.ury.backend.database.exceptions;
+
+/**
+ * Exception thrown when the database credentials required to
+ * log into the URY database under a user class are missing,
+ * and thus the log-in cannot continue.
+ *
+ * The best practice for handling a MissingCredentialsException
+ * is to attempt to log into the database with a less privileged
+ * user class or, if the credentials for read-only access are
+ * missing, give up.
+ *
+ * @author Matt Windsor
+ */
+
+public class MissingCredentialsException extends Exception
+{
+
+ /**
+ *
+ */
+
+ private static final long serialVersionUID = -397479334359858162L;
+
+
+ /**
+ * Construct a new MissingCredentialsException with a
+ * default reason.
+ */
+
+ public
+ MissingCredentialsException ()
+ {
+ super ("Missing credentials.");
+ }
+
+
+ /**
+ * Construct a new MissingCredentialsException.
+ *
+ * @param reason The explanation for the exception.
+ */
+
+ public
+ MissingCredentialsException (String reason)
+ {
+ super (reason);
+ }
+}
diff --git a/src/uk/org/ury/backend/database/exceptions/MissingPropertyException.java b/src/uk/org/ury/backend/database/exceptions/MissingPropertyException.java
new file mode 100644
index 0000000..485771b
--- /dev/null
+++ b/src/uk/org/ury/backend/database/exceptions/MissingPropertyException.java
@@ -0,0 +1,47 @@
+/**
+ *
+ */
+package uk.org.ury.backend.database.exceptions;
+
+
+/**
+ * Exception thrown when a DatabaseItem is queried for a property
+ * that does not exist.
+ *
+ * This is (usually) not a fatal error.
+ *
+ * @author Matt Windsor
+ */
+
+public class MissingPropertyException extends Exception
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7353531873142099828L;
+
+
+/**
+ * Construct a new MissingPropertyException with a
+ * default reason.
+ */
+
+ public
+ MissingPropertyException ()
+ {
+ super ("Query failure.");
+ }
+
+
+ /**
+ * Construct a new MissingPropertyException.
+ *
+ * @param reason The explanation for the exception.
+ */
+
+ public
+ MissingPropertyException (String reason)
+ {
+ super (reason);
+ }
+}
diff --git a/src/uk/org/ury/backend/database/exceptions/QueryFailureException.java b/src/uk/org/ury/backend/database/exceptions/QueryFailureException.java
new file mode 100644
index 0000000..6c01e61
--- /dev/null
+++ b/src/uk/org/ury/backend/database/exceptions/QueryFailureException.java
@@ -0,0 +1,45 @@
+/**
+ *
+ */
+package uk.org.ury.backend.database.exceptions;
+
+
+/**
+ * Exception thrown when the database backend fails to execute
+ * a query.
+ *
+ * @author Matt Windsor
+ */
+
+public class QueryFailureException extends Exception
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7353531873142099828L;
+
+
+/**
+ * Construct a new QueryFailureException with a
+ * default reason.
+ */
+
+ public
+ QueryFailureException ()
+ {
+ super ("Query failure.");
+ }
+
+
+ /**
+ * Construct a new QueryFailureException.
+ *
+ * @param reason The explanation for the exception.
+ */
+
+ public
+ QueryFailureException (String reason)
+ {
+ super (reason);
+ }
+}
diff --git a/src/uk/org/ury/backend/database/exceptions/package.html b/src/uk/org/ury/backend/database/exceptions/package.html
new file mode 100644
index 0000000..b5e7cac
--- /dev/null
+++ b/src/uk/org/ury/backend/database/exceptions/package.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+"http://www.w3.org/TR/html4/strict.dtd">
+
+<HTML>
+ <HEAD>
+ <TITLE>uk.org.ury.database.exceptions</TITLE>
+ </HEAD>
+ <BODY>
+ <P>Exceptions thrown by the database services classes.</P>
+ </BODY>
+</HTML> \ No newline at end of file
diff --git a/src/uk/org/ury/backend/database/package.html b/src/uk/org/ury/backend/database/package.html
new file mode 100644
index 0000000..2b138b8
--- /dev/null
+++ b/src/uk/org/ury/backend/database/package.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+"http://www.w3.org/TR/html4/strict.dtd">
+
+<HTML>
+ <HEAD>
+ <TITLE>uk.org.ury.database</TITLE>
+ </HEAD>
+ <BODY>
+ <P>Database services for the URY Presenter Suite.</P>
+ <P>The classes provided within this package are expected to be
+ used by the back-end through utility classes, and <EM>not</EM>
+ by the frontend, which should use the server API to indirectly
+ query the database.</P>
+ </BODY>
+</HTML> \ No newline at end of file