diff options
Diffstat (limited to 'src/uk/org/ury/server/Server.java')
-rw-r--r-- | src/uk/org/ury/server/Server.java | 611 |
1 files changed, 77 insertions, 534 deletions
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; + } } |