# HG changeset patch # User Jaroslav Tulach # Date 1367769853 -7200 # Node ID 40fce839ac01173329061204f4eaf70bc6ed7e61 # Parent 80715a1dd72ec3bc76fad657619228b87ac81ff2 Chat is functional (based on GET) diff -r 80715a1dd72e -r 40fce839ac01 serverside/src/main/java/org/apidesign/bck2brwsr/demo/serverside/ChatClient.java --- a/serverside/src/main/java/org/apidesign/bck2brwsr/demo/serverside/ChatClient.java Sun May 05 17:20:46 2013 +0200 +++ b/serverside/src/main/java/org/apidesign/bck2brwsr/demo/serverside/ChatClient.java Sun May 05 18:04:13 2013 +0200 @@ -36,36 +36,47 @@ */ @Model(className = "ChatModel", properties = { @Property(name = "user", type = String.class), - @Property(name = "text", type = String.class), + @Property(name = "comment", type = String.class), @Property(name = "msgs", type = Message.class, array = true) }) class ChatClient { @ComputedProperty - static boolean sendEnabled(String user, String text) { - boolean res = user != null && text != null && !user.isEmpty() && !text.isEmpty(); - try { - if (true) throw new IllegalStateException("Query for msg '" + text + "' by user " + user + " res: " + res); - } catch (Exception ex) { - - } + static boolean sendEnabled(String user, String comment) { + boolean res = user != null && comment != null && !user.isEmpty() && !comment.isEmpty(); return res; } @Function static void submit(ChatModel m) { - if (!sendEnabled(m.getUser(), m.getText())) { + if (!sendEnabled(m.getUser(), m.getComment())) { return; } - Message msg = new Message(CNTX); - msg.setComment(m.getText()); - msg.setUser(m.getUser()); - m.getMsgs().add(msg); + m.postComment(m.getUser(), m.getComment()); + } + + @OnReceive(url = "/chat/addComment?user={user}&comment={comment}") + static void postComment(ChatModel m, Message addedMessage) { + if (addedMessage.getComment().equals(m.getComment())) { + m.setComment(""); + } } @OnReceive(url = "/chat?since=0") static void initialRead(ChatModel m, Query q) { m.getMsgs().clear(); m.getMsgs().addAll(q.getMessages()); + moreMessages(m); + } + + @OnReceive(url = "/chat?since={since}") + static void updateMsgs(ChatModel m, Query q) { + m.getMsgs().addAll(q.getMessages()); + moreMessages(m); + } + + private static void moreMessages(ChatModel m) { + long now = System.currentTimeMillis(); + m.updateMsgs("" + now); } static final Context CNTX = Context.findDefault(ChatClient.class); @@ -76,6 +87,11 @@ m.setUser("system"); chm.getMsgs().add(m); chm.applyBindings(); - chm.initialRead(); + try { + // XXX: this should not be in static initializer - + // XXX: prevents unit testing! + chm.initialRead(); + } catch (Throwable ex) { + } } } diff -r 80715a1dd72e -r 40fce839ac01 serverside/src/main/java/org/apidesign/bck2brwsr/demo/serverside/ChatServerResource.java --- a/serverside/src/main/java/org/apidesign/bck2brwsr/demo/serverside/ChatServerResource.java Sun May 05 17:20:46 2013 +0200 +++ b/serverside/src/main/java/org/apidesign/bck2brwsr/demo/serverside/ChatServerResource.java Sun May 05 18:04:13 2013 +0200 @@ -26,13 +26,20 @@ import java.io.Closeable; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.IdentityHashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.inject.Singleton; import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.Suspended; import javax.ws.rs.core.MediaType; @@ -44,10 +51,11 @@ import org.glassfish.jersey.server.ContainerFactory; import org.glassfish.jersey.server.ResourceConfig; -/** Server side of the chat application. - */ -@Path("/") +/** Server side of the chat application.*/ +@Path("/") @Singleton public final class ChatServerResource { + private static final Logger LOG = Logger.getLogger(ChatServerResource.class.getName()); + public static void main(String... args) throws Exception { ResourceConfig rc = new ResourceConfig(ChatServerResource.class); GrizzlyHttpContainer c = ContainerFactory.createContainer(GrizzlyHttpContainer.class, rc); @@ -73,17 +81,53 @@ msgs.add(welcome); } + private final Map awaiting = new IdentityHashMap<>(); + @Produces(MediaType.APPLICATION_JSON) - @GET public void getResources(@Suspended AsyncResponse ar) { - Query q = new Query(Context.findDefault(Query.class)); - q.getMessages().addAll(msgs); - ar.resume(q); + @GET public synchronized void getResources( + @QueryParam("since") @DefaultValue("0") long since, + @Suspended AsyncResponse ar + ) { + Query q = new Query(Context.findDefault(ChatServerResource.class)); + for (Message m : msgs) { + if (m.getWhen() >= since) { + q.getMessages().add(m); + } + } + if (!q.getMessages().isEmpty()) { + ar.resume(q); + } else { + awaiting.put(ar, since); + } } - @Consumes(MediaType.APPLICATION_JSON) - @PUT public void publish(Message msg) { - if (msg != null) { - msgs.add(msg); + private void handleAwaiting(long newest) { + assert Thread.holdsLock(this); + AGAIN: for (;;) { + for (Map.Entry entry : awaiting.entrySet()) { + AsyncResponse ar = entry.getKey(); + Long since = entry.getValue(); + if (since <= newest) { + awaiting.remove(ar); + getResources(since, ar); + continue AGAIN; + } + } + return; } } + + @Path("addComment") @GET + public synchronized Message publish( + @QueryParam("user") String user, + @QueryParam("comment") String comment + ) { + Message msg = new Message(Context.findDefault(ChatServerResource.class)); + msg.setUser(user); + msg.setComment(comment); + msg.setWhen(System.currentTimeMillis()); + msgs.add(msg); + handleAwaiting(msg.getWhen()); + return msg; + } } diff -r 80715a1dd72e -r 40fce839ac01 serverside/src/main/resources/org/apidesign/bck2brwsr/demo/serverside/chat.html --- a/serverside/src/main/resources/org/apidesign/bck2brwsr/demo/serverside/chat.html Sun May 05 17:20:46 2013 +0200 +++ b/serverside/src/main/resources/org/apidesign/bck2brwsr/demo/serverside/chat.html Sun May 05 18:04:13 2013 +0200 @@ -33,7 +33,7 @@
Username:
Message:
- +
    diff -r 80715a1dd72e -r 40fce839ac01 serverside/src/test/java/org/apidesign/bck2brwsr/demo/serverside/ChatClientTest.java --- a/serverside/src/test/java/org/apidesign/bck2brwsr/demo/serverside/ChatClientTest.java Sun May 05 17:20:46 2013 +0200 +++ b/serverside/src/test/java/org/apidesign/bck2brwsr/demo/serverside/ChatClientTest.java Sun May 05 18:04:13 2013 +0200 @@ -42,14 +42,14 @@ @Test public void hasSendEnabled() { ChatModel m = new ChatModel(Context.EMPTY); assertFalse(m.isSendEnabled(), "By default disabled"); - m.setText("some msg"); + m.setComment("some msg"); m.setUser("by me"); assertTrue(m.isSendEnabled(), "Now it is enabled"); m.setUser(null); assertFalse(m.isSendEnabled(), "No user means disabled"); m.setUser("by him"); assertTrue(m.isSendEnabled(), "Again enabled"); - m.setText(""); + m.setComment(""); assertFalse(m.isSendEnabled(), "Empty text means disabled"); } }