import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import com.oreilly.servlet.ServletUtils; public class ChatPage extends HttpServlet implements Runnable { static final int MESSAGE_ARCHIVE_SIZE = 10; // save the last 10 messages ChatServlet chat = null; // the servlet to reuse String[] messages = new String[MESSAGE_ARCHIVE_SIZE]; // circular array int messageIndex = 0; // index into the messages array Thread update = null; // thread to update new messages // Gets new messages from the chat servlet and inserts them in // the messages circular array. public void run() { while (true) { String message = chat.getNextMessage(); synchronized (this) { messages[messageIndex] = message; messageIndex = (messageIndex + 1) % MESSAGE_ARCHIVE_SIZE; } } } // Prints the message archive (the 10 latest messages) and a text // field where the reader can input a new message. public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); // Turn off caching, so the latest messages are always displayed. // (Works around a Netscape problem.) res.setHeader("Pragma", "no-cache"); // For our first request, "chat" is null and needs to use // ServletUtils.getServlet() to get the ChatServlet instance. // Then we need to start another thread to listen for chat's // new messages. if (chat == null) { chat = (ChatServlet)ServletUtils.getServlet( "ChatServlet", req, getServletContext()); if (chat != null) { update = new Thread(this); update.start(); } } // Print a pretty header. out.println(""); out.println("ChatPage"); out.println("

Welcome to ChatPage!

"); // Print the message archive, oldest first. // Synchronized so it doesn't change while we're printing it. synchronized (this) { out.println("Recent messages:

"); int i = messageIndex; do { String message = messages[i]; if (message != null) out.println(message + "

"); i = (i + 1) % MESSAGE_ARCHIVE_SIZE; } while (i != messageIndex); } // Print a button that gets new messages. out.println("

"); out.println(""); out.println("
"); // Print a form where the reader can submit a new message. out.println("
"); out.println("
"); out.println("Submit a message:"); out.println(""); out.println("
"); // Print a pretty footer. out.println("
"); out.println("
"); out.println("Special thanks to ChatServlet for acting as our back-end"); out.println("
"); out.println(""); } // Accepts messages for broadcast. public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // If our first request happens to be a POST, we need to set "chat" // and start our update thread just like we do for a GET request. if (chat == null) { chat = (ChatServlet)ServletUtils.getServlet( "ChatServlet", req, getServletContext()); if (chat != null) { update = new Thread(this); update.start(); Thread.currentThread().yield(); // let the run() method start } } // Get the client's username. It's non-null only if ChatPage is // protected by client authentication. String user = req.getRemoteUser(); if (user == null) user = "anonymous"; // Get and broadcast the message. String message = req.getParameter("message"); if (message != null && chat != null) { chat.broadcastMessage(user + ": " + message); Thread.currentThread().yield(); // let the message be broadcast } // Have doGet() print the updated message archive and the form. doGet(req, res); } // Stops the background thread. public void destroy() { if (update != null) update.stop(); } public String getServletInfo() { return "An HTML chat server front end, reusing ChatServlet"; } }