95-702 OCT Fall 2008 Homework 2 Due: Thursday, September 25, 2008 ========== ================================= In class we reviewed three java programs that used TCP sockets to play knock knock jokes. In this lab you will remove all of the socket code and build two web based applications that play knock knock. The first application will be a web site using Tomcat and the second will be a web service using JDK 6 JAX-WS 2.0. In the spirit of code reuse, we will not make any changes to the KnockKnockProtocol class provided. All of the code needs to be well documented. This includes the code provided by Sun. That is, you will comment the code that implements the finite state machine. Try to make it easy for a reader to understand what is going on. This will convince us that you have studied the code and understand what is going on. Part 1. 50 Points Knock Knock Joke Web Application using Tomcat =============================================================== Build a small web application (web site) using Tomcat. This web application will contain the files web.xml, KnockKnockServlet.java and KnockKnockProtocol.java only. That is, the application will not contain any separate HTML or JSP files. The servlet will be accessed by browsers with the URL: http://localhost:6502/KnockKnockProject/KnockKnock. On the initial visit, the servlet will create a new KnockKnockProtocol object and add it to an HTTPSession. The first response will automatically return a cookie to the browser. You do not need to create the cookies in your code. You should ensure that this is the case by viewing coookies in your browser. Experiment and try creating new sessions by clearing old cookies. The HTTPSession object will associate a particular KnockKnockProtocol object with a particular cookie. The servlet will first respond with the prompt "Knock Knock" followed by a text box. The prompt "Knock Knock" must be retrieved by the servlet from the KnockKnockProtocol object associated with this session. When the user responds to the initial "Knock Knock" the same servlet is executed again. The KnockKnockProtocol object associated with this user session is accessed from the HTTPSession object. This approach allows us to have several knock knock users playing knock knock jokes at the same time. There will be a separate KnockKnockProtocol object for each user. Each of these will track the state of the protocol. The game should be playable and error messages displayed on the browser as they are generated by the protocol handler. You should experiment with more than one browser using the application at the same time. You will need either two browsers (IE and Opera for example) or you may wish to visit the web application from a separate machine. In the latter case, you need to be connected to the internet and replace the string 'localhost' with the IP address of the web server. Part 2. 50 Points Knock Knock Joke Web Service using JDK 6 JAX-WS 2.0 ===================================================================== The web service will be constructed with JAX-WS 2.0 using JDK 6. The client will be a console application written in Java. There is no need for Tomcat in this part of homework 2. The web service will be written in JDK6 and JDK6 provides its own web server. When writing the service, use the apt tool as shown on the slides. When writing the Java client, start by using the wsimport tool. You will not be using any TCP sockets in your code. The console application will be executed with the command java KnockKnockClient. The execution will proceed in the same way as the original socket based solution. In the web service case, you may assume that there is a single visitor. You need not concern yourself with cookies or sessions. The socket code from Sun is included below. KnockKnockClient.java ===================== // From Sun Microsystems import java.io.*; import java.net.*; public class KnockKnockClient { public static void main(String[] args) throws IOException { Socket kkSocket = null; PrintWriter out = null; BufferedReader in = null; try { kkSocket = new Socket("localhost", 4444); out = new PrintWriter(kkSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream())); } catch (UnknownHostException e) { System.err.println("Don't know about host: localhost"); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to: taranis."); System.exit(1); } BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String fromServer; String fromUser; while ((fromServer = in.readLine()) != null) { System.out.println("Server: " + fromServer); if (fromServer.equals("Bye.")) break; fromUser = stdIn.readLine(); if (fromUser != null) { System.out.println("Client: " + fromUser); out.println(fromUser); } } out.close(); in.close(); stdIn.close(); kkSocket.close(); } } KnocKnockServer.java ==================== // From Sun Microsystems import java.net.*; import java.io.*; public class KnockKnockServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(4444); } catch (IOException e) { System.err.println("Could not listen on port: 4444."); System.exit(1); } Socket clientSocket = null; try { clientSocket = serverSocket.accept(); } catch (IOException e) { System.err.println("Accept failed."); System.exit(1); } PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader( new InputStreamReader( clientSocket.getInputStream())); String inputLine, outputLine; KnockKnockProtocol kkp = new KnockKnockProtocol(); outputLine = kkp.processInput(null); out.println(outputLine); while ((inputLine = in.readLine()) != null) { outputLine = kkp.processInput(inputLine); out.println(outputLine); if (outputLine.equals("Bye.")) break; } out.close(); in.close(); clientSocket.close(); serverSocket.close(); } } KnockKnockProtocol.java ======================= // From Sun Microsystems import java.net.*; import java.io.*; public class KnockKnockProtocol { private static final int WAITING = 0; private static final int SENTKNOCKKNOCK = 1; private static final int SENTCLUE = 2; private static final int ANOTHER = 3; private static final int NUMJOKES = 5; private int state = WAITING; private int currentJoke = 0; private String[] clues = { "Turnip", "Little Old Lady", "Atch", "Who", "Who" }; private String[] answers = { "Turnip the heat, it's cold in here!", "I didn't know you could yodel!", "Bless you!", "Is there an owl in here?", "Is there an echo in here?" }; public String processInput(String theInput) { String theOutput = null; if (state == WAITING) { theOutput = "Knock! Knock!"; state = SENTKNOCKKNOCK; } else if (state == SENTKNOCKKNOCK) { if (theInput.equalsIgnoreCase("Who's there?")) { theOutput = clues[currentJoke]; state = SENTCLUE; } else { theOutput = "You're supposed to say \"Who's there?\"! " + "Try again. Knock! Knock!"; } } else if (state == SENTCLUE) { if (theInput.equalsIgnoreCase(clues[currentJoke] + " who?")) { theOutput = answers[currentJoke] + " Want another? (y/n)"; state = ANOTHER; } else { theOutput = "You're supposed to say \"" + clues[currentJoke] + " who?\"" + "! Try again. Knock! Knock!"; state = SENTKNOCKKNOCK; } } else if (state == ANOTHER) { if (theInput.equalsIgnoreCase("y")) { theOutput = "Knock! Knock!"; if (currentJoke == (NUMJOKES - 1)) currentJoke = 0; else currentJoke++; state = SENTKNOCKKNOCK; } else { theOutput = "Bye."; state = WAITING; } } return theOutput; } }