![]() |
![]() |
Web chat with
Let's start by developing a simple servlet:
Test it:burrowww.cs.indiana.edu% cd $myServlets burrowww.cs.indiana.edu% emacs ChatServlet.java burrowww.cs.indiana.edu% cat ChatServlet.java import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ChatServlet extends HttpServlet { public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); out.println("Yes, I am here (GET)."); } public void doPost (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { } } burrowww.cs.indiana.edu% javac ChatServlet.java burrowww.cs.indiana.edu%
Now let's develop an applet:http://burrowww.cs.indiana.edu:32xxx/examples/servlet/ChatServlet
Compile and test the applet:burrowww.cs.indiana.edu% cd $TOMCAT_HOME/webapps/ROOT burrowww.cs.indiana.edu% mkdir chat burrowww.cs.indiana.edu% cd chat burrowww.cs.indiana.edu% emacs Larry.html burrowww.cs.indiana.edu% cat Larry.html <html> <applet code=ChatApplet width=400 height=400> <param name=user value="Larry"> </applet> </html> burrowww.cs.indiana.edu% emacs ChatApplet.java burrowww.cs.indiana.edu% cat ChatApplet.java import java.applet.*; import java.awt.*; import java.net.*; public class ChatApplet extends Applet { TextArea text; Label label; TextField input; 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("Type here: "); input = new TextField(); input.setEditable(true); setLayout(new BorderLayout()); add("Center", text); Panel panel = new Panel(); panel.setLayout(new BorderLayout()); panel.add("West", label); panel.add("Center", input); add("South", panel); text.appendText("URL: " + codebase + "\n"); } public void start() { text.appendText("Your name is: " + user + "\n"); } } burrowww.cs.indiana.edu%
Create two more files:http://burrowww.cs.indiana.edu:32xxx/chat/Larry.html
Test them:burrowww.cs.indiana.edu% pwd /nfs/paca/home/user1/dgerman/apache/jakarta-tomcat/webapps/ROOT/chat burrowww.cs.indiana.edu% ls -l Larry.html -rw-r--r-- 1 dgerman students 112 Nov 1 19:59 Larry.html burrowww.cs.indiana.edu% cp Larry.html Michael.html burrowww.cs.indiana.edu% cp Larry.html Tony.html burrowww.cs.indiana.edu% emacs Michael.html burrowww.cs.indiana.edu% cat Michael.html <html> <applet code=ChatApplet width=400 height=400> <param name=user value="Michael"> </applet> </html> burrowww.cs.indiana.edu% emacs Tony.html burrowww.cs.indiana.edu% ls -l *.html -rw-r--r-- 1 dgerman students 112 Nov 1 19:59 Larry.html -rw-r--r-- 1 dgerman students 114 Nov 1 20:09 Michael.html -rw-r--r-- 1 dgerman students 111 Nov 1 20:10 Tony.html burrowww.cs.indiana.edu% cat Tony.html <html> <applet code=ChatApplet width=400 height=400> <param name=user value="Tony"> </applet> </html> burrowww.cs.indiana.edu% ls -l *.html -rw-r--r-- 1 dgerman students 112 Nov 1 19:59 Larry.html -rw-r--r-- 1 dgerman students 114 Nov 1 20:09 Michael.html -rw-r--r-- 1 dgerman students 111 Nov 1 20:10 Tony.html burrowww.cs.indiana.edu% pwd /nfs/paca/home/user1/dgerman/apache/jakarta-tomcat/webapps/ROOT/chat burrowww.cs.indiana.edu%
Now let's enhance a bit the applet:http://burrowww.cs.indiana.edu:32xxx/chat/Michael.html http://burrowww.cs.indiana.edu:32xxx/chat/Tony.html
We test again.import java.applet.*; import java.awt.*; import java.net.*; public class ChatApplet extends Applet { TextArea text; Label label; TextField input; 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("Type here: "); input = new TextField(); input.setEditable(true); setLayout(new BorderLayout()); add("Center", text); Panel panel = new Panel(); panel.setLayout(new BorderLayout()); panel.add("West", label); panel.add("Center", input); add("South", panel); text.appendText("URL: " + codebase + "\n"); } public void start() { text.appendText("Your name is: " + user + "\n"); } public boolean handleEvent(Event event) { switch (event.id) { case Event.ACTION_EVENT: if (event.target == input) { text.appendText(user + ": " + input.getText() + "\n"); input.setText(""); return true; } } return false; } }
At this point the applet takes input from the user and writes it back immediately.
Let's enhance the applet a bit more.
Let's make it contact the server each time the user types something.
Test this again.import java.applet.*; import java.awt.*; import java.net.*; import java.io.*; public class ChatApplet extends Applet { TextArea text; Label label; TextField input; 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("Type here: "); input = new TextField(); input.setEditable(true); setLayout(new BorderLayout()); add("Center", text); Panel panel = new Panel(); panel.setLayout(new BorderLayout()); panel.add("West", label); panel.add("Center", input); add("South", panel); text.appendText("URL: " + codebase + "\n"); } public void start() { text.appendText("Your name is: " + user + "\n"); } public boolean handleEvent(Event event) { switch (event.id) { case Event.ACTION_EVENT: if (event.target == input) { text.appendText(user + ": " + input.getText() + "\n"); input.setText(""); text.appendText("Server: " + contactServer()); return true; } } return false; } String contactServer() { try { URL servlet = new URL("http://burrowww.cs.indiana.edu:21xxx/examples/servlet/ChatServlet"); URL url = new URL(servlet.toExternalForm()); URLConnection con = url.openConnection(); con.setUseCaches(false); InputStream in = con.getInputStream(); DataInputStream data = new DataInputStream(new BufferedInputStream(in)); return data.readLine(); } catch (Exception e) { return ("Error: " + e.toString()); } } }
We could try to bounce the message off the server but it's better to abstract a bit.
Let's add some potential functionality with a new class:
As you can see this class is abstracting an HTTP message.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(); } }
It expects a servlet and it has four main methods:
sendGetMessage
(two methods, name is overloaded)
sendPostMessage
(two methods, also overloaded)
Modulo the on-line API docs and our current knowledge of HTTP this class definition is clear.
So we place this in the same directory as the applet.
How are we going to use it?
It will be used by the applet to send messages to the server.
Notice that the applet's contactServer
is
similar to part of sendGetMessage
above.
So we need to make a few changes to the applet.
Now we need to make a significant leap.import java.applet.*; import java.awt.*; import java.net.*; import java.io.*; public class ChatApplet extends Applet { TextArea text; Label label; TextField input; 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("Type here: "); input = new TextField(); input.setEditable(true); setLayout(new BorderLayout()); add("Center", text); Panel panel = new Panel(); panel.setLayout(new BorderLayout()); panel.add("West", label); panel.add("Center", input); add("South", panel); text.appendText("URL: " + codebase + "\n"); } public void start() { text.appendText("Your name is: " + user + "\n"); } public boolean handleEvent(Event event) { switch (event.id) { case Event.ACTION_EVENT: if (event.target == input) { text.appendText(user + ": " + input.getText() + "\n"); input.setText(""); text.appendText("Server: " + contactServer()); return true; } } return false; } String contactServer() { String nextMessage = null; try { URL servlet = new URL("http://burrowww.cs.indiana.edu:21xxx/examples/servlet/ChatServlet"); HttpMessage msg = new HttpMessage(servlet); InputStream in = msg.sendGetMessage(); DataInputStream data = new DataInputStream(new BufferedInputStream(in)); nextMessage = data.readLine(); } catch (Exception e) { return ("Error: " + e.toString()); } return nextMessage + "\n"; } }
Here's what the server becomes:
This servlet is much more general.import java.io.*; import java.net.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class ChatServlet 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; } }
It accepts incoming POST calls that contain messages (producers).
It also accepts incoming GET messages that act as consumers.
If there's at least one producer and no consumers the producer waits until a consumer comes by.
When we get consumers and no producers the consumers wait until at least one producer shows up.
Here's the basic idea:
Let's make the applet send itself a message through the servlet.
First it sends a GET to the servlet to register.
A sink is created for the login.
Then the applet broadcasts something, this goes into the source, and the sink is immediately notified.
The message then returns to the applet.
Here's the applet:
Understanding how the applet works is really crucial.import java.applet.*; import java.awt.*; import java.net.*; import java.io.*; import java.util.*; public class ChatApplet 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("Type here: "); input = new TextField(); input.setEditable(true); setLayout(new BorderLayout()); add("Center", text); Panel panel = new Panel(); panel.setLayout(new BorderLayout()); panel.add("West", label); panel.add("Center", input); add("South", panel); text.appendText("URL: " + codebase + "\n"); } public void start() { thread = new Thread(this); thread.start(); } public void run() { while (true) { text.appendText(contactServer()); } } public boolean handleEvent(Event event) { switch (event.id) { case Event.ACTION_EVENT: if (event.target == input) { broadcastMessage(input.getText() + "\n"); input.setText(""); return true; } } return false; } void broadcastMessage(String message) { message = user + ": " + message; try { URL url = new URL("http://burrowww.cs.indiana.edu:21xxx/examples/servlet/ChatServlet"); HttpMessage msg = new HttpMessage(url); Properties props = new Properties(); props.put("message", message); msg.sendPostMessage(props); } catch (Exception ignored) { } } String contactServer() { String nextMessage = null; try { URL servlet = new URL("http://burrowww.cs.indiana.edu:21xxx/examples/servlet/ChatServlet"); HttpMessage msg = new HttpMessage(servlet); 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"; } }
Because there's nothing else to be done.
We're now finished with this stage, and with all stages.
Let's test it.
Open three windows and connect
Then chat.
Customizing your servlet entry point.
Here's a simple way of avoiding .html
point-of-entry files:
import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Chat extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html"); resp.getWriter().println( "<html><head><title>WebChat</title></head><body bgcolor=white>" + "<form method=POST action=/examples/servlet/Chat>Type your name here: " + "<input type=text name=namefield size=10> <p> then push <input " + " type=submit value=Proceed> (or hit Enter) </form></body></html>" ); } public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html"); resp.getWriter().println( "<html><body bgcolor=white><h1>Hello, <font color=blue>" + req.getParameter("namefield") + "</font>!</h1>" + " <applet code=ChatApplet " + "codebase=\"http://burrowww.cs.indiana.edu:32xxx/chat\"\n" + " width=400 height=400> \n" + " <param name=user value=\"" + req.getParameter("namefield") + "\"> \n" + " </applet>" + " </body></html>" ); } }