Skip to content

Commit

Permalink
Simplify code following DeferredResult change for RC1
Browse files Browse the repository at this point in the history
  • Loading branch information
rstoyanchev committed Oct 25, 2012
1 parent db57ba4 commit 2dbd457
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 190 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,70 +7,56 @@

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

@Controller
@RequestMapping("/mvc/chat/{topic}/{user}")
@RequestMapping("/mvc/chat")
public class ChatController {

private final Map<String, ChatParticipant> chatParticipants = new ConcurrentHashMap<String, ChatParticipant>();

private final ChatRepository chatRepository;

private final Map<DeferredResult<List<String>>, Integer> chatRequests =
new ConcurrentHashMap<DeferredResult<List<String>>, Integer>();


@Autowired
public ChatController(ChatRepository chatRepository) {
this.chatRepository = chatRepository;
}

/**
* Return chat messages immediately or hold the response till new chat messages
* become available.
*/
@RequestMapping(method=RequestMethod.GET, produces="application/json")
@RequestMapping(method=RequestMethod.GET)
@ResponseBody
public Object getMessages(@PathVariable String topic, @PathVariable String user, @RequestParam int messageIndex) {
ChatParticipant participant = getChatParticipant(topic, user);
DeferredResult<List<String>> deferredResult = new DeferredResult<List<String>>(null, Collections.<String>emptyList());
List<String> messages = participant.getMessages(deferredResult, messageIndex);
return messages.isEmpty() ? deferredResult : messages;
}
public DeferredResult<List<String>> getMessages(@RequestParam int messageIndex) {

DeferredResult<List<String>> result = new DeferredResult<List<String>>(null, Collections.emptyList());
this.chatRequests.put(result, messageIndex);

private ChatParticipant getChatParticipant(String topic, String user) {
String key = topic + ":" + user;
ChatParticipant participant = this.chatParticipants.get(key);
if (participant == null) {
participant = new ChatParticipant(topic, this.chatRepository);
this.chatParticipants.put(key, participant);
List<String> messages = this.chatRepository.getMessages(messageIndex);
if (!messages.isEmpty()) {
this.chatRequests.remove(result);
result.setResult(messages);
}
return participant;

return result;
}

/**
* Post a message to participants in the chat.
*/
@RequestMapping(method=RequestMethod.POST)
@ResponseBody
public void postMessage(@PathVariable String topic, @PathVariable String user, @RequestParam String message) {
String chatMessage = "[" + user + "] " + message;
this.chatRepository.addMessage(topic, chatMessage);
for (ChatParticipant participant : this.chatParticipants.values()) {
participant.handleMessage(topic, chatMessage);
}
public void postMessage(@RequestParam String message) {
this.chatRepository.addMessage(message);
updateChatRequests();
}

/**
* End participation in a chat.
*/
@RequestMapping(method=RequestMethod.DELETE)
@ResponseBody
public void removeParticipant(@PathVariable String topic, @PathVariable String user) {
ChatParticipant participant = this.chatParticipants.remove(topic + ":" + user);
participant.exitChat();
private void updateChatRequests() {
for (DeferredResult<List<String>> result : this.chatRequests.keySet()) {
Integer index = this.chatRequests.remove(result);
List<String> messages = this.chatRepository.getMessages(index);
result.setResult(messages);
}
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@

import java.util.List;

/**
* A repository for persisting chat messages.
*/
public interface ChatRepository {

List<String> getMessages(String topic, int messageIndex);
List<String> getMessages(int messageIndex);

void addMessage(String topic, String message);
void addMessage(String message);

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,26 @@

import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

/**
* Stores chat messages in-memory.
*/
@Repository
public class InMemoryChatRepository implements ChatRepository {

private final ConcurrentHashMap<String, List<String>> messages = new ConcurrentHashMap<String, List<String>>();
private final List<String> messages = new CopyOnWriteArrayList<String>();

public List<String> getMessages(String topic, int messageIndex) {
List<String> chatMessages = this.messages.get(topic);
if (chatMessages == null) {
public List<String> getMessages(int index) {
if (this.messages.isEmpty()) {
return Collections.<String> emptyList();
}
else {
Assert.isTrue((messageIndex >= 0) && (messageIndex <= chatMessages.size()), "Invalid messageIndex");
return chatMessages.subList(messageIndex, chatMessages.size());
}
Assert.isTrue((index >= 0) && (index <= this.messages.size()), "Invalid message index");
return this.messages.subList(index, this.messages.size());
}

public void addMessage(String topic, String message) {
initChat(topic);
this.messages.get(topic).add(message);
}

private void initChat(String topic) {
if (!this.messages.containsKey(topic)) {
this.messages.putIfAbsent(topic, new CopyOnWriteArrayList<String>());
}
public void addMessage(String message) {
this.messages.add(message);
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package org.springframework.samples.async.config;

import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
Expand All @@ -24,6 +28,11 @@ public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(30*1000L);
}

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJacksonHttpMessageConverter());
}

public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("chat");
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/webapp/WEB-INF/templates/chat.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<body>
<h1>Chat</h1>

<form id="joinChatForm" th:action="@{/mvc/chat/general}" data-bind="visible: activePollingXhr() == null">
<form id="joinChatForm" th:action="@{/mvc/chat}" data-bind="visible: activePollingXhr() == null">
<p>
<label for="user">User: </label>
<input id="user" name="user" type="text" data-bind="value: userName"/>
Expand All @@ -16,7 +16,7 @@ <h1>Chat</h1>
</p>
</form>

<form id="leaveChatForm" th:action="@{/mvc/chat/general}" data-bind="visible: activePollingXhr() != null">
<form id="leaveChatForm" th:action="@{/mvc/chat}" data-bind="visible: activePollingXhr() != null">
<p>
You're chatting as <strong data-bind="text: userName"></strong>
<button id="leave" type="submit" data-bind="click: leaveChat">Leave Chat</button>
Expand All @@ -27,7 +27,7 @@ <h1>Chat</h1>
<textarea rows="15" cols="60" readonly="readonly" data-bind="text: chatContent"></textarea>
</div>

<form id="postMessageForm" th:action="@{/mvc/chat/general}" data-bind="visible: activePollingXhr() != null">
<form id="postMessageForm" th:action="@{/mvc/chat}" data-bind="visible: activePollingXhr() != null">
<p>
<input id="message" name="message" type="text" data-bind="value: message" />
<button id="post" type="submit" data-bind="click: postMessage">Post</button>
Expand Down
15 changes: 3 additions & 12 deletions src/main/webapp/resources/js/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ $(document).ready(function() {
return;
}
var form = $("#joinChatForm");
that.activePollingXhr($.ajax({url : getChatUrl(form), type : "GET", data : form.serialize(),
that.activePollingXhr($.ajax({url : form.attr("action"), type : "GET", data : form.serialize(),
success : function(messages) {
for ( var i = 0; i < messages.length; i++) {
that.chatContent(that.chatContent() + messages[i] + "\n");
Expand All @@ -42,14 +42,11 @@ $(document).ready(function() {
$('#message').focus();
}

function getChatUrl(form) {
return form.attr("action") + "/" + that.userName();
}

that.postMessage = function() {
if (that.message().trim() != '') {
var form = $("#postMessageForm");
$.ajax({url : getChatUrl(form), type : "POST", data : form.serialize(),
$.ajax({url : form.attr("action"), type : "POST",
data : "message=[" + that.userName() + "] " + $("#postMessageForm input[name=message]").val(),
error : function(xhr) {
console.error("Error posting chat message: status=" + xhr.status + ", statusText=" + xhr.statusText);
}
Expand All @@ -61,12 +58,6 @@ $(document).ready(function() {
that.leaveChat = function() {
that.activePollingXhr(null);
resetUI();
var form = $("#leaveChatForm");
$.ajax({url : getChatUrl(form), type : 'DELETE',
error : function(xhr) {
console.error("Error while leaving chat: status=" + xhr.status + ", statusText=" + xhr.statusText);
}
});
this.userName('');
}

Expand Down
Loading

0 comments on commit 2dbd457

Please sign in to comment.