# HG changeset patch # User Jaroslav Tulach # Date 1367854819 -7200 # Node ID fd9a16bbfd0e12cf2cc1301402c2e2b131bf6bf6 # Parent 84266695c06fae3df3ca0e45e220883fc1b69925 Splitting the client/server example into three independent modules diff -r 84266695c06f -r fd9a16bbfd0e chat/client/bck2brwsr-assembly.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/client/bck2brwsr-assembly.xml Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,67 @@ + + + + + bck2brwsr + + zip + + client + + + false + runtime + lib + + *:jar + *:rt + + + + false + provided + + *:js + + true + / + + + + + ${project.build.directory}/${project.build.finalName}.jar + / + + + ${project.build.directory}/classes/org/apidesign/html/chatserver/client/chat.html + / + index.html + + + + diff -r 84266695c06f -r fd9a16bbfd0e chat/client/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/client/pom.xml Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,121 @@ + + + 4.0.0 + + chat-demo + org.apidesign.html + 1.0-SNAPSHOT + + + org.apidesign.html.demo + chat-client + 1.0-SNAPSHOT + jar + + Chat Client Bck2Brwsr + + + + java.net + Java.net + https://maven.java.net/content/repositories/releases/ + + + + + netbeans + NetBeans + http://bits.netbeans.org/maven2/ + + + + + java.net + Java.net + https://maven.java.net/content/repositories/releases/ + + + + + + + UTF-8 + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + true + lib/ + + + + + + maven-assembly-plugin + 2.4 + + + distro-assembly + package + + single + + + + bck2brwsr-assembly.xml + + + + + + + + + + + org.apidesign.html + net.java.html.json + ${net.java.html.version} + jar + + + ${project.groupId} + chat-model + ${project.version} + + + org.testng + testng + 6.8 + test + jar + + + org.apidesign.bck2brwsr + emul + ${bck2brwsr.version} + rt + runtime + + + org.apidesign.bck2brwsr + vm4brwsr + ${bck2brwsr.version} + zip + js + provided + + + org.apidesign.html + ko-bck2brwsr + ${net.java.html.version} + runtime + + + diff -r 84266695c06f -r fd9a16bbfd0e chat/client/src/main/java/org/apidesign/html/chatserver/client/ChatClient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/client/src/main/java/org/apidesign/html/chatserver/client/ChatClient.java Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,104 @@ +/** + * The MIT License (MIT) + * + * Copyright (C) 2013 Jaroslav Tulach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.apidesign.html.chatserver.client; + +import net.java.html.json.ComputedProperty; +import net.java.html.json.Context; +import net.java.html.json.Function; +import net.java.html.json.Model; +import net.java.html.json.OnReceive; +import net.java.html.json.Property; +import org.apidesign.html.chatserver.model.Message; +import org.apidesign.html.chatserver.model.Query; + +/** + * + * @author Jaroslav Tulach + */ +@Model(className = "ChatModel", properties = { + @Property(name = "user", 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 comment) { + boolean res = user != null && comment != null && !user.isEmpty() && !comment.isEmpty(); + return res; + } + + @Function + static void submit(ChatModel m) { + if (!sendEnabled(m.getUser(), m.getComment())) { + return; + } + 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 = 0; + for (Message msg : m.getMsgs()) { + if (now < msg.getSince()) { + now = msg.getSince(); + } + } + m.updateMsgs("" + (now + 1)); + } + + static final Context CNTX = Context.findDefault(ChatClient.class); + static { + ChatModel chm = new ChatModel(CNTX); + Message m = new Message(CNTX); + m.setComment("Waiting for messages from the server..."); + m.setUser("system"); + chm.getMsgs().add(m); + chm.applyBindings(); + try { + // XXX: this should not be in static initializer - + // XXX: prevents unit testing! + chm.initialRead(); + } catch (Throwable ex) { + } + } +} diff -r 84266695c06f -r fd9a16bbfd0e chat/client/src/main/resources/org/apidesign/html/chatserver/client/chat.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/client/src/main/resources/org/apidesign/html/chatserver/client/chat.html Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,54 @@ + + + + + Chat via Jersey Server + + + +
Username:
+ +
Message:
+ + + +
    +
  • + @ + : + +
  • +
+ + + + + + diff -r 84266695c06f -r fd9a16bbfd0e chat/client/src/test/java/org/apidesign/html/chatserver/client/ChatClientTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/client/src/test/java/org/apidesign/html/chatserver/client/ChatClientTest.java Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,51 @@ +/** + * The MIT License (MIT) + * + * Copyright (C) 2013 Jaroslav Tulach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.apidesign.html.chatserver.client; + +import net.java.html.json.Context; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class ChatClientTest { + public ChatClientTest() { + } + + @Test public void hasSendEnabled() { + ChatModel m = new ChatModel(Context.EMPTY); + assertFalse(m.isSendEnabled(), "By default disabled"); + 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.setComment(""); + assertFalse(m.isSendEnabled(), "Empty text means disabled"); + } +} diff -r 84266695c06f -r fd9a16bbfd0e chat/model/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/model/pom.xml Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,32 @@ + + + 4.0.0 + + org.apidesign.html + chat-demo + 1.0-SNAPSHOT + + org.apidesign.html.demo + chat-model + 1.0-SNAPSHOT + Shared Model of a Message + http://maven.apache.org + + UTF-8 + + + + org.apidesign.html + net.java.html.json + ${net.java.html.version} + jar + + + org.testng + testng + 6.5.2 + test + + + diff -r 84266695c06f -r fd9a16bbfd0e chat/model/src/main/java/org/apidesign/html/chatserver/model/MessageImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/model/src/main/java/org/apidesign/html/chatserver/model/MessageImpl.java Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,59 @@ +/** + * The MIT License (MIT) + * + * Copyright (C) 2013 Jaroslav Tulach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.apidesign.html.chatserver.model; + +import net.java.html.json.ComputedProperty; +import net.java.html.json.Model; +import net.java.html.json.Property; + +/** Generic model of communication between browser and a chat server. + * The same code is then used on the server, on the client and even in unit + * tests. + * + * @author Jaroslav Tulach + */ +@Model(className = "Message", properties = { + @Property(name = "user", type = String.class), + @Property(name = "comment", type = String.class), + @Property(name = "since", type = long.class) +}) +class MessageImpl { + @ComputedProperty static String at(long since) { + long delta = since / 1000; + if (delta <= 0) { + return "Boot-time"; + } + if (delta < 60) { + return delta + "s"; + } + delta /= 60; + return delta + "min"; + } + + @Model(className = "Query", properties = { + @Property(name = "messages", type = Message.class, array = true) + }) + class QryMsgs { + } +} diff -r 84266695c06f -r fd9a16bbfd0e chat/model/src/test/java/org/apidesign/html/chatserver/model/MessageImplTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/model/src/test/java/org/apidesign/html/chatserver/model/MessageImplTest.java Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,46 @@ +/** + * The MIT License (MIT) + * + * Copyright (C) 2013 Jaroslav Tulach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.apidesign.html.chatserver.model; + +import net.java.html.json.Context; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class MessageImplTest { + + @Test public void properlyConvertedToSeconds() { + Message msg = new Message(Context.EMPTY); + msg.setSince(5143); + assertEquals(msg.getAt(), "5s"); + } + @Test public void properlyConvertedToMinutes() { + Message msg = new Message(Context.EMPTY); + msg.setSince(63564); + assertEquals(msg.getAt(), "1min"); + } +} \ No newline at end of file diff -r 84266695c06f -r fd9a16bbfd0e chat/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/pom.xml Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,40 @@ + + + 4.0.0 + + demo + org.apidesign.html + 1.0-SNAPSHOT + + org.apidesign.html + chat-demo + 1.0-SNAPSHOT + pom + Chat Server with Jersey and Bck2Brwsr + + UTF-8 + 0.2 + 0.7 + MINIMAL + + + model + client + server + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + + + + + + \ No newline at end of file diff -r 84266695c06f -r fd9a16bbfd0e chat/server/nbactions.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/server/nbactions.xml Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,35 @@ + + + + + run + + process-classes + exec:java + + + diff -r 84266695c06f -r fd9a16bbfd0e chat/server/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/server/pom.xml Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,105 @@ + + + 4.0.0 + + org.apidesign.html + chat-demo + 1.0-SNAPSHOT + + org.apidesign.html.demo + chat-server + 1.0-SNAPSHOT + Chat Server Using @Model + http://maven.apache.org + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + org.apidesign.bck2brwsr.demo.chatserver.impl.Main + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.7 + + + process-resources + unpack-client-code + + unpack + + + + + org.apidesign.html.demo + chat-client + 1.0-SNAPSHOT + zip + bck2brwsr + + + ${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/chatserver/impl/ + + + + + + + + + + org.apidesign.html + net.java.html.json + ${net.java.html.version} + jar + + + org.glassfish.jersey.incubator + html-json + 0.1-SNAPSHOT + runtime + + + org.testng + testng + 6.5.2 + test + + + org.glassfish.jersey.connectors + jersey-grizzly-connector + 2.0-SNAPSHOT + + + org.glassfish.jersey.containers + jersey-container-grizzly2-http + 2.0-SNAPSHOT + jar + + + org.glassfish.grizzly + grizzly-http-server + 2.3.1 + + + org.apidesign.html.demo + chat-model + 1.0-SNAPSHOT + jar + + + diff -r 84266695c06f -r fd9a16bbfd0e chat/server/src/main/java/org/apidesign/bck2brwsr/demo/chatserver/impl/ChatServerResource.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/server/src/main/java/org/apidesign/bck2brwsr/demo/chatserver/impl/ChatServerResource.java Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,108 @@ +/** + * The MIT License (MIT) + * + * Copyright (C) 2013 Jaroslav Tulach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.apidesign.bck2brwsr.demo.chatserver.impl; + +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.DefaultValue; +import javax.ws.rs.GET; +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 net.java.html.json.Context; +import org.apidesign.html.chatserver.model.Message; +import org.apidesign.html.chatserver.model.Query; + +/** Server side of the chat application.*/ +@Path("/chat/") @Singleton +public final class ChatServerResource { + private static final Logger LOG = Logger.getLogger(ChatServerResource.class.getName()); + private static final long started = System.currentTimeMillis() - 10; + + private List msgs = new ArrayList<>(); + { + Message welcome = new Message(Context.findDefault(Message.class)); + welcome.setUser("system"); + welcome.setComment("Welcome and enjoy!"); + welcome.setSince(10); + msgs.add(welcome); + } + + private final Map awaiting = new IdentityHashMap<>(); + + @Produces(MediaType.APPLICATION_JSON) + @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.getSince()>= since) { + q.getMessages().add(m); + } + } + if (!q.getMessages().isEmpty()) { + ar.resume(q); + } else { + awaiting.put(ar, since); + } + } + + 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.setSince(System.currentTimeMillis() - started); + msgs.add(msg); + handleAwaiting(msg.getSince()); + return msg; + } +} diff -r 84266695c06f -r fd9a16bbfd0e chat/server/src/main/java/org/apidesign/bck2brwsr/demo/chatserver/impl/ClientPagesResource.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/server/src/main/java/org/apidesign/bck2brwsr/demo/chatserver/impl/ClientPagesResource.java Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,45 @@ +/** + * The MIT License (MIT) + * + * Copyright (C) 2013 Jaroslav Tulach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.apidesign.bck2brwsr.demo.chatserver.impl; + +import java.io.InputStream; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +/** + * + * @author Jaroslav Tulach + */ +@Path("/") +public final class ClientPagesResource { + @GET public InputStream indexHtml() { + return clientData("index.html"); + } + + @GET @Path("{resource:.*}") + public InputStream clientData(@PathParam("resource") String res) { + return ClientPagesResource.class.getResourceAsStream("client/" + res); + } +} diff -r 84266695c06f -r fd9a16bbfd0e chat/server/src/main/java/org/apidesign/bck2brwsr/demo/chatserver/impl/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chat/server/src/main/java/org/apidesign/bck2brwsr/demo/chatserver/impl/Main.java Mon May 06 17:40:19 2013 +0200 @@ -0,0 +1,47 @@ +/** + * The MIT License (MIT) + * + * Copyright (C) 2013 Jaroslav Tulach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.apidesign.bck2brwsr.demo.chatserver.impl; + +import java.net.URI; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; +import org.glassfish.jersey.server.ResourceConfig; + +/** Starts chat server based on Jersey. + * + * @author Jaroslav Tulach + */ +final class Main { + public static void main(String... args) throws Exception { + ResourceConfig rc = new ResourceConfig( + ChatServerResource.class, ClientPagesResource.class + ); + URI u = new URI("http://localhost:8080/"); + HttpServer server = GrizzlyHttpServerFactory.createHttpServer(u, rc); + System.err.println("Server running at " + u); + System.in.read(); + server.stop(); + } + +} diff -r 84266695c06f -r fd9a16bbfd0e pom.xml --- a/pom.xml Sun May 05 18:11:29 2013 +0200 +++ b/pom.xml Mon May 06 17:40:19 2013 +0200 @@ -13,12 +13,12 @@ UTF-8 - 0.7-SNAPSHOT + 0.7 COPYING twitter - serverside + chat diff -r 84266695c06f -r fd9a16bbfd0e serverside/nbactions.xml --- a/serverside/nbactions.xml Sun May 05 18:11:29 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ - - - - - run - - process-classes - exec:java - - - diff -r 84266695c06f -r fd9a16bbfd0e serverside/pom.xml --- a/serverside/pom.xml Sun May 05 18:11:29 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ - - - 4.0.0 - - org.apidesign.html - demo - 1.0-SNAPSHOT - - org.apidesign.bck2brwsr - demo-serverside - 1.0-SNAPSHOT - Bck2Brwsr and Bck2Server - http://maven.apache.org - - UTF-8 - 0.2 - 0.8-SNAPSHOT - MINIMAL - org/apidesign/bck2brwsr/demo/serverside/chat.html - - - - - org.codehaus.mojo - exec-maven-plugin - 1.2.1 - - org.apidesign.bck2brwsr.demo.serverside.ChatServerResource - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.7 - 1.7 - - - - - - - org.apidesign.html - net.java.html.json - ${net.java.html.version} - jar - - - org.glassfish.jersey.incubator - html-json - 0.1-SNAPSHOT - runtime - - - org.apidesign.html - ko-bck2brwsr - ${net.java.html.version} - runtime - - - ${project.groupId} - launcher.http - ${bck2brwsr.version} - compile - - - grizzly-http-server - org.glassfish.grizzly - - - - - ${project.groupId} - emul - ${bck2brwsr.version} - rt - runtime - - - org.testng - testng - 6.5.2 - test - - - org.glassfish.jersey.connectors - jersey-grizzly-connector - 2.0-SNAPSHOT - - - org.glassfish.jersey.containers - jersey-container-grizzly2-http - 2.0-SNAPSHOT - jar - - - org.glassfish.grizzly - grizzly-http-server - 2.3.1 - - - diff -r 84266695c06f -r fd9a16bbfd0e 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 18:11:29 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (C) 2013 Jaroslav Tulach - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.apidesign.bck2brwsr.demo.serverside; - -import net.java.html.json.ComputedProperty; -import net.java.html.json.Context; -import net.java.html.json.Function; -import net.java.html.json.Model; -import net.java.html.json.OnReceive; -import net.java.html.json.Property; - -/** - * - * @author Jaroslav Tulach - */ -@Model(className = "ChatModel", properties = { - @Property(name = "user", 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 comment) { - boolean res = user != null && comment != null && !user.isEmpty() && !comment.isEmpty(); - return res; - } - - @Function - static void submit(ChatModel m) { - if (!sendEnabled(m.getUser(), m.getComment())) { - return; - } - 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); - static { - ChatModel chm = new ChatModel(CNTX); - Message m = new Message(CNTX); - m.setComment("Waiting for messages from the server..."); - m.setUser("system"); - chm.getMsgs().add(m); - chm.applyBindings(); - try { - // XXX: this should not be in static initializer - - // XXX: prevents unit testing! - chm.initialRead(); - } catch (Throwable ex) { - } - } -} diff -r 84266695c06f -r fd9a16bbfd0e 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 18:11:29 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (C) 2013 Jaroslav Tulach - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.apidesign.bck2brwsr.demo.serverside; - -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; -import net.java.html.json.Context; -import org.apidesign.bck2brwsr.launcher.Launcher; -import org.glassfish.grizzly.http.server.HttpServer; -import org.glassfish.grizzly.http.server.ServerConfiguration; -import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer; -import org.glassfish.jersey.server.ContainerFactory; -import org.glassfish.jersey.server.ResourceConfig; - -/** 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); - Closeable s = Launcher.showURL( - "bck2brwsr", ChatClient.class.getClassLoader(), - "/org/apidesign/bck2brwsr/demo/serverside/chat.html" - ); - Launcher l = (Launcher) s; - Callable f = (Callable) l; - HttpServer server = (HttpServer) f.call(); - ServerConfiguration conf = server.getServerConfiguration(); - conf.addHttpHandler(c, "/chat"); - System.in.read(); - s.close(); - } - - private List msgs = new ArrayList<>(); - { - Message welcome = new Message(Context.findDefault(Message.class)); - welcome.setUser("system"); - welcome.setComment("Welcome and enjoy!"); - welcome.setWhen(System.currentTimeMillis()); - msgs.add(welcome); - } - - private final Map awaiting = new IdentityHashMap<>(); - - @Produces(MediaType.APPLICATION_JSON) - @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); - } - } - - 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 84266695c06f -r fd9a16bbfd0e serverside/src/main/java/org/apidesign/bck2brwsr/demo/serverside/MessageImpl.java --- a/serverside/src/main/java/org/apidesign/bck2brwsr/demo/serverside/MessageImpl.java Sun May 05 18:11:29 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (C) 2013 Jaroslav Tulach - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.apidesign.bck2brwsr.demo.serverside; - -import net.java.html.json.ComputedProperty; -import net.java.html.json.Model; -import net.java.html.json.Property; - -/** - * - * @author Jaroslav Tulach - */ -@Model(className = "Message", properties = { - @Property(name = "user", type = String.class), - @Property(name = "comment", type = String.class), - @Property(name = "when", type = long.class) -}) -class MessageImpl { - private static final long start = System.currentTimeMillis(); - - static long startTime() { - return start; - } - - @ComputedProperty static String at(long when) { - long delta = (when - start) / 1000; - if (delta <= 0) { - return "Before BigBeng"; - } - if (delta < 60) { - return delta + "s"; - } - delta /= 60; - return delta + "min"; - } - - @Model(className = "Query", properties = { - @Property(name = "messages", type = Message.class, array = true) - }) - class QryMsgs { - } -} diff -r 84266695c06f -r fd9a16bbfd0e 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 18:11:29 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ - - - - - Chat via Jersey Server - - - -
Username:
- -
Message:
- - - -
    -
  • - @ - : - -
  • -
- - - - - - diff -r 84266695c06f -r fd9a16bbfd0e 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 18:11:29 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (C) 2013 Jaroslav Tulach - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.apidesign.bck2brwsr.demo.serverside; - -import net.java.html.json.Context; -import static org.testng.Assert.*; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -public class ChatClientTest { - public ChatClientTest() { - } - - @Test public void hasSendEnabled() { - ChatModel m = new ChatModel(Context.EMPTY); - assertFalse(m.isSendEnabled(), "By default disabled"); - 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.setComment(""); - assertFalse(m.isSendEnabled(), "Empty text means disabled"); - } -}