You should not make any changes to AlarmServer.java and AlarmClient.java, but you will need to read through them and understand how they work. Pay particular attention to the way in which the server determines the port it will be listening on.
You can practise running the AlarmServer and AlarmClient from the command line, which will help you to understand how they work.
While the AlarmServer and AlarmClient can be run from the command line as stand-alone programs, that is not their main purpose. Instead, you will be writing your own code (TimeServerP4.java and TimeClientP4.java) to create and use AlarmServer and AlarmClient objects in order to extend the TIME protocol.
Previously, the TIME protocol possessed only the single message type GETTIME. In this assignment, you will be adding the new message type SETALARM. When a TimeClient sends a SETALARM request to a TimeServer, it specifies an "alarm time" in the format HH:MM:SS (using the 24-hour clock). The TimeServer immediately responds with a simple response indicating that the request was processed successfully. Later, when the TimeServer's own time reaches the requested alarm time, the TimeClient must be notified, resulting in the TimeClient printing out the string "BEEP BEEP BEEP BEEP (yes, this is your wake up call)". The TimeServer must be capable of having multiple alarms set to go off in the future, possibly from different clients.
You will also be improving the usability of the TimeClient by making it interactive. Instead of issuing a single request, getting a response, and then exiting, the TimeClient will sit in a loop, accepting requests until the user exits. Specifically, the TimeClient should perform a GETTIME when the user enters "g", a SETALARM when the user enters "a HH:MM:SS", and should exit when the user enters "q".
Following is an example of the outputs when the server is running on the machine blackbird.dickinson.edu, and the client is run on the machine albatross.dickinson.edu.
First, we start the server on blackbird:
blackbird:/tmp jmac$ java TimeServerP4 56765
Then, we run the client on albatross, and start entering commands:
albatross:/tmp jmac$ java TimeClientP4 blackbird 56765 Enter 'g' to get the time from the timeserver, or 'a HH:MM:SS' to set an alarm > g TimeServer says time is 17:33:04 > g TimeServer says time is 17:33:08 > a 17:33:45 Received successful response from the TimeServer. Alarm has been set for 17:33:45 > g TimeServer says time is 17:33:28 > g TimeServer says time is 17:33:34 > BEEP BEEP BEEP BEEP (yes, this is your wake up call) g TimeServer says time is 17:33:49 > q bye albatross:/tmp jmac$
Your solution should contain exactly 2 files, called TimeServerP4.java and TimeClientP4.java. If you define any other classes, add them to one of these files as we did with the MyHttpRequest class in assignment P2. Submit your code to Web-CAT by first making a zip file of these two Java files. (Do not submit AlarmServer.java and AlarmClient.java; remember, you are not permitted to edit these files.)
Your first step should be to copy your code from assignment P3 into new files called TimeServerP4.java and TimeClientP4.java. Search and replace "P3" with "P4" to reflect the new class names. If you were unable to complete assignment P3, or are unhappy with using your own solution, you may request a solution from the instructor.
Your next step should be to carefully plan how you will use the AlarmServer and AlarmClient classes. Specifically: will TimeServerP4 use AlarmServer objects, AlarmClient objects, or both? Under what circumstances will these objects be created? Now answer the same questions for TimeClientP4.
Next, work through the "Example outputs" above, writing out the exact messages that must be sent to and from all of your TimeServerP4, TimeClientP4, AlarmServer, and AlarmClient objects in order for the example to work correctly.
Finally, you are ready to start writing code. Here are a couple of snippets that should help. Firstly, some example code for reading the user's input in a loop:
BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); boolean quit = false; while (!quit) { System.out.print("> "); System.out.flush(); String input = in.readLine(); if (input.startsWith("g")) { ... } else if (input.startsWith("a")) { ... } else if (input.startsWith("q")) { quit = true; System.out.println("bye"); } }Second, a method for computing the number of milliseconds between the current time, and another time specified as a string:
/** * Return the offset between the timeVal parameter given * as a string in 24-hour format HH:MM:SS, and the * current system time, computed in milliseconds. If * timeVal is earlier than the current system time, we * assume it refers to the next day, so the value * returned is nonnegative. * * @param timeVal * in 24-hour format HH:MM:SS * @return milliseconds between current system time and * timeVal */ public long computeTimeOffset(String timeVal) { StringTokenizer tokens = new StringTokenizer( timeVal, ":"); int hours = Integer.parseInt(tokens.nextToken()); int minutes = Integer.parseInt(tokens.nextToken()); int seconds = Integer.parseInt(tokens.nextToken()); Calendar now = Calendar.getInstance(); long hourDiff = ((long) (hours - now .get(Calendar.HOUR_OF_DAY))) * 3600 * 1000; long minuteDiff = ((long) (minutes - now .get(Calendar.MINUTE))) * 60 * 1000; long secondDiff = ((long) (seconds - now .get(Calendar.SECOND))) * 1000; long totalDiff = hourDiff + minuteDiff + secondDiff; // add a day's worth of milliseconds if the offset // is negative if (totalDiff < 0) { totalDiff += 24 * 3600 * 1000; } return totalDiff; }
The instructor's implementation, available as instructorTIME.zip, is provided as Java byte code only, so you will not be able to tackle this problem by inspecting the code. Instead, use Wireshark to determine the exact format of the messages used in the instructor's TIME protocol, then alter your own code to conform to this format.