|
CSCI A348/A548Lecture Notes 27 Fall 1999 |
This is going to be an involved assignment. At the end you will have seen a lot of essential Java elements in action, and will have solved in the process your homework 8 assignment and a great deal (more than 90%) of your semester group project. For this project teams could merge, creating larger teams, if you think it helps you.
I start by creating all the code in a directory
That's where I will create the following source code files:/u/dgerman/November/apache_1.3.9/htdocs/hw8
tucotuco.cs.indiana.edu% ls -l total 4 -rw-r--r-- 1 dgerman students 708 Nov 30 12:09 ChatServer.java -rw-r--r-- 1 dgerman students 1254 Nov 30 09:07 HttpChatApplet.java -rw-r--r-- 1 dgerman students 645 Nov 30 10:13 HttpMessage.java tucotuco.cs.indiana.edu% pwd /nfs/paca/home/user1/dgerman/November/apache_1.3.9/htdocs/1201 tucotuco.cs.indiana.edu%Well, all right, then. What do the files contain?
HttpChatApplet.java looks like this:
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
public class HttpChatApplet extends Applet implements Runnable {
TextArea text;
Label label;
TextField input;
Thread thread;
String user;
public void init()
{
URL codebase = getCodeBase();
user = getParameter("user");
if (user == null) user = "anonymous";
text = new TextArea();
text.setEditable(false);
label = new Label("Say something: ");
input = new TextField();
input.setEditable(true);
setLayout(new BorderLayout());
Panel panel = new Panel();
panel.setLayout(new BorderLayout());
add("Center", text);
add("South", panel);
panel.add("West", label);
panel.add("Center", input);
}
public void start()
{
thread = new Thread(this);
thread.start();
}
String getNextMessage()
{
String nextMessage = null;
while (nextMessage == null) {
try {
URL url = new URL(getCodeBase(), "/servlet/ChatServer");
HttpMessage msg = new HttpMessage(url);
InputStream in = msg.sendGetMessage();
DataInputStream data = new DataInputStream(
new BufferedInputStream(
in));
nextMessage = data.readLine();
} catch (Exception e) {
try { Thread.sleep(5000); }
catch (InterruptedException ignored) { }
}
}
return nextMessage + "\n";
}
public void run() {
while (true)
text.appendText(getNextMessage());
}
public void stop() {
thread.stop();
thread = null;
}
void broadcastMessage(String message) {
message = user + ": " + message;
try {
URL url = new URL(getCodeBase(), "/servlet/ChatServer");
HttpMessage msg = new HttpMessage(url);
Properties props = new Properties();
props.put("message", message);
msg.sendPostMessage(props);
} catch (Exception ignored) { }
}
public boolean handleEvent(Event event) {
switch (event.id) {
case Event.ACTION_EVENT:
if (event.target == input) {
broadcastMessage(input.getText());
input.setText("");
return true;
}
}
return false;
}
}
Notice how it talks to the server named ChatServer by using an
object of type HttpMessage that is exemplified below. (We also
notice that it makes use of the 1.0 (deprecated) version of the AWT but that
can be fixed easily).
import java.io.*;
import java.net.*;
import java.util.*;
public class HttpMessage {
URL servlet = null;
String args = null;
public HttpMessage(URL servlet)
{
this.servlet = servlet;
}
public InputStream sendGetMessage() throws IOException
{
return sendGetMessage(null);
}
public InputStream sendGetMessage(Properties args) throws IOException
{
String argString = "";
if (args != null) { argString = "?" + toEncodedString(args); }
URL url = new URL(servlet.toExternalForm() + argString);
URLConnection con = url.openConnection();
con.setUseCaches(false);
return con.getInputStream();
}
public InputStream sendPostMessage() throws IOException {
return sendPostMessage(null);
}
public InputStream sendPostMessage(Properties args) throws IOException
{
String argString = "";
if (args != null) {
argString = toEncodedString(args);
}
URLConnection con = servlet.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
con.setRequestProperty(
"Content-Type", "application/x-www-form-urlencoded"
);
DataOutputStream out = new DataOutputStream(con.getOutputStream());
out.writeBytes(argString);
out.flush();
out.close();
return con.getInputStream();
}
private String toEncodedString(Properties args)
{
StringBuffer buf = new StringBuffer();
Enumeration names = args.propertyNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
String value = args.getProperty(name);
buf.append(URLEncoder.encode(name) + "=" + URLEncoder.encode(value));
if (names.hasMoreElements()) buf.append("&");
}
return buf.toString();
}
}
Now that we have these two files we can compile the applet, and two
classes are going to be created, one for the applet the other one for
the helper class (that abstracts HTTP messages).
Now we write the servlet:
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ChatServer extends HttpServlet {
MessageSource source = new MessageSource();
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
res.setContentType("text/plain");
PrintWriter out = res.getWriter();
out.println(getNextMessage());
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
String message = req.getParameter("message");
if (message != null) broadcastMessage(message);
res.setStatus(res.SC_NO_CONTENT);
}
public String getNextMessage()
{
return new MessageSink().getNextMessage(source);
}
public void broadcastMessage(String message)
{
source.sendMessage(message);
}
}
class MessageSource
extends Observable
{
public void sendMessage(String message)
{
setChanged();
notifyObservers(message);
}
}
class MessageSink
implements Observer
{
String message = null;
synchronized public void update(Observable o, Object arg)
{
message = (String)arg;
notify();
}
synchronized public String getNextMessage(MessageSource source)
{
source.addObserver(this);
while (message == null) {
try {
wait();
} catch (Exception ignored) { }
}
source.deleteObserver(this);
String messageCopy = message;
message = null;
return messageCopy;
}
}
This file contains the source code for three classes. If we compile it
we obtain three class files. Once we obtain the bytecode files we move
them to the servlets directories and get ready to run the
application. But how do we distribute the clients?
We need to send the applets to the browsers.
So we create three files which differ in only one place.
First we create Larry.html,
<html>
<applet code=HttpChatApplet
codebase=/1201
width=400 height=400>
<param name=user value="Larry">
</applet>
</html>
then Michael.html,
<html>
<applet code=HttpChatApplet
codebase=/1201
width=400 height=400>
<param name=user value="Michael">
</applet>
</html>
and finally Tony.html:
<html>
<applet code=HttpChatApplet
codebase=/1201
width=400 height=400>
<param name=user value="Tony">
</applet>
</html>
They differ only in the value of one parameter (the user's
name, marked in red). Now you can
connect to either one of them and participate in the conversation under
one of these three names:
What's left?
You need to