Захотелось написать своеобразный "анонимный чат".
Имеется сервлет:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
public class ChatServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AsyncContext asyncContext = request.startAsync(request, response);
ServletContext servletContext = request.getServletContext();
String message = request.getParameter("message");
String username = request.getParameter("username");
Queue<Message> messageQueue = (Queue<Message>) servletContext.getAttribute("messages");
messageQueue.add(new Message(message, username));
asyncContext.complete();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AsyncContext asyncContext = request.startAsync(request, response);
asyncContext.setTimeout(1000*60*5L);
ServletContext servletContext = request.getServletContext();
((Queue<AsyncContext>)servletContext.getAttribute("chatUsers")).add(asyncContext);
}
}
WebListener:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
@WebListener
public class ChatService implements ServletContextListener {
@Override
public void contextInitialized(final ServletContextEvent servletContextEvent) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
final Queue<AsyncContext> chatUsers = new ConcurrentLinkedQueue<AsyncContext>();
servletContextEvent.getServletContext().setAttribute("chatUsers", chatUsers);
Queue<Message> messages = new ConcurrentLinkedQueue<Message>();
servletContextEvent.getServletContext().setAttribute("messages", messages);
Executor messageExecutor = Executors.newCachedThreadPool();
final Executor chatExecutor = Executors.newCachedThreadPool();
while (true) {
if (!messages.isEmpty()) {
final Message message = messages.poll();
messageExecutor.execute(new Runnable() {
@Override
public void run() {
while(!chatUsers.isEmpty()) {
final AsyncContext asyncContext = chatUsers.poll();
chatExecutor.execute(new Runnable() {
@Override
public void run() {
try {
ServletResponse response = asyncContext.getResponse();
response.setContentType("text/xml");
response.getWriter().write(messageAsXml(message));
asyncContext.complete();
} catch (IOException e) {
e.printStackTrace();
}
}
private String messageAsXml(final Message message) {
StringBuffer sb = new StringBuffer();
sb.append("<message>")
.append("<username>")
.append(message.username)
.append("</username>")
.append("<text>")
.append(message.message)
.append("</text>")
.append("</message>");
return sb.toString();
}
});
}
}
});
}
}
}
});
t.start();
}
и на клиенте:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
<script>
$(document).ready(function(){
function getData() {
$.ajax({
url: "chat",
type: "GET",
dataType: "xml",
context: document.body,
success: function(data){
var username = $(data).find('username').text();
var text = $(data).find('text').text();
var history = $('#chat_msgs').text();
$('#chat_msgs').html(history + username + ": " + text + "\n");
getData();
}
});
}
$("#sendMsg").click(function(event){
$.post("chat", $("#msgForm").serialize());
$('#message').val('');
});
getData();
});
</script>
Сейчас, все, кто подключаются попадают, в одно соединение и переписка идет в одном текстовом пространстве.
Как реализовать пулл подобных соединений? Может быть есть более правильное решение?