# HG changeset patch # User Jaroslav Tulach # Date 1461307993 -7200 # Node ID 2d0750864a98c86d99dafeea5179c0ac9b6d948e # Parent f57278ddd70e2e3d68b9291a10f50ff3c828c9b6 Using WebSocket on the client and on the server while keeping their ability to talk to each other diff -r f57278ddd70e -r 2d0750864a98 chat/client/src/main/java/org/apidesign/demo/chat/ChatClient.java --- a/chat/client/src/main/java/org/apidesign/demo/chat/ChatClient.java Fri Apr 22 06:14:38 2016 +0200 +++ b/chat/client/src/main/java/org/apidesign/demo/chat/ChatClient.java Fri Apr 22 08:53:13 2016 +0200 @@ -30,6 +30,7 @@ import net.java.html.json.Property; import org.apidesign.demo.chat.shared.Message; import org.apidesign.demo.chat.shared.Query; +import org.apidesign.demo.chat.shared.Reply; /** * @@ -56,7 +57,7 @@ Message msg = new Message(); msg.setUser(m.getUser()); msg.setComment(m.getComment()); - m.postComment(m.getUrl(), msg); + m.socket(m.getUrl(), new Query().assignPost(msg)); } static void cantChat(ChatModel model, Exception err) { @@ -64,44 +65,22 @@ } - @OnReceive(url = "{url}/chat", method = "POST", data = Message.class, onError = "cantChat") - static void postComment(ChatModel m, Message addedMessage) { - if (addedMessage.getComment().equals(m.getComment())) { - m.setComment(""); + @OnReceive(url = "{url}/chat", method = "WebSocket", data = Query.class, onError = "cantChat") + static void socket(ChatModel m, Reply reply) { + if (reply == null) { + m.getMsgs().add(new Message("System", "Connected to server at " + m.getUrl() + "/chat!", 0)); + return; } - } - - @OnReceive(url = "{url}/chat?since=0", onError = "cantChat") - static void initialRead(ChatModel m, Query q) { m.getMsgs().clear(); - m.getMsgs().addAll(q.getMessages()); - moreMessages(m); - } - - @OnReceive(url = "{url}/chat?since={since}", onError = "cantChat") - static void updateMsgs(ChatModel m, Query q) { - m.getMsgs().addAll(q.getMessages()); - moreMessages(m); - } - - private static void moreMessages(ChatModel m) { - long now = 0; - for (Message msg : m.getMsgs()) { - if (now < msg.getSince()) { - now = msg.getSince(); - } - } - m.updateMsgs(m.getUrl(), "" + (now + 1)); + m.getMsgs().addAll(reply.getMessages()); } public static void onPageLoad() { ChatModel chm = new ChatModel(); - chm.setUrl("http://localhost:8080"); - Message m = new Message(); - m.setComment("Waiting for messages from the server..."); - m.setUser("system"); + chm.setUrl("ws://localhost:8080"); + Message m = new Message("System", "Waiting for messages from the server...", 0); chm.getMsgs().add(m); chm.applyBindings(); - chm.initialRead(chm.getUrl()); + chm.socket(chm.getUrl(), null); } } diff -r f57278ddd70e -r 2d0750864a98 chat/server/pom.xml --- a/chat/server/pom.xml Fri Apr 22 06:14:38 2016 +0200 +++ b/chat/server/pom.xml Fri Apr 22 08:53:13 2016 +0200 @@ -8,82 +8,89 @@ chat-server jar - chat Jersey based Server + Chat WebSocket Server 1.7 1.7 + 2.3.8 - - - org.netbeans.html - net.java.html.json - ${net.java.html.version} - jar - - - org.glassfish.jersey.media - html-json - ${jersey.version} - runtime - - - - org.netbeans.html - net.java.html.json - - - org.netbeans.html - ko-ws-tyrus - - - - - org.testng - testng - test - - - org.glassfish.jersey.connectors - jersey-grizzly-connector - ${jersey.version} - - - org.glassfish.jersey.containers - jersey-container-grizzly2-http - ${jersey.version} - jar - - - org.glassfish.jersey.core - jersey-common - ${jersey.version} - runtime - - - ko-ws-tyrus - org.netbeans.html - jar - ${net.java.html.version} - runtime - - - - org.glassfish.grizzly - grizzly-framework - - - org.glassfish.grizzly - grizzly-http-server - - - - - org.apidesign.demo - chat-shared - ${project.version} - jar - - + + + + org.netbeans.html + net.java.html + ${net.java.html.version} + jar + + + org.netbeans.html + net.java.html.json + ${net.java.html.version} + jar + + + javax.websocket-api + javax.websocket + jar + 1.0 + + + + + org.glassfish.tyrus + tyrus-client + 1.3.1 + runtime + + + org.glassfish.tyrus + tyrus-container-grizzly-client + 1.3.1 + runtime + + + + + + + org.netbeans.html + ko4j + ${net.java.html.version} + jar + + + org.glassfish.grizzly + grizzly-http-server-core + ${grizzly.version} + jar + + + org.glassfish.grizzly + grizzly-websockets-server + ${grizzly.version} + jar + + + org.glassfish.grizzly + grizzly-http-server + ${grizzly.version} + + + org.glassfish.grizzly + grizzly-http-servlet + ${grizzly.version} + + + javax.servlet + javax.servlet-api + 3.1.0 + + + ${project.groupId} + chat-shared + ${project.version} + + diff -r f57278ddd70e -r 2d0750864a98 chat/server/src/main/java/org/apidesign/demo/chat/server/ChatServerResource.java --- a/chat/server/src/main/java/org/apidesign/demo/chat/server/ChatServerResource.java Fri Apr 22 06:14:38 2016 +0200 +++ b/chat/server/src/main/java/org/apidesign/demo/chat/server/ChatServerResource.java Fri Apr 22 08:53:13 2016 +0200 @@ -24,27 +24,14 @@ package org.apidesign.demo.chat.server; import java.util.ArrayList; -import java.util.IdentityHashMap; import java.util.List; -import java.util.Map; 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.POST; -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; import org.apidesign.demo.chat.shared.Message; -import org.apidesign.demo.chat.shared.Query; +import org.glassfish.grizzly.websockets.WebSocket; +import org.glassfish.grizzly.websockets.WebSocketApplication; /** Server side of the chat application.*/ -@Path("/chat/") @Singleton -public final class ChatServerResource { +public final class ChatServerResource extends WebSocketApplication { private static final Logger LOG = Logger.getLogger(ChatServerResource.class.getName()); private static final long started = System.currentTimeMillis() - 10; @@ -56,7 +43,9 @@ welcome.setSince(10); msgs.add(welcome); } - + + +/* private final Map awaiting = new IdentityHashMap<>(); @Produces(MediaType.APPLICATION_JSON) @@ -100,4 +89,10 @@ handleAwaiting(msg.getSince()); return msg; } +*/ + + @Override + public void onMessage(WebSocket socket, String text) { + super.onMessage(socket, text); + } } diff -r f57278ddd70e -r 2d0750864a98 chat/server/src/main/java/org/apidesign/demo/chat/server/Main.java --- a/chat/server/src/main/java/org/apidesign/demo/chat/server/Main.java Fri Apr 22 06:14:38 2016 +0200 +++ b/chat/server/src/main/java/org/apidesign/demo/chat/server/Main.java Fri Apr 22 08:53:13 2016 +0200 @@ -23,28 +23,29 @@ */ package org.apidesign.demo.chat.server; -import java.io.IOException; import java.net.Inet4Address; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.URI; import java.util.Enumeration; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerResponseContext; -import javax.ws.rs.container.ContainerResponseFilter; +import org.glassfish.grizzly.PortRange; import org.glassfish.grizzly.http.server.HttpServer; -import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; -import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.grizzly.http.server.NetworkListener; +import org.glassfish.grizzly.websockets.WebSocketAddOn; +import org.glassfish.grizzly.websockets.WebSocketEngine; /** Starts REST server based on Jersey. */ -final class Main implements ContainerResponseFilter { +final class Main { public static void main(String... args) throws Exception { - ResourceConfig rc = new ResourceConfig( - ChatServerResource.class, Main.class - ); + HttpServer server = HttpServer.createSimpleServer(null, new PortRange(8080, 8080)); + final WebSocketAddOn addon = new WebSocketAddOn(); + for (NetworkListener listener : server.getListeners()) { + listener.registerAddOn(addon); + } + WebSocketEngine.getEngine().register("", "/chat", new ChatServerResource()); + server.start(); URI u = new URI("http://0.0.0.0:8080/"); - HttpServer server = GrizzlyHttpServerFactory.createHttpServer(u, rc); System.err.println("Server running on following IP addresses:"); dumpIPs(); System.err.println("Press Enter to shutdown the server"); @@ -52,17 +53,6 @@ server.stop(); } - @Override - public void filter( - ContainerRequestContext requestContext, - ContainerResponseContext r - ) throws IOException { - r.getHeaders().add("Access-Control-Allow-Origin", "*"); - r.getHeaders().add("Access-Control-Allow-Credentials", "true"); - r.getHeaders().add("Access-Control-Allow-Headers", "Content-Type"); - r.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); - } - private static void dumpIPs() throws Exception { Enumeration en = NetworkInterface.getNetworkInterfaces(); while (en.hasMoreElements()) { diff -r f57278ddd70e -r 2d0750864a98 chat/shared/src/main/java/org/apidesign/demo/chat/shared/MessageImpl.java --- a/chat/shared/src/main/java/org/apidesign/demo/chat/shared/MessageImpl.java Fri Apr 22 06:14:38 2016 +0200 +++ b/chat/shared/src/main/java/org/apidesign/demo/chat/shared/MessageImpl.java Fri Apr 22 08:53:13 2016 +0200 @@ -51,9 +51,17 @@ return delta + "min"; } - @Model(className = "Query", properties = { + @Model(className = "Query", builder = "assign", properties = { + @Property(name = "since", type = int.class), + @Property(name = "post", type = Message.class), + }) + class QueryCntrl { + } + + @Model(className = "Reply", properties = { + @Property(name = "since", type = int.class), @Property(name = "messages", type = Message.class, array = true) }) - class QryMsgs { + class ReplyCntrl { } }