Author: kkolinko Date: Sat Apr 17 01:59:56 2010 New Revision: 935105 URL: http://svn.apache.org/viewvc?rev=935105&view=rev Log: Improve the ChatServlet comet example. 1. Fix possible deadlock in ChatServlet$MessageSender, similar to BZ 48843. 2. Properly wake up ChatServlet$MessageSender when the servlet is destroyed. 3. Filter special characters when printing the message in ChatServlet. 4. Provide an explicit charset everywhere. 5. Fix frames layout. Fix redirections. Use target="<name>" attribute in HTML to send request to a particular frame. 6. Fix DTDs. Use frameset DTD for the page containing frames. 7. Add "xxx joined the chat" message at startup. 8. Rename chat.jsp -> index.jsp, so that the entry point to this example is more visible. 9. Corrected the link that opens a new chat window. It referenced an undefined JavaScript function. Now it is implemented just by using target="_blank". 10. Added submit button to the form pages. 11. Minor message tweaks.
Added: tomcat/trunk/webapps/examples/jsp/chat/index.jsp - copied, changed from r934640, tomcat/trunk/webapps/examples/jsp/chat/chat.jsp Removed: tomcat/trunk/webapps/examples/jsp/chat/chat.jsp Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/chat/ChatServlet.java tomcat/trunk/webapps/examples/jsp/chat/login.jsp tomcat/trunk/webapps/examples/jsp/chat/post.jsp Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/chat/ChatServlet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/chat/ChatServlet.java?rev=935105&r1=935104&r2=935105&view=diff ============================================================================== --- tomcat/trunk/webapps/examples/WEB-INF/classes/chat/ChatServlet.java (original) +++ tomcat/trunk/webapps/examples/WEB-INF/classes/chat/ChatServlet.java Sat Apr 17 01:59:56 2010 @@ -41,6 +41,8 @@ public class ChatServlet private static final long serialVersionUID = 1L; + private static final String CHARSET = "UTF-8"; + protected ArrayList<HttpServletResponse> connections = new ArrayList<HttpServletResponse>(); protected MessageSender messageSender = null; @@ -82,7 +84,7 @@ public class ChatServlet if ("login".equals(action)) { String nickname = request.getParameter("nickname"); request.getSession(true).setAttribute("nickname", nickname); - response.sendRedirect("post.jsp"); + response.sendRedirect("index.jsp"); event.close(); return; } @@ -114,15 +116,20 @@ public class ChatServlet HttpServletRequest request, HttpServletResponse response) throws IOException { log("Begin for session: " + request.getSession(true).getId()); - + + response.setContentType("text/html; charset=" + CHARSET); + PrintWriter writer = response.getWriter(); - writer.println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">"); + writer.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">"); writer.println("<html><head><title>JSP Chat</title></head><body bgcolor=\"#FFFFFF\">"); + writer.println("<div>Welcome to the chat. <a href='chat'>Click here to reload this window</a></div>"); writer.flush(); synchronized(connections) { connections.add(response); } + + messageSender.send("Tomcat", request.getSession(true).getAttribute("nickname") + " joined the chat."); } protected void end(CometEvent event, HttpServletRequest request, HttpServletResponse response) @@ -136,7 +143,6 @@ public class ChatServlet writer.println("</body></html>"); event.close(); - } protected void error(CometEvent event, HttpServletRequest request, HttpServletResponse response) @@ -170,10 +176,12 @@ public class ChatServlet protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Compatibility method: equivalent method using the regular connection model + response.setContentType("text/html; charset=" + CHARSET); PrintWriter writer = response.getWriter(); - writer.println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">"); + writer.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">"); writer.println("<html><head><title>JSP Chat</title></head><body bgcolor=\"#FFFFFF\">"); - writer.println("Chat example only supports Comet processing"); + writer.println("Chat example only supports Comet processing. "); + writer.println("Configure a connector that supports Comet and try again."); writer.println("</body></html>"); } @@ -192,6 +200,9 @@ public class ChatServlet public void stop() { running = false; + synchronized (messages) { + messages.notify(); + } } public void send(String user, String message) { @@ -209,34 +220,29 @@ public class ChatServlet // Loop until we receive a shutdown command while (running) { - // Loop if endpoint is paused - - if (messages.size() == 0) { + String[] pendingMessages; + synchronized (messages) { try { - synchronized (messages) { + if (messages.size() == 0) { messages.wait(); } } catch (InterruptedException e) { // Ignore } + pendingMessages = messages.toArray(new String[0]); + messages.clear(); } synchronized (connections) { - String[] pendingMessages = null; - synchronized (messages) { - pendingMessages = messages.toArray(new String[0]); - messages.clear(); - } for (int i = 0; i < connections.size(); i++) { try { PrintWriter writer = connections.get(i).getWriter(); for (int j = 0; j < pendingMessages.length; j++) { - // FIXME: Add HTML filtering - writer.println(pendingMessages[j] + "<br/>"); + writer.println("<div>"+filter(pendingMessages[j]) + "</div>"); } writer.flush(); } catch (IOException e) { - log("IOExeption sending message", e); + log("IOException sending message", e); } } } @@ -247,7 +253,38 @@ public class ChatServlet } - - - + /** + * Filter the specified message string for characters that are sensitive + * in HTML. + * + * @param message The message string to be filtered + * @author Copied from org.apache.catalina.util.RequestUtil#filter(String) + */ + protected static String filter(String message) { + if (message == null) + return (null); + + char content[] = new char[message.length()]; + message.getChars(0, message.length(), content, 0); + StringBuilder result = new StringBuilder(content.length + 50); + for (int i = 0; i < content.length; i++) { + switch (content[i]) { + case '<': + result.append("<"); + break; + case '>': + result.append(">"); + break; + case '&': + result.append("&"); + break; + case '"': + result.append("""); + break; + default: + result.append(content[i]); + } + } + return (result.toString()); + } } Copied: tomcat/trunk/webapps/examples/jsp/chat/index.jsp (from r934640, tomcat/trunk/webapps/examples/jsp/chat/chat.jsp) URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/jsp/chat/index.jsp?p2=tomcat/trunk/webapps/examples/jsp/chat/index.jsp&p1=tomcat/trunk/webapps/examples/jsp/chat/chat.jsp&r1=934640&r2=935105&rev=935105&view=diff ============================================================================== --- tomcat/trunk/webapps/examples/jsp/chat/chat.jsp (original) +++ tomcat/trunk/webapps/examples/jsp/chat/index.jsp Sat Apr 17 01:59:56 2010 @@ -1,4 +1,10 @@ -<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<%...@page contentType="text/html; charset=UTF-8" %> +<% if (session.getAttribute("nickname") == null) { + response.sendRedirect("login.jsp"); + return; +} +%> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"> <html> <!-- Licensed to the Apache Software Foundation (ASF) under one or more @@ -19,14 +25,8 @@ <head> <title>JSP Chat</title> </head> - -<body bgcolor="#FFFFFF"> - -<!-- Body --> -<frameset> +<frameset rows="1*,4*"> <frame name="post" src="post.jsp" scrolling="no" title="Post message"> <frame name="chat" src="chat" scrolling="yes" title="Chat"> </frameset> - -</body> </html> Modified: tomcat/trunk/webapps/examples/jsp/chat/login.jsp URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/jsp/chat/login.jsp?rev=935105&r1=935104&r2=935105&view=diff ============================================================================== --- tomcat/trunk/webapps/examples/jsp/chat/login.jsp (original) +++ tomcat/trunk/webapps/examples/jsp/chat/login.jsp Sat Apr 17 01:59:56 2010 @@ -1,4 +1,5 @@ -<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<%...@page contentType="text/html; charset=UTF-8" %> <html> <!-- Licensed to the Apache Software Foundation (ASF) under one or more @@ -22,9 +23,10 @@ <body bgcolor="#FFFFFF"> -<form method="POST" action='chat' name="loginForm"> -<input type="hidden" name="action" value="login"/> -Nickname: <input type="text" name="nickname"/> +<form method="POST" action='chat' target="_top" name="loginForm"> +<input type="hidden" name="action" value="login"> +Nickname: <input type="text" name="nickname"> +<input type="submit"> </form> </body> Modified: tomcat/trunk/webapps/examples/jsp/chat/post.jsp URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/jsp/chat/post.jsp?rev=935105&r1=935104&r2=935105&view=diff ============================================================================== --- tomcat/trunk/webapps/examples/jsp/chat/post.jsp (original) +++ tomcat/trunk/webapps/examples/jsp/chat/post.jsp Sat Apr 17 01:59:56 2010 @@ -1,4 +1,5 @@ -<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<%...@page contentType="text/html; charset=UTF-8" %> <html> <!-- Licensed to the Apache Software Foundation (ASF) under one or more @@ -23,14 +24,32 @@ <body bgcolor="#FFFFFF"> <form method="POST" action='chat' name="postForm"> -<input type="hidden" name="action" value="post"/> -Message: <input type="text" name="message"/> +<input type="hidden" name="action" value="post"> +Message: <input type="text" name="message"> +<input type="submit"> </form> <br> -<br> - -<a href="javascript:openWindow('http://127.0.0.1:8080/examples/jsp/chat/chat', 640, 480 ,0 ,0 ,0 ,0 ,0 ,1 ,10 ,10 )">Click to open chat window</a> - +<% + String serverName = request.getServerName(); + if ("localhost".equals(serverName)) { + serverName = "127.0.0.1"; + } else if ("127.0.0.1".equals(serverName)) { + serverName = "localhost"; + } + + String chatUrl = request.getScheme() + "://" + serverName + ":" + + request.getServerPort() + request.getContextPath() + + request.getServletPath(); + + // strip "post.jsp" from the address + chatUrl = chatUrl.substring(0, chatUrl.lastIndexOf("/") + 1); +%> +<a target="_blank" href="<%=chatUrl %>">Click to open a new chat window</a> +<em>Note</em>: To avoid hitting the limit on the count of simultaneous +connections to the same host, imposed by the +<a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4">HTTP specification</a>, +the second chat window should be opened using a different URL, e.g. with +an IP address instead of the host name. </body> </html> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org