aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/uk/org/ury/client/Client.java65
-rw-r--r--src/uk/org/ury/client/test/ClientTest.java64
-rw-r--r--src/uk/org/ury/config/ConfigReader.java4
-rw-r--r--src/uk/org/ury/database/DatabaseDriver.java29
-rw-r--r--src/uk/org/ury/database/DatabaseItem.java30
-rw-r--r--src/uk/org/ury/frontend/AbstractFrontendModule.java11
-rw-r--r--src/uk/org/ury/frontend/FrontendApplet.java343
-rw-r--r--src/uk/org/ury/frontend/FrontendControlPanel.java18
-rw-r--r--src/uk/org/ury/frontend/FrontendError.java15
-rw-r--r--src/uk/org/ury/frontend/FrontendFrame.java125
-rw-r--r--src/uk/org/ury/frontend/FrontendMaster.java45
-rw-r--r--src/uk/org/ury/frontend/FrontendModulePanel.java10
-rw-r--r--src/uk/org/ury/frontend/FrontendPanel.java42
-rw-r--r--src/uk/org/ury/frontend/FrontendSubBanner.java5
-rw-r--r--src/uk/org/ury/frontend/exceptions/LoadFailureException.java44
-rw-r--r--src/uk/org/ury/frontend/exceptions/UICreationFailureException.java44
-rw-r--r--src/uk/org/ury/library/LibraryRequestHandler.java144
-rw-r--r--src/uk/org/ury/library/LibraryUtils.java112
-rw-r--r--src/uk/org/ury/library/item/LibraryItem.java26
-rw-r--r--src/uk/org/ury/library/item/LibraryItemProperty.java62
-rw-r--r--src/uk/org/ury/library/viewer/LibraryTableModel.java184
-rw-r--r--src/uk/org/ury/library/viewer/LibraryViewer.java95
-rw-r--r--src/uk/org/ury/library/viewer/LibraryViewerPanel.java10
-rw-r--r--src/uk/org/ury/library/viewer/library_viewer_gui.xml12
-rw-r--r--src/uk/org/ury/server/RequestHandler.java44
-rw-r--r--src/uk/org/ury/server/Server.java432
-rw-r--r--src/uk/org/ury/server/ServerProtocol.java37
-rw-r--r--src/uk/org/ury/server/ServerRequestHandler.java96
-rw-r--r--src/uk/org/ury/server/exceptions/HandleFailureException.java46
-rw-r--r--src/uk/org/ury/server/protocol/Directive.java69
-rw-r--r--src/uk/org/ury/show/ShowChannel.java41
-rw-r--r--src/uk/org/ury/show/ShowUtils.java80
-rw-r--r--src/uk/org/ury/show/item/ShowItem.java68
-rw-r--r--src/uk/org/ury/show/item/ShowItemProperty.java26
-rw-r--r--src/uk/org/ury/show/viewer/ChannelPanel.java52
-rw-r--r--src/uk/org/ury/show/viewer/LibraryControlPanel.java15
-rw-r--r--src/uk/org/ury/show/viewer/ShowViewer.java131
-rw-r--r--src/uk/org/ury/show/viewer/ShowViewerPanel.java44
-rw-r--r--src/uk/org/ury/show/viewer/TrackBin.java51
-rw-r--r--src/uk/org/ury/show/viewer/channel_panel.xml2
-rw-r--r--src/uk/org/ury/show/viewer/library_control_panel.xml14
-rw-r--r--src/uk/org/ury/show/viewer/show_viewer_gui.xml59
-rw-r--r--src/uk/org/ury/show/viewer/show_viewer_gui_old.xml46
-rw-r--r--src/uk/org/ury/show/viewer/show_viewer_gui_panels.xml43
-rw-r--r--src/uk/org/ury/show/viewer/track_bin.xml2
-rw-r--r--src/uk/org/ury/testrig/ApplicationLauncher.java32
-rw-r--r--src/uk/org/ury/testrig/DemoControlPanel.java14
-rw-r--r--src/uk/org/ury/testrig/DemoMenu.java100
-rw-r--r--src/uk/org/ury/testrig/DemoMenuPanel.java90
-rw-r--r--src/uk/org/ury/testrig/Launcher.java17
-rw-r--r--src/uk/org/ury/testrig/demo_control_panel.xml8
51 files changed, 2748 insertions, 450 deletions
diff --git a/src/uk/org/ury/client/Client.java b/src/uk/org/ury/client/Client.java
new file mode 100644
index 0000000..f0b2679
--- /dev/null
+++ b/src/uk/org/ury/client/Client.java
@@ -0,0 +1,65 @@
+package uk.org.ury.client;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Client
+{
+ /**
+ * Get a raw response from the server.
+ *
+ * @param file The "file", including path and query string, to
+ * fetch from the server.
+ *
+ * @return The response from the server, as a List of lines.
+ */
+
+ public List<String>
+ get (String file)
+ {
+ URL url = null;
+ URLConnection uc = null;
+ List<String> result = new ArrayList<String> ();
+
+ try
+ {
+ url = new URL ("http://localhost:8000" + file);
+ }
+ catch (MalformedURLException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace ();
+ }
+
+ try
+ {
+ uc = url.openConnection ();
+
+ BufferedReader in = new BufferedReader (new InputStreamReader
+ (uc.getInputStream ()));
+
+
+ String inputLine;
+
+ for (inputLine = in.readLine();
+ inputLine != null;
+ inputLine = in.readLine())
+ {
+ result.add (inputLine);
+ }
+ }
+ catch (IOException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace ();
+ }
+
+ return result;
+ }
+}
diff --git a/src/uk/org/ury/client/test/ClientTest.java b/src/uk/org/ury/client/test/ClientTest.java
new file mode 100644
index 0000000..085bebb
--- /dev/null
+++ b/src/uk/org/ury/client/test/ClientTest.java
@@ -0,0 +1,64 @@
+/**
+ *
+ */
+package uk.org.ury.client.test;
+
+import static org.junit.Assert.*;
+
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import uk.org.ury.client.Client;
+
+/**
+ * JUnit test for the low-level client logic.
+ *
+ * @author Matt Windsor
+ */
+
+public class ClientTest
+{
+
+ /**
+ * @throws java.lang.Exception
+ */
+
+ @Before
+ public void
+ setUp () throws Exception
+ {
+ }
+
+
+ /**
+ * @throws java.lang.Exception
+ */
+
+ @After
+ public void
+ tearDown () throws Exception
+ {
+ }
+
+
+ /**
+ * Test method for {@link uk.org.ury.client.Client#get(java.lang.String)}.
+ */
+
+ @Test
+ public void
+ testGet ()
+ {
+ Client client = new Client ();
+
+ List<String> response = client.get ("/server/ServerRequestHandler?function=test");
+
+ Assert.assertEquals ("INFO: Test succeeded.", response.get (2));
+ }
+
+}
diff --git a/src/uk/org/ury/config/ConfigReader.java b/src/uk/org/ury/config/ConfigReader.java
index 04deb49..ed2d852 100644
--- a/src/uk/org/ury/config/ConfigReader.java
+++ b/src/uk/org/ury/config/ConfigReader.java
@@ -1,7 +1,5 @@
package uk.org.ury.config;
-import java.io.File;
-
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -54,7 +52,7 @@ public class ConfigReader {
try {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
- Document doc = docBuilder.parse (new File(configFile));
+ Document doc = docBuilder.parse (configFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("auth");
diff --git a/src/uk/org/ury/database/DatabaseDriver.java b/src/uk/org/ury/database/DatabaseDriver.java
index a7db32e..7c71827 100644
--- a/src/uk/org/ury/database/DatabaseDriver.java
+++ b/src/uk/org/ury/database/DatabaseDriver.java
@@ -35,7 +35,8 @@ public class DatabaseDriver
* Construct a new DatabaseDriver with the given user class.
*
* @param config The config with login details.
- * @param userclass The user class to log in to the database with.
+ *
+ * @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).
@@ -49,7 +50,8 @@ public class DatabaseDriver
*/
public
- DatabaseDriver (ConfigReader config, UserClass type) throws MissingCredentialsException, ConnectionFailureException
+ DatabaseDriver (ConfigReader config, UserClass type)
+ throws MissingCredentialsException, ConnectionFailureException
{
try
{
@@ -73,7 +75,8 @@ public class DatabaseDriver
*/
private void
- connect (ConfigReader config, UserClass type) throws SQLException
+ connect (ConfigReader config, UserClass type)
+ throws SQLException
{
if (config == null)
throw new IllegalArgumentException ("Supplied null config.");
@@ -113,23 +116,18 @@ public class DatabaseDriver
* @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
{
- try
- {
- Statement st = conn.createStatement ();
- st.setFetchSize (fetchSize);
+ Statement st = conn.createStatement ();
+ st.setFetchSize (fetchSize);
- return st.executeQuery (sql);
- }
- catch (SQLException e)
- {
- e.printStackTrace ();
- return null;
- }
+ return st.executeQuery (sql);
}
@@ -154,7 +152,8 @@ public class DatabaseDriver
*/
public ResultSet
- executeQuery (String sql, Object[] params, int fetchSize) throws SQLException
+ executeQuery (String sql, Object[] params, int fetchSize)
+ throws SQLException
{
PreparedStatement st = conn.prepareStatement (sql);
diff --git a/src/uk/org/ury/database/DatabaseItem.java b/src/uk/org/ury/database/DatabaseItem.java
index 4f6d34d..f151dbf 100644
--- a/src/uk/org/ury/database/DatabaseItem.java
+++ b/src/uk/org/ury/database/DatabaseItem.java
@@ -1,8 +1,11 @@
package uk.org.ury.database;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import uk.org.ury.database.exceptions.MissingPropertyException;
+import uk.org.ury.server.protocol.Directive;
/**
@@ -21,6 +24,7 @@ public abstract class DatabaseItem<E, T>
{
private Map<E, T> properties;
+
/**
* Construct a new item from an existing list of properties.
*
@@ -67,4 +71,30 @@ public abstract class DatabaseItem<E, T>
else
throw new MissingPropertyException (property.toString ());
}
+
+
+ /**
+ * Map down the item into a server response body.
+ *
+ * This relies on E and T having meaningful toString methods.
+ *
+ * @return a list of lines representing the response.
+ */
+
+ public List<String>
+ asResponse ()
+ {
+ // TODO: Fan out implementation details into separate class
+
+ List<String> response = new ArrayList<String> ();
+
+ for (E property : properties.keySet ())
+ {
+ if (properties.get (property) != null)
+ response.add (property.toString () + ": "
+ + properties.get (property).toString ());
+ }
+
+ return response;
+ }
}
diff --git a/src/uk/org/ury/frontend/AbstractFrontendModule.java b/src/uk/org/ury/frontend/AbstractFrontendModule.java
index 99ff9cf..b5b55b6 100644
--- a/src/uk/org/ury/frontend/AbstractFrontendModule.java
+++ b/src/uk/org/ury/frontend/AbstractFrontendModule.java
@@ -1,6 +1,5 @@
package uk.org.ury.frontend;
-import javax.swing.JApplet;
/**
* An abstract implementation of the FrontendModule interface.
@@ -9,7 +8,7 @@ import javax.swing.JApplet;
*
*/
-public abstract class AbstractFrontendModule extends JApplet implements FrontendModule
+public abstract class AbstractFrontendModule implements FrontendModule
{
/**
@@ -17,11 +16,5 @@ public abstract class AbstractFrontendModule extends JApplet implements Frontend
*/
private static final long serialVersionUID = 5309585577127763538L;
-
- /**
- * Initialise the module as an applet.
- */
-
- public abstract void
- init ();
+ /* Space for rent */
}
diff --git a/src/uk/org/ury/frontend/FrontendApplet.java b/src/uk/org/ury/frontend/FrontendApplet.java
new file mode 100644
index 0000000..18f0c7a
--- /dev/null
+++ b/src/uk/org/ury/frontend/FrontendApplet.java
@@ -0,0 +1,343 @@
+/**
+ *
+ */
+package uk.org.ury.frontend;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+
+import javax.swing.JApplet;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+import uk.org.ury.frontend.exceptions.LoadFailureException;
+import uk.org.ury.testrig.Launcher;
+
+/**
+ * A frame that hosts a FrontendModulePanel, used for serving frontend
+ * panels in a window (application mode).
+ *
+ * @author Matt Windsor
+ *
+ */
+
+public class FrontendApplet extends JApplet implements FrontendMaster, Launcher
+{
+ /**
+ *
+ */
+
+ private static final long serialVersionUID = 740928181256928433L;
+
+ private FrontendModulePanel child;
+ private FrontendControlPanel cpanel;
+
+
+ /**
+ * Main method.
+ *
+ * @param args The command-line arguments to the program. These
+ * will currently be ignored.
+ */
+
+ @Override
+ public void
+ init ()
+ {
+ try
+ {
+ javax.swing.SwingUtilities.invokeAndWait (new Runnable()
+ {
+ public void
+ run ()
+ {
+ try
+ {
+ loadModule (DEFAULT_MODULE_NAME);
+ }
+ catch (LoadFailureException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace ();
+ }
+ setupUI ();
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace ();
+ System.err.println("createGUI didn't successfully complete");
+ }
+ }
+
+
+ /**
+ * Set up the user interface of the frame.
+ */
+
+ @Override
+ public void
+ setupUI ()
+ {
+ try
+ {
+ // Set System L&F
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName ());
+ }
+ catch (UnsupportedLookAndFeelException e)
+ {
+ // handle exception
+ }
+ catch (ClassNotFoundException e)
+ {
+ // handle exception
+ }
+ catch (InstantiationException e)
+ {
+ // handle exception
+ }
+ catch (IllegalAccessException e)
+ {
+ // handle exception
+ }
+
+
+ // Composition
+
+ add (child, BorderLayout.CENTER);
+
+ setPreferredSize (new Dimension (800, 600));
+ setMinimumSize (new Dimension (800, 600));
+
+ setVisible (true);
+ }
+
+
+ /**
+ * Load a module into the frontend frame.
+ *
+ * Loading will fail with a fatal error if the class is not found,
+ * or is not an implementor of FrontendModule.
+ *
+ * @param moduleName The fully qualified class-name of the module,
+ * minus the leading "uk.org.ury." domain.
+ *
+ * @throws LoadFailureException if the class is
+ * not found, or is not an implementor of
+ * FrontendModule.
+ */
+
+ @Override
+ public void
+ loadModule (String moduleName)
+ throws LoadFailureException
+ {
+ Class<?> moduleClass = null;
+
+ try
+ {
+ moduleClass = Class.forName ("uk.org.ury." + moduleName);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new LoadFailureException ("Could not load module: "
+ + e.getMessage ());
+ }
+
+
+ if (FrontendModule.class.isAssignableFrom (moduleClass) == false)
+ {
+ throw new LoadFailureException ("Could not load module: Not a FrontendModule");
+ }
+ else
+ {
+ FrontendModulePanel temp = child;
+
+ try
+ {
+ child = ((FrontendModule) moduleClass.newInstance ()).runFrontend (this);
+ }
+ catch (InstantiationException e)
+ {
+ throw new LoadFailureException ("Could not load module: "
+ + e.getMessage ());
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new LoadFailureException ("Could not load module: "
+ + e.getMessage ());
+ }
+
+ if (temp != null)
+ remove (temp);
+
+ getContentPane ().add (child, BorderLayout.CENTER);
+ child.setMaster (this);
+
+ repaint ();
+ }
+ }
+
+
+ /**
+ * Load a module into the frontend frame, additionally installing
+ * a control panel to communicate with the previous module.
+ *
+ * Loading will fail with a fatal error if the class is not found,
+ * or is not an implementor of FrontendModule.
+ *
+ * @param moduleName The fully qualified class-name of the module,
+ * minus the leading "uk.org.ury." domain.
+ *
+ * @param cPanelName The fully qualified class-name of the control
+ * panel to install, minus the leading
+ * "uk.org.ury." domain.
+ *
+ * @throws LoadFailureException if the class is
+ * not found, or is not an implementor of
+ * FrontendModule.
+ */
+
+ @Override
+ public void
+ loadModule (String moduleName, String cPanelName)
+ throws LoadFailureException
+ {
+ FrontendModulePanel newParent = child;
+ loadModule (moduleName);
+ FrontendModulePanel newChild = child;
+
+ loadControlPanel (cPanelName, newParent, newChild);
+ }
+
+
+ /**
+ * Load and install a control panel class given the class name.
+ *
+ * @param cPanelName The fully qualified class-name of the control
+ * panel to load, minus the leading
+ * "uk.org.ury." domain.
+ *
+ * @param parent The parent panel in the relationship modelled
+ * by the control panel interface.
+ *
+ * @param child The child panel in the relationship modelled
+ * by the control panel interface.
+ *
+ * @throws LoadFailureException if the class is
+ * not found, or is not an implementor of
+ * FrontendControlPanel.
+ */
+
+ private void
+ loadControlPanel (String cPanelName, FrontendModulePanel parent,
+ FrontendModulePanel child)
+ throws LoadFailureException
+ {
+ Class<?> cPanelClass = null;
+
+ try
+ {
+ cPanelClass = Class.forName ("uk.org.ury." + cPanelName);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new LoadFailureException ("Could not load control panel: "
+ + e.getMessage ());
+ }
+
+
+ if (FrontendControlPanel.class.isAssignableFrom (cPanelClass))
+ {
+ FrontendControlPanel temp = cpanel;
+
+ try
+ {
+ cpanel = ((FrontendControlPanel) cPanelClass.newInstance ());
+ }
+ catch (InstantiationException e)
+ {
+ throw new LoadFailureException ("Could not load control panel: "
+ + e.getMessage ());
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new LoadFailureException ("Could not load control panel: "
+ + e.getMessage ());
+ }
+
+ if (temp != null)
+ remove (temp);
+
+ cpanel.setPanels (parent, child);
+ cpanel.setMaster (this);
+ cpanel.setPreviousCPanel (temp);
+
+ add (cpanel, BorderLayout.SOUTH);
+ repaint ();
+ }
+ }
+
+
+ /**
+ * Restore an existing module and control panel into the frontend
+ * frame.
+ *
+ * @param mpanel The module panel to restore.
+ *
+ * @param cpanel The control panel to restore, if any. A null
+ * value signifies a lack of control panel.
+ *
+ * @throws IllegalArgumentException if the mpanel is null.
+ */
+
+ @Override
+ public void
+ restoreModule (FrontendModulePanel mpanel,
+ FrontendControlPanel cpanel)
+ {
+ if (mpanel == null)
+ throw new IllegalArgumentException ("mpanel is null.");
+
+ remove (child);
+ remove (this.cpanel);
+
+ child = mpanel;
+ add (child);
+
+ if (cpanel != null)
+ add (cpanel, BorderLayout.SOUTH);
+
+ this.cpanel = cpanel;
+
+ repaint ();
+ }
+
+
+ /**
+ * Report a fatal error,
+ *
+ * @param message The message, eg the exception message, to report
+ * to the user.
+ */
+
+ @Override
+ public void
+ fatalError (String message)
+ {
+ FrontendError.reportFatal (message, this);
+ }
+
+
+ /**
+ * @return the resource directory.
+ */
+
+ @Override
+ public String
+ getResourceDirectory ()
+ {
+ return getCodeBase () + "res/";
+ }
+} \ No newline at end of file
diff --git a/src/uk/org/ury/frontend/FrontendControlPanel.java b/src/uk/org/ury/frontend/FrontendControlPanel.java
index 5b7f486..b79021a 100644
--- a/src/uk/org/ury/frontend/FrontendControlPanel.java
+++ b/src/uk/org/ury/frontend/FrontendControlPanel.java
@@ -3,6 +3,8 @@
*/
package uk.org.ury.frontend;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
+
/**
* Abstract class for frontend module control panels.
@@ -38,26 +40,16 @@ public abstract class FrontendControlPanel extends FrontendPanel
* @param xmlPath The path, relative from this source file, to the
* XML file from which this panel will read its
* layout.
+ *
+ * @throws UICreationFailureException if the UI creation fails.
*/
public
FrontendControlPanel (String xmlPath)
+ throws UICreationFailureException
{
super (xmlPath, null);
}
-
-
- /**
- * Set the frontend master to which this panel is bound.
- *
- * @param master The master to set.
- */
-
- public void
- setMaster (FrontendMaster master)
- {
- this.master = master;
- }
/**
diff --git a/src/uk/org/ury/frontend/FrontendError.java b/src/uk/org/ury/frontend/FrontendError.java
index a08b966..4a13c0a 100644
--- a/src/uk/org/ury/frontend/FrontendError.java
+++ b/src/uk/org/ury/frontend/FrontendError.java
@@ -29,8 +29,8 @@ public class FrontendError
/**
* Create an error dialogue to report a fatal error.
*
- * @string message The message, eg the exception message,
- * to report to the user.
+ * @param message The message, eg the exception message,
+ * to report to the user.
*/
public static void
@@ -47,4 +47,15 @@ public class FrontendError
System.exit (-1);
}
+
+
+ public static void
+ reportFatal (String message, FrontendApplet panel)
+ {
+ // TODO: Log
+
+ // TODO: Error dialogue
+
+ System.out.println (message);
+ }
}
diff --git a/src/uk/org/ury/frontend/FrontendFrame.java b/src/uk/org/ury/frontend/FrontendFrame.java
index aabdfbd..39cb89b 100644
--- a/src/uk/org/ury/frontend/FrontendFrame.java
+++ b/src/uk/org/ury/frontend/FrontendFrame.java
@@ -11,6 +11,8 @@ import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
+import uk.org.ury.frontend.exceptions.LoadFailureException;
+
/**
* A frame that hosts a FrontendModulePanel, used for serving frontend
* panels in a window (application mode).
@@ -31,11 +33,39 @@ public class FrontendFrame extends JFrame implements FrontendMaster
private FrontendModulePanel child;
private FrontendControlPanel cpanel;
+
+ /**
+ * Construct a new FrontendFrame given an initial frontend module.
+ *
+ * Loading will fail with a fatal error if the class is not found,
+ * or is not an implementor of FrontendModule.
+ *
+ * @param moduleName The fully qualified class-name of the module,
+ * minus the leading "uk.org.ury." domain.
+ */
+
public
- FrontendFrame (FrontendModulePanel parent)
+ FrontendFrame (String moduleName)
+ {
+ super ("URY newBAPS");
+ try
+ {
+ loadModule (moduleName);
+ }
+ catch (LoadFailureException e)
+ {
+ fatalError (e.getMessage ());
+ }
+ }
+
+
+ /**
+ * Set up the user interface of the frame.
+ */
+
+ public void
+ setupUI ()
{
- super (parent.getName ());
-
try
{
// Set System L&F
@@ -43,7 +73,7 @@ public class FrontendFrame extends JFrame implements FrontendMaster
}
catch (UnsupportedLookAndFeelException e)
{
- // handle exception
+ // handle exception
}
catch (ClassNotFoundException e)
{
@@ -60,21 +90,19 @@ public class FrontendFrame extends JFrame implements FrontendMaster
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
- this.child = parent;
-
Container cp = getContentPane ();
// Banner
-
- banner = new FrontendBanner (parent.getName ());
+ System.out.println (child);
+ banner = new FrontendBanner (child.getName ());
// Composition
cp.add (banner, BorderLayout.NORTH);
- cp.add (parent, BorderLayout.CENTER);
+ cp.add (child, BorderLayout.CENTER);
setPreferredSize (new Dimension (800, 600));
- setMinimumSize (new Dimension (800, 600));
+ setMinimumSize (new Dimension (800, 600));
pack ();
setVisible (true);
@@ -89,11 +117,16 @@ public class FrontendFrame extends JFrame implements FrontendMaster
*
* @param moduleName The fully qualified class-name of the module,
* minus the leading "uk.org.ury." domain.
+ *
+ * @throws LoadFailureException if the class is
+ * not found, or is not an implementor of
+ * FrontendModule.
*/
@Override
public void
loadModule (String moduleName)
+ throws LoadFailureException
{
Class<?> moduleClass = null;
@@ -103,11 +136,16 @@ public class FrontendFrame extends JFrame implements FrontendMaster
}
catch (ClassNotFoundException e)
{
- FrontendError.reportFatal ("Could not load module: " + e.getMessage (), this);
+ throw new LoadFailureException ("Could not load module: "
+ + e.getMessage ());
}
- if (FrontendModule.class.isAssignableFrom (moduleClass))
+ if (FrontendModule.class.isAssignableFrom (moduleClass) == false)
+ {
+ throw new LoadFailureException ("Could not load module: Not a FrontendModule");
+ }
+ else
{
FrontendModulePanel temp = child;
@@ -117,17 +155,24 @@ public class FrontendFrame extends JFrame implements FrontendMaster
}
catch (InstantiationException e)
{
- FrontendError.reportFatal ("Could not load module: " + e.getMessage (), this);
+ throw new LoadFailureException ("Could not load module: "
+ + e.getMessage ());
}
catch (IllegalAccessException e)
{
- FrontendError.reportFatal ("Could not load module: " + e.getMessage (), this);
+ throw new LoadFailureException ("Could not load module: "
+ + e.getMessage ());
}
- remove (temp);
+ if (temp != null)
+ remove (temp);
+
add (child);
+ child.setMaster (this);
+
+ if (banner != null)
+ banner.setTitle (child.getName ());
- banner.setTitle (child.getName ());
pack ();
}
}
@@ -146,11 +191,16 @@ public class FrontendFrame extends JFrame implements FrontendMaster
* @param cPanelName The fully qualified class-name of the control
* panel to install, minus the leading
* "uk.org.ury." domain.
+ *
+ * @throws LoadFailureException if the class is
+ * not found, or is not an implementor of
+ * FrontendModule.
*/
@Override
public void
loadModule (String moduleName, String cPanelName)
+ throws LoadFailureException
{
FrontendModulePanel newParent = child;
loadModule (moduleName);
@@ -172,11 +222,16 @@ public class FrontendFrame extends JFrame implements FrontendMaster
*
* @param child The child panel in the relationship modelled
* by the control panel interface.
+ *
+ * @throws LoadFailureException if the class is
+ * not found, or is not an implementor of
+ * FrontendControlPanel.
*/
-
+
private void
loadControlPanel (String cPanelName, FrontendModulePanel parent,
FrontendModulePanel child)
+ throws LoadFailureException
{
Class<?> cPanelClass = null;
@@ -186,7 +241,8 @@ public class FrontendFrame extends JFrame implements FrontendMaster
}
catch (ClassNotFoundException e)
{
- FrontendError.reportFatal ("Could not load control panel: " + e.getMessage (), this);
+ throw new LoadFailureException ("Could not load control panel: "
+ + e.getMessage ());
}
@@ -200,11 +256,13 @@ public class FrontendFrame extends JFrame implements FrontendMaster
}
catch (InstantiationException e)
{
- FrontendError.reportFatal ("Could not load module: " + e.getMessage (), this);
+ throw new LoadFailureException ("Could not load control panel: "
+ + e.getMessage ());
}
catch (IllegalAccessException e)
{
- FrontendError.reportFatal ("Could not load module: " + e.getMessage (), this);
+ throw new LoadFailureException ("Could not load control panel: "
+ + e.getMessage ());
}
if (temp != null)
@@ -255,4 +313,31 @@ public class FrontendFrame extends JFrame implements FrontendMaster
pack ();
repaint ();
}
+
+
+ /**
+ * Report a fatal error,
+ *
+ * @param message The message, eg the exception message, to report
+ * to the user.
+ */
+
+ @Override
+ public void
+ fatalError (String message)
+ {
+ FrontendError.reportFatal (message, this);
+ }
+
+
+ /**
+ * @return the resource directory.
+ */
+
+ @Override
+ public String
+ getResourceDirectory ()
+ {
+ return "res/";
+ }
}
diff --git a/src/uk/org/ury/frontend/FrontendMaster.java b/src/uk/org/ury/frontend/FrontendMaster.java
index c169d04..0a89e89 100644
--- a/src/uk/org/ury/frontend/FrontendMaster.java
+++ b/src/uk/org/ury/frontend/FrontendMaster.java
@@ -3,6 +3,8 @@
*/
package uk.org.ury.frontend;
+import uk.org.ury.frontend.exceptions.LoadFailureException;
+
/**
* Interface for classes providing the parent unit of a frontend
@@ -24,10 +26,15 @@ public interface FrontendMaster
*
* @param moduleName The fully qualified class-name of the module,
* minus the leading "uk.org.ury." domain.
+ *
+ * @throws LoadFailureException if the class is
+ * not found, or is not an implementor of
+ * FrontendModule.
*/
public void
- loadModule (String moduleName);
+ loadModule (String moduleName)
+ throws LoadFailureException;
/**
@@ -40,13 +47,18 @@ public interface FrontendMaster
* @param moduleName The fully qualified class-name of the module,
* minus the leading "uk.org.ury." domain.
*
- * @param cpanelName The fully qualified class-name of the control
+ * @param cPanelName The fully qualified class-name of the control
* panel to install, minus the leading
* "uk.org.ury." domain.
+ *
+ * @throws LoadFailureException if the class is
+ * not found, or is not an implementor of
+ * FrontendModule.
*/
public void
- loadModule (String moduleName, String cPanelName);
+ loadModule (String moduleName, String cPanelName)
+ throws LoadFailureException;
/**
@@ -62,4 +74,31 @@ public interface FrontendMaster
public void
restoreModule (FrontendModulePanel mpanel, FrontendControlPanel cpanel);
+
+
+ /**
+ * Report a fatal error,
+ *
+ * @param message The message, eg the exception message, to report
+ * to the user.
+ */
+
+ public void
+ fatalError (String message);
+
+
+ /**
+ * Set up the frontend master's user interface.
+ */
+
+ public void
+ setupUI ();
+
+
+ /**
+ * @return the resource directory.
+ */
+
+ public String
+ getResourceDirectory ();
}
diff --git a/src/uk/org/ury/frontend/FrontendModulePanel.java b/src/uk/org/ury/frontend/FrontendModulePanel.java
index 148875f..f5009c4 100644
--- a/src/uk/org/ury/frontend/FrontendModulePanel.java
+++ b/src/uk/org/ury/frontend/FrontendModulePanel.java
@@ -3,6 +3,8 @@
*/
package uk.org.ury.frontend;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
+
/**
* A frontend user interface panel.
@@ -52,11 +54,14 @@ public abstract class FrontendModulePanel extends FrontendPanel
* layout.
*
* @param master The FrontendMaster driving the frontend.
+ *
+ * @throws UICreationFailureException if the UI creation fails.
*/
public
FrontendModulePanel (FrontendModule module, String xmlPath,
FrontendMaster master)
+ throws UICreationFailureException
{
super (xmlPath, master);
this.module = module;
@@ -82,9 +87,4 @@ public abstract class FrontendModulePanel extends FrontendPanel
{
return module;
}
-
-
- /**
- *
- */
}
diff --git a/src/uk/org/ury/frontend/FrontendPanel.java b/src/uk/org/ury/frontend/FrontendPanel.java
index 0ec8003..931f86b 100644
--- a/src/uk/org/ury/frontend/FrontendPanel.java
+++ b/src/uk/org/ury/frontend/FrontendPanel.java
@@ -6,11 +6,18 @@ import javax.swing.JPanel;
import org.swixml.SwingEngine;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
+
/**
* An extension of JPanel providing common functionality for user
* interface panels in the URY system frontend.
*
+ * Most notably, this includes automated access to XML-based
+ * preparation of the user interface provided by the panel,
+ * using an appropriate constructor call giving the XML file from
+ * which the user interface form should be read.
+ *
* @author Matt Windsor
*
*/
@@ -27,7 +34,9 @@ public class FrontendPanel extends JPanel
/**
* Construct a new, blank FrontendPanel.
*
- * @param master The FrontendMaster driving the frontend.
+ * @param master The FrontendMaster driving the frontend, if any.
+ * For direct instantiations of this class,
+ * providing null here is guaranteed to be safe.
*/
public
@@ -43,17 +52,22 @@ public class FrontendPanel extends JPanel
* Construct a new FrontendPanel from an XML layout.
*
* This is the preferred means of constructing FrontendPanels, and
- * uses SWIXml to construct the panel layout.
+ * uses an XML-based engine to construct the panel layout.
*
* @param xmlPath The path, relative from this source file, to the
* XML file from which this panel will read its
* layout.
*
- * @param master The FrontendMaster driving the frontend.
+ * @param master The FrontendMaster driving the frontend, if any.
+ * For direct instantiations of this class,
+ * providing null here is guaranteed to be safe.
+ *
+ * @throws UICreationFailureException if the UI creation fails.
*/
public
FrontendPanel (String xmlPath, FrontendMaster master)
+ throws UICreationFailureException
{
super ();
@@ -65,8 +79,10 @@ public class FrontendPanel extends JPanel
URL path = getClass ().getResource (xmlPath);
if (path == null)
- FrontendError.reportFatal ("UI creation failure: XML layout "
- + xmlPath + " does not exist.", null);
+ throw new UICreationFailureException ("UI creation failure:"
+ + "XML layout "
+ + xmlPath
+ + " does not exist.");
SwingEngine se = new SwingEngine (this);
@@ -85,7 +101,21 @@ public class FrontendPanel extends JPanel
}
catch (Exception e)
{
- FrontendError.reportFatal ("UI creation failure: " + e.getMessage (), null);
+ throw new UICreationFailureException ("UI creation failure: "
+ + e.getMessage ());
}
}
+
+
+ /**
+ * Set the frontend master.
+ *
+ * @param master The new frontend master to use.
+ */
+
+ public void
+ setMaster (FrontendMaster master)
+ {
+ this.master = master;
+ }
}
diff --git a/src/uk/org/ury/frontend/FrontendSubBanner.java b/src/uk/org/ury/frontend/FrontendSubBanner.java
index da162bb..6942fe1 100644
--- a/src/uk/org/ury/frontend/FrontendSubBanner.java
+++ b/src/uk/org/ury/frontend/FrontendSubBanner.java
@@ -2,7 +2,6 @@ package uk.org.ury.frontend;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
-import javax.swing.JTextArea;
import javax.swing.UIManager;
@@ -15,6 +14,10 @@ import javax.swing.UIManager;
public class FrontendSubBanner extends JLabel
{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7843563245601622086L;
private static final String TITLE_PREFIX = "<html><b>";
private static final String TITLE_SUFFIX = "</b></html>";
diff --git a/src/uk/org/ury/frontend/exceptions/LoadFailureException.java b/src/uk/org/ury/frontend/exceptions/LoadFailureException.java
new file mode 100644
index 0000000..691eaa0
--- /dev/null
+++ b/src/uk/org/ury/frontend/exceptions/LoadFailureException.java
@@ -0,0 +1,44 @@
+/**
+ *
+ */
+package uk.org.ury.frontend.exceptions;
+
+
+/**
+ * Exception thrown when the loading of a new frontend module fails.
+ *
+ * @author Matt Windsor
+ */
+
+public class LoadFailureException extends Exception
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7353531873142099828L;
+
+
+/**
+ * Construct a new LoadFailureException with a
+ * default reason.
+ */
+
+ public
+ LoadFailureException ()
+ {
+ super ("Module load failure.");
+ }
+
+
+ /**
+ * Construct a new LoadFailureException.
+ *
+ * @param reason The explanation for the exception.
+ */
+
+ public
+ LoadFailureException (String reason)
+ {
+ super (reason);
+ }
+}
diff --git a/src/uk/org/ury/frontend/exceptions/UICreationFailureException.java b/src/uk/org/ury/frontend/exceptions/UICreationFailureException.java
new file mode 100644
index 0000000..6d51ef3
--- /dev/null
+++ b/src/uk/org/ury/frontend/exceptions/UICreationFailureException.java
@@ -0,0 +1,44 @@
+/**
+ *
+ */
+package uk.org.ury.frontend.exceptions;
+
+
+/**
+ * Exception thrown when the creation of a UI element fails.
+ *
+ * @author Matt Windsor
+ */
+
+public class UICreationFailureException extends Exception
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7353531873142099828L;
+
+
+/**
+ * Construct a new UICreationFailureException with a
+ * default reason.
+ */
+
+ public
+ UICreationFailureException ()
+ {
+ super ("UI creation failure.");
+ }
+
+
+ /**
+ * Construct a new UICreationFailureException.
+ *
+ * @param reason The explanation for the exception.
+ */
+
+ public
+ UICreationFailureException (String reason)
+ {
+ super (reason);
+ }
+}
diff --git a/src/uk/org/ury/library/LibraryRequestHandler.java b/src/uk/org/ury/library/LibraryRequestHandler.java
new file mode 100644
index 0000000..30bb7fc
--- /dev/null
+++ b/src/uk/org/ury/library/LibraryRequestHandler.java
@@ -0,0 +1,144 @@
+/**
+ *
+ */
+package uk.org.ury.library;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import uk.org.ury.database.DatabaseDriver;
+import uk.org.ury.database.UserClass;
+import uk.org.ury.database.exceptions.ConnectionFailureException;
+import uk.org.ury.database.exceptions.MissingCredentialsException;
+import uk.org.ury.database.exceptions.QueryFailureException;
+import uk.org.ury.library.exceptions.EmptySearchException;
+import uk.org.ury.library.item.LibraryItem;
+import uk.org.ury.server.Server;
+import uk.org.ury.server.RequestHandler;
+import uk.org.ury.server.exceptions.HandleFailureException;
+import uk.org.ury.server.protocol.Directive;
+
+/**
+ * A request handler for library queries.
+ *
+ * @author Matt Windsor
+ */
+
+public class LibraryRequestHandler implements RequestHandler
+{
+ /**
+ * Handle a server GET request (that is, a request for data
+ * output).
+ *
+ * @param parameters A key-value map of parameters supplied with
+ * the server request. Typically, the function
+ * parameter will detail the function that the
+ * request handler is expected to perform.
+ *
+ * @param server The server from which the request originated.
+ * This will be able to provide the handler with
+ * pooled resources, for example the database.
+ *
+ * @return A list of lines to return in the body of the
+ * server's response to the client.
+ *
+ * @throws HandleFailureException if the handler cannot
+ * handle the request.
+ */
+
+ @Override
+ public List<String>
+ handleGetRequest (Map<String, String> parameters, Server server)
+ throws HandleFailureException
+ {
+ List<String> response = new ArrayList<String> ();
+
+ if (parameters.containsKey ("function"))
+ {
+ String function = parameters.get ("function");
+
+ if (function.equals ("search"))
+ {
+ doSearch (parameters, response, server);
+ }
+ else if (function.equals ("help"))
+ {
+ response.add ("INFO: Available functions:");
+ response.add ("INFO: search (string) - search library for string.");
+ }
+ else
+ throw new HandleFailureException ("Unknown function: "
+ + function + ". (Try 'function=help'.)");
+
+ }
+ else
+ throw new HandleFailureException ("No function provided. (Try 'function=help'.)");
+
+ return response;
+ }
+
+
+ /**
+ * Perform a library search, populating the response list.
+ *
+ * @param parameters A key-value map of parameters supplied with
+ * the server request. Typically, the function
+ * parameter will detail the function that the
+ * request handler is expected to perform.
+ *
+ * @param response The response list to populate.
+ *
+ * @param server The server providing database resources.
+ *
+ * @throws HandleFailureException if an error occurs
+ * that thwarts the handling of the request.
+ */
+
+ private void
+ doSearch (Map<String, String> parameters,
+ List<String> response, Server server)
+ throws HandleFailureException
+ {
+ if (parameters.containsKey ("search") == false)
+ throw new HandleFailureException ("Search term is missing.");
+ else if (parameters.get ("search") == null)
+ throw new HandleFailureException ("Search term is null.");
+
+ String search = parameters.get ("search");
+ DatabaseDriver dd = null;
+
+ try
+ {
+ dd = server.getDatabaseConnection (UserClass.READ_ONLY);
+ }
+ catch (MissingCredentialsException e)
+ {
+ throw new HandleFailureException (e.getMessage ());
+ }
+ catch (ConnectionFailureException e)
+ {
+ throw new HandleFailureException (e.getMessage ());
+ }
+
+ try
+ {
+ for (LibraryItem li : LibraryUtils.search (dd, search))
+ {
+ response.add (Directive.ITEM_START.toString ());
+
+ response.addAll (li.asResponse ());
+
+ response.add (Directive.ITEM_END.toString ());
+ }
+ }
+ catch (QueryFailureException e)
+ {
+ throw new HandleFailureException (e.getMessage ());
+ }
+ catch (EmptySearchException e)
+ {
+ throw new HandleFailureException (e.getMessage ());
+ }
+ }
+}
diff --git a/src/uk/org/ury/library/LibraryUtils.java b/src/uk/org/ury/library/LibraryUtils.java
index a280738..8a71285 100644
--- a/src/uk/org/ury/library/LibraryUtils.java
+++ b/src/uk/org/ury/library/LibraryUtils.java
@@ -8,12 +8,16 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Map;
import uk.org.ury.database.DatabaseDriver;
import uk.org.ury.database.exceptions.QueryFailureException;
-import uk.org.ury.library.LibraryItemProperty;
import uk.org.ury.library.exceptions.EmptySearchException;
+import uk.org.ury.library.item.LibraryItem;
+import uk.org.ury.library.item.LibraryItemProperty;
+import uk.org.ury.server.protocol.Directive;
/**
@@ -77,13 +81,9 @@ public class LibraryUtils
+ " t.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,"
- + " digitised, clean,"
- + " a.fname AS fnameadd, a.sname AS snameadd, b.fname AS fnameedit, b.sname AS snameedit"
+ + " shelfletter, shelfnumber, cdid, digitised, clean"
+ " FROM rec_record AS r"
+ " INNER JOIN rec_track AS t ON (r.recordid = t.recordid)"
- + " INNER JOIN member AS a ON (a.memberid = r.memberid_add)"
- + " LEFT JOIN member AS b ON (b.memberid = r.memberid_lastedit)"
+ " WHERE t.title ILIKE ?"
+ " OR t.artist ILIKE ?"
+ " OR r.title ILIKE ?"
@@ -126,7 +126,7 @@ public class LibraryUtils
{
// Translate SQL columns into a list of properties.
- HashMap<LibraryItemProperty, String> properties = new HashMap<LibraryItemProperty, String> ();
+ Map<LibraryItemProperty, String> properties = new HashMap<LibraryItemProperty, String> ();
for (LibraryItemProperty p : LibraryItemProperty.values ())
{
@@ -144,4 +144,102 @@ public class LibraryUtils
return new LibraryItem (properties);
}
+
+
+ /**
+ * Construct items from a server response body.
+ *
+ * @param response The list of strings that constitute the response.
+ *
+ * @return a list of LibraryItems corresponding to the item
+ * stanzas in the response.
+ */
+
+ public static List<LibraryItem>
+ extractItemsFromResponse (List<String> response)
+ {
+ List<LibraryItem> result = new ArrayList<LibraryItem> ();
+
+ boolean inItem = false;
+ List<String> itemBuffer = new ArrayList<String> ();
+
+ for (String line : response)
+ {
+ if (inItem == false)
+ {
+ if (line.startsWith (Directive.ITEM_START.toString ()))
+ {
+ inItem = true;
+ itemBuffer.clear ();
+ }
+ }
+
+ if (inItem == true)
+ {
+ itemBuffer.add (line);
+
+ if (line.startsWith (Directive.ITEM_END.toString ()))
+ {
+ inItem = false;
+ result.add (createItemFromResponse (itemBuffer));
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Construct a new item from a server response fragment.
+ *
+ * @param response The list of strings that constitutes the response.
+ * The list must begin with Directive.ITEM_START and
+ * end with Directive.ITEM_END's string
+ * representations and otherwise contain solely
+ * Directive.ITEM_PROPERTY lines.
+ *
+ * @return a LibraryItem embodying the properties described
+ * in the response fragment.
+ *
+ * @throws IllegalArgumentException if the response is
+ * malformed or null, or if the instantiation of
+ * DatabaseItem does not use String as its data type.
+ */
+
+ public static LibraryItem
+ createItemFromResponse (List<String> response)
+ {
+ // TODO: More appropriate exceptions.
+
+ if (response == null)
+ throw new IllegalArgumentException ("Response is null.");
+ else if (response.get (0).equals (Directive.ITEM_START.toString ())
+ && response.get (response.size () - 1)
+ .equals (Directive.ITEM_END.toString ()))
+ {
+ // Response of size 2 must be blank.
+ if (response.size () <= 2)
+ throw new IllegalArgumentException ("Blank response.");
+
+ Map<LibraryItemProperty, String> properties = new HashMap<LibraryItemProperty, String> ();
+
+ for (int i = 0; i < response.size () - 1; i++)
+ {
+ // TODO: fan out impl. details to separate class
+ if (response.get (i)
+ .startsWith (Directive.ITEM_PROPERTY.toString ()))
+ {
+ String[] responseTuple = response.get (i).split (":=");
+
+ properties.put (LibraryItemProperty.getFromSQL (responseTuple[1]),
+ responseTuple[2]);
+ }
+ }
+
+ return new LibraryItem (properties);
+ }
+ else
+ throw new IllegalArgumentException ("Malformed response.");
+ }
}
diff --git a/src/uk/org/ury/library/item/LibraryItem.java b/src/uk/org/ury/library/item/LibraryItem.java
new file mode 100644
index 0000000..d2a790b
--- /dev/null
+++ b/src/uk/org/ury/library/item/LibraryItem.java
@@ -0,0 +1,26 @@
+/**
+ *
+ */
+package uk.org.ury.library.item;
+
+
+import java.util.Map;
+
+import uk.org.ury.database.DatabaseItem;
+
+
+/**
+ * An item in the URY library.
+ *
+ * @author Matt Windsor
+ */
+
+public class LibraryItem extends DatabaseItem<LibraryItemProperty,
+ String>
+{
+ public
+ LibraryItem (Map<LibraryItemProperty, String> properties)
+ {
+ super (properties);
+ }
+} \ No newline at end of file
diff --git a/src/uk/org/ury/library/item/LibraryItemProperty.java b/src/uk/org/ury/library/item/LibraryItemProperty.java
new file mode 100644
index 0000000..44f5f22
--- /dev/null
+++ b/src/uk/org/ury/library/item/LibraryItemProperty.java
@@ -0,0 +1,62 @@
+package uk.org.ury.library.item;
+
+/**
+ * The parameters that are stored in the LibraryItem.
+ *
+ * @author Matt Windsor
+ */
+
+public enum LibraryItemProperty
+ {
+ // Constant SQL identifier
+ TITLE ("title"),
+ ALBUM ("album"),
+ ARTIST ("artist"),
+ LABEL ("label"),
+ STATUS ("status"),
+ MEDIUM ("medium"),
+ FORMAT ("format"),
+ DATE_RELEASED ("datereleased"),
+ DATE_ADDED ("dateadded"),
+ DATE_EDITED ("dateedited"),
+ SHELF_LETTER ("shelfletter"),
+ SHELF_NUMBER ("shelfnumber"),
+ CD_ID ("cdid"),
+ IS_DIGITISED ("digitised"),
+ IS_CLEAN ("clean");
+
+
+ public final String sql;
+
+
+ private
+ LibraryItemProperty (String sql)
+ {
+ this.sql = sql;
+ }
+
+
+ /**
+ * Retrieve a LibraryItemProperty given its SQL identifier.
+ *
+ * @param string The SQL identifier.
+ * @return The first property to match.
+ *
+ * @throws IllegalArgumentException if no matches were
+ * found.
+ */
+
+ public static LibraryItemProperty
+ getFromSQL (String string)
+ {
+ // TODO: Better exception?
+
+ for (LibraryItemProperty prop : values ())
+ {
+ if (prop.sql.equals (string))
+ return prop;
+ }
+
+ throw new IllegalArgumentException ("Nonexistent property SQL.");
+ }
+ }; \ No newline at end of file
diff --git a/src/uk/org/ury/library/viewer/LibraryTableModel.java b/src/uk/org/ury/library/viewer/LibraryTableModel.java
new file mode 100644
index 0000000..1ce5709
--- /dev/null
+++ b/src/uk/org/ury/library/viewer/LibraryTableModel.java
@@ -0,0 +1,184 @@
+/**
+ *
+ */
+package uk.org.ury.library.viewer;
+
+import java.util.List;
+
+import javax.swing.table.AbstractTableModel;
+
+import uk.org.ury.database.exceptions.MissingPropertyException;
+import uk.org.ury.library.item.LibraryItem;
+import uk.org.ury.library.item.LibraryItemProperty;
+
+
+/**
+ * A table model for the library viewer.
+ *
+ * @author Matt Windsor
+ */
+
+public class LibraryTableModel extends AbstractTableModel
+{
+
+ /**
+ *
+ */
+
+ private static final long serialVersionUID = -1744980619128903509L;
+
+ private List<LibraryItem> data;
+
+
+ /**
+ * Construct a new table model.
+ *
+ * @param data The list of data on which the model will be based.
+ */
+
+ public
+ LibraryTableModel (List<LibraryItem> data)
+ {
+ this.data = data;
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.TableModel#getColumnCount()
+ */
+
+ @Override
+ public int
+ getColumnCount ()
+ {
+ return 6;
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.TableModel#getRowCount()
+ */
+
+ @Override
+ public int
+ getRowCount ()
+ {
+ return data.size ();
+ }
+
+
+ /**
+ * @param c The column whose class should be investigated.
+ *
+ * @return the column class of column c.
+ */
+
+ @Override
+ public Class<?>
+ getColumnClass (int c)
+ {
+ return getValueAt (0, c).getClass ();
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.TableModel#getValueAt(int, int)
+ */
+
+ @Override
+ public Object
+ getValueAt (int rowIndex, int columnIndex)
+ {
+ LibraryItem li = data.get (rowIndex);
+
+ try
+ {
+ String[] columnData = {li.get (LibraryItemProperty.TITLE),
+ li.get (LibraryItemProperty.ARTIST),
+ li.get (LibraryItemProperty.ALBUM)};
+
+ switch (columnIndex)
+ {
+ default: // Title, artist, album, unknown
+
+ if (columnIndex >= columnData.length)
+ return "Unknown";
+ else
+ return columnData[columnIndex];
+
+ case 3: // Medium
+
+ // TODO: Make this less kludge-y
+
+ String mediumString = li.get (LibraryItemProperty.MEDIUM);
+
+ if (mediumString.equals ("c"))
+ return "Compact Disc";
+ else if (mediumString.equals ("7"))
+ return "7\" Vinyl";
+ else if (mediumString.equals ("2"))
+ return "12\" Vinyl";
+ else
+ return "Unrecognised";
+
+ case 4: // Clean?
+
+ // Return true if marked true, false if marked false or unknown etc.
+
+ String cleanString = li.get (LibraryItemProperty.IS_CLEAN);
+
+ // TODO: Nicer way of showing this
+
+ if (cleanString.equals ("y"))
+ return "Yes";
+ else if (cleanString.equals ("n"))
+ return "No";
+ else
+ return "???";
+
+ case 5: // isDigitised
+
+ // Return true if marked true, false if marked false or unknown etc.
+
+ String digitisedString = li.get (LibraryItemProperty.IS_DIGITISED);
+
+ if (digitisedString.equals ("t"))
+ return true;
+ else
+ return false;
+ }
+ }
+ catch (MissingPropertyException e)
+ {
+ return "Unknown";
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.TableModel#getColumnName(int, int)
+ */
+
+ @Override
+ public String
+ getColumnName (int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return "Title";
+ case 1:
+ return "Artist";
+ case 2:
+ return "Album";
+ case 3:
+ return "Medium";
+ case 4:
+ return "Clean?";
+ case 5:
+ return "On system?";
+ default:
+ return "ERROR";
+ }
+ }
+}
diff --git a/src/uk/org/ury/library/viewer/LibraryViewer.java b/src/uk/org/ury/library/viewer/LibraryViewer.java
index a98fa54..9587d5e 100644
--- a/src/uk/org/ury/library/viewer/LibraryViewer.java
+++ b/src/uk/org/ury/library/viewer/LibraryViewer.java
@@ -1,27 +1,21 @@
package uk.org.ury.library.viewer;
-import java.lang.reflect.InvocationTargetException;
-
import java.util.ArrayList;
import java.util.List;
-import javax.swing.SwingUtilities;
-
import uk.org.ury.config.ConfigReader;
import uk.org.ury.database.DatabaseDriver;
import uk.org.ury.database.UserClass;
import uk.org.ury.database.exceptions.MissingCredentialsException;
import uk.org.ury.database.exceptions.QueryFailureException;
import uk.org.ury.frontend.AbstractFrontendModule;
-import uk.org.ury.frontend.FrontendError;
-import uk.org.ury.frontend.FrontendFrame;
import uk.org.ury.frontend.FrontendMaster;
import uk.org.ury.frontend.FrontendModulePanel;
-
-import uk.org.ury.library.LibraryItem;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
import uk.org.ury.library.LibraryUtils;
import uk.org.ury.library.exceptions.EmptySearchException;
+import uk.org.ury.library.item.LibraryItem;
public class LibraryViewer extends AbstractFrontendModule
{
@@ -33,7 +27,6 @@ public class LibraryViewer extends AbstractFrontendModule
private DatabaseDriver dd;
private List<LibraryItem> libraryList;
private LibraryViewerPanel panel;
- private FrontendFrame frame;
private ConfigReader config;
@@ -53,64 +46,9 @@ public class LibraryViewer extends AbstractFrontendModule
System.out.println(e);
}
- frame = null;
libraryList = new ArrayList<LibraryItem> ();
panel = null;
}
-
-
- /**
- * Initialise the library viewer frontend as an applet.
- */
-
- public void
- init ()
- {
- frame = null;
- libraryList = new ArrayList<LibraryItem> ();
- panel = null;
-
-
- try
- {
- SwingUtilities.invokeAndWait (new Runnable ()
- {
- public void
- run ()
- {
- panel.setOpaque (true);
- setContentPane (panel);
-
- runFrontend (null);
- }
-
- });
- }
- 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, null);
-
- add (panel);
- }
/**
@@ -129,14 +67,22 @@ public class LibraryViewer extends AbstractFrontendModule
catch (MissingCredentialsException e)
{
// TODO: Privilege de-escalation
- FrontendError.reportFatal (e.getMessage (), frame);
+ master.fatalError (e.getMessage ());
}
catch (Exception f)
{
- FrontendError.reportFatal (f.getMessage (), frame);
+ master.fatalError (f.getMessage ());
}
- panel = new LibraryViewerPanel (this, master);
+ try
+ {
+ panel = new LibraryViewerPanel (this, master);
+ }
+ catch (UICreationFailureException e)
+ {
+ master.fatalError (e.getMessage ());
+ }
+
return panel;
}
@@ -152,19 +98,16 @@ public class LibraryViewer extends AbstractFrontendModule
*
* @throws EmptySearchException if the search string is
* empty or null (from LibraryUtils.search).
+ *
+ * @throws QueryFailureException if the search query
+ * fails (from LibraryUtils.search).
*/
public void
- doSearch (String search) throws EmptySearchException
+ doSearch (String search)
+ throws EmptySearchException, QueryFailureException
{
- try
- {
- libraryList = LibraryUtils.search (dd, search);
- }
- catch (QueryFailureException e)
- {
- FrontendError.reportFatal (e.getMessage (), frame);
- }
+ libraryList = LibraryUtils.search (dd, search);
}
diff --git a/src/uk/org/ury/library/viewer/LibraryViewerPanel.java b/src/uk/org/ury/library/viewer/LibraryViewerPanel.java
index 7638822..e453095 100644
--- a/src/uk/org/ury/library/viewer/LibraryViewerPanel.java
+++ b/src/uk/org/ury/library/viewer/LibraryViewerPanel.java
@@ -14,9 +14,10 @@ import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
+import uk.org.ury.database.exceptions.QueryFailureException;
import uk.org.ury.frontend.FrontendMaster;
import uk.org.ury.frontend.FrontendModulePanel;
-import uk.org.ury.library.LibraryTableModel;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
import uk.org.ury.library.exceptions.EmptySearchException;
@@ -59,10 +60,13 @@ public class LibraryViewerPanel extends FrontendModulePanel
* @param viewer The LibraryViewer controlling this LibraryViewerPanel.
*
* @param master The FrontendMaster driving the frontend.
+ *
+ * @throws UICreationFailureException if the UI creation fails.
*/
public
LibraryViewerPanel (LibraryViewer viewer, FrontendMaster master)
+ throws UICreationFailureException
{
super (viewer, "library_viewer_gui.xml", master);
@@ -138,6 +142,10 @@ public class LibraryViewerPanel extends FrontendModulePanel
{
master.doSearch (searchField.getText ());
}
+ catch (QueryFailureException e)
+ {
+ searchFailureMessage = "Search failed: " + e.getMessage ();
+ }
catch (EmptySearchException e)
{
searchFailureMessage = "Please type in a search term.";
diff --git a/src/uk/org/ury/library/viewer/library_viewer_gui.xml b/src/uk/org/ury/library/viewer/library_viewer_gui.xml
index 6b7e745..5177e3f 100644
--- a/src/uk/org/ury/library/viewer/library_viewer_gui.xml
+++ b/src/uk/org/ury/library/viewer/library_viewer_gui.xml
@@ -1,13 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<panel layout="BorderLayout">
- <hbox constraints="BorderLayout.NORTH" border="EmptyBorder(5,5,5,5)" size="640,32">
- <label text="Search for:" labelfor="searchField" displayedmnemonic="VK_F"
- font="Verdana-BOLD-14" />
+ <hbox constraints="BorderLayout.NORTH" border="EmptyBorder(5,5,5,5)">
+ <label text="Search for:" labelfor="searchField" displayedmnemonic="VK_F" />
<hbox border="EmptyBorder(0,5,0,5)">
<textfield id="searchField" mnemonic="VK_F" action="search" />
</hbox>
- <button id="searchButton" text="Search" mnemonic="VK_S" action="search"
- font="Verdana-BOLD-14" />
+ <button id="searchButton" text="Search" mnemonic="VK_S" action="search" />
</hbox>
<hbox constraints="BorderLayout.CENTER" border="EmptyBorder(0,5,0,5)">
@@ -16,14 +14,14 @@
</scrollpane>
<panel id="searchingPanel" constraints="BorderLayout.CENTER" visible="false"
layout="BorderLayout">
- <label id="searchingLabel" text="Searching..." font="Verdana-BOLD-16"
+ <label id="searchingLabel" text="Searching..."
constraints="BorderLayout.CENTER" horizontalalignment="CENTER" />
<progressbar id="searchingProgressBar" indeterminate="true"
constraints="BorderLayout.SOUTH" />
</panel>
<panel id="messagePanel" constraints="BorderLayout.CENTER" visible="false"
layout="BorderLayout">
- <label id="messageLabel" text="Searching..." font="Verdana-BOLD-16"
+ <label id="messageLabel" text="You shouldn't see this."
constraints="BorderLayout.CENTER" horizontalalignment="CENTER" />
</panel>
</hbox>
diff --git a/src/uk/org/ury/server/RequestHandler.java b/src/uk/org/ury/server/RequestHandler.java
new file mode 100644
index 0000000..a8f434d
--- /dev/null
+++ b/src/uk/org/ury/server/RequestHandler.java
@@ -0,0 +1,44 @@
+package uk.org.ury.server;
+
+import java.util.List;
+import java.util.Map;
+
+import uk.org.ury.server.exceptions.HandleFailureException;
+
+
+/**
+ * Interface for classes that can handle requests addressed to their
+ * class name from the main server.
+ *
+ * For an example of how to implement a RequestHandler, see
+ * ServerRequestHandler.
+ *
+ * @author Matt Windsor
+ */
+
+public interface RequestHandler
+{
+ /**
+ * Handle a server GET request (that is, a request for data
+ * output).
+ *
+ * @param parameters A key-value map of parameters supplied with the
+ * server request. Typically, the "function"
+ * parameter will detail the function that the
+ * request handler is expected to perform.
+ *
+ * @param server The server from which the request originated.
+ * This will be able to provide the handler with
+ * pooled resources, for example the database.
+ *
+ * @return A list of lines to return in the body of the
+ * server's response to the client.
+ *
+ * @throws HandleFailureException if the handler cannot
+ * handle the request.
+ */
+
+ public List<String>
+ handleGetRequest (Map<String, String> parameters, Server server)
+ throws HandleFailureException;
+}
diff --git a/src/uk/org/ury/server/Server.java b/src/uk/org/ury/server/Server.java
new file mode 100644
index 0000000..8a25916
--- /dev/null
+++ b/src/uk/org/ury/server/Server.java
@@ -0,0 +1,432 @@
+/**
+ *
+ */
+package uk.org.ury.server;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+
+import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.net.URLDecoder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+
+import uk.org.ury.config.ConfigReader;
+import uk.org.ury.database.DatabaseDriver;
+import uk.org.ury.database.UserClass;
+import uk.org.ury.database.exceptions.ConnectionFailureException;
+import uk.org.ury.database.exceptions.MissingCredentialsException;
+import uk.org.ury.server.exceptions.HandleFailureException;
+
+/**
+ * The unified URY server, accepting requests over HTTP.
+ *
+ * @author Matt Windsor
+ */
+
+public class Server
+{
+
+ private ServerSocket serverSocket;
+
+ private static final String HTTP_VERSION = "HTTP/1.1";
+ private static final String SERVER_VERSION = "SLUT 0.0";
+ private static final String DOCTYPE =
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""
+ + "\"http://www.w3.org/TR/html4/strict.dtd\">";
+ private static final String INDEX_HTML =
+ "\n<html>"
+ + "\n <head>"
+ + "\n <title>" + SERVER_VERSION + "</title>"
+ + "\n </head>"
+ + "\n <body>"
+ + "\n <h1>Welcome to the " + SERVER_VERSION + " server</h1>"
+ + "\n <p>This server exposes a class-based API for accessing"
+ + "\n the internals of the " + SERVER_VERSION + " system.</p>"
+ + "\n <p>See the documentation for details.</p>"
+ + "\n </body>"
+ + "\n</html>";
+
+
+ /**
+ * The main method, which serves to create a server.
+ *
+ * @param args The argument vector.
+ */
+
+ public static void
+ main (String[] args)
+ {
+ Server srv = new Server ();
+ srv.run ();
+ }
+
+
+ /**
+ * Run the server.
+ */
+
+ private void
+ run ()
+ {
+ try
+ {
+ serverSocket = new ServerSocket (8000);
+ }
+ catch (IOException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace ();
+ }
+
+ Socket clientSocket = null;
+
+ while (true)
+ {
+ System.out.println ("Accepting connections... bring 'em on!");
+
+ try
+ {
+ clientSocket = serverSocket.accept ();
+ }
+ catch (IOException e)
+ {
+ System.out.println ("SLUT: Accept failed on port 8000. I'm bailing.");
+ System.exit (-1);
+ }
+
+ try
+ {
+ doConnection (clientSocket);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace ();
+ }
+ finally
+ {
+ try
+ {
+ clientSocket.close ();
+ }
+ catch (IOException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+ public void
+ doConnection (Socket clientSocket)
+ throws IOException
+ {
+ PrintWriter out = new PrintWriter (clientSocket.getOutputStream(), true);
+ BufferedReader in = new BufferedReader (new InputStreamReader (
+ clientSocket.getInputStream()));
+ String inputLine;
+
+ //initiate conversation with client
+
+ List<String> buffer = new ArrayList<String> ();
+
+
+ for (inputLine = in.readLine (); inputLine != null; inputLine = in.readLine ())
+ {
+ if (inputLine.equals (""))
+ break;
+
+ buffer.add (inputLine);
+
+ if (inputLine.startsWith ("Expect:")
+ && inputLine.split (":")[1].startsWith ("100-continue"))
+ out.print ("HTTP/1.1 100 Continue\n\r\n");
+
+ out.flush ();
+ }
+
+ processBuffer (buffer, out);
+
+ out.flush ();
+ out.close ();
+ in.close ();
+
+ System.out.println ("Just finished with this one...");
+ }
+
+
+ public void
+ processBuffer (List<String> buffer, PrintWriter out)
+ {
+ String requestStart = buffer.get (0);
+
+ System.out.println (requestStart);
+
+ if (requestStart.startsWith ("GET"))
+ {
+ System.out.println ("That was a GET...");
+ handleGet (buffer, out);
+ }
+ else
+ {
+ System.out.println ("Uh-oh! I don't know what to do!");
+
+ out.println (HTTP_VERSION + " 501 Not Implemented");
+ out.println ("Connection: close");
+ out.print ("\r\n");
+ }
+ }
+
+ public void
+ handleGet (List<String> buffer, PrintWriter out)
+ {
+ String[] getsplit = buffer.get (0).split (" ");
+ String path = getsplit[1];
+
+ if (path.equals ("/index.html")
+ || path.equals ("/"))
+ {
+ // Someone's trying to get the index page!
+ // Humour them.
+
+ out.println (HTTP_VERSION + " 200 OK");
+ out.println ("Connection: close");
+ out.print ("\r\n");
+
+ out.println (DOCTYPE + INDEX_HTML);
+ }
+ else
+ {
+ // Convert this into a URL and fan out the various parts of it.
+
+ URL pathURL = null;
+
+ try
+ {
+ pathURL = new URL ("http://localhost" + path);
+ }
+ catch (MalformedURLException e1)
+ {
+ serveError (400, "Malformed URL.", out);
+ }
+
+
+ String className = "uk.org.ury" + pathURL.getPath ().replace ('/', '.');
+ System.out.println (className);
+ Class<?> newClass = null;
+
+
+ try
+ {
+ newClass = Class.forName (className);
+ }
+ catch (ClassNotFoundException e)
+ {
+ serveError (404, "Class " + className + " not found.", out);
+ return;
+ }
+
+ if (RequestHandler.class.isAssignableFrom (newClass))
+ {
+ String queryString = pathURL.getQuery ();
+ Map<String, String> parameters;
+ try
+ {
+ parameters = parseQueryString (queryString);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ serveError (500, "URL decode failure for class "
+ + className
+ + " (" + e.getMessage () + ").", out);
+ return;
+ }
+
+ List<String> response;
+
+ try
+ {
+ RequestHandler srh = ((RequestHandler) newClass.newInstance ());
+ response = srh.handleGetRequest (parameters, this);
+ }
+ catch (InstantiationException e)
+ {
+ serveError (500, "Instantiation exception for class "
+ + className
+ + " (" + e.getMessage () + ").", out);
+ return;
+ }
+ catch (IllegalAccessException e)
+ {
+ serveError (500, "Illegal access exception for class "
+ + className
+ + " (" + e.getMessage () + ").", out);
+ return;
+ }
+ catch (HandleFailureException e)
+ {
+ serveError (500, "Failed to handle request for class "
+ + className
+ + " (" + e.getMessage () + ").", out);
+ return;
+ }
+
+ // If we made it this far, the response is A-OK.
+
+ out.println (HTTP_VERSION + " 200 OK");
+ out.println ("Content-Type: text/plain");
+ out.print ("\r\n");
+
+ out.println ("START");
+
+ for (String line : response)
+ out.println (line);
+
+ out.println ("END");
+
+ out.flush ();
+ }
+ else
+ {
+ serveError (404, "Class " + className + " does not handle requests.", out);
+ return;
+ }
+ }
+ }
+
+
+ /**
+ * Serve a HTTP plain-text error.
+ *
+ * @param code HTTP status code to use.
+ * @param reason The reason to display to the client.
+ * @param out The output stream.
+ */
+
+ private void
+ serveError (int code, String reason, PrintWriter out)
+ {
+ String errorStatus = "";
+
+ switch (code)
+ {
+ case 400:
+ errorStatus = "400 Bad Request";
+ break;
+ case 404:
+ errorStatus = "404 Not Found";
+ break;
+ default:
+ errorStatus = "500 Internal Server Error";
+ break;
+ }
+
+ out.println (HTTP_VERSION + " " + errorStatus);
+ out.println ("Content-Type: text/plain");
+ out.println ("Connection: close");
+ out.print ("\r\n");
+
+ out.println ("ERROR: " + reason);
+ out.flush ();
+ }
+
+
+ /**
+ * Parse a query string, populating a key-value map of the
+ * URL-unescaped results.
+ *
+ * @param query The query string to parse.
+ *
+ * @return A map associating parameter keys and values.
+ *
+ * @throws UnsupportedEncodingException if the URL decoder
+ * fails.
+ */
+
+ public Map<String, String>
+ parseQueryString (String query)
+ throws UnsupportedEncodingException
+ {
+ Map<String, String> params = new HashMap<String, String> ();
+
+ // At least one parameter
+ if (query != null
+ && query.endsWith ("&") == false)
+ {
+ String[] qsplit = {query};
+
+ // More than one parameter - split the query.
+ if (query.contains ("&"))
+ qsplit = query.split ("&");
+
+
+ for (String param : qsplit)
+ {
+ // Has a value
+ if (param.contains ("=")
+ && param.endsWith ("=") == false)
+ {
+ String[] paramsplit = param.split ("=");
+ params.put (URLDecoder.decode (paramsplit[0], "UTF-8"),
+ URLDecoder.decode (paramsplit[1], "UTF-8"));
+ }
+ // Doesn't have a value
+ else if (param.contains ("=") == false)
+ {
+ params.put (URLDecoder.decode (param, "UTF-8"), null);
+ }
+ }
+ }
+
+ return params;
+ }
+
+
+ /**
+ * Get a database connection using the given user class.
+ *
+ * @param userClass The user class to get a connection for.
+ *
+ * @return a database connection, which may or may not
+ * have been created on this call.
+ *
+ * @throw MissingCredentialsException if the credentials
+ * for the given userclass are missing.
+ *
+ * @throw ConnectionFailureException if the connection
+ * failed.
+ */
+
+ public DatabaseDriver
+ getDatabaseConnection (UserClass userClass)
+ throws MissingCredentialsException, ConnectionFailureException
+ {
+ // TODO: Singleton
+
+ ConfigReader config = new ConfigReader ("res/conf.xml");
+
+ return new DatabaseDriver (config, UserClass.READ_ONLY);
+ }
+
+
+ /**
+ * @return the version string of the server.
+ */
+
+ public String
+ getVersion ()
+ {
+ return SERVER_VERSION;
+ }
+}
diff --git a/src/uk/org/ury/server/ServerProtocol.java b/src/uk/org/ury/server/ServerProtocol.java
new file mode 100644
index 0000000..92d2955
--- /dev/null
+++ b/src/uk/org/ury/server/ServerProtocol.java
@@ -0,0 +1,37 @@
+package uk.org.ury.server;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The BAPS server protocol (a minimal implementation of HTTP 1.1) handler.
+ *
+ * @author Matt Windsor
+ *
+ */
+
+public class ServerProtocol
+{
+ public static final String GET_HEADER = "HTTP/1.1 200 OK\n";
+
+ public List<String> buffer;
+
+
+ public
+ ServerProtocol ()
+ {
+ buffer = new ArrayList<String> ();
+ }
+
+ public String
+ processInput (String string)
+ {
+ if (string.equals (""))
+ {
+ System.out.println ("Bingo!");
+ return "HTTP/1.1 200 OK\nConnection: Close\n\r\n<html><head></head><body>poo</body></html>\n\r\n";
+ }
+ return "";
+ }
+
+}
diff --git a/src/uk/org/ury/server/ServerRequestHandler.java b/src/uk/org/ury/server/ServerRequestHandler.java
new file mode 100644
index 0000000..f67f927
--- /dev/null
+++ b/src/uk/org/ury/server/ServerRequestHandler.java
@@ -0,0 +1,96 @@
+/**
+ *
+ */
+package uk.org.ury.server;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import uk.org.ury.server.Server;
+import uk.org.ury.server.RequestHandler;
+import uk.org.ury.server.exceptions.HandleFailureException;
+
+
+/**
+ * A request handler for server queries.
+ *
+ * @author Matt Windsor
+ */
+
+public class ServerRequestHandler implements RequestHandler
+{
+ /**
+ * Handle a server GET request (that is, a request for data
+ * output).
+ *
+ * @param parameters A key-value map of parameters supplied with
+ * the server request. Typically, the function
+ * parameter will detail the function that the
+ * request handler is expected to perform.
+ *
+ * @param server The server from which the request originated.
+ * This will be able to provide the handler with
+ * pooled resources, for example the database.
+ *
+ * @return A list of lines to return in the body of the
+ * server's response to the client.
+ *
+ * @throws HandleFailureException if the handler cannot
+ * handle the request.
+ */
+
+ @Override
+ public List<String>
+ handleGetRequest (Map<String, String> parameters, Server server)
+ throws HandleFailureException
+ {
+ List<String> response = new ArrayList<String> ();
+
+ if (parameters.containsKey ("function"))
+ {
+ String function = parameters.get ("function");
+
+ if (function.equals ("info"))
+ {
+ getInfo (response, server);
+ }
+ else if (function.equals ("help"))
+ {
+ response.add ("INFO: Available functions:");
+ response.add ("INFO: info - Get server information.");
+ }
+ else if (function.equals ("test"))
+ response.add ("INFO: Test succeeded.");
+ else
+ throw new HandleFailureException ("Unknown function: "
+ + function + ". (Try 'function=help'.)");
+
+ }
+ else
+ throw new HandleFailureException ("No function provided. (Try 'function=help'.)");
+
+ return response;
+ }
+
+
+ /**
+ * Retrieve information about the server.
+ *
+ * @param response The response list to populate.
+ *
+ * @param server The server providing database resources.
+ *
+ * @throws HandleFailureException if an error occurs
+ * that thwarts the handling of the request.
+ */
+
+ private void
+ getInfo (List<String> response, Server server)
+ throws HandleFailureException
+ {
+ response.add ("INFO: University Radio York BAPS Replacement");
+ response.add ("INFO: Server version is " + server.getVersion ());
+ }
+
+}
diff --git a/src/uk/org/ury/server/exceptions/HandleFailureException.java b/src/uk/org/ury/server/exceptions/HandleFailureException.java
new file mode 100644
index 0000000..063cc52
--- /dev/null
+++ b/src/uk/org/ury/server/exceptions/HandleFailureException.java
@@ -0,0 +1,46 @@
+/**
+ *
+ */
+package uk.org.ury.server.exceptions;
+
+/**
+ * Generic exception thrown when a server request handler fails to
+ * handle a request.
+ *
+ * @author Matt Windsor
+ */
+
+public class HandleFailureException extends Exception
+{
+
+ /**
+ * Change this! ---v
+ */
+
+ private static final long serialVersionUID = -397479334359858162L;
+
+
+ /**
+ * Construct a new HandleFailureException with a
+ * default reason.
+ */
+
+ public
+ HandleFailureException ()
+ {
+ super ("Server request handler failed to handle the request.");
+ }
+
+
+ /**
+ * Construct a new HandleFailureException.
+ *
+ * @param reason The explanation for the exception.
+ */
+
+ public
+ HandleFailureException (String reason)
+ {
+ super (reason);
+ }
+}
diff --git a/src/uk/org/ury/server/protocol/Directive.java b/src/uk/org/ury/server/protocol/Directive.java
new file mode 100644
index 0000000..0d7a162
--- /dev/null
+++ b/src/uk/org/ury/server/protocol/Directive.java
@@ -0,0 +1,69 @@
+/**
+ *
+ */
+package uk.org.ury.server.protocol;
+
+/**
+ * Directives supported by the protocol.
+ *
+ * @author Matt Windsor
+ */
+
+public enum Directive
+ {
+ // ID String representation Singleton?
+
+ /** Directive marking the start of an item block. */
+ ITEM_START ("ITEM-START" , false),
+
+ /** Directive marking a property inside an item block. */
+ ITEM_PROPERTY ("PROP" , false),
+
+ /** Directive marking the end of an item block. */
+ ITEM_END ("ITEM-END" , false);
+
+
+
+ private String strRep; // String representation
+ private boolean isSingleton; // Is a singleton?
+
+
+ /**
+ * Construct a new Directive.
+ *
+ * @param strRep The string representation of the Directive.
+ *
+ * @param isSingleton If true, then the Directive accepts no
+ * properties. If false, then the Directive
+ * must be provided with at least one.
+ */
+
+ private
+ Directive (String strRep, boolean isSingleton)
+ {
+ this.strRep = strRep;
+ this.isSingleton = isSingleton;
+ }
+
+
+ /**
+ * @return the string representation.
+ */
+
+ public String
+ toString ()
+ {
+ return strRep;
+ }
+
+
+ /**
+ * @return true if the directive has no properties.
+ */
+
+ public Boolean
+ isSingleton ()
+ {
+ return isSingleton;
+ }
+ }
diff --git a/src/uk/org/ury/show/ShowChannel.java b/src/uk/org/ury/show/ShowChannel.java
index 6aa3ee8..8448e0f 100644
--- a/src/uk/org/ury/show/ShowChannel.java
+++ b/src/uk/org/ury/show/ShowChannel.java
@@ -3,6 +3,10 @@ package uk.org.ury.show;
import java.util.ArrayList;
import java.util.List;
+import javax.swing.AbstractListModel;
+
+import uk.org.ury.show.item.ShowItem;
+
/**
* A channel of ShowItems in a show.
@@ -10,8 +14,13 @@ import java.util.List;
* @author Matt Windsor
*/
-public class ShowChannel
+public class ShowChannel extends AbstractListModel
{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4651104185166068150L;
+
/* Items enqueued in channel. */
private List<ShowItem> items;
@@ -50,6 +59,7 @@ public class ShowChannel
" out of bounds.");
items.add (index, item);
+ fireIntervalAdded (this, index, index);
}
@@ -66,6 +76,7 @@ public class ShowChannel
throw new IllegalArgumentException ("Item is null.");
items.add (item);
+ fireIntervalAdded (this, items.size () - 1, items.size () - 1);
}
@@ -89,4 +100,32 @@ public class ShowChannel
return items.get (index);
}
+
+
+ /**
+ * List model retrieval wrapper for get.
+ *
+ * @param index The index of the item to retrieve from the channel.
+ *
+ * @return the item at the given index in the list.
+ */
+
+ @Override
+ public Object
+ getElementAt (int index)
+ {
+ return get (index);
+ }
+
+
+ /**
+ * @return the size of the list.
+ */
+
+ @Override
+ public int
+ getSize ()
+ {
+ return items.size ();
+ }
}
diff --git a/src/uk/org/ury/show/ShowUtils.java b/src/uk/org/ury/show/ShowUtils.java
index 11a5dad..aa041d9 100644
--- a/src/uk/org/ury/show/ShowUtils.java
+++ b/src/uk/org/ury/show/ShowUtils.java
@@ -12,8 +12,8 @@ import java.util.List;
import uk.org.ury.database.DatabaseDriver;
import uk.org.ury.database.exceptions.QueryFailureException;
-import uk.org.ury.show.ShowItem;
-import uk.org.ury.show.ShowItemProperty;
+import uk.org.ury.show.item.ShowItem;
+import uk.org.ury.show.item.ShowItemProperty;
/**
@@ -40,6 +40,65 @@ public class ShowUtils
/**
+ * Return the names of the public track folders, or "bins".
+ *
+ * @param db The database to query.
+ *
+ * @return a list of the public folder names.
+ * The list may be empty.
+ *
+ * @throws IllegalArgumentException if the database is
+ * null, the show ID is negative or the
+ * channel index falls out of bounds.
+ *
+ * @throws QueryFailureException if the database backend
+ * yielded an error while executing the search
+ * query.
+ */
+
+ public static List<String>
+ getPublicFolders (DatabaseDriver db)
+ throws QueryFailureException
+ {
+ if (db == null)
+ throw new IllegalArgumentException ("Database handle is null.");
+
+
+ List<String> results = new ArrayList<String> ();
+
+
+ ResultSet rs = null;
+
+ try
+ {
+ rs = db.executeQuery ("SELECT share AS name, description"
+ + " FROM baps_filefolder"
+ + " WHERE baps_filefolder.public"
+ + " = TRUE"
+ + " ORDER BY filefolderid ASC", MAX_RESULTS);
+ }
+ catch (SQLException e1)
+ {
+ throw new QueryFailureException (e1.getMessage ());
+ }
+
+ try
+ {
+ while (rs.next ())
+ {
+ results.add (rs.getString (2));
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new QueryFailureException (e.getMessage ());
+ }
+
+ return results;
+ }
+
+
+ /**
* Given a show and a channel, retrieve a list of all show items
* bound to that channel for the show.
*
@@ -48,6 +107,9 @@ public class ShowUtils
* @param showID The unique number that identifies the show.
*
* @param channel The index of the channel to query.
+ *
+ * @return a list of ShowItems extracted from the show and
+ * channel. The list may be empty.
*
* @throws IllegalArgumentException if the database is
* null, the show ID is negative or the
@@ -56,9 +118,6 @@ public class ShowUtils
* @throws QueryFailureException if the database backend
* yielded an error while executing the search
* query.
- *
- * @return a list of ShowItems extracted from the show and
- * channel. The list may be empty.
*/
public static List<ShowItem>
@@ -83,18 +142,19 @@ public class ShowUtils
try
{
- rs = db.executeQuery ("SELECT name1, name2, positionid"
+ rs = db.executeQuery ("SELECT name1, name2, position"
+ " FROM baps_show"
+ " INNER JOIN baps_listing"
+ " ON baps_show.showid"
+ " = baps_listing.showid"
+ " INNER JOIN baps_item"
+ " ON baps_listing.listingid"
- + " = baps_show.showid"
+ + " = baps_item.listingid"
+ " WHERE baps_show.showid"
+ " = ?"
+ " AND baps_listing.channel"
- + " = ?", params, MAX_RESULTS);
+ + " = ?"
+ + " ORDER BY position ASC", params, MAX_RESULTS);
}
catch (SQLException e)
{
@@ -118,12 +178,12 @@ public class ShowUtils
/**
- * Translate a row retrieved from the database into a LibraryItem.
+ * Translate a row retrieved from the database into a ShowItem.
*
* @param rs The result-set, or database cursor, pointing to the
* row to translate.
*
- * @return A new LibraryItem containing the properties extracted
+ * @return A new ShowItem containing the properties extracted
* from the translated row.
*/
diff --git a/src/uk/org/ury/show/item/ShowItem.java b/src/uk/org/ury/show/item/ShowItem.java
new file mode 100644
index 0000000..0a9154f
--- /dev/null
+++ b/src/uk/org/ury/show/item/ShowItem.java
@@ -0,0 +1,68 @@
+/**
+ *
+ */
+package uk.org.ury.show.item;
+
+
+import java.util.Map;
+
+import uk.org.ury.database.DatabaseItem;
+import uk.org.ury.database.exceptions.MissingPropertyException;
+
+
+/**
+ * An item in the show database.
+ *
+ * @author Matt Windsor
+ */
+
+public class ShowItem extends DatabaseItem<ShowItemProperty, String>
+{
+ /**
+ * Construct a new ShowItem.
+ *
+ * @param properties The map of properties to store in the show item.
+ */
+
+ public
+ ShowItem (Map<ShowItemProperty, String> properties)
+ {
+ super (properties);
+ }
+
+
+ /**
+ * @return a string representation of the ShowItem.
+ */
+
+ @Override
+ public String
+ toString ()
+ {
+ String name1;
+ String name2;
+
+ try
+ {
+ name1 = get (ShowItemProperty.NAME1);
+ }
+ catch (MissingPropertyException e1)
+ {
+ name1 = "Unknown";
+ }
+
+ try
+ {
+ name2 = get (ShowItemProperty.NAME2);
+ }
+ catch (MissingPropertyException e2)
+ {
+ name2 = null;
+ }
+
+ if (name2 != null)
+ return name1 + " - " + name2;
+ else
+ return name1;
+ }
+}
diff --git a/src/uk/org/ury/show/item/ShowItemProperty.java b/src/uk/org/ury/show/item/ShowItemProperty.java
new file mode 100644
index 0000000..a4239b5
--- /dev/null
+++ b/src/uk/org/ury/show/item/ShowItemProperty.java
@@ -0,0 +1,26 @@
+package uk.org.ury.show.item;
+
+
+/**
+ * Enumeration of the parameters that are stored in a ShowItem.
+ *
+ * @author Matt Windsor
+ */
+
+public enum ShowItemProperty
+ {
+ // Constant SQL identifier
+ NAME1 ("name1"),
+ NAME2 ("name2"),
+ POSITION ("positionid");
+
+
+ public final String sql;
+
+
+ private
+ ShowItemProperty (String sql)
+ {
+ this.sql = sql;
+ }
+ }; \ No newline at end of file
diff --git a/src/uk/org/ury/show/viewer/ChannelPanel.java b/src/uk/org/ury/show/viewer/ChannelPanel.java
index 99a616a..54e33dd 100644
--- a/src/uk/org/ury/show/viewer/ChannelPanel.java
+++ b/src/uk/org/ury/show/viewer/ChannelPanel.java
@@ -4,29 +4,32 @@
package uk.org.ury.show.viewer;
import java.awt.event.KeyEvent;
-import java.net.URL;
-import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
-import javax.swing.JPanel;
-import org.swixml.SwingEngine;
-
-import uk.org.ury.frontend.FrontendError;
-import uk.org.ury.frontend.FrontendSubBanner;
+import uk.org.ury.frontend.FrontendPanel;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
import uk.org.ury.show.ShowChannel;
/**
- * A panel displaying channel informstion.
+ * A panel displaying channel information.
*
* @author Matt Windsor.
*/
-public class ChannelPanel extends JPanel
+public class ChannelPanel extends FrontendPanel
{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 897125684384350966L;
+
+
+ /* Components created and exposed by the XML engine. */
+
private JLabel channelName;
private JList itemList;
private JButton playButton;
@@ -44,33 +47,16 @@ public class ChannelPanel extends JPanel
* @param number The number of the channel.
*
* @param channel The channel whose data the ChannelPanel is viewing.
+ *
+ * @throws UICreationFailureException if the UI creation fails.
*/
public
ChannelPanel (int number, ShowChannel channel)
+ throws UICreationFailureException
{
- super ();
-
- // Acquire path.
-
- URL path = getClass ().getResource ("channel_panel.xml");
-
- if (path == null)
- FrontendError.reportFatal ("UI creation failure: XML layout does not exist.", null);
-
- SwingEngine se = new SwingEngine (this);
- se.getTaglib ().registerTag ("subbanner", FrontendSubBanner.class);
-
- // Read the XML.
-
- try
- {
- se.insert (path, this);
- }
- catch (Exception e)
- {
- FrontendError.reportFatal ("UI creation failure: " + e.getMessage (), null);
- }
+ super ("channel_panel.xml", null);
+
// Tweak buttons to add function key mnemonics, if function keys are available.
@@ -92,9 +78,7 @@ public class ChannelPanel extends JPanel
}
// Test stuff
- DefaultListModel test = new DefaultListModel ();
- test.add (0, "Test");
- itemList.setModel (test);
+ itemList.setModel (channel);
channelName.setText ("Channel " + number);
}
}
diff --git a/src/uk/org/ury/show/viewer/LibraryControlPanel.java b/src/uk/org/ury/show/viewer/LibraryControlPanel.java
index cf5eec2..c385f05 100644
--- a/src/uk/org/ury/show/viewer/LibraryControlPanel.java
+++ b/src/uk/org/ury/show/viewer/LibraryControlPanel.java
@@ -2,6 +2,7 @@ package uk.org.ury.show.viewer;
import uk.org.ury.frontend.FrontendControlPanel;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
/**
@@ -14,8 +15,22 @@ import uk.org.ury.frontend.FrontendControlPanel;
public class LibraryControlPanel extends FrontendControlPanel
{
+ /**
+ *
+ */
+
+ private static final long serialVersionUID = -4260057656619439704L;
+
+
+ /**
+ * Construct a new LibraryControlPanel.
+ *
+ * @throws UICreationFailureException if the UI creation fails.
+ */
+
public
LibraryControlPanel ()
+ throws UICreationFailureException
{
super ("library_control_panel.xml");
}
diff --git a/src/uk/org/ury/show/viewer/ShowViewer.java b/src/uk/org/ury/show/viewer/ShowViewer.java
index 8a0e46a..24e696b 100644
--- a/src/uk/org/ury/show/viewer/ShowViewer.java
+++ b/src/uk/org/ury/show/viewer/ShowViewer.java
@@ -1,21 +1,20 @@
package uk.org.ury.show.viewer;
-import java.lang.reflect.InvocationTargetException;
-
-import javax.swing.SwingUtilities;
+import java.util.List;
import uk.org.ury.config.ConfigReader;
import uk.org.ury.database.DatabaseDriver;
import uk.org.ury.database.UserClass;
import uk.org.ury.database.exceptions.MissingCredentialsException;
+import uk.org.ury.database.exceptions.QueryFailureException;
import uk.org.ury.frontend.AbstractFrontendModule;
-import uk.org.ury.frontend.FrontendError;
-import uk.org.ury.frontend.FrontendFrame;
import uk.org.ury.frontend.FrontendMaster;
import uk.org.ury.frontend.FrontendModulePanel;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
import uk.org.ury.show.ShowChannel;
import uk.org.ury.show.ShowUtils;
+import uk.org.ury.show.item.ShowItem;
/**
@@ -39,7 +38,6 @@ public class ShowViewer extends AbstractFrontendModule
private DatabaseDriver dd;
private ShowChannel[] channels;
private ShowViewerPanel panel;
- private FrontendFrame frame;
private ConfigReader config;
@@ -50,75 +48,11 @@ public class ShowViewer extends AbstractFrontendModule
public
ShowViewer ()
{
- try
- {
- config = new ConfigReader ("res/conf.xml");
- }
- catch (MissingCredentialsException e)
- {
- System.out.println(e);
- }
-
- frame = null;
channels = new ShowChannel[ShowUtils.NUM_CHANNELS];
}
/**
- * Initialise the library viewer frontend as an applet.
- */
-
- public void
- init ()
- {
- frame = null;
- channels = new ShowChannel[ShowUtils.NUM_CHANNELS];
- panel = new ShowViewerPanel (this, null);
-
-
- try
- {
- SwingUtilities.invokeAndWait (new Runnable ()
- {
- public void
- run ()
- {
- panel.setOpaque (true);
- setContentPane (panel);
-
- runFrontend (null);
- }
-
- });
- }
- 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 ShowViewerPanel (this, null);
-
- add (panel);
- }
-
-
- /**
* Run the library viewer frontend.
*/
@@ -127,6 +61,18 @@ public class ShowViewer extends AbstractFrontendModule
runFrontend (FrontendMaster master)
{
dd = null;
+ config = null;
+
+ try
+ {
+ config = new ConfigReader (master.getResourceDirectory () + "conf.xml");
+ }
+ catch (MissingCredentialsException e)
+ {
+ System.out.println(e);
+ }
+
+
try
{
@@ -135,14 +81,39 @@ public class ShowViewer extends AbstractFrontendModule
catch (MissingCredentialsException e)
{
// TODO: Privilege de-escalation
- FrontendError.reportFatal (e.getMessage (), frame);
+ master.fatalError (e.getMessage ());
}
catch (Exception f)
{
- FrontendError.reportFatal (f.getMessage (), frame);
+ master.fatalError (f.getMessage ());
+ }
+
+ for (int i = 0; i < channels.length; i++)
+ {
+ channels[i] = new ShowChannel ();
+
+ try
+ {
+ for (ShowItem item : ShowUtils.getChannelList (dd, 4696, i))
+ {
+ channels[i].add (item);
+ }
+ }
+ catch (QueryFailureException e)
+ {
+ master.fatalError (e.getMessage ());
+ }
+ }
+
+ try
+ {
+ panel = new ShowViewerPanel (this, master);
+ }
+ catch (UICreationFailureException e)
+ {
+ master.fatalError (e.getMessage ());
}
- panel = new ShowViewerPanel (this, master);
return panel;
}
@@ -157,4 +128,18 @@ public class ShowViewer extends AbstractFrontendModule
// TODO Auto-generated method stub
return channels;
}
+
+
+ /**
+ * @return the list of bin names.
+ *
+ * @throws QueryFailureException if the underlying database query
+ * fails.
+ */
+
+ public List<String>
+ getBins () throws QueryFailureException
+ {
+ return ShowUtils.getPublicFolders (dd);
+ }
}
diff --git a/src/uk/org/ury/show/viewer/ShowViewerPanel.java b/src/uk/org/ury/show/viewer/ShowViewerPanel.java
index e9cce90..ce1b794 100644
--- a/src/uk/org/ury/show/viewer/ShowViewerPanel.java
+++ b/src/uk/org/ury/show/viewer/ShowViewerPanel.java
@@ -4,17 +4,23 @@
package uk.org.ury.show.viewer;
import java.awt.GridLayout;
+import java.util.List;
import javax.swing.JPanel;
-import javax.swing.JSplitPane;
+import uk.org.ury.database.exceptions.QueryFailureException;
import uk.org.ury.frontend.FrontendMaster;
import uk.org.ury.frontend.FrontendModulePanel;
+import uk.org.ury.frontend.exceptions.LoadFailureException;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
import uk.org.ury.show.ShowChannel;
/**
- * Frontend panel providing access to an underlying lshow viewer.
+ * Frontend panel providing access to an underlying show viewer.
+ *
+ * The various show user interfaces (show editor, playout etc.)
+ * are derived from this.
*
* @author Matt Windsor, Nathan Lasseter
*/
@@ -29,21 +35,27 @@ public class ShowViewerPanel extends FrontendModulePanel
/* Panel widgets exposed by the SwiXML user interface. */
- private JSplitPane mainSplit;
- private JSplitPane binSplit;
private JPanel channelGroupPanel;
private JPanel binGroupPanel;
+
/**
* Construct a new ShowViewerPanel.
*
+ * The panel will interface with the given show viewer and is
+ * expected to be placed as a sub-component in the given
+ * FrontendMaster.
+ *
* @param viewer The ShowViewer controlling this LibraryViewerPanel.
*
* @param master The FrontendMaster driving the frontend.
+ *
+ * @throws UICreationFailureException if the UI creation fails.
*/
public
ShowViewerPanel (ShowViewer viewer, FrontendMaster master)
+ throws UICreationFailureException
{
super (viewer, "show_viewer_gui.xml", master);
@@ -62,7 +74,17 @@ public class ShowViewerPanel extends FrontendModulePanel
// TEST
- String binNames[] = {"Jingles", "Beds", "Adverts"};
+ List<String> binNames = null;
+
+ try
+ {
+ binNames = viewer.getBins ();
+ }
+ catch (QueryFailureException e)
+ {
+ master.fatalError (e.getMessage ());
+ }
+
TrackBin tb;
for (String name : binNames)
@@ -72,7 +94,7 @@ public class ShowViewerPanel extends FrontendModulePanel
binGroupPanel.add (tb);
}
- binGroupPanel.setLayout (new GridLayout (1, 3));
+ binGroupPanel.setLayout (new GridLayout (1, binNames.size ()));
}
@@ -98,6 +120,14 @@ public class ShowViewerPanel extends FrontendModulePanel
public void
search ()
{
- master.loadModule ("library.viewer.LibraryViewer", "show.viewer.LibraryControlPanel");
+ try
+ {
+ master.loadModule ("library.viewer.LibraryViewer",
+ "show.viewer.LibraryControlPanel");
+ }
+ catch (LoadFailureException e)
+ {
+ master.fatalError (e.getMessage ());
+ }
}
}
diff --git a/src/uk/org/ury/show/viewer/TrackBin.java b/src/uk/org/ury/show/viewer/TrackBin.java
index a95b183..7234912 100644
--- a/src/uk/org/ury/show/viewer/TrackBin.java
+++ b/src/uk/org/ury/show/viewer/TrackBin.java
@@ -3,16 +3,10 @@
*/
package uk.org.ury.show.viewer;
-import java.net.URL;
-
import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-
-import org.swixml.SwingEngine;
-import uk.org.ury.frontend.FrontendError;
-import uk.org.ury.frontend.FrontendSubBanner;
+import uk.org.ury.frontend.FrontendPanel;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
/**
@@ -21,10 +15,17 @@ import uk.org.ury.frontend.FrontendSubBanner;
* @author Matt Windsor.
*/
-public class TrackBin extends JPanel
+public class TrackBin extends FrontendPanel
{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -5414923374901972511L;
+
+
+ /* Components created and exposed by the XML engine. */
+
private JLabel binName;
- private JList itemList;
/**
@@ -34,37 +35,19 @@ public class TrackBin extends JPanel
* XML manifest "track_bin.xml" in the same directory as
* this class file.
*
+ * TODO: add track list into constructor
+ *
* @param name The name of the bin.
*
- * TODO: add track list into constructor
+ * @throws UICreationFailureException if the UI creation fails.
*/
public
TrackBin (String name)
+ throws UICreationFailureException
{
- super ();
-
- // Acquire path.
-
- URL path = getClass ().getResource ("track_bin.xml");
-
- if (path == null)
- FrontendError.reportFatal ("UI creation failure: XML layout does not exist.", null);
-
- SwingEngine se = new SwingEngine (this);
- se.getTaglib ().registerTag ("subbanner", FrontendSubBanner.class);
-
- // Read the XML.
-
- try
- {
- se.insert (path, this);
- }
- catch (Exception e)
- {
- FrontendError.reportFatal ("UI creation failure: " + e.getMessage (), null);
- }
-
+ super ("track_bin.xml", null);
+
// Tweak name.
binName.setText (name);
diff --git a/src/uk/org/ury/show/viewer/channel_panel.xml b/src/uk/org/ury/show/viewer/channel_panel.xml
index 2aac663..bf576ce 100644
--- a/src/uk/org/ury/show/viewer/channel_panel.xml
+++ b/src/uk/org/ury/show/viewer/channel_panel.xml
@@ -4,7 +4,7 @@
constraints="BorderLayout.NORTH" />
<vbox constraints="BorderLayout.CENTER">
<scrollpane id="itemScroller" constraints="BorderLayout.CENTER">
- <list id="itemList" />
+ <list id="itemList" visiblerowcount="1" />
</scrollpane>
</vbox>
<vbox constraints="BorderLayout.SOUTH">
diff --git a/src/uk/org/ury/show/viewer/library_control_panel.xml b/src/uk/org/ury/show/viewer/library_control_panel.xml
index 79e5777..bdf8af0 100644
--- a/src/uk/org/ury/show/viewer/library_control_panel.xml
+++ b/src/uk/org/ury/show/viewer/library_control_panel.xml
@@ -1,13 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<panel>
- <hbox border="EmptyBorder(0,5,5,5)" size="640,32">
- <button id="backButton" text="Back to Show" mnemonic="VK_B" action="back"
- font="Verdana-BOLD-14" />
- <button id="c1Button" text="Add to Channel 1" mnemonic="VK_1" action="addch1"
- font="Verdana-BOLD-14" />
- <button id="c2Button" text="Add to Channel 2" mnemonic="VK_2" action="addch2"
- font="Verdana-BOLD-14" />
- <button id="c3Button" text="Add to Channel 3" mnemonic="VK_3" action="addch3"
- font="Verdana-BOLD-14" />
+ <hbox border="EmptyBorder(0,5,5,5)">
+ <button id="backButton" text="Back to Show" mnemonic="VK_B" action="back" />
+ <button id="c1Button" text="Add to Channel 1" mnemonic="VK_1" action="addch1" />
+ <button id="c2Button" text="Add to Channel 2" mnemonic="VK_2" action="addch2" />
+ <button id="c3Button" text="Add to Channel 3" mnemonic="VK_3" action="addch3" />
</hbox>
</panel>
diff --git a/src/uk/org/ury/show/viewer/show_viewer_gui.xml b/src/uk/org/ury/show/viewer/show_viewer_gui.xml
index 67c9cb4..90b8cb5 100644
--- a/src/uk/org/ury/show/viewer/show_viewer_gui.xml
+++ b/src/uk/org/ury/show/viewer/show_viewer_gui.xml
@@ -1,48 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<panel layout="BorderLayout">
- <hbox constraints="BorderLayout.NORTH" border="EmptyBorder(5,5,5,5)" size="640,32">
+ <hbox constraints="BorderLayout.NORTH" border="EmptyBorder(5,5,5,5)">
<button id="loadButton" text="Load Show or Template..." mnemonic="VK_L"
- action="load"
- font="Verdana-BOLD-14" />
+ action="load" />
<button id="searchButton" text="Search Record Library" mnemonic="VK_S"
- action="search"
- font="Verdana-BOLD-14" />
+ action="search" />
<glue />
<button id="helpButton" text="Help..." mnemonic="VK_H"
- action="help"
- font="Verdana-BOLD-14" />
+ action="help" />
<button id="feedbackButton" text="Feedback..." mnemonic="VK_F"
- action="feedback"
- font="Verdana-BOLD-14" />
+ action="feedback" />
</hbox>
- <splitpane constraints="BorderLayout.CENTER" border="EmptyBorder(0,5,0,5)"
- id="mainSplit" orientation="0" dividerlocation="400">
- <splitpane orientation="0" size="640,340" id="binSplit" dividerlocation="100">
- <panel layout="BorderLayout">
- <subbanner text="Useful Tracks"
- constraints="BorderLayout.NORTH" />
- <scrollpane id="binScrollPane" size="640,150"
- constraints="BorderLayout.CENTER">
- <panel id="binGroupPanel" />
- </scrollpane>
- </panel>
- <panel layout="BorderLayout">
- <subbanner text="Sound Channels"
- constraints="BorderLayout.NORTH" />
- <scrollpane id="channelScrollPane" size="640,360"
- constraints="BorderLayout.CENTER">
- <panel id="channelGroupPanel" />
- </scrollpane>
- </panel>
- </splitpane>
- <panel layout="BorderLayout">
+ <panel layout="BorderLayout" constraints="BorderLayout.CENTER">
+ <panel layout="BorderLayout" constraints="BorderLayout.NORTH">
+ <subbanner text="Useful Tracks"
+ constraints="BorderLayout.NORTH" />
+ <scrollpane id="binScrollPane"
+ constraints="BorderLayout.CENTER">
+ <panel id="binGroupPanel" />
+ </scrollpane>
+ </panel>
+ <panel layout="BorderLayout" constraints="BorderLayout.CENTER">
+ <subbanner text="Sound Channels"
+ constraints="BorderLayout.NORTH" />
+ <scrollpane id="channelScrollPane"
+ constraints="BorderLayout.CENTER">
+ <panel id="channelGroupPanel" />
+ </scrollpane>
+ </panel>
+ <panel layout="BorderLayout" constraints="BorderLayout.SOUTH">
<subbanner text="Quick Notes"
constraints="BorderLayout.NORTH" />
- <textarea id="noteArea" size="640,100" border="LoweredBevelBorder"
- text="Type quick notes here..." />
+ <textarea id="noteArea" border="LoweredBevelBorder"
+ text="Type quick notes here..." rows="3" />
</panel>
- </splitpane>
+ </panel>
<hbox constraints="BorderLayout.SOUTH" border="EmptyBorder(5,5,5,5)">
<hint text="For help, click the Help button." />
diff --git a/src/uk/org/ury/show/viewer/show_viewer_gui_old.xml b/src/uk/org/ury/show/viewer/show_viewer_gui_old.xml
new file mode 100644
index 0000000..d11e579
--- /dev/null
+++ b/src/uk/org/ury/show/viewer/show_viewer_gui_old.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<panel layout="BorderLayout">
+ <hbox constraints="BorderLayout.NORTH" border="EmptyBorder(5,5,5,5)">
+ <button id="loadButton" text="Load Show or Template..." mnemonic="VK_L"
+ action="load" />
+ <button id="searchButton" text="Search Record Library" mnemonic="VK_S"
+ action="search" />
+ <glue />
+ <button id="helpButton" text="Help..." mnemonic="VK_H"
+ action="help" />
+ <button id="feedbackButton" text="Feedback..." mnemonic="VK_F"
+ action="feedback" />
+ </hbox>
+
+ <splitpane constraints="BorderLayout.CENTER" border="EmptyBorder(0,5,0,5)"
+ id="mainSplit" orientation="0">
+ <splitpane orientation="0" id="binSplit">
+ <panel layout="BorderLayout">
+ <subbanner text="Useful Tracks"
+ constraints="BorderLayout.NORTH" />
+ <scrollpane id="binScrollPane"
+ constraints="BorderLayout.CENTER">
+ <panel id="binGroupPanel" />
+ </scrollpane>
+ </panel>
+ <panel layout="BorderLayout">
+ <subbanner text="Sound Channels"
+ constraints="BorderLayout.NORTH" />
+ <scrollpane id="channelScrollPane"
+ constraints="BorderLayout.CENTER">
+ <panel id="channelGroupPanel" />
+ </scrollpane>
+ </panel>
+ </splitpane>
+ <panel layout="BorderLayout">
+ <subbanner text="Quick Notes"
+ constraints="BorderLayout.NORTH" />
+ <textarea id="noteArea" border="LoweredBevelBorder"
+ text="Type quick notes here..." rows="3" />
+ </panel>
+ </splitpane>
+
+ <hbox constraints="BorderLayout.SOUTH" border="EmptyBorder(5,5,5,5)">
+ <hint text="For help, click the Help button." />
+ </hbox>
+</panel>
diff --git a/src/uk/org/ury/show/viewer/show_viewer_gui_panels.xml b/src/uk/org/ury/show/viewer/show_viewer_gui_panels.xml
new file mode 100644
index 0000000..eda711b
--- /dev/null
+++ b/src/uk/org/ury/show/viewer/show_viewer_gui_panels.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<panel layout="BorderLayout">
+ <hbox constraints="BorderLayout.NORTH" border="EmptyBorder(5,5,5,5)">
+ <button id="loadButton" text="Load Show or Template..." mnemonic="VK_L"
+ action="load" />
+ <button id="searchButton" text="Search Record Library" mnemonic="VK_S"
+ action="search" />
+ <glue />
+ <button id="helpButton" text="Help..." mnemonic="VK_H"
+ action="help" />
+ <button id="feedbackButton" text="Feedback..." mnemonic="VK_F"
+ action="feedback" />
+ </hbox>
+
+ <panel constraints="BorderLayout.CENTER" layout="BorderLayout>
+ <panel layout="BorderLayout" constraints="BorderLayout.NORTH">
+ <subbanner text="Useful Tracks"
+ constraints="BorderLayout.NORTH" />
+ <scrollpane id="binScrollPane"
+ constraints="BorderLayout.CENTER">
+ <panel id="binGroupPanel" />
+ </scrollpane>
+ </panel>
+ <panel layout="BorderLayout" constraints="BorderLayout.CENTER">
+ <subbanner text="Sound Channels"
+ constraints="BorderLayout.NORTH" />
+ <scrollpane id="channelScrollPane"
+ constraints="BorderLayout.CENTER">
+ <panel id="channelGroupPanel" />
+ </scrollpane>
+ </panel>
+ <panel layout="BorderLayout" constraints="BorderLayout.SOUTH">
+ <subbanner text="Quick Notes"
+ constraints="BorderLayout.NORTH" />
+ <textarea id="noteArea" border="LoweredBevelBorder"
+ text="Type quick notes here..." rows="3" />
+ </panel>
+ </panel>
+
+ <hbox constraints="BorderLayout.SOUTH" border="EmptyBorder(5,5,5,5)">
+ <hint text="For help, click the Help button." />
+ </hbox>
+</panel>
diff --git a/src/uk/org/ury/show/viewer/track_bin.xml b/src/uk/org/ury/show/viewer/track_bin.xml
index 988c1a4..d1ff9da 100644
--- a/src/uk/org/ury/show/viewer/track_bin.xml
+++ b/src/uk/org/ury/show/viewer/track_bin.xml
@@ -4,7 +4,7 @@
constraints="BorderLayout.NORTH" />
<vbox>
<scrollpane id="itemScroller">
- <list id="itemList" />
+ <list id="itemList" visiblerowcount="5" />
</scrollpane>
</vbox>
</panel> \ No newline at end of file
diff --git a/src/uk/org/ury/testrig/ApplicationLauncher.java b/src/uk/org/ury/testrig/ApplicationLauncher.java
new file mode 100644
index 0000000..ce48722
--- /dev/null
+++ b/src/uk/org/ury/testrig/ApplicationLauncher.java
@@ -0,0 +1,32 @@
+/**
+ *
+ */
+package uk.org.ury.testrig;
+
+import uk.org.ury.frontend.FrontendFrame;
+
+
+/**
+ * An application-based entry point into the frontend.
+ *
+ * If provided with no arguments, this will launch the main menu.
+ *
+ * @author Matt Windsor
+ */
+
+public class ApplicationLauncher implements Launcher
+{
+ /**
+ * Main method.
+ *
+ * @param args The command-line arguments to the program. These
+ * will currently be ignored.
+ */
+
+ public static void
+ main (String[] args)
+ {
+ FrontendFrame fr = new FrontendFrame (DEFAULT_MODULE_NAME);
+ fr.setupUI ();
+ }
+}
diff --git a/src/uk/org/ury/testrig/DemoControlPanel.java b/src/uk/org/ury/testrig/DemoControlPanel.java
index 7e4b439..85789c5 100644
--- a/src/uk/org/ury/testrig/DemoControlPanel.java
+++ b/src/uk/org/ury/testrig/DemoControlPanel.java
@@ -2,6 +2,7 @@ package uk.org.ury.testrig;
import uk.org.ury.frontend.FrontendControlPanel;
+import uk.org.ury.frontend.exceptions.UICreationFailureException;
/**
@@ -14,8 +15,21 @@ import uk.org.ury.frontend.FrontendControlPanel;
public class DemoControlPanel extends FrontendControlPanel
{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7558888612002013312L;
+
+
+ /**
+ * Constructs a new DemoControlPanel.
+ *
+ * @throws UICreationFailureException if the UI creation fails.
+ */
+
public
DemoControlPanel ()
+ throws UICreationFailureException
{
super ("demo_control_panel.xml");
}
diff --git a/src/uk/org/ury/testrig/DemoMenu.java b/src/uk/org/ury/testrig/DemoMenu.java
index bc4636b..19e68d9 100644
--- a/src/uk/org/ury/testrig/DemoMenu.java
+++ b/src/uk/org/ury/testrig/DemoMenu.java
@@ -1,13 +1,9 @@
package uk.org.ury.testrig;
-import java.awt.GridLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.JButton;
-
-import uk.org.ury.frontend.FrontendFrame;
+import uk.org.ury.frontend.AbstractFrontendModule;
+import uk.org.ury.frontend.FrontendMaster;
import uk.org.ury.frontend.FrontendModulePanel;
+import uk.org.ury.frontend.exceptions.LoadFailureException;
/**
@@ -17,23 +13,13 @@ import uk.org.ury.frontend.FrontendModulePanel;
*
*/
-public class DemoMenu
+public class DemoMenu extends AbstractFrontendModule
{
- private FrontendFrame frame;
-
/**
- * Main method.
*
- * @param args The command-line arguments to the program. These
- * will be ignored.
*/
-
- public static void
- main (String[] args)
- {
- DemoMenu dm = new DemoMenu ();
- dm.run ();
- }
+ private static final long serialVersionUID = -5264235507636809476L;
+ private FrontendMaster master;
/**
@@ -43,70 +29,36 @@ public class DemoMenu
public void
loadModule (String module)
{
- frame.loadModule (module, "testrig.DemoControlPanel");
+ try
+ {
+ master.loadModule (module, "testrig.DemoControlPanel");
+ }
+ catch (LoadFailureException e)
+ {
+ master.fatalError (e.getMessage ());
+ }
}
+
/**
* Run the demo menu, creating a user interface.
*/
public void
run ()
- {
- FrontendModulePanel panel = new FrontendModulePanel (null, frame)
- {
- private static final long serialVersionUID = 1L;
-
- {
- setLayout (new GridLayout (2, 1));
-
- JButton lb = new JButton ("Library Viewer Demo");
- JButton sb = new JButton ("Show Viewer Demo");
-
- lb.addActionListener (new ActionListener ()
- {
+ {
- @Override
- public void
- actionPerformed (ActionEvent arg0)
- {
- loadModule ("library.viewer.LibraryViewer");
- }
-
- });
-
-
- sb.addActionListener (new ActionListener ()
- {
+ }
- @Override
- public void
- actionPerformed (ActionEvent arg0)
- {
- loadModule ("show.viewer.ShowViewer");
- }
-
- });
-
-
- add (lb);
- add (sb);
- }
+
+ /**
+ * Run the demo menu in frontend mode.
+ */
-
- /**
- * @return the name of the module.
- */
-
- @Override
- public String
- getName ()
- {
- return "Demo Menu";
- }
- };
-
-
- frame = new FrontendFrame (panel);
+ @Override
+ public FrontendModulePanel
+ runFrontend (FrontendMaster master)
+ {
+ return new DemoMenuPanel (master);
}
}
diff --git a/src/uk/org/ury/testrig/DemoMenuPanel.java b/src/uk/org/ury/testrig/DemoMenuPanel.java
new file mode 100644
index 0000000..69cf982
--- /dev/null
+++ b/src/uk/org/ury/testrig/DemoMenuPanel.java
@@ -0,0 +1,90 @@
+package uk.org.ury.testrig;
+
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+
+import uk.org.ury.frontend.FrontendMaster;
+import uk.org.ury.frontend.FrontendModulePanel;
+import uk.org.ury.frontend.exceptions.LoadFailureException;
+
+public class DemoMenuPanel extends FrontendModulePanel
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5268978856289909262L;
+
+
+ /**
+ * Construct a new DemoMenuPanel.
+ *
+ * @param inMaster The new frontend master of the panel, if any.
+ */
+
+ public
+ DemoMenuPanel (FrontendMaster inMaster)
+ {
+ super (null, inMaster);
+
+ setLayout (new GridLayout (2, 1));
+
+ JButton lb = new JButton ("Library Viewer Demo");
+ JButton sb = new JButton ("Show Viewer Demo");
+
+ lb.addActionListener (new ActionListener ()
+ {
+ @Override
+ public void
+ actionPerformed (ActionEvent arg0)
+ {
+ try
+ {
+ master.loadModule ("library.viewer.LibraryViewer",
+ "testrig.DemoControlPanel");
+ }
+ catch (LoadFailureException e)
+ {
+ master.fatalError (e.getMessage ());
+ }
+ }
+ });
+
+
+ sb.addActionListener (new ActionListener ()
+ {
+ @Override
+ public void
+ actionPerformed (ActionEvent arg0)
+ {
+ try
+ {
+ master.loadModule ("show.viewer.ShowViewer",
+ "testrig.DemoControlPanel");
+ }
+ catch (LoadFailureException e)
+ {
+ master.fatalError (e.getMessage ());
+ }
+ }
+ });
+
+
+ add (lb);
+ add (sb);
+ }
+
+
+ /**
+ * @return the name of the module.
+ */
+
+ @Override
+ public String
+ getName ()
+ {
+ return "Demo Menu";
+ }
+}
diff --git a/src/uk/org/ury/testrig/Launcher.java b/src/uk/org/ury/testrig/Launcher.java
new file mode 100644
index 0000000..d5126c7
--- /dev/null
+++ b/src/uk/org/ury/testrig/Launcher.java
@@ -0,0 +1,17 @@
+/**
+ *
+ */
+package uk.org.ury.testrig;
+
+
+/**
+ * Interface for entry points into the frontend.
+ *
+ * @author Matt Windsor
+ */
+
+
+public interface Launcher
+{
+ public String DEFAULT_MODULE_NAME = "testrig.DemoMenu";
+}
diff --git a/src/uk/org/ury/testrig/demo_control_panel.xml b/src/uk/org/ury/testrig/demo_control_panel.xml
index cade1dd..a9b5329 100644
--- a/src/uk/org/ury/testrig/demo_control_panel.xml
+++ b/src/uk/org/ury/testrig/demo_control_panel.xml
@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<panel>
- <hbox border="EmptyBorder(0,5,5,5)" size="640,32">
- <button id="backButton" text="Back to Demo Menu" mnemonic="VK_B" action="back"
- font="Verdana-BOLD-14" />
- <button id="aboutButton" text="About..." mnemonic="VK_A" action="about"
- font="Verdana-BOLD-14" />
+ <hbox border="EmptyBorder(0,5,5,5)">
+ <button id="backButton" text="Back to Demo Menu" mnemonic="VK_B" action="back" />
+ <button id="aboutButton" text="About..." mnemonic="VK_A" action="about" />
</hbox>
</panel>