Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
SSEA Ringers Handout 07 Summer 2012 August 16th, 2012 Web Server Architecture More Robust Server import import import import import import import import java.net.Socket; java.net.ServerSocket; java.util.Map; java.util.HashMap; java.util.StringTokenizer; java.util.Scanner; java.io.IOException; java.io.PrintWriter; /** * Provides the implementation of a generic web server. * The web server maintains a map of paths (e.g. "/math") * to WebServices (e.g. MathService) and relies on the * WebService to decide how the request should be handled. */ public class WebServer { /** * Provides the entry point for the web server. Following some * one-time configuration steps (e.g. compiling the list of * supported services, creating a server socket to listen for * all requests), the server loops for all of time, suspending execution * while it waits for a request. As requests come in, the service reads * the request, decides if it can handle it, and if so dispatches the * request to the correct service. * * Implementation: * self-configure * while (true) { * wait-for-request * read-request * if (can-handle-request) { * dispatch-request-to-service * } * } */ public static void main(String[] args) throws IOException { WebServer server = new WebServer(); while (true) { Socket s = server.accept(); Scanner scanner = new Scanner(s.getInputStream()); server.digestHeaderInformation(scanner); String requestedPath = server.getRequestPath(); if (server.serviceMap.containsKey(requestedPath)) { Map<String, String> map = server.getParameterMap(); WebService service = server.serviceMap.get(requestedPath); if (service.canHandleRequest(map)) { PrintWriter pw = new PrintWriter(s.getOutputStream()); service.handleRequest(map, pw); pw.flush(); 2 } } s.close(); } } // private methods private WebServer() { Scanner stdin = new Scanner(System.in); ss = null; while (ss == null) { System.out.print("Port number? "); try { port = Short.parseShort(stdin.nextLine()); ss = new ServerSocket(port); } catch (NumberFormatException nfe) { System.err.println("You didn't enter a valid port number. " + "Please try again"); } catch (IOException ioe) { System.err.println("That port is either reserver or in use. " + "Please select another."); } } serviceMap = new HashMap<String, WebService>(); serviceMap.put("/math", new MathService()); } private Socket accept() throws IOException { return ss.accept(); } private void digestHeaderInformation(Scanner scanner) { StringTokenizer st = new StringTokenizer(scanner.nextLine()); st.nextToken(); // ignored, so skip over it requestedURL = st.nextToken(); String line; do { line = scanner.nextLine(); } while (line.length() > 0); } private Map<String, String> getParameterMap() { String query = getRequestQuery(); Map<String, String> map = new HashMap<String, String>(); for (String param : query.split("&")) { String[] pair = param.split("="); String key = pair[0]; if (!key.isEmpty()) { String value = pair.length > 1 ? pair[1] : ""; map.put(key, value); } } return map; } private String getRequestPath() { int pos = requestedURL.indexOf('?'); 3 if (pos == -1) return requestedURL; return requestedURL.substring(0, pos); } private String getRequestQuery() { String query = requestedURL; int pos = query.indexOf('?'); if (pos != -1) { query = query.substring(pos + 1); } // truncate fragment (e.g. "#conclusion") pos = query.indexOf('#'); if (pos != -1) { query = query.substring(0, pos); } return query; } private private private private short port; ServerSocket ss; String requestedURL; Map<String, WebService> serviceMap; } import java.util.Map; import java.io.PrintWriter; /** * Defines the notion of a web service without committing to any * specific implementation. A web server defines when a particular * WebService is needed, but the WebService itself decides if it's * capable of handling a request and how it should be handled. In general, * a WebService can determine whether or not it can handle a request by * looking at the parameter map (that is, the HashMap of string-string * pairs encoded as a string, just after the ? in an URL.) */ abstract public class WebService { abstract public boolean canHandleRequest(Map<String, String> map); abstract public void handleRequest(Map<String, String> map, PrintWriter pw); /** * Rudimentary method useful to all concrete subclasses, this method * publishes the response code (e.g. 200, 301, 302, 404). It's intended * to be the very first thing published the the requesting server, so that * consumer (the web browser, the application, etc.) knows whether things * worked out or not. * * Example Output: * HTTP/1.0 200 * <blank line> */ protected void postHeader(PrintWriter pw, int code) { pw.println("HTTP/1.0 " + code); pw.println(); } 4 /** * Publishes the content with the given response code. */ protected void postResponse(PrintWriter pw, int code, String payload) { postHeader(pw, code); pw.println(payload); } } import java.util.Map; import java.io.PrintWriter; /** * Provides a concrete implementation of a WebService that * does basic addition, subtraction, and multiplication. * Provided the parameter map includes "method", "first", * and "second", the MathService will try to handle it. * Provided everything works out, the MathService will * response with code 200 and post the arithmetic result as * the HTML content. If something is wrong (arguments aren't * numbers, arithmetic operation isn't supported, etc.), then * we issue a 404 (the code for not found), pretend that we * "couldn't find the page" identified by the bogus * argument set. */ public class MathService extends WebService { public boolean canHandleRequest(Map<String, String> map) { return map.containsKey("method") && map.containsKey("first") && map.containsKey("second"); } public void handleRequest(Map<String, String> map, PrintWriter pw) { try { String method = map.get("method"); int first = Integer.parseInt(map.get("first")); int second = Integer.parseInt(map.get("second")); if (method.equals("add")) { postResponse(pw, 200, Integer.toString(first + second)); } else if (method.equals("subtract")) { postResponse(pw, 200, Integer.toString(first - second)); } else if (method.equals("multiply")) { postResponse(pw, 200, Integer.toString(first * second)); } else { postHeader(pw, 404); } } catch (Exception e) { postHeader(pw, 404); } } }