aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Windsor <mbw500@student.cs.york.ac.uk>2011-02-17 23:28:47 +0000
committerMatt Windsor <mbw500@student.cs.york.ac.uk>2011-02-17 23:28:47 +0000
commit8f3c9af4bb9edb599bdc6c8da24e74beee4e1bf1 (patch)
tree48c2dd82034844aa44c513369d494656efdc6fcb
Initial commit; initial work on the library viewer which can be run either as an applet or an application; database connection is set up to connect to localhost as testing has necessitated using a gSTM SSH tunnel.
-rw-r--r--.classpath7
-rw-r--r--.project17
-rw-r--r--.settings/org.eclipse.jdt.core.prefs12
-rw-r--r--README0
-rw-r--r--src/uk/org/ury/database/DatabaseDriver.java122
-rw-r--r--src/uk/org/ury/database/DatabaseLogin.java150
-rw-r--r--src/uk/org/ury/database/UserClass.java24
-rw-r--r--src/uk/org/ury/database/credentials/.gitignore1
-rw-r--r--src/uk/org/ury/database/exceptions/ConnectionFailureException.java44
-rw-r--r--src/uk/org/ury/database/exceptions/MissingCredentialsException.java52
-rw-r--r--src/uk/org/ury/frontend/AbstractFrontendModule.java27
-rw-r--r--src/uk/org/ury/frontend/FrontendError.java50
-rw-r--r--src/uk/org/ury/frontend/FrontendFrame.java67
-rw-r--r--src/uk/org/ury/frontend/FrontendModule.java31
-rw-r--r--src/uk/org/ury/frontend/FrontendPanel.java34
-rw-r--r--src/uk/org/ury/frontend/images/ury.jpgbin0 -> 30139 bytes
-rw-r--r--src/uk/org/ury/frontend/images/ury.pngbin0 -> 10143 bytes
-rw-r--r--src/uk/org/ury/library/LibraryItem.java446
-rw-r--r--src/uk/org/ury/library/viewer/LibraryViewer.java197
-rw-r--r--src/uk/org/ury/library/viewer/LibraryViewerPanel.java130
20 files changed, 1411 insertions, 0 deletions
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..5d626e6
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="lib" path="lib/postgresql-9.0-801.jdbc4.jar"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/.project b/.project
new file mode 100644
index 0000000..4bf2012
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>SLUT</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..f5238da
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Wed Feb 16 20:20:45 GMT 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README
diff --git a/src/uk/org/ury/database/DatabaseDriver.java b/src/uk/org/ury/database/DatabaseDriver.java
new file mode 100644
index 0000000..0f03267
--- /dev/null
+++ b/src/uk/org/ury/database/DatabaseDriver.java
@@ -0,0 +1,122 @@
+package uk.org.ury.database;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+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
+ *
+ */
+
+public class DatabaseDriver
+{
+ /* The JDBC path used to connect to the URY database. */
+ private String DATABASE_PATH = "jdbc:postgresql://localhost/membership";
+
+ /* The database connection. */
+ private Connection conn;
+
+
+ /**
+ * Construct a new DatabaseDriver with the given user class.
+ *
+ * @param userclass 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 (UserClass userclass) throws MissingCredentialsException, ConnectionFailureException
+ {
+ DatabaseLogin login = null;
+
+ switch (userclass)
+ {
+ case READ_ONLY:
+ login = DatabaseLogin.getLoginFromFile ("read_only.txt");
+ break;
+ case READ_WRITE:
+ login = DatabaseLogin.getLoginFromFile ("read_write.txt");
+ default:
+ throw new IllegalArgumentException ("Unused user class.");
+ }
+
+
+ try
+ {
+ System.out.println ("Trying to acquire connection...");
+
+ connect (login);
+
+ System.out.println ("...connection succeeded.");
+ }
+ catch (SQLException e)
+ {
+ throw new ConnectionFailureException (e.getMessage ());
+ }
+
+ }
+
+
+ public void
+ connect (DatabaseLogin login) throws SQLException
+ {
+ if (login == null)
+ throw new IllegalArgumentException ("Supplied null login.");
+
+ if (login.getUsername () == null)
+ throw new IllegalArgumentException ("Login has no associated username.");
+
+ if (login.getPassword () == null)
+ throw new IllegalArgumentException ("Login has no associated password.");
+
+ conn = DriverManager.getConnection (DATABASE_PATH,
+ login.getUsername (),
+ login.getPassword ());
+ }
+
+
+ /**
+ * Execute a SQL statement.
+ *
+ * @param sql The SQL statement to execute.
+ *
+ * @return the JDBC results set.
+ */
+
+ public ResultSet
+ executeQuery (String sql)
+ {
+ try
+ {
+ Statement st = conn.createStatement ();
+ st.setFetchSize (50);
+
+ return st.executeQuery (sql);
+ }
+ catch (SQLException e)
+ {
+ e.printStackTrace ();
+ return null;
+ }
+ }
+}
diff --git a/src/uk/org/ury/database/DatabaseLogin.java b/src/uk/org/ury/database/DatabaseLogin.java
new file mode 100644
index 0000000..e2f22bf
--- /dev/null
+++ b/src/uk/org/ury/database/DatabaseLogin.java
@@ -0,0 +1,150 @@
+/**
+ *
+ */
+package uk.org.ury.database;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URL;
+
+import uk.org.ury.database.exceptions.MissingCredentialsException;
+
+
+/**
+ * A login username/password pair.
+ *
+ * @author Matt Windsor
+ */
+
+public class DatabaseLogin
+{
+ private String username;
+ private String password;
+
+
+ /**
+ * Create a new DatabaseLogin.
+ *
+ * This constructor is intentionally left private to prevent
+ * coders from hard-coding passwords. Please read database
+ * credentials from a source external to the program code.
+ *
+ * @param username The database username.
+ * @param password The database password.
+ *
+ * @see getLoginFromFile
+ */
+
+ private
+ DatabaseLogin (String username, String password)
+ {
+ this.username = username;
+ this.password = password;
+ }
+
+
+ /**
+ * Retrieve login credentials from a plaintext file.
+ *
+ * The credentials should be listed in the following format:
+ *
+ * username <newline>
+ * password
+ *
+ * @param file The filename of the file
+ *
+ * @return a new DatabaseLogin containing the information
+ * retrieved from the file.
+ *
+ * @throws IllegalArgumentException if the filename is null.
+ *
+ * @throws MissingCredentialsException if the file does not exist
+ * or is of the wrong format.
+ */
+
+ public static DatabaseLogin
+ getLoginFromFile (String file) throws MissingCredentialsException
+ {
+ // Find the credentials file.
+
+ if (file == null)
+ throw new IllegalArgumentException ("Supplied null credentials filename.");
+
+ URL fileURL = DatabaseLogin.class.getResource ("credentials/" + file);
+
+ if (fileURL == null)
+ throw new MissingCredentialsException ("Credentials file "
+ + file
+ + " not found.");
+
+
+ String username = null;
+ String password = null;
+ BufferedReader reader = null;
+
+
+ try
+ {
+ reader = new BufferedReader (new FileReader (fileURL.getFile ()));
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new MissingCredentialsException ("Credentials file "
+ + file
+ + " not found.");
+ }
+
+ try
+ {
+ username = reader.readLine ();
+ password = reader.readLine ();
+ }
+ catch (IOException e)
+ {
+ throw new MissingCredentialsException ("Credentials file "
+ + file
+ + "is invalid.");
+ }
+ finally
+ {
+ try
+ {
+ reader.close ();
+ }
+ catch (IOException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace ();
+ }
+ }
+
+
+ DatabaseLogin login = new DatabaseLogin (username, password);
+
+ return login;
+ }
+
+
+ /**
+ * @return the username.
+ */
+
+ public String
+ getUsername ()
+ {
+ return username;
+ }
+
+
+ /**
+ * @return the password.
+ */
+
+ public String
+ getPassword ()
+ {
+ return password;
+ }
+}
diff --git a/src/uk/org/ury/database/UserClass.java b/src/uk/org/ury/database/UserClass.java
new file mode 100644
index 0000000..8f30952
--- /dev/null
+++ b/src/uk/org/ury/database/UserClass.java
@@ -0,0 +1,24 @@
+/**
+ *
+ */
+package uk.org.ury.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
+ {
+ READ_ONLY,
+ READ_WRITE
+ }
diff --git a/src/uk/org/ury/database/credentials/.gitignore b/src/uk/org/ury/database/credentials/.gitignore
new file mode 100644
index 0000000..2211df6
--- /dev/null
+++ b/src/uk/org/ury/database/credentials/.gitignore
@@ -0,0 +1 @@
+*.txt
diff --git a/src/uk/org/ury/database/exceptions/ConnectionFailureException.java b/src/uk/org/ury/database/exceptions/ConnectionFailureException.java
new file mode 100644
index 0000000..030b24f
--- /dev/null
+++ b/src/uk/org/ury/database/exceptions/ConnectionFailureException.java
@@ -0,0 +1,44 @@
+/**
+ *
+ */
+package uk.org.ury.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/database/exceptions/MissingCredentialsException.java b/src/uk/org/ury/database/exceptions/MissingCredentialsException.java
new file mode 100644
index 0000000..2e45526
--- /dev/null
+++ b/src/uk/org/ury/database/exceptions/MissingCredentialsException.java
@@ -0,0 +1,52 @@
+/**
+ *
+ */
+package uk.org.ury.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/frontend/AbstractFrontendModule.java b/src/uk/org/ury/frontend/AbstractFrontendModule.java
new file mode 100644
index 0000000..99ff9cf
--- /dev/null
+++ b/src/uk/org/ury/frontend/AbstractFrontendModule.java
@@ -0,0 +1,27 @@
+package uk.org.ury.frontend;
+
+import javax.swing.JApplet;
+
+/**
+ * An abstract implementation of the FrontendModule interface.
+ *
+ * @author Matt Windsor
+ *
+ */
+
+public abstract class AbstractFrontendModule extends JApplet implements FrontendModule
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5309585577127763538L;
+
+
+ /**
+ * Initialise the module as an applet.
+ */
+
+ public abstract void
+ init ();
+}
diff --git a/src/uk/org/ury/frontend/FrontendError.java b/src/uk/org/ury/frontend/FrontendError.java
new file mode 100644
index 0000000..a08b966
--- /dev/null
+++ b/src/uk/org/ury/frontend/FrontendError.java
@@ -0,0 +1,50 @@
+/**
+ *
+ */
+package uk.org.ury.frontend;
+
+import javax.swing.JOptionPane;
+
+/**
+ * Factory for descriptive error dialogues.
+ *
+ * @author Matt Windsor
+ *
+ */
+
+public class FrontendError
+{
+ private final static String FATAL_TITLE = "Unrecoverable Error";
+
+ private final static String FATAL_PREFIX =
+ "An unrecoverable error has occurred, and the program must close "
+ + "immediately.\n"
+ + "Any unsaved work may have been permanently lost.\n\n"
+ + "Please let URY Computing know about this error.\n\n"
+ + "The error message reported was:\n\t";
+
+ private final static String FATAL_SUFFIX = "";
+
+
+ /**
+ * Create an error dialogue to report a fatal error.
+ *
+ * @string message The message, eg the exception message,
+ * to report to the user.
+ */
+
+ public static void
+ reportFatal (String message, FrontendFrame frame)
+ {
+ // TODO: Log
+
+ // TODO: Replace with bespoke error dialogue?
+
+ JOptionPane.showMessageDialog (frame,
+ FATAL_PREFIX + message + FATAL_SUFFIX,
+ FATAL_TITLE,
+ JOptionPane.ERROR_MESSAGE);
+
+ System.exit (-1);
+ }
+}
diff --git a/src/uk/org/ury/frontend/FrontendFrame.java b/src/uk/org/ury/frontend/FrontendFrame.java
new file mode 100644
index 0000000..d27a85a
--- /dev/null
+++ b/src/uk/org/ury/frontend/FrontendFrame.java
@@ -0,0 +1,67 @@
+/**
+ *
+ */
+package uk.org.ury.frontend;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.FlowLayout;
+
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+/**
+ * A frame that hosts a FrontendPanel, used for serving frontend
+ * panels in a window (application mode).
+ *
+ * @author Matt Windsor
+ *
+ */
+
+public class FrontendFrame extends JFrame
+{
+ /**
+ *
+ */
+
+ private static final long serialVersionUID = 740928181256928433L;
+
+ private FrontendPanel parent;
+
+ public
+ FrontendFrame (FrontendPanel parent)
+ {
+ super (parent.getName ());
+
+ setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
+
+ this.parent = parent;
+
+ Container cp = getContentPane ();
+
+ // Banner
+
+ JPanel banner = new JPanel ();
+ JLabel bannerLabel = new JLabel ("<html><h1><font color=white>"
+ + parent.getName () + "</font></h1></html>");
+
+ bannerLabel.setBorder (BorderFactory.createEmptyBorder (5, 15, 5, 5));
+
+ banner.setLayout (new FlowLayout (FlowLayout.LEFT));
+ banner.setBackground (new Color (0, 0, 0));
+ banner.add (new JLabel (new ImageIcon (getClass ().getResource ("images/ury.png"))));
+ banner.add (bannerLabel);
+
+ // Composition
+
+ cp.add (banner, BorderLayout.NORTH);
+ cp.add (parent, BorderLayout.CENTER);
+
+ pack ();
+ setVisible (true);
+ }
+}
diff --git a/src/uk/org/ury/frontend/FrontendModule.java b/src/uk/org/ury/frontend/FrontendModule.java
new file mode 100644
index 0000000..407b2db
--- /dev/null
+++ b/src/uk/org/ury/frontend/FrontendModule.java
@@ -0,0 +1,31 @@
+/**
+ *
+ */
+package uk.org.ury.frontend;
+
+/**
+ * Interface for all system modules that are to be reachable from
+ * the frontend array.
+ *
+ * Frontend-exposed modules must:
+ *
+ * - be runnable standalone, as either an application or an applet;
+ *
+ * - contain their user interface in a subclass of FrontendPanel
+ * which can be embedded either in a FrontendFrame, a web page
+ * or another module;
+ *
+ * - use the frontend error reporting systems.
+ *
+ * An abstract implementation of this interface,
+ * AbstractFrontendModule, is provided to simplify the creation of
+ * frontend modules.
+ *
+ * @author Matt Windsor
+ *
+ */
+
+public interface FrontendModule
+{
+ // Space for rent
+}
diff --git a/src/uk/org/ury/frontend/FrontendPanel.java b/src/uk/org/ury/frontend/FrontendPanel.java
new file mode 100644
index 0000000..e2e8c44
--- /dev/null
+++ b/src/uk/org/ury/frontend/FrontendPanel.java
@@ -0,0 +1,34 @@
+/**
+ *
+ */
+package uk.org.ury.frontend;
+
+import javax.swing.JPanel;
+
+/**
+ * A frontend user interface panel.
+ *
+ * All frontend user interfaces should subclass this as their main
+ * interface space, so that frontend panels can include each other
+ * and panels can be embedded into application frames or applets.
+ *
+ * @author Matt Windsor
+ *
+ */
+public abstract class FrontendPanel extends JPanel
+{
+ /**
+ *
+ */
+
+ private static final long serialVersionUID = 5616222530691425635L;
+
+ public
+ FrontendPanel ()
+ {
+ super ();
+ }
+
+ public abstract String
+ getName ();
+}
diff --git a/src/uk/org/ury/frontend/images/ury.jpg b/src/uk/org/ury/frontend/images/ury.jpg
new file mode 100644
index 0000000..96d2740
--- /dev/null
+++ b/src/uk/org/ury/frontend/images/ury.jpg
Binary files differ
diff --git a/src/uk/org/ury/frontend/images/ury.png b/src/uk/org/ury/frontend/images/ury.png
new file mode 100644
index 0000000..f71a461
--- /dev/null
+++ b/src/uk/org/ury/frontend/images/ury.png
Binary files differ
diff --git a/src/uk/org/ury/library/LibraryItem.java b/src/uk/org/ury/library/LibraryItem.java
new file mode 100644
index 0000000..0e44be5
--- /dev/null
+++ b/src/uk/org/ury/library/LibraryItem.java
@@ -0,0 +1,446 @@
+/**
+ *
+ */
+package uk.org.ury.library;
+
+/**
+ * An item in the URY library.
+ *
+ * @author Matt Windsor
+ */
+
+public class LibraryItem
+{
+ private String title;
+ private String artist;
+ private String label;
+ private String status;
+ private String medium;
+ private String format;
+ private String dateReleased;
+ private String dateAdded;
+ private String dateEdited;
+ private String shelfLetter;
+ private String shelfNumber;
+ private String addForename;
+ private String addSurname;
+ private String editForename;
+ private String editSurname;
+ private String cdID;
+ private int addMemberID;
+ private int editMemberID;
+
+ public
+ LibraryItem ()
+ {
+ }
+
+
+ /**
+ * @return the title
+ */
+
+ public String
+ getTitle ()
+ {
+ return title;
+ }
+
+
+ /**
+ * @param title the title to set
+ */
+
+ public void
+ setTitle (String title)
+ {
+ this.title = title;
+ }
+
+
+ /**
+ * @return the artist
+ */
+
+ public String
+ getArtist ()
+ {
+ return artist;
+ }
+
+
+ /**
+ * @param artist the artist to set
+ */
+
+ public void
+ setArtist (String artist)
+ {
+ this.artist = artist;
+ }
+
+
+ /**
+ * @return the label
+ */
+
+ public String
+ getLabel ()
+ {
+ return label;
+ }
+
+
+ /**
+ * @param label the label to set
+ */
+
+ public void
+ setLabel (String label)
+ {
+ this.label = label;
+ }
+
+
+ /**
+ * @return the status
+ */
+
+ public String
+ getStatus ()
+ {
+ return status;
+ }
+
+
+ /**
+ * @param status the status to set
+ */
+
+ public void
+ setStatus (String status)
+ {
+ this.status = status;
+ }
+
+
+ /**
+ * @return the medium
+ */
+
+ public String
+ getMedium ()
+ {
+ return medium;
+ }
+
+
+ /**
+ * @param medium the medium to set
+ */
+
+ public void
+ setMedium (String medium)
+ {
+ this.medium = medium;
+ }
+
+
+ /**
+ * @return the format
+ */
+
+ public String
+ getFormat ()
+ {
+ return format;
+ }
+
+
+ /**
+ * @param format the format to set
+ */
+
+ public void
+ setFormat (String format)
+ {
+ this.format = format;
+ }
+
+
+ /**
+ * @return the dateReleased
+ */
+
+ public String
+ getDateReleased ()
+ {
+ return dateReleased;
+ }
+
+
+ /**
+ * @param dateReleased the dateReleased to set
+ */
+
+ public void
+ setDateReleased (String dateReleased)
+ {
+ this.dateReleased = dateReleased;
+ }
+
+
+ /**
+ * @return the dateAdded
+ */
+
+ public String
+ getDateAdded ()
+ {
+ return dateAdded;
+ }
+
+
+ /**
+ * @param dateAdded the dateAdded to set
+ */
+
+ public void
+ setDateAdded (String dateAdded)
+ {
+ this.dateAdded = dateAdded;
+ }
+
+
+ /**
+ * @return the dateEdited
+ */
+
+ public String
+ getDateEdited ()
+ {
+ return dateEdited;
+ }
+
+
+ /**
+ * @param dateEdited the dateEdited to set
+ */
+
+ public void
+ setDateEdited (String dateEdited)
+ {
+ this.dateEdited = dateEdited;
+ }
+
+
+ /**
+ * @return the shelfLetter
+ */
+
+
+ public String
+ getShelfLetter ()
+ {
+ return shelfLetter;
+ }
+
+
+ /**
+ * @param shelfLetter the shelfLetter to set
+ */
+
+ public void
+ setShelfLetter (String shelfLetter)
+ {
+ this.shelfLetter = shelfLetter;
+ }
+
+
+ /**
+ * @return the shelfNumber
+ */
+
+ public String
+ getShelfNumber ()
+ {
+ return shelfNumber;
+ }
+
+
+ /**
+ * @param shelfNumber the shelfNumber to set
+ */
+
+ public void
+ setShelfNumber (String shelfNumber)
+ {
+ this.shelfNumber = shelfNumber;
+ }
+
+
+ /**
+ * @return the addForename
+ */
+
+ public String
+ getAddForename ()
+ {
+ return addForename;
+ }
+
+
+ /**
+ * @param addForename the addForename to set
+ */
+
+ public void
+ setAddForename (String addForename)
+ {
+ this.addForename = addForename;
+ }
+
+
+ /**
+ * @return the addSurname
+ */
+
+ public String
+ getAddSurname ()
+ {
+ return addSurname;
+ }
+
+
+ /**
+ * @param addSurname the addSurname to set
+ */
+
+ public void
+ setAddSurname (String addSurname)
+ {
+ this.addSurname = addSurname;
+ }
+
+
+ /**
+ * @return the editForename
+ */
+
+ public String
+ getEditForename ()
+ {
+ return editForename;
+ }
+
+
+ /**
+ * @param editForename the editForename to set
+ */
+
+ public void
+ setEditForename (String editForename)
+ {
+ this.editForename = editForename;
+ }
+
+
+ /**
+ * @return the editSurname
+ */
+
+ public String
+ getEditSurname ()
+ {
+ return editSurname;
+ }
+
+
+ /**
+ * @param editSurname the editSurname to set
+ */
+
+ public void
+ setEditSurname (String editSurname)
+ {
+ this.editSurname = editSurname;
+ }
+
+
+ /**
+ * @return the cdID
+ */
+
+ public String
+ getCdID ()
+ {
+ return cdID;
+ }
+
+
+ /**
+ * @param cdID the cdID to set
+ */
+
+ public void
+ setCdID (String cdID)
+ {
+ this.cdID = cdID;
+ }
+
+
+ /**
+ * @return the addMemberID
+ */
+
+ public int
+ getAddMemberID ()
+ {
+ return addMemberID;
+ }
+
+
+ /**
+ * @param addMemberID the addMemberID to set
+ */
+
+ public void
+ setAddMemberID (int addMemberID)
+ {
+ this.addMemberID = addMemberID;
+ }
+
+
+ /**
+ * @return the editMemberID
+ */
+
+ public int
+ getEditMemberID ()
+ {
+ return editMemberID;
+ }
+
+
+ /**
+ * @param editMemberID the editMemberID to set
+ */
+
+ public void
+ setEditMemberID (int editMemberID)
+ {
+ this.editMemberID = editMemberID;
+ }
+
+
+ /**
+ * @return a human-readable string representation of the item.
+ */
+
+ @Override
+ public String
+ toString ()
+ {
+ return getArtist () + " - " + getTitle () + " (" + getShelfLetter () + getShelfNumber () + ")";
+ }
+}
diff --git a/src/uk/org/ury/library/viewer/LibraryViewer.java b/src/uk/org/ury/library/viewer/LibraryViewer.java
new file mode 100644
index 0000000..234e1eb
--- /dev/null
+++ b/src/uk/org/ury/library/viewer/LibraryViewer.java
@@ -0,0 +1,197 @@
+package uk.org.ury.library.viewer;
+
+import java.lang.reflect.InvocationTargetException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.SwingUtilities;
+
+import uk.org.ury.database.DatabaseDriver;
+import uk.org.ury.database.UserClass;
+import uk.org.ury.database.exceptions.MissingCredentialsException;
+import uk.org.ury.frontend.AbstractFrontendModule;
+import uk.org.ury.frontend.FrontendError;
+import uk.org.ury.frontend.FrontendFrame;
+import uk.org.ury.frontend.FrontendModule;
+import uk.org.ury.library.LibraryItem;
+
+public class LibraryViewer extends AbstractFrontendModule
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2782366476480563739L;
+ private List<LibraryItem> libraryList;
+ private LibraryViewerPanel panel;
+ private FrontendFrame frame;
+
+
+ /**
+ * Main function, for running this module as a standalone
+ * application.
+ *
+ * @param args The command-line argument array.
+ */
+
+ public static void
+ main (String[] args)
+ {
+ LibraryViewer lv = new LibraryViewer ();
+ lv.runFrontendInFrame ();
+ }
+
+
+ /**
+ * Construct a new LibraryViewer.
+ */
+
+ public
+ LibraryViewer ()
+ {
+ frame = null;
+ panel = new LibraryViewerPanel (this);
+ }
+
+
+ /**
+ * Initialise the library viewer frontend as an applet.
+ */
+
+ public void
+ init ()
+ {
+ frame = null;
+ panel = new LibraryViewerPanel (this);
+
+
+ try
+ {
+ SwingUtilities.invokeAndWait (new Runnable ()
+ {
+ public void
+ run ()
+ {
+ panel.setOpaque (true);
+ setContentPane (panel);
+
+ runFrontend ();
+ }
+
+ });
+ }
+ catch (InterruptedException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace ();
+ }
+ catch (InvocationTargetException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace ();
+ }
+ }
+
+
+ /**
+ * Run the library viewer frontend as an applet.
+ */
+
+ public void
+ start ()
+ {
+ frame = null;
+ panel = new LibraryViewerPanel (this);
+
+ add (panel);
+ }
+
+ /**
+ * Run the library viewer frontend in a FrontendFrame.
+ */
+
+ public void
+ runFrontendInFrame ()
+ {
+ FrontendFrame frame = new FrontendFrame (panel);
+ this.frame = frame;
+
+ runFrontend ();
+ }
+
+
+ /**
+ * Run the library viewer frontend.
+ */
+
+ private void
+ runFrontend ()
+ {
+ DatabaseDriver dd = null;
+
+ try
+ {
+ dd = new DatabaseDriver (UserClass.READ_ONLY);
+ }
+ catch (MissingCredentialsException e)
+ {
+ // TODO: Privilege de-escalation
+ FrontendError.reportFatal (e.getMessage (), frame);
+ }
+ catch (Exception f)
+ {
+ FrontendError.reportFatal (f.getMessage (), frame);
+ }
+
+
+ System.out.println ("connection success");
+
+ ResultSet rs = dd.executeQuery ("SELECT title, artist, recordlabel AS label, status, media AS medium, format,"
+ + " datereleased, EXTRACT(EPOCH FROM dateadded) as dateadded,"
+ + " EXTRACT(EPOCH FROM datetime_lastedit) AS dateedited,"
+ + " shelfletter, shelfnumber, cdid, memberid_add, memberid_lastedit,"
+ + " a.fname AS fnameadd, a.sname AS snameadd, b.fname AS fnameedit, b.sname AS snameedit"
+ + " FROM rec_record AS r"
+ + " INNER JOIN member AS a ON (a.memberid = r.memberid_add)"
+ + " LEFT JOIN member AS b ON (b.memberid = r.memberid_lastedit)");
+
+
+ libraryList = new ArrayList<LibraryItem> ();
+
+ try
+ {
+ while (rs.next ())
+ {
+ LibraryItem li = new LibraryItem ();
+
+ li.setTitle (rs.getString ("title"));
+ li.setArtist (rs.getString ("artist"));
+ li.setLabel (rs.getString ("label"));
+ li.setStatus (rs.getString ("status"));
+ li.setMedium (rs.getString ("medium"));
+ li.setFormat (rs.getString ("format"));
+ li.setDateReleased (rs.getString ("datereleased"));
+ li.setDateEdited (rs.getString ("dateedited"));
+ li.setShelfLetter (rs.getString ("shelfletter"));
+ li.setShelfNumber (rs.getString ("shelfnumber"));
+ li.setCdID (rs.getString ("cdid"));
+ li.setAddMemberID (rs.getInt ("memberid_add"));
+ li.setEditMemberID (rs.getInt ("memberid_lastedit"));
+ li.setAddForename (rs.getString ("fnameadd"));
+ li.setAddSurname (rs.getString ("snameadd"));
+ li.setEditForename (rs.getString ("fnameedit"));
+ li.setEditSurname (rs.getString ("snameedit"));
+
+ System.out.println (li);
+
+ libraryList.add (li);
+ }
+ }
+ catch (SQLException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/uk/org/ury/library/viewer/LibraryViewerPanel.java b/src/uk/org/ury/library/viewer/LibraryViewerPanel.java
new file mode 100644
index 0000000..6a100a6
--- /dev/null
+++ b/src/uk/org/ury/library/viewer/LibraryViewerPanel.java
@@ -0,0 +1,130 @@
+/**
+ *
+ */
+package uk.org.ury.library.viewer;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.GroupLayout;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+
+import uk.org.ury.frontend.FrontendPanel;
+
+/**
+ * @author Matt Windsor
+ */
+
+public class LibraryViewerPanel extends FrontendPanel
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2441616418398056712L;
+
+
+ /* Controller of this panel. */
+ private LibraryViewer master;
+
+ /* Panel widgets. */
+ private JLabel titleLabel;
+ private JLabel artistLabel;
+
+ private JTextField titleField;
+ private JTextField artistField;
+
+ private JButton searchButton;
+
+
+ /**
+ * Construct a new LibraryViewerPanel.
+ *
+ * @param master The LibraryViewer controlling this LibraryViewerPanel.
+ */
+
+ public
+ LibraryViewerPanel (LibraryViewer master)
+ {
+ super ();
+
+ this.master = master;
+
+ GroupLayout layout = new GroupLayout (this);
+
+ setLayout (layout);
+
+ layout.setAutoCreateGaps (true);
+ layout.setAutoCreateContainerGaps (true);
+
+ titleLabel = new JLabel ("By title: ");
+ artistLabel = new JLabel ("By artist: ");
+
+ titleField = new JTextField ("Type part of the title here.");
+ titleLabel.setDisplayedMnemonic ('T');
+ titleLabel.setLabelFor (titleField);
+
+ artistField = new JTextField ("Type part of the artist name here.");
+ artistLabel.setDisplayedMnemonic ('A');
+ artistLabel.setLabelFor (artistField);
+
+ searchButton = new JButton ("Search");
+
+ searchButton.addActionListener (new ActionListener ()
+ {
+ public void
+ actionPerformed (ActionEvent event)
+ {
+ }
+ });
+
+
+ // Layout
+
+
+ layout.setHorizontalGroup
+ (
+ layout.createSequentialGroup ()
+ .addGroup (layout.createParallelGroup (GroupLayout.Alignment.LEADING)
+ .addComponent (titleLabel)
+ .addComponent (artistLabel))
+ .addGroup (layout.createParallelGroup (GroupLayout.Alignment.LEADING)
+ .addComponent (titleField)
+ .addComponent (artistField))
+ .addGroup (layout.createParallelGroup (GroupLayout.Alignment.LEADING)
+ .addComponent (searchButton))
+ );
+
+ layout.setVerticalGroup
+ (
+ layout.createSequentialGroup ()
+ .addGroup (layout.createParallelGroup (GroupLayout.Alignment.LEADING)
+ .addComponent (titleLabel)
+ .addComponent (titleField)
+ .addComponent (searchButton))
+ .addGroup (layout.createParallelGroup (GroupLayout.Alignment.LEADING)
+ .addComponent (artistLabel)
+ .addComponent (artistField))
+ );
+
+ layout.linkSize(SwingConstants.HORIZONTAL, titleField, artistField);
+ layout.linkSize(SwingConstants.VERTICAL, titleField, artistField);
+ }
+
+
+ /**
+ * @return the name of the panel.
+ *
+ * @see uk.org.ury.frontend.FrontendPanel#getName()
+ */
+
+ @Override
+ public String
+ getName ()
+ {
+ return "Library Viewer Demo";
+ }
+
+}