Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit c03bf4d

Browse files
committed
Support for Web Sockets
1 parent b5c95a0 commit c03bf4d

25 files changed

Lines changed: 1081 additions & 85 deletions

TODO

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
* Cleanup WebSocket API
2+
* Log error from WebSocket
3+
* Tests for Web Socket

examples/fout.txt

552 Bytes
Binary file not shown.

examples/src/main/java/jooby/MyApp.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,18 @@ public class MyApp extends Jooby {
234234
resp.send(em.createQuery("from User").getResultList());
235235
});
236236

237+
get("/", (req, res) -> res.send(Viewable.of("ws", new Object())));
238+
239+
ws("/ws", (ws) -> {
240+
ws.onMessage(message -> {
241+
System.out.println(message.to(User.class));
242+
System.out.println(message.stringValue());
243+
ws.send(message.to(User.class), () -> {System.out.println("Sent!");});
244+
});
245+
246+
ws.send("Hello web browser");
247+
})
248+
.consumes(MediaType.json);
237249
}
238250

239251
public static void main(final String[] args) throws Exception {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
application.port=8090
2+
13
db=mem
24

35
hikari.maximumPoolSize = 10
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<html>
2+
<body>
3+
<script type="text/javascript">
4+
var ws = new WebSocket("ws://localhost:8090/ws");
5+
6+
ws.onopen = function() {
7+
console.log("opened");
8+
ws.send('{"firstName": "John", "lastName": "Doe"}');
9+
};
10+
11+
ws.onmessage = function (evt) {
12+
console.log("Message: " + evt.data);
13+
};
14+
15+
ws.onclose = function(err) {
16+
console.log(err);
17+
console.log("Closed!");
18+
};
19+
20+
ws.onerror = function(err) {
21+
console.log(err);
22+
alert("Error: " + err);
23+
};
24+
</script>
25+
</body>
26+
</html>

jooby-core/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@
6767
<artifactId>jetty-server</artifactId>
6868
</dependency>
6969

70+
<dependency>
71+
<groupId>org.eclipse.jetty.websocket</groupId>
72+
<artifactId>websocket-server</artifactId>
73+
</dependency>
74+
7075
<!-- Test dependencies -->
7176
<dependency>
7277
<groupId>ch.qos.logback</groupId>

jooby-core/src/main/java/jooby/BodyConverter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package jooby;
22

33
import java.util.List;
4+
import java.util.Set;
45

56
import javax.annotation.Nonnull;
67

78
import jooby.Response.Body;
89

910
import com.google.common.annotations.Beta;
11+
import com.google.inject.Key;
1012
import com.google.inject.TypeLiteral;
1113

1214
/**
@@ -19,6 +21,8 @@
1921
@Beta
2022
public interface BodyConverter {
2123

24+
Key<Set<BodyConverter>> KEY = Key.get( new TypeLiteral<Set<BodyConverter>>() {});
25+
2226
/**
2327
* Produces the list of compatibles media types. At least one must be provided.
2428
*

jooby-core/src/main/java/jooby/Jooby.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,12 @@ public Route.Err.Handler logError(final Route.Err.Handler err) {
682682
};
683683
}
684684

685+
public WebSocket.Definition ws(final String path, final WebSocket.Handler handler) {
686+
WebSocket.Definition ws = new WebSocket.Definition(path, handler);
687+
bag.add(ws);
688+
return ws;
689+
}
690+
685691
/**
686692
* <h1>Bootstrap</h1>
687693
* <p>
@@ -765,6 +771,10 @@ public void configure(final Binder binder) {
765771
Multibinder<Route.Definition> definitions = Multibinder
766772
.newSetBinder(binder, Route.Definition.class);
767773

774+
// Web Sockets
775+
Multibinder<WebSocket.Definition> sockets = Multibinder
776+
.newSetBinder(binder, WebSocket.Definition.class);
777+
768778
// Request Modules
769779
Multibinder<Request.Module> requestModule = Multibinder
770780
.newSetBinder(binder, Request.Module.class);
@@ -777,12 +787,14 @@ public void configure(final Binder binder) {
777787
binder.bind(File.class).annotatedWith(Names.named("java.io.tmpdir"))
778788
.toInstance(new File(config.getString("java.io.tmpdir")));
779789

780-
// modules and routes
790+
// modules, routes and websockets
781791
bag.forEach(candidate -> {
782792
if (candidate instanceof Jooby.Module) {
783793
install((Jooby.Module) candidate, mode, config, binder);
784794
} else if (candidate instanceof Route.Definition) {
785795
definitions.addBinding().toInstance((Route.Definition) candidate);
796+
} else if (candidate instanceof WebSocket.Definition) {
797+
sockets.addBinding().toInstance((WebSocket.Definition) candidate);
786798
} else {
787799
Class<?> routeClass = (Class<?>) candidate;
788800
Routes.routes(mode, routeClass)

jooby-core/src/main/java/jooby/MediaType.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ private MediaType doFirst(final List<MediaType> candidates) {
177177
*/
178178
public static final MediaType json = new MediaType("application", "json");
179179

180+
private static final MediaType jsonLike = new MediaType("application", "*+json");
181+
180182
/**
181183
* Any text media type.
182184
*/
@@ -222,6 +224,8 @@ private MediaType doFirst(final List<MediaType> candidates) {
222224

223225
public static MediaType xml = new MediaType("application", "xml");
224226

227+
private static MediaType xmlLike = new MediaType("application", "*+xml");
228+
225229
/**
226230
* Track the type of this media type.
227231
*/
@@ -304,6 +308,23 @@ public String name() {
304308
return type + "/" + subtype;
305309
}
306310

311+
public boolean isText() {
312+
if (text.matches(this)) {
313+
return true;
314+
}
315+
if (this.equals(MediaType.javascript)) {
316+
return true;
317+
}
318+
if (jsonLike.matches(this)) {
319+
return true;
320+
}
321+
if (xmlLike.matches(this)) {
322+
return true;
323+
}
324+
325+
return false;
326+
}
327+
307328
@Override
308329
public int compareTo(final MediaType that) {
309330
if (this == that) {
@@ -352,7 +373,7 @@ public boolean matches(final MediaType that) {
352373
return true;
353374
}
354375
if (subtype.startsWith("*")) {
355-
return that.subtype.endsWith(subtype.substring(1));
376+
return subtype.substring(1).endsWith(that.subtype);
356377
}
357378
}
358379
return false;

jooby-core/src/main/java/jooby/Route.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,6 @@ public interface Route {
114114
@Beta
115115
class Definition {
116116

117-
private static final List<MediaType> ALL = ImmutableList.of(MediaType.all);
118-
119117
private String name = "anonymous";
120118

121119
/**
@@ -132,13 +130,13 @@ class Definition {
132130
* Defines the media types that the methods of a resource class or can accept. Default is:
133131
* {@literal *}/{@literal *}.
134132
*/
135-
private List<MediaType> consumes = ALL;
133+
private List<MediaType> consumes = MediaType.ALL;
136134

137135
/**
138136
* Defines the media types that the methods of a resource class or can produces. Default is:
139137
* {@literal *}/{@literal *}.
140138
*/
141-
private List<MediaType> produces = ALL;
139+
private List<MediaType> produces = MediaType.ALL;
142140

143141
private Verb verb;
144142

0 commit comments

Comments
 (0)