diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/uk/org/ury/client/Client.java | 96 | ||||
-rw-r--r-- | src/uk/org/ury/client/test/ClientTest.java | 84 | ||||
-rw-r--r-- | src/uk/org/ury/frontend/FrontendApplet.java | 572 | ||||
-rw-r--r-- | src/uk/org/ury/library/LibraryRequestHandler.java | 4 | ||||
-rw-r--r-- | src/uk/org/ury/library/viewer/LibraryViewer.java | 275 | ||||
-rw-r--r-- | src/uk/org/ury/library/viewer/LibraryViewer.properties | 2 | ||||
-rw-r--r-- | src/uk/org/ury/library/viewer/LibraryViewerPanel.java | 408 | ||||
-rw-r--r-- | src/uk/org/ury/protocol/ProtocolUtils.java | 147 | ||||
-rw-r--r-- | src/uk/org/ury/server/ApiRequestHandler.java | 42 | ||||
-rw-r--r-- | src/uk/org/ury/server/HttpHandler.java | 343 | ||||
-rw-r--r-- | src/uk/org/ury/server/HttpListenerThread.java | 125 | ||||
-rw-r--r-- | src/uk/org/ury/server/HttpWorkerThread.java | 104 | ||||
-rw-r--r-- | src/uk/org/ury/server/Server.java | 611 | ||||
-rw-r--r-- | src/uk/org/ury/server/ServerRequestHandler.java | 4 | ||||
-rw-r--r-- | src/uk/org/ury/show/viewer/ShowViewer.java | 205 |
15 files changed, 1495 insertions, 1527 deletions
diff --git a/src/uk/org/ury/client/Client.java b/src/uk/org/ury/client/Client.java index 1a3b53a..69a095a 100644 --- a/src/uk/org/ury/client/Client.java +++ b/src/uk/org/ury/client/Client.java @@ -13,58 +13,48 @@ import java.util.Map; import uk.org.ury.protocol.ProtocolUtils; import uk.org.ury.protocol.exceptions.DecodeFailureException; -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 key-value map. - * @throws DecodeFailureException if the decode failed. - */ - - public Map<?, ?> - get (String file) throws DecodeFailureException - { - URL url = null; - URLConnection uc = null; - String result = ""; - - 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; +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 key-value map. + * @throws DecodeFailureException + * if the decode failed. + */ - for (inputLine = in.readLine(); - inputLine != null; - inputLine = in.readLine()) - { - result += inputLine; - } - } - catch (IOException e) - { - // TODO Auto-generated catch block - e.printStackTrace (); - } - - return ProtocolUtils.decode (result); - } + public Map<?, ?> get(String file) throws DecodeFailureException { + URL url = null; + URLConnection uc = null; + String result = ""; + + 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 += inputLine; + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return ProtocolUtils.decode(result); + } } diff --git a/src/uk/org/ury/client/test/ClientTest.java b/src/uk/org/ury/client/test/ClientTest.java index 707a80f..3ee70ef 100644 --- a/src/uk/org/ury/client/test/ClientTest.java +++ b/src/uk/org/ury/client/test/ClientTest.java @@ -15,59 +15,43 @@ import uk.org.ury.client.Client; import uk.org.ury.protocol.Directive; import uk.org.ury.protocol.exceptions.DecodeFailureException; - /** * 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 (); - - Map<?, ?> response = null; - - try - { - response = client.get ("/server/ServerRequestHandler?function=test"); - } - catch (DecodeFailureException e) - { - e.printStackTrace (); - } - - Assert.assertEquals ("Test succeeded.", response.get (Directive.INFO.toString ())); - } +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(); + + Map<?, ?> response = null; + + try { + response = client.get("/server/ServerRequestHandler?function=test"); + } catch (DecodeFailureException e) { + e.printStackTrace(); + } + + Assert.assertEquals("Test succeeded.", + response.get(Directive.INFO.toString())); + } } diff --git a/src/uk/org/ury/frontend/FrontendApplet.java b/src/uk/org/ury/frontend/FrontendApplet.java index 18f0c7a..8e0e229 100644 --- a/src/uk/org/ury/frontend/FrontendApplet.java +++ b/src/uk/org/ury/frontend/FrontendApplet.java @@ -14,330 +14,268 @@ 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). + * 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. +public class FrontendApplet extends JApplet implements FrontendMaster, Launcher { + /** * - * @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. - */ + private static final long serialVersionUID = 740928181256928433L; - @Override - public void - fatalError (String message) - { - FrontendError.reportFatal (message, this); - } + private FrontendModulePanel child; + private FrontendControlPanel cpanel; - - /** - * @return the resource directory. - */ - - @Override - public String - getResourceDirectory () - { - return getCodeBase () + "res/"; - } + /** + * Main method. + */ + + @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/library/LibraryRequestHandler.java b/src/uk/org/ury/library/LibraryRequestHandler.java index ad174b8..1c4ad96 100644 --- a/src/uk/org/ury/library/LibraryRequestHandler.java +++ b/src/uk/org/ury/library/LibraryRequestHandler.java @@ -17,7 +17,7 @@ import uk.org.ury.library.exceptions.EmptySearchException; import uk.org.ury.library.item.LibraryItem; import uk.org.ury.protocol.Directive; import uk.org.ury.server.Server; -import uk.org.ury.server.RequestHandler; +import uk.org.ury.server.ApiRequestHandler; import uk.org.ury.server.exceptions.HandleFailureException; @@ -27,7 +27,7 @@ import uk.org.ury.server.exceptions.HandleFailureException; * @author Matt Windsor */ -public class LibraryRequestHandler implements RequestHandler +public class LibraryRequestHandler implements ApiRequestHandler { /** * Handle a server GET request (that is, a request for data diff --git a/src/uk/org/ury/library/viewer/LibraryViewer.java b/src/uk/org/ury/library/viewer/LibraryViewer.java index 9e854b7..11496cb 100644 --- a/src/uk/org/ury/library/viewer/LibraryViewer.java +++ b/src/uk/org/ury/library/viewer/LibraryViewer.java @@ -1,3 +1,14 @@ +/* + * LibraryViewer.java + * ------------------ + * + * Part of the URY Frontend Platform + * + * V0.00 2011/03/20 + * + * (C) 2011 URY Computing + */ + package uk.org.ury.library.viewer; import java.util.ArrayList; @@ -7,168 +18,134 @@ import java.util.Map; import java.util.Set; import uk.org.ury.client.Client; - import uk.org.ury.frontend.AbstractFrontendModule; import uk.org.ury.frontend.FrontendMaster; import uk.org.ury.frontend.FrontendModulePanel; import uk.org.ury.frontend.exceptions.UICreationFailureException; - 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.protocol.Directive; import uk.org.ury.protocol.ProtocolUtils; import uk.org.ury.protocol.exceptions.DecodeFailureException; import uk.org.ury.protocol.exceptions.InvalidMessageException; - /** * Module for investigating the track library. - * - * @author Matt Windsor - * + * + * @author Matt Windsor */ - -public class LibraryViewer extends AbstractFrontendModule -{ - /** - * - */ - - private static final long serialVersionUID = -2782366476480563739L; - private List<LibraryItem> libraryList; - private LibraryViewerPanel panel; - - - /** - * Construct a new LibraryViewer as a frontend object. - */ - - public - LibraryViewer () - { - libraryList = new ArrayList<LibraryItem> (); - panel = null; - } - - - /** - * Run the library viewer frontend. - */ - - public FrontendModulePanel - runFrontend (FrontendMaster master) - { - try - { - panel = new LibraryViewerPanel (this, master); - } - catch (UICreationFailureException e) - { - master.fatalError (e.getMessage ()); - } - - return panel; - } - - - /** - * Do a library search. - * - * This will update the library list to reflect the results of the - * search. - * - * @param search The string fragment to use in searches. - * Cannot be empty or null. - * - * @throws EmptySearchException if the search string is - * empty or null (from LibraryUtils.search). - * - * @throws InvalidMessageException if the response from - * the server is invalid. - */ - - public void - doSearch (String search) - throws EmptySearchException, InvalidMessageException - { - // TODO: fan out? - - if (search == null || search == "") - throw new EmptySearchException (); - - - Client cl = new Client (); - Map<?, ?> response = null; - libraryList.clear (); - - try - { - response = cl.get ("/library/LibraryRequestHandler?function=search&search=" + search); - } - catch (DecodeFailureException e) - { - throw new InvalidMessageException (e.getMessage ()); - } - - // Check to see if this is Map<String, ?> by looking for the status, - // which should always be in a valid response. - - - if (ProtocolUtils.responseIsOK (response) == false) - throw new InvalidMessageException ((String) - response.get (Directive.REASON.toString ())); - - // Should contain a list of items, even if there are no items. - if (response.containsKey (Directive.ITEMS.toString ()) == false) - throw new InvalidMessageException ("No item set returned."); - - if ((response.get (Directive.ITEMS.toString ()) instanceof List<?>) == false) - throw new InvalidMessageException ("Malformed item list."); - - - for (Object obj : (List<?>) response.get (Directive.ITEMS.toString ())) - { - Map<LibraryItemProperty, String> properties - = new HashMap<LibraryItemProperty, String> (); - - if (obj instanceof Map<?, ?> == false) - throw new InvalidMessageException ("Malformed item."); - - Set<?> keySet = ((Map<?, ?>) obj).keySet (); - - // Check to make sure this item has only String-String mappings. - for (Object key : keySet) - { - if ((key instanceof String - && ((Map<?, ?>) obj).get (key) instanceof String) - == false) - throw new InvalidMessageException ("Not a valid property."); - else if (LibraryItemProperty.valueOf ((String) key) == null) - throw new InvalidMessageException ("Property type " - + key + " not recognised."); - else - properties.put (LibraryItemProperty.valueOf ((String) key), - (String) ((Map<?, ?>) obj).get (key)); - - } - - libraryList.add (new LibraryItem (properties)); - } - - //libraryList = LibraryUtils.search (dd, search); - } - - - /** - * @return the current library list. - */ - - public List<LibraryItem> - getLibraryList () - { - return libraryList; - } +public class LibraryViewer extends AbstractFrontendModule { + /** + * + */ + private static final long serialVersionUID = -2782366476480563739L; + private List<LibraryItem> libraryList; + private LibraryViewerPanel panel; + + /** + * Construct a new LibraryViewer as a frontend object. + */ + public LibraryViewer() { + libraryList = new ArrayList<LibraryItem>(); + panel = null; + } + + /** + * Run the library viewer frontend. + */ + @Override + public FrontendModulePanel runFrontend(FrontendMaster master) { + try { + panel = new LibraryViewerPanel(this, master); + } catch (UICreationFailureException e) { + master.fatalError(e.getMessage()); + } + + return panel; + } + + /** + * Do a library search. + * + * This will update the library list to reflect the results of the search. + * + * @param search + * The string fragment to use in searches. Cannot be empty or + * null. + * + * @throws EmptySearchException + * if the search string is empty or null (from + * LibraryUtils.search). + * + * @throws InvalidMessageException + * if the response from the server is invalid. + */ + public void doSearch(String search) throws EmptySearchException, + InvalidMessageException { + // TODO: fan out? + + if (search == null || search == "") + throw new EmptySearchException(); + + Client cl = new Client(); + Map<?, ?> response = null; + libraryList.clear(); + + try { + response = cl + .get("/library/LibraryRequestHandler?function=search&search=" + + search); + } catch (DecodeFailureException e) { + throw new InvalidMessageException(e.getMessage()); + } + + /* + * Check to see if this is Map<String, ?> by looking for the status, + * which should always be in a valid response. + */ + + if (ProtocolUtils.responseIsOK(response) == false) + throw new InvalidMessageException( + (String) response.get(Directive.REASON.toString())); + + // Should contain a list of items, even if there are no items. + if (response.containsKey(Directive.ITEMS.toString()) == false) + throw new InvalidMessageException("No item set returned."); + + if ((response.get(Directive.ITEMS.toString()) instanceof List<?>) == false) + throw new InvalidMessageException("Malformed item list."); + + for (Object obj : (List<?>) response.get(Directive.ITEMS.toString())) { + Map<LibraryItemProperty, String> properties = new HashMap<LibraryItemProperty, String>(); + + if (obj instanceof Map<?, ?> == false) + throw new InvalidMessageException("Malformed item."); + + Set<?> keySet = ((Map<?, ?>) obj).keySet(); + + // Check to make sure this item has only String-String mappings. + for (Object key : keySet) { + if ((key instanceof String && ((Map<?, ?>) obj).get(key) instanceof String) == false) + throw new InvalidMessageException("Not a valid property."); + else if (LibraryItemProperty.valueOf((String) key) == null) + throw new InvalidMessageException("Property type " + key + + " not recognised."); + else + properties.put(LibraryItemProperty.valueOf((String) key), + (String) ((Map<?, ?>) obj).get(key)); + + } + + libraryList.add(new LibraryItem(properties)); + } + } + + /** + * @return the current library list. + */ + + public List<LibraryItem> getLibraryList() { + return libraryList; + } } diff --git a/src/uk/org/ury/library/viewer/LibraryViewer.properties b/src/uk/org/ury/library/viewer/LibraryViewer.properties index 677cbc5..bb88988 100644 --- a/src/uk/org/ury/library/viewer/LibraryViewer.properties +++ b/src/uk/org/ury/library/viewer/LibraryViewer.properties @@ -3,7 +3,7 @@ MODULE_NAME = Library Viewer Demo // Search errors // 1st parameter: search term, 2nd parameter: failure reason etc. -ERR_UNKNOWN = Unknown error while searching for '%1$s'. +ERR_UNKNOWN = Unknown error. ERR_SEARCH_FAILED = Search for '%1$s' failed: %2$s ERR_EMPTY_SEARCH = Please type in a search term. ERR_NO_RESULTS = Sorry, but no results were found for '%1$s'. diff --git a/src/uk/org/ury/library/viewer/LibraryViewerPanel.java b/src/uk/org/ury/library/viewer/LibraryViewerPanel.java index b3ffdd3..c3ec351 100644 --- a/src/uk/org/ury/library/viewer/LibraryViewerPanel.java +++ b/src/uk/org/ury/library/viewer/LibraryViewerPanel.java @@ -1,8 +1,15 @@ -/** +/* + * LibraryViewerPanel.java + * ----------------------- + * + * Part of the URY Frontend Platform + * + * V0.00 2011/03/20 * + * (C) 2011 URY Computing */ -package uk.org.ury.library.viewer; +package uk.org.ury.library.viewer; import java.util.ResourceBundle; import java.util.concurrent.ExecutionException; @@ -14,242 +21,197 @@ import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.SwingWorker; - import uk.org.ury.frontend.FrontendMaster; import uk.org.ury.frontend.FrontendModulePanel; import uk.org.ury.frontend.HintField; import uk.org.ury.frontend.exceptions.UICreationFailureException; - import uk.org.ury.library.exceptions.EmptySearchException; - import uk.org.ury.protocol.exceptions.InvalidMessageException; - /** * Frontend panel providing access to an underlying library viewer. * * @author Matt Windsor, Nathan Lasseter */ +public class LibraryViewerPanel extends FrontendModulePanel { + /** + * + */ + private static final long serialVersionUID = -2441616418398056712L; -public class LibraryViewerPanel extends FrontendModulePanel -{ - /** - * - */ - private static final long serialVersionUID = -2441616418398056712L; - - - /* Panel widgets exposed by the SwiXML user interface. */ - - private JTable resultsTable; - private JScrollPane resultsPane; - - private JPanel messagePanel; - private JLabel messageLabel; - - private JPanel searchingPanel; - private JLabel searchingLabel; - - private JTextField searchField; - private JButton searchButton; - private JLabel searchForLabel; - - private HintField hint; - - - /* This contains the last search failure message, for use in - * letting the user know what happened. - */ - - private String searchFailureMessage; - - - // Resource bundle. - - private ResourceBundle rb; - - - /** - * Construct a new LibraryViewerPanel. - * - * @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 - { - /* The UI implementation is contained in library_viewer_gui.xml. - * - * See this file for more details. + /* Panel widgets exposed by the SwiXML user interface. */ + + private JTable resultsTable; + private JScrollPane resultsPane; + + private JPanel messagePanel; + private JLabel messageLabel; + + private JPanel searchingPanel; + private JLabel searchingLabel; + + private JTextField searchField; + private JButton searchButton; + private JLabel searchForLabel; + + private HintField hint; + + /* + * This contains the last search failure message, for use in letting the + * user know what happened. */ - - super (viewer, "library_viewer_gui.xml", master); - - - // Fill in locale-specific data. - - rb = ResourceBundle.getBundle ("uk.org.ury.library.viewer.LibraryViewer"); - - searchFailureMessage = rb.getString ("ERR_UNKNOWN"); - - searchingLabel.setText (rb.getString ("MSG_SEARCHING")); - searchForLabel.setText (rb.getString ("LBL_SEARCHFOR")); - searchButton.setText (rb.getString ("BTN_SEARCH")); - hint.setText (rb.getString ("HINT")); - - // Fine-tune table - - resultsTable.setAutoCreateRowSorter (true); - } - - - /** - * @return the name of the panel. - * - * @see uk.org.ury.frontend.FrontendModulePanel#getModuleName() - */ - - @Override - public String - getModuleName () - { - return rb.getString ("MODULE_NAME"); - } - - - /** - * Action method for performing a search, bound by the UI XML - * manifest to the search field and button. - */ - - public void - search () - { - /* We can't let the user search while another search is going on, - * but it's not good to let the search "freeze" the UI. + + private String searchFailureMessage; + + // Resource bundle. + + private ResourceBundle rb; + + /** + * Construct a new LibraryViewerPanel. + * + * @param viewer + * The LibraryViewer controlling this LibraryViewerPanel. * - * Hence the search function disables all sensitive parts of the - * interface and launches a search as a background process. + * @param master + * The FrontendMaster driving the frontend. * - * We also swap the results table or no-results panel out for a - * panel that says "Searching...", in the interests of - * user-friendliness. + * @throws UICreationFailureException + * if the UI creation fails. */ - - searchField.setEnabled (false); - searchButton.setEnabled (false); - resultsPane.setVisible (false); - messagePanel.setVisible (false); - searchingPanel.setVisible (true); - searchingLabel.setText (String.format (rb.getString ("MSG_SEARCHING"), - searchField.getText ())); - - final LibraryViewer master = (LibraryViewer) getModule (); - - - SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void> () - { - private String searchTerm = ""; - - - /** - * Perform a task in a separate thread from event-dispatch. - * - * In this case, perform a search. - * - * @return whether or not the search was successful. - */ - - @Override - public Boolean - doInBackground () - { - searchTerm = searchField.getText (); - - try - { - master.doSearch (searchTerm); - } - catch (InvalidMessageException e) - { - searchFailureMessage = String.format (rb.getString ("ERR_SEARCH_FAILED"), - searchTerm, e.getMessage ()); - return false; - } - catch (EmptySearchException e) - { - searchFailureMessage = rb.getString ("ERR_EMPTY_SEARCH"); - return false; - } - - return true; - } - - - /** - * Perform post-search cleanup and finalisation. - */ - - @Override - public void - done () - { - // Figure out whether or not the search succeeded. - - boolean hasSucceeded = false; - - try - { - hasSucceeded = this.get (); - } - catch (InterruptedException e) - { - e.printStackTrace (); - } - catch (ExecutionException e) - { - searchFailureMessage = String.format (rb.getString ("ERR_SEARCH_FAILED"), - searchTerm, e.getMessage ()); - } - - - /* Re-enable widgets and swap panels according to whether - * or not results were found. - */ - - searchField.setEnabled (true); - searchButton.setEnabled (true); - searchingPanel.setVisible (false); - - if (hasSucceeded == false) - { - messageLabel.setText (searchFailureMessage); - messagePanel.setVisible (true); - } - else if (master.getLibraryList ().size () == 0) - { - messageLabel.setText (String.format (rb.getString ("ERR_NO_RESULTS"), - searchTerm)); - messagePanel.setVisible (true); - } - else - { - // Force table update with new results. - - resultsTable.setModel (new LibraryTableModel (master.getLibraryList ())); - - messagePanel.setVisible (false); - resultsPane.setVisible (true); - } - } - }; - - - worker.execute (); - } + + public LibraryViewerPanel(LibraryViewer viewer, FrontendMaster master) + throws UICreationFailureException { + /* + * The UI implementation is contained in library_viewer_gui.xml. + * + * See this file for more details. + */ + super(viewer, "library_viewer_gui.xml", master); + + // Fill in locale-specific data. + rb = ResourceBundle + .getBundle("uk.org.ury.library.viewer.LibraryViewer"); + + searchFailureMessage = rb.getString("ERR_UNKNOWN"); + + searchingLabel.setText(rb.getString("MSG_SEARCHING")); + searchForLabel.setText(rb.getString("LBL_SEARCHFOR")); + searchButton.setText(rb.getString("BTN_SEARCH")); + hint.setText(rb.getString("HINT")); + + // Fine-tune table + resultsTable.setAutoCreateRowSorter(true); + } + + /** + * @return the name of the panel. + * + * @see uk.org.ury.frontend.FrontendModulePanel#getModuleName() + */ + @Override + public String getModuleName() { + return rb.getString("MODULE_NAME"); + } + + /** + * Action method for performing a search, bound by the UI XML manifest to + * the search field and button. + */ + public void search() { + /* + * We can't let the user search while another search is going on, but + * it's not good to let the search "freeze" the UI. + * + * Hence the search function disables all sensitive parts of the + * interface and launches a search as a background process. + * + * We also swap the results table or no-results panel out for a panel + * that says "Searching...", in the interests of user-friendliness. + */ + searchField.setEnabled(false); + searchButton.setEnabled(false); + resultsPane.setVisible(false); + messagePanel.setVisible(false); + searchingPanel.setVisible(true); + searchingLabel.setText(String.format(rb.getString("MSG_SEARCHING"), + searchField.getText())); + + final LibraryViewer master = (LibraryViewer) getModule(); + + SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() { + private String searchTerm = ""; + + /** + * Perform a task in a separate thread from event-dispatch. + * + * In this case, perform a search. + * + * @return whether or not the search was successful. + */ + @Override + public Boolean doInBackground() { + searchTerm = searchField.getText(); + + try { + master.doSearch(searchTerm); + } catch (InvalidMessageException e) { + searchFailureMessage = String.format( + rb.getString("ERR_SEARCH_FAILED"), searchTerm, + e.getMessage()); + return false; + } catch (EmptySearchException e) { + searchFailureMessage = rb.getString("ERR_EMPTY_SEARCH"); + return false; + } + + return true; + } + + /** + * Perform post-search cleanup and finalisation. + */ + @Override + public void done() { + // Figure out whether or not the search succeeded. + boolean hasSucceeded = false; + + try { + hasSucceeded = this.get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + searchFailureMessage = String.format( + rb.getString("ERR_SEARCH_FAILED"), searchTerm, + e.getMessage()); + } + + /* + * Re-enable widgets and swap panels according to whether or not + * results were found. + */ + searchField.setEnabled(true); + searchButton.setEnabled(true); + searchingPanel.setVisible(false); + + if (hasSucceeded == false) { + messageLabel.setText(searchFailureMessage); + messagePanel.setVisible(true); + } else if (master.getLibraryList().size() == 0) { + messageLabel.setText(String.format( + rb.getString("ERR_NO_RESULTS"), searchTerm)); + messagePanel.setVisible(true); + } else { + // Force table update with new results. + resultsTable.setModel(new LibraryTableModel(master + .getLibraryList())); + + messagePanel.setVisible(false); + resultsPane.setVisible(true); + } + } + }; + + worker.execute(); + } } diff --git a/src/uk/org/ury/protocol/ProtocolUtils.java b/src/uk/org/ury/protocol/ProtocolUtils.java index d38eeed..b2d3ed9 100644 --- a/src/uk/org/ury/protocol/ProtocolUtils.java +++ b/src/uk/org/ury/protocol/ProtocolUtils.java @@ -11,88 +11,75 @@ import org.json.simple.JSONValue; import uk.org.ury.protocol.exceptions.DecodeFailureException; import uk.org.ury.protocol.exceptions.InvalidMessageException; - /** - * Utilities for converting between strings encoded in the response - * protocol and collections of items, as well as validating and - * unpicking protocol messages. + * Utilities for converting between strings encoded in the response protocol and + * collections of items, as well as validating and unpicking protocol messages. + * + * @author Matt Windsor * - * @author Matt Windsor - * */ -public class ProtocolUtils -{ - /** - * Encode a key-value map into a protocol string. - * - * The map can contain strings, lists and other maps. Other - * types may be accepted by the underlying encoding engine, - * but the above types are the only ones explicitly accepted. - * - * @param items The key-value map of items, which should contain - * strings, lists and maps. The keys of any map - * should be protocol directives. - * - * @return A string containing the encoded representation of - * the map. - */ - - public static String - encode (Map<String, Object> items) - { - return JSONValue.toJSONString (items); - } - - - /** - * Decode a protocol string into a key-value map. - * - * @param string The string to decode. - * - * @return A key-value map mapping directives to strings, - * lists and maps. - * - * @throws DecodeFailureException if the decoding engine - * returns something other than a map. - */ - - public static Map<?, ?> - decode (String string) throws DecodeFailureException - { - Object result = JSONValue.parse (string); - - if (result instanceof JSONObject) - return (JSONObject) result; - else - throw new DecodeFailureException ("Result not a map."); - } - - - /** - * Check if a response is flagged as having OK status. - * - * @param response The response message, as a key-value map - * (eg in decoded format). - * - * @return true if the response is flagged with OK status, - * false if not (eg ERROR status). - * - * @throws InvalidMessageException if the response is - * invalid (eg the status is missing). - */ - - public static boolean - responseIsOK (Map<?, ?> response) - throws InvalidMessageException - { - if (response.containsKey (Directive.STATUS.toString ()) == false) - throw new InvalidMessageException ("No status line in response."); - - if ((response.get (Directive.STATUS.toString ()) instanceof String) == false) - throw new InvalidMessageException ("Status is not a string."); - - return (((String) response.get (Directive.STATUS.toString ())) - .equals (Status.OK.toString ())); - } +public class ProtocolUtils { + /** + * Encode a key-value map into a protocol string. + * + * The map can contain strings, lists and other maps. Other types may be + * accepted by the underlying encoding engine, but the above types are the + * only ones explicitly accepted. + * + * @param items + * The key-value map of items, which should contain strings, + * lists and maps. The keys of any map should be protocol + * directives. + * + * @return A string containing the encoded representation of the map. + */ + public static String encode(Map<String, Object> items) { + return JSONValue.toJSONString(items); + } + + /** + * Decode a protocol string into a key-value map. + * + * @param string + * The string to decode. + * + * @return A key-value map mapping directives to strings, lists and maps. + * + * @throws DecodeFailureException + * if the decoding engine returns something other than a map. + */ + public static Map<?, ?> decode(String string) throws DecodeFailureException { + Object result = JSONValue.parse(string); + + if (result instanceof JSONObject) + return (JSONObject) result; + else + throw new DecodeFailureException("Result not a map."); + } + + /** + * Check if a response is flagged as having OK status. + * + * @param response + * The response message, as a key-value map (eg in decoded + * format). + * + * @return true if the response is flagged with OK status, false if not (eg + * ERROR status). + * + * @throws InvalidMessageException + * if the response is invalid (eg the status is missing). + */ + public static boolean responseIsOK(Map<?, ?> response) + throws InvalidMessageException { + if (response.containsKey(Directive.STATUS.toString()) == false) + throw new InvalidMessageException("No status line in response."); + + if ((response.get(Directive.STATUS.toString()) instanceof String) == false) + throw new InvalidMessageException("Status is not a string."); + + return (((String) response.get(Directive.STATUS.toString())) + .equals(Status.OK.toString())); + } } diff --git a/src/uk/org/ury/server/ApiRequestHandler.java b/src/uk/org/ury/server/ApiRequestHandler.java new file mode 100644 index 0000000..a2290f8 --- /dev/null +++ b/src/uk/org/ury/server/ApiRequestHandler.java @@ -0,0 +1,42 @@ +package uk.org.ury.server; + +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 ApiRequestHandler +{ + /** + * 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 series of key-value pairs to pass back to + * the client. + * + * @throws HandleFailureException if the handler cannot + * handle the request. + */ + + public Map<String, Object> + handleGetRequest (Map<String, String> parameters, Server server) + throws HandleFailureException; +} diff --git a/src/uk/org/ury/server/HttpHandler.java b/src/uk/org/ury/server/HttpHandler.java new file mode 100644 index 0000000..41b4dc4 --- /dev/null +++ b/src/uk/org/ury/server/HttpHandler.java @@ -0,0 +1,343 @@ +/* + * HttpHandler.java + * --------------------- + * + * Part of the URY Server Platform + * + * V0.00 2011/03/20 + * + * (C) 2011 URY Computing + * + * Based on the HttpCore example code, which is available under the + * Apache License, version 2.0; the copyright notice provided with + * said code follows. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package uk.org.ury.server; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.entity.StringEntity; +import org.apache.http.protocol.HTTP; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.json.simple.JSONValue; + +import uk.org.ury.protocol.Directive; +import uk.org.ury.protocol.Status; +import uk.org.ury.server.exceptions.BadRequestException; +import uk.org.ury.server.exceptions.HandleFailureException; +import uk.org.ury.server.exceptions.HandlerNotFoundException; +import uk.org.ury.server.exceptions.HandlerSetupFailureException; +import uk.org.ury.server.exceptions.HandlingException; +import uk.org.ury.server.exceptions.NotAHandlerException; + +/** + * @author Matt Windsor, Apache Software Foundation + */ +public class HttpHandler implements HttpRequestHandler { + private Server server; + + /** + * Construct a new HttpHandler. + * + * @param server + * The server whose HTTP requests are to be handled by this + * handler. + */ + public HttpHandler(Server server) { + this.server = server; + } + + /** + * Handle a HTTP request. + * + * @param request + * The HTTP request. + * + * @param response + * The response that the handler will populate during the + * handling of the request. + * + * @param context + * The HTTP context. + */ + @Override + public void handle(HttpRequest request, HttpResponse response, + HttpContext context) throws HttpException, IOException { + String method = request.getRequestLine().getMethod() + .toUpperCase(Locale.ENGLISH); + + if (method.equals("GET")) { + try { + handleGet(request, response, context); + } catch (HandlerNotFoundException e) { + // TODO: log + serveError(request, response, HttpStatus.SC_NOT_FOUND, + e.getMessage()); + } catch (BadRequestException e) { + // TODO: log + serveError(request, response, HttpStatus.SC_BAD_REQUEST, + e.getMessage()); + } catch (HandlingException e) { + serveError(request, response, + HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + } else { + serveError(request, response, HttpStatus.SC_NOT_IMPLEMENTED, + "Method not implemented."); + } + } + + /** + * Handle a HTTP GET request. + * + * @param request + * The HTTP request. + * + * @param response + * The response that the handler will populate during the + * handling of the request. + * + * @param context + * The HTTP context. + * + * @throws HandlerNotFoundException + * if the client requested a request handler that could not be + * found on the class path. + * + * @throws HandlerSetupFailureException + * if the handler was found but could not be set up (eg does not + * implement appropriate interface or cannot be instantiated). + * + * @throws HandleFailureException + * if an appropriate handler was contacted, but it failed to + * process the request. + * + * @throws BadRequestException + * if the request was malformed or invalid. + * + * @throws NotAHandlerException + * if the class requested to handle the request is not a + * handler. + */ + public void handleGet(HttpRequest request, HttpResponse response, + HttpContext context) throws HandlerNotFoundException, + HandlerSetupFailureException, HandleFailureException, + BadRequestException, NotAHandlerException { + String path = request.getRequestLine().getUri(); + + if (path.equals("/index.html") || path.equals("/")) { + // Someone's trying to get the index page! + // Humour them. + + response.setStatusLine(request.getProtocolVersion(), + HttpStatus.SC_OK, "OK"); + + StringEntity entity = null; + + try { + entity = new StringEntity(Server.DOCTYPE + Server.INDEX_HTML); + } catch (UnsupportedEncodingException e) { + throw new HandlerSetupFailureException("(Index page)", e); + } + + entity.setContentType("text/html"); + + response.setEntity(entity); + } 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 e) { + throw new BadRequestException(e); + } + + String className = "uk.org.ury" + + pathURL.getPath().replace('/', '.'); + System.out.println(className); + Class<?> newClass = null; + + try { + newClass = Class.forName(className); + } catch (ClassNotFoundException e) { + throw new HandlerNotFoundException(className, e); + } + + if (ApiRequestHandler.class.isAssignableFrom(newClass) == false) + throw new NotAHandlerException(className); + + String queryString = pathURL.getQuery(); + Map<String, String> parameters; + + try { + parameters = parseQueryString(queryString); + } catch (UnsupportedEncodingException e) { + throw new HandlerSetupFailureException(className, e); + } + + Map<String, Object> content = null; + + try { + ApiRequestHandler srh = ((ApiRequestHandler) newClass + .newInstance()); + content = srh.handleGetRequest(parameters, server); + } catch (InstantiationException e) { + throw new HandlerSetupFailureException(className, e); + } catch (IllegalAccessException e) { + throw new HandlerSetupFailureException(className, e); + } + + // Everything seems OK, so make the response. + + response.setStatusLine(request.getProtocolVersion(), + HttpStatus.SC_OK, "OK"); + + content.put(Directive.STATUS.toString(), Status.OK.toString()); + + StringEntity entity = null; + + try { + entity = new StringEntity(JSONValue.toJSONString(content)); + } catch (UnsupportedEncodingException e) { + throw new HandlerSetupFailureException(className, e); + } + + entity.setContentType(HTTP.PLAIN_TEXT_TYPE); + response.setEntity(entity); + } + } + + /** + * Serve a HTTP plain-text error as the HTTP response for a request. + * + * @param request + * The request that is being responded to. + * + * @param response + * The response to populate with the error message. + * + * @param code + * HTTP status code to use. + * + * @param reason + * The reason to display to the client. + */ + private void serveError(HttpRequest request, HttpResponse response, + int code, String reason) { + // Get the reason string to put in the error response. + String statusReason = ""; + + switch (code) { + case HttpStatus.SC_BAD_REQUEST: + statusReason = "Bad Request"; + break; + case HttpStatus.SC_NOT_FOUND: + statusReason = "Not Found"; + break; + default: + case HttpStatus.SC_INTERNAL_SERVER_ERROR: + statusReason = "Internal Server Error"; + break; + } + + response.setStatusLine(request.getProtocolVersion(), code, statusReason); + StringEntity entity = null; + + try { + Map<String, Object> content = new HashMap<String, Object>(); + + content.put(Directive.STATUS.toString(), Status.ERROR.toString()); + content.put(Directive.REASON.toString(), reason); + + entity = new StringEntity(JSONValue.toJSONString(content)); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (entity != null) { + entity.setContentType(HTTP.PLAIN_TEXT_TYPE); + response.setEntity(entity); + } + } + + /** + * 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; + } +} diff --git a/src/uk/org/ury/server/HttpListenerThread.java b/src/uk/org/ury/server/HttpListenerThread.java new file mode 100644 index 0000000..9396d0b --- /dev/null +++ b/src/uk/org/ury/server/HttpListenerThread.java @@ -0,0 +1,125 @@ +/* + * HttpListenerThread.java + * ----------------------- + * + * Part of the URY Server Platform + * + * V0.00 2011/03/20 + * + * (C) 2011 URY Computing + * + * Based on the HttpCore example code, which is available under the + * Apache License, version 2.0; the copyright notice provided with + * said code follows. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package uk.org.ury.server; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +import org.apache.http.HttpResponseInterceptor; +import org.apache.http.impl.DefaultConnectionReuseStrategy; +import org.apache.http.impl.DefaultHttpResponseFactory; +import org.apache.http.impl.DefaultHttpServerConnection; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.params.HttpParams; +import org.apache.http.params.SyncBasicHttpParams; +import org.apache.http.protocol.HttpProcessor; +import org.apache.http.protocol.HttpRequestHandlerRegistry; +import org.apache.http.protocol.HttpService; +import org.apache.http.protocol.ImmutableHttpProcessor; +import org.apache.http.protocol.ResponseConnControl; +import org.apache.http.protocol.ResponseContent; +import org.apache.http.protocol.ResponseDate; +import org.apache.http.protocol.ResponseServer; + +/** + * Listener thread for the URY server HTTP interface. + * + * @author Matt Windsor, Apache Software Foundation + */ +public class HttpListenerThread extends Thread { + private ServerSocket ssocket; + private HttpParams params; + private HttpProcessor httpproc; + private HttpRequestHandlerRegistry registry; + private HttpService service; + + public HttpListenerThread(int port, Server server) throws IOException { + ssocket = new ServerSocket(port); + params = new SyncBasicHttpParams(); + + params + .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000) + .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) + .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false) + .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) + .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); + + httpproc = new ImmutableHttpProcessor(new HttpResponseInterceptor[] { + new ResponseDate(), + new ResponseServer(), + new ResponseContent(), + new ResponseConnControl() + }); + + registry = new HttpRequestHandlerRegistry(); + registry.register("*", new HttpHandler(server)); + + service = new HttpService(httpproc, + new DefaultConnectionReuseStrategy(), + new DefaultHttpResponseFactory(), registry, params); + } + + /** + * Thread execution body. + */ + @Override + public void run() { + while (Thread.interrupted() == false) { + Socket csocket = null; + DefaultHttpServerConnection conn + = new DefaultHttpServerConnection(); + Thread thread = null; + + try { + csocket = ssocket.accept(); + conn.bind(csocket, params); + } catch (IOException e) { + e.printStackTrace(); + break; + } + + thread = new HttpWorkerThread(service, conn); + thread.setDaemon(true); + thread.start(); + } + } +} diff --git a/src/uk/org/ury/server/HttpWorkerThread.java b/src/uk/org/ury/server/HttpWorkerThread.java new file mode 100644 index 0000000..246038c --- /dev/null +++ b/src/uk/org/ury/server/HttpWorkerThread.java @@ -0,0 +1,104 @@ +/* + * HttpWorkerThread.java + * --------------------- + * + * Part of the URY Server Platform + * + * V0.00 2011/03/20 + * + * (C) 2011 URY Computing + * + * Based on the HttpCore example code, which is available under the + * Apache License, version 2.0; the copyright notice provided with + * said code follows. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package uk.org.ury.server; + +import java.io.IOException; +import java.io.InterruptedIOException; + +import org.apache.http.ConnectionClosedException; +import org.apache.http.HttpException; +import org.apache.http.HttpServerConnection; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpService; + +/** + * A worker thread in the server HTTP interface. + * + * This thread handles requests from the connected client, passing them to the + * request handler(s). + * + * @author Matt Windsor, Apache Software Foundation + */ +public class HttpWorkerThread extends Thread { + private final HttpService service; + private final HttpServerConnection conn; + + /** + * Construct a new HttpWorkerThread. + * + * @param service + * The HTTP service the thread is working for. + * @param conn + * The connection the thread is listening on. + */ + public HttpWorkerThread(HttpService service, HttpServerConnection conn) { + super(); + this.service = service; + this.conn = conn; + } + + /** + * Thread execution body. + */ + public void run() { + HttpContext context = new BasicHttpContext(null); + + try { + while (Thread.interrupted() == false && conn.isOpen()) { + service.handleRequest(conn, context); + } + } catch (ConnectionClosedException e) { + System.out.println("Client closed connection."); + } catch (InterruptedIOException e) { + System.out.println("Interrupted IO: " + e.getMessage()); + } catch (IOException e) { + e.printStackTrace(); + } catch (HttpException e) { + e.printStackTrace(); + } finally { + try { + conn.shutdown(); + } catch (IOException e) { + // Ignore + } + } + } +} diff --git a/src/uk/org/ury/server/Server.java b/src/uk/org/ury/server/Server.java index e75cb97..2419915 100644 --- a/src/uk/org/ury/server/Server.java +++ b/src/uk/org/ury/server/Server.java @@ -1,555 +1,98 @@ -/** +/* + * Server.java + * ----------- + * + * Part of the URY Server Platform + * + * V0.00 2011/03/20 * + * (C) 2011 URY Computing */ + 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 org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.HttpVersion; -import org.apache.http.ParseException; -import org.apache.http.entity.StringEntity; -import org.apache.http.message.BasicHttpResponse; -import org.apache.http.protocol.HTTP; -import org.apache.http.util.EntityUtils; -import org.json.simple.JSONValue; 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.protocol.Directive; -import uk.org.ury.protocol.Status; -import uk.org.ury.server.exceptions.BadRequestException; -import uk.org.ury.server.exceptions.HandleFailureException; -import uk.org.ury.server.exceptions.HandlerNotFoundException; -import uk.org.ury.server.exceptions.HandlerSetupFailureException; -import uk.org.ury.server.exceptions.HandlingException; -import uk.org.ury.server.exceptions.NotAHandlerException; /** * The unified URY server, accepting requests over HTTP. * - * @author Matt Windsor + * @author Matt Windsor */ - -public class Server -{ - - private ServerSocket serverSocket; - - 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 class Server { + public static final String SERVER_VERSION = "SLUT 0.0"; + public static final String DOCTYPE = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"" + + "\"http://www.w3.org/TR/html4/strict.dtd\">"; + public 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(); } - } - - 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); - - HttpResponse response; - - if (requestStart.startsWith ("GET")) - { - System.out.println ("That was a GET..."); - try - { - response = handleGet (buffer); - } - catch (HandlerNotFoundException e) - { - // TODO: log - response = serveError (HttpStatus.SC_NOT_FOUND, - e.getMessage ()); - } - catch (BadRequestException e) - { - // TODO: log - response = serveError (HttpStatus.SC_BAD_REQUEST, - e.getMessage ()); - } - catch (HandlingException e) - { - response = serveError (HttpStatus.SC_INTERNAL_SERVER_ERROR, - e.getMessage ()); - } - } - else - { - System.out.println ("Uh-oh! I don't know what to do!"); - response = serveError (HttpStatus.SC_NOT_IMPLEMENTED, - "Feature not implemented yet."); - } - - - // Now send the response. - - for (Header h : response.getAllHeaders ()) - { - out.println (h); - } - - try - { - out.print (EntityUtils.toString (response.getEntity ())); - } - catch (ParseException e) - { - // TODO Auto-generated catch block - e.printStackTrace (); - } - catch (IOException e) - { - // TODO Auto-generated catch block - e.printStackTrace (); - } - } - - - /** - * Handle a HTTP GET request. - * - * @param buffer The HTTP request as a list of strings. - * - * @return The HTTP response. - * - * @throws HandlerNotFoundException if the client requested - * a request handler that could not be found on the - * class path. - * - * @throws HandlerSetupFailureException if the handler was - * found but could not be set up (eg does not - * implement appropriate interface or cannot be - * instantiated). - * - * @throws HandleFailureException if an appropriate handler - * was contacted, but it failed to process the - * request. - * - * @throws BadRequestException if the request was malformed - * or invalid. - * - * @throws NotAHandlerException if the class requested to - * handle the request is not a handler. - */ - - public HttpResponse - handleGet (List<String> buffer) - throws HandlerNotFoundException, HandlerSetupFailureException, - HandleFailureException, BadRequestException, NotAHandlerException - { - HttpResponse response = null; - - 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. - - response = new BasicHttpResponse (HttpVersion.HTTP_1_1, - HttpStatus.SC_OK, - "OK"); - - StringEntity entity = null; - - try - { - entity = new StringEntity (DOCTYPE + INDEX_HTML); - } - catch (UnsupportedEncodingException e) - { - throw new HandlerSetupFailureException ("(Index page)", e); - } - - response.setEntity (entity); - } - 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 e) - { - throw new BadRequestException (e); - } - - String className = "uk.org.ury" + pathURL.getPath ().replace ('/', '.'); - System.out.println (className); - Class<?> newClass = null; - - - try - { - newClass = Class.forName (className); - } - catch (ClassNotFoundException e) - { - throw new HandlerNotFoundException (className, e); - } - - - // Check for error (response set) here. - - if (response == null - && RequestHandler.class.isAssignableFrom (newClass)) - { - String queryString = pathURL.getQuery (); - Map<String, String> parameters; - - try - { - parameters = parseQueryString (queryString); - } - catch (UnsupportedEncodingException e) - { - throw new HandlerSetupFailureException (className, e); - } - - Map<String, Object> content = null; - - try - { - RequestHandler srh = ((RequestHandler) newClass.newInstance ()); - content = srh.handleGetRequest (parameters, this); - } - catch (InstantiationException e) - { - throw new HandlerSetupFailureException (className, e); - } - catch (IllegalAccessException e) - { - throw new HandlerSetupFailureException (className, e); - } - - - // Everything seems OK, so make the response. - - response = new BasicHttpResponse (HttpVersion.HTTP_1_1, - HttpStatus.SC_OK, - "OK"); - - content.put (Directive.STATUS.toString (), - Status.OK.toString ()); - - StringEntity entity = null; - - try - { - entity = new StringEntity (JSONValue.toJSONString (content)); - } - catch (UnsupportedEncodingException e) - { - throw new HandlerSetupFailureException (className, e); - } - - entity.setContentType (HTTP.PLAIN_TEXT_TYPE); - response.setEntity (entity); - } - else - throw new NotAHandlerException (className); - } - - return response; - } - - - /** - * Serve a HTTP plain-text error as a HTTP response. - * - * @param code HTTP status code to use. - * @param reason The reason to display to the client. - * - * @return the HTTP response for the error. - */ - - private HttpResponse - serveError (int code, String reason) - { - // Get the reason string to put in the error response. - - String statusReason = ""; - - switch (code) - { - case HttpStatus.SC_BAD_REQUEST: - statusReason = "Bad Request"; - break; - case HttpStatus.SC_NOT_FOUND: - statusReason = "Not Found"; - break; - default: - case HttpStatus.SC_INTERNAL_SERVER_ERROR: - statusReason = "Internal Server Error"; - break; - } - - HttpResponse response = new BasicHttpResponse (HttpVersion.HTTP_1_1, - code, statusReason); - StringEntity entity = null; - - try - { - Map<String, Object> content = new HashMap<String, Object> (); - - content.put (Directive.STATUS.toString (), - Status.ERROR.toString ()); - content.put (Directive.REASON.toString (), - reason); - - entity = new StringEntity (JSONValue.toJSONString (content)); - } - catch (UnsupportedEncodingException e) - { - // TODO Auto-generated catch block - e.printStackTrace (); - } - - if (entity != null) - { - entity.setContentType (HTTP.PLAIN_TEXT_TYPE); - response.setEntity (entity); - } - - return response; - } - - - /** - * 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); - } + /** + * Run the server. + */ + private void run() { + Thread thread = null; + + try { + thread = new HttpListenerThread(8000, this); + } catch (IOException e) { + e.printStackTrace(); + System.exit(-1); + } + + thread.setDaemon(false); + thread.run(); + } + /** + * 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. + * + * @throws MissingCredentialsException + * if the credentials for the given userclass are missing. + * + * @throws 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; - } + /** + * @return the version string of the server. + */ + public String getVersion() { + return SERVER_VERSION; + } } diff --git a/src/uk/org/ury/server/ServerRequestHandler.java b/src/uk/org/ury/server/ServerRequestHandler.java index c8d4f39..df67faf 100644 --- a/src/uk/org/ury/server/ServerRequestHandler.java +++ b/src/uk/org/ury/server/ServerRequestHandler.java @@ -7,7 +7,7 @@ import java.util.HashMap; import java.util.Map; import uk.org.ury.server.Server; -import uk.org.ury.server.RequestHandler; +import uk.org.ury.server.ApiRequestHandler; import uk.org.ury.server.exceptions.HandleFailureException; @@ -17,7 +17,7 @@ import uk.org.ury.server.exceptions.HandleFailureException; * @author Matt Windsor */ -public class ServerRequestHandler implements RequestHandler +public class ServerRequestHandler implements ApiRequestHandler { /** * Handle a server GET request (that is, a request for data diff --git a/src/uk/org/ury/show/viewer/ShowViewer.java b/src/uk/org/ury/show/viewer/ShowViewer.java index 24e696b..d11e8d5 100644 --- a/src/uk/org/ury/show/viewer/ShowViewer.java +++ b/src/uk/org/ury/show/viewer/ShowViewer.java @@ -1,3 +1,14 @@ +/* + * ShowViewer.java + * --------------- + * + * Part of the URY Frontend Platform + * + * V0.00 2011/03/20 + * + * (C) 2011 URY Computing + */ + package uk.org.ury.show.viewer; import java.util.List; @@ -11,135 +22,97 @@ import uk.org.ury.frontend.AbstractFrontendModule; 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; - /** * Frontend module for viewing show details. * - * This serves as the base for the show playout and editor classes, - * but can be used stand-alone as an (admittedly rather pointless) - * module. + * This serves as the base for the show playout and editor classes, but can be + * used stand-alone as an (admittedly rather pointless) module. + * + * @author Matt Windsor * - * @author Matt Windsor - * */ +public class ShowViewer extends AbstractFrontendModule { + /** + * + */ -public class ShowViewer extends AbstractFrontendModule -{ - /** - * - */ - - private static final long serialVersionUID = -2782366476480563739L; - private DatabaseDriver dd; - private ShowChannel[] channels; - private ShowViewerPanel panel; - private ConfigReader config; - - - /** - * Construct a new ShowViewer as a frontend object. - */ - - public - ShowViewer () - { - channels = new ShowChannel[ShowUtils.NUM_CHANNELS]; - } - - - /** - * Run the library viewer frontend. - */ - - @Override - public FrontendModulePanel - runFrontend (FrontendMaster master) - { - dd = null; - config = null; - - try - { - config = new ConfigReader (master.getResourceDirectory () + "conf.xml"); - } - catch (MissingCredentialsException e) - { - System.out.println(e); + private static final long serialVersionUID = -2782366476480563739L; + private DatabaseDriver dd; + private ShowChannel[] channels; + private ShowViewerPanel panel; + private ConfigReader config; + + /** + * Construct a new ShowViewer as a frontend object. + */ + public ShowViewer() { + channels = new ShowChannel[ShowUtils.NUM_CHANNELS]; } - - - - try - { - dd = new DatabaseDriver (config, UserClass.READ_ONLY); - } - catch (MissingCredentialsException e) - { - // TODO: Privilege de-escalation - master.fatalError (e.getMessage ()); - } - catch (Exception f) - { - 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 ()); - } - - return panel; - } + /** + * Run the library viewer frontend. + */ + @Override + public FrontendModulePanel runFrontend(FrontendMaster master) { + dd = null; + config = null; + + try { + config = new ConfigReader(master.getResourceDirectory() + + "conf.xml"); + } catch (MissingCredentialsException e) { + System.out.println(e); + } + + try { + dd = new DatabaseDriver(config, UserClass.READ_ONLY); + } catch (MissingCredentialsException e) { + // TODO: Privilege de-escalation + master.fatalError(e.getMessage()); + } catch (Exception f) { + master.fatalError(f.getMessage()); + } - /** - * @return the channel array. - */ - - public ShowChannel[] - getChannels () - { - // TODO Auto-generated method stub - return channels; - } + for (int i = 0; i < channels.length; i++) { + channels[i] = new ShowChannel(); - - /** - * @return the list of bin names. - * - * @throws QueryFailureException if the underlying database query - * fails. - */ + try { + for (ShowItem item : ShowUtils.getChannelList(dd, 4696, i)) { + channels[i].add(item); + } + } catch (QueryFailureException e) { + master.fatalError(e.getMessage()); + } + } - public List<String> - getBins () throws QueryFailureException - { - return ShowUtils.getPublicFolders (dd); - } + try { + panel = new ShowViewerPanel(this, master); + } catch (UICreationFailureException e) { + master.fatalError(e.getMessage()); + } + + return panel; + } + + /** + * @return the channel array. + */ + public ShowChannel[] getChannels() { + // 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); + } } |