Lab Notes Thirteen: Web Chat, the Crux of It

The purpose of these notes is to get to the bottom of what's needed for Homework Six.

Step One: An Auxiliary Class

       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(); 
         } 
       }

Step Two: The Applet Itself

       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:32xxx/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:32xxx/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"; 
           } 

       } 
Make sure you contact your server. That's the purpose of the red blinking.

Step Three: Your Servlet.

       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;
           }
       }
You should have noticed the extra two classes at the bottom.

You know that you're done at this point, and only need to clarify how you distribute the applet. You could create HTML files but one soon realizes that that's not very flexible. Here's a servlet that takes your name, and produces an HTML that contains the name as a parameter to an APPLET tag. That initializes the applet adequately.

Step Four: Custom Entry Point

       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>"

            ); 

         } 
              

       }
So now that we have four things, what do we do with them?

Here are the steps for your installation:

  1. First create a folder $TOMCAT_HOME/webapps/ROOT/chat

  2. Place HttpMessage.java and ChatApplet.java there and compile them.

  3. Go to $myServlets now to install the servlets.

  4. Place ChatServlet.java and Chat.java there.

  5. Update the red blinking things and compile the servlets.

    Watch for (and fix) pico-broken lines in Chat.java (see below).

  6. Go to http://burrowww.cs.indiana.edu:32xxx/examples/servlet/Chat and test it.

Here I am thinking that these notes can't go wrong.

Well, let me follow them exactly to see if they work or not.

Script started on Wed Nov 28 12:34:33 2001
burrowww.cs.indiana.edu% date
Wed Nov 28 12:34:35 EST 2001
burrowww.cs.indiana.edu% pwd
/nfs/paca/home/user1/dgerman
burrowww.cs.indiana.edu% cd $TOMCAT_HOME/webapps/ROOT
burrowww.cs.indiana.edu% ls -ld chat
ls: chat: No such file or directory
burrowww.cs.indiana.edu% mkdir chat
burrowww.cs.indiana.edu% cd chat 
burrowww.cs.indiana.edu% pwd
/nfs/paca/home/user1/dgerman/apache/jakarta-tomcat-3.2.3/webapps/ROOT/chat
burrowww.cs.indiana.edu% pico ChatApplet.java
burrowww.cs.indiana.edu% ls -l
total 7
-rw-r--r--   1 dgerman  faculty      3133 Nov 28 12:36 ChatApplet.java
-rw-r--r--   1 dgerman  faculty      2236 Nov 28 12:39 HttpMessage.java
burrowww.cs.indiana.edu% javac *.java
Note: ChatApplet.java uses or overrides a deprecated API.  Recompile with "-deprecation" for details.
1 warning
burrowww.cs.indiana.edu% cd $myServlets
burrowww.cs.indiana.edu% pico Chat.java
burrowww.cs.indiana.edu% ls -ld Chat*
-rw-r--r--   1 dgerman  faculty      1684 Nov 28 12:40 Chat.java
-rw-r--r--   1 dgerman  faculty      1308 Nov 27 18:46 ChatServlet.class
-rw-r--r--   1 dgerman  faculty      2119 Nov 27 18:46 ChatServlet.java
burrowww.cs.indiana.edu% rm ChatServ*
burrowww.cs.indiana.edu% ls -ld Chat*
-rw-r--r--   1 dgerman  faculty      1684 Nov 28 12:40 Chat.java
burrowww.cs.indiana.edu% pico ChatServlet.java
burrowww.cs.indiana.edu% ls -ld Chat*
-rw-r--r--   1 dgerman  faculty      1684 Nov 28 12:40 Chat.java
-rw-r--r--   1 dgerman  faculty      2244 Nov 28 12:41 ChatServlet.java
burrowww.cs.indiana.edu% javac Chat.java
Chat.java:16: String not terminated at end of line.
                "<html><head><title>WebChat</title></head><body 
                ^
Chat.java:17: ')' expected.
bgcolor=white>"
^
Chat.java:17: String not terminated at end of line.
bgcolor=white>"
              ^
Chat.java:18: String not terminated at end of line.
              + "<form method=POST action=/examples/servlet/Chat>Type your 
                ^
Chat.java:19: String not terminated at end of line.
name here: " 
           ^
Chat.java:20: String not terminated at end of line.
              + "<input type=text name=namefield size=10> <p> then push <input 
                ^
Chat.java:21: String not terminated at end of line.
" 
^
Chat.java:22: String not terminated at end of line.
              + " type=submit value=Proceed> (or hit Enter) 
                ^
Chat.java:23: String not terminated at end of line.
</form></body></html>"
                     ^
Chat.java:52: '}' expected.
         } 
          ^
10 errors
burrowww.cs.indiana.edu% pico Chat.java
burrowww.cs.indiana.edu% javac Chat*.java
Chat.java:48: '}' expected.
         } 
          ^
1 error
burrowww.cs.indiana.edu% pico Chat.java
burrowww.cs.indiana.edu% javac Chat*.java
burrowww.cs.indiana.edu% pwd
/nfs/paca/home/user1/dgerman/apache/jakarta-tomcat-3.2.3/webapps/examples/WEB-INF/classes
burrowww.cs.indiana.edu% exit
burrowww.cs.indiana.edu% 
script done on Wed Nov 28 12:46:48 2001
It almost worked without a flaw. I had a couple of typos and forgot about broken lines.

Pico breaks lines (wraps them around in narrow windows).

But other than that it worked just fine and you can see it working here.


Last updated on November 28, 2001, by Adrian German for A348/A548