diff options
Diffstat (limited to 'src')
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> |