jax-rs 2.1 reloaded€¦ · #devoxxus jax-rs 2.1 reloaded santiago pericas-geertsen jax-rs co-spec...

37
#DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

Upload: others

Post on 08-Aug-2020

33 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen

JAX-RS Co-Spec Lead

#jax-rs @spericas

Page 2: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Agenda

•  Reactive Extensions

•  Server-Sent Events

•  Non-Blocking IO

#jax-rs @spericas

Page 3: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Reactive Extensions

#jax-rs @spericas

Page 4: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Asynchronous Processing in 2.0

Server side:

•  Using @Suspended and AsyncResponse

•  Resume execution on a different thread

Client side:

•  Future<T>

•  InvocationCallback<T>

4

Page 5: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Example Using Future<T>

5

What’s the problem here?

Client client = ClientBuilder.newClient();WebTarget target = client.target(“http://…”);

Future<String> f = target.request().async().get(String.class);

// some time later …

String user = f.get();

Page 6: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Example using InvocationCallback<T>

6

WebTarget target = client.target(“http://…”);

target.request().async().get( new InvocationCallback<String>() { @Override public void completed(String user) { // do something } @Override public void failed(Throwable t) { // do something } });

Page 7: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Example using InvocationCallback<T>

7

target1.request().async().get(new InvocationCallback<String>() { public void completed(String user) { target2.request().header(“user”, user).async().get( new InvocationCallback<String>() { public void completed(String quote) { System.out.println(quote); } public void failed(Throwable t) { // do something } }); } public void failed(Throwable t) { // do something }}));

Page 8: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Some use cases for Async Computations

•  Compose two or more asynchronous tasks

•  Combine the output of two or more asynchronous tasks

•  Consume value of asynchronous task

•  Wait for all tasks in a collection to complete

•  Wait for any of the tasks in a collection to complete

And many more …

Page 9: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Meet CompletionStage<T> in JAX-RS

9

CompletionStage<String> cs1 = target1.request().rx().get(String.class);

CompletionStage<String> cs2 = cs1.thenCompose(user -> target2.request().header(“user”, user) .rx().get(String.class));

cs2.thenAccept(quote -> System.out.println(quote));

Page 10: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

What about other Rx libraries?

10

Client client = client.register(ObservableRxInvokerProvider.class); Observable<String> of = client.target("forecast/{destination}”) .resolveTemplate("destination", "mars”) .request() .rx(ObservableRxInvoker.class) .get(String.class);

of.subscribe(System.out::println);

Register a Provider

Override default Invoker

Page 11: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Server-Sent Events Summary

•  New invoker to support Rx

•  Default support for CompletionStage

•  Extension mechanism for other Rx libraries

11

Page 12: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Server-Sent Events

#jax-rs @spericas

Page 13: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Server-Sent Events

•  Originally W3C (HTML5), now maintainted by WHATWG

•  HTTP-based protocol for one-way server to client messaging

•  Special media type text/event-stream

13

Page 14: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Client API

14

try (SseEventSource source = SseEventSource.target(“http://…”).build()) { source.subscribe(System.out::println); source.open(); Thread.sleep(500); } catch (InterruptedException e) { // falls through }

Publisher

Page 15: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Server API

15

@GET @Produces(“text/event-stream”) public void eventStream( @Context SseEventSink eventSink, @Context Sse sse) { executor.execute(() -> { try (SseEventSink sink = eventSink) { eventSink.onNext(sse.newEvent("event1")); eventSink.onNext(sse.newEvent("event2")); eventSink.close(); } catch (IOException e) {

// handle exception } });}

Subscriber

Page 16: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Broadcasting (1 of 2)

16

@Path("/") @Singletonpublic class SseResource {

private final Sse sse; private final SseBroadcaster sseBroadcaster;

public SseResource(@Context Sse sse) { this.sse = sse; this.sseBroadcaster = sse.newBroadcaster(); } …

One Publisher

Lifecycle controlled by

App

Page 17: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Broadcasting (2 of 2)

17

@GET @Path(“subscribe”) @Produces(MediaType.SERVER_SENT_EVENTS) public void subscribe(@Context SseEventSink eventSink) { eventSink.onNext(sse.newEvent("welcome!")); sseBroadcaster.subscribe(eventSink); }

@POST @Path(“broadcast”) @Consumes(MediaType.MULTIPART_FORM_DATA) public void broadcast(@FormParam("event") String event) { sseBroadcaster.broadcast(sse.newEvent(event)); } … }

Many Subscribers

Page 18: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Reactive Extensions Summary

•  New types SseEventSink, SseEventSource, Sse and SseBroadcaster

•  Sse and SseEventSink’s lifecycle controlled by runtime

•  Singleton scope useful for broadcasting

18

Page 19: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Non-Blocking IO

#jax-rs @spericas

Page 20: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Motivation

•  Certain apps need more control over IO

•  Higher throughput is hard with blocking IO

•  Precedence with StreamingOutput

20

Page 21: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

StreamingOutput in JAX-RS

21

@GETpublic Response get() { return Response.ok(new StreamingOutput() { @Override public void write(OutputStream out) throws … { out.write(…); } }).build();}

Direct access to stream Still blocking!

Page 22: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

First NIO Proposal

22

return Response.ok().entity( out -> { try { final int n = in.read(buffer); if (n >= 0) { out.write(buffer, 0, n); return true; // more to write } in.close(); return false; // we're done } catch (IOException e) { … } }).build();

Write handler

Page 23: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

First Proposal Limitations

•  Byte streams are not sufficient in JAX-RS

•  We want POJOs!

•  What about JAX-RS readers, writers and interceptors?

•  Poor integration with other third-party libraries and APIs

23

Page 24: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Current Proposal: Flows

•  Standardized in Java 9

•  Originaly appeared in Reactive Streams

•  Not just bytes, POJOs too

•  Possibility of integration with third-party libraries and APIs

24

Page 25: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Simple Concepts

25

Publisher

Subscriber

Processor

Publisher

Subscriber

0

N

Processor

Page 26: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Why and when to NIO?

•  Non-blocking code tends to be more involved

•  Beneficial for large payloads

•  Large payloads often involve collections

•  In Flow terms, a collection of Pojos is a Publisher<Pojo>

26

Page 27: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Processing a collection

27

@POST@Consumes(“application/json”)void process(Publisher<Pojo> pojos, @Suspended AsyncResponse response) { pojos.subscribe(new Subscriber<Pojo> { public onNext(Pojo pojo) { // process single pojo } public onComplete() { return response.ok().build(); } … } }

Asynchronous by nature

Page 28: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

MessageBodyReader for Pojo?

•  MessageBodyReader for Pojo or Publisher<Pojo>?

•  We need a new type of Reader: NioBodyReader

•  Knows how to process a collection of Pojos

•  May use MessageBodyReader for each Pojo

•  (Ditto for MessageBodyWriters …)

28

Page 29: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Pojo Processor in REST

29

@POST@Consumes(“application/json”)@Produces(“application/json”)Publisher<Pojo> process(Publisher<Pojo> pojos, @Suspended AsyncResponse response) { Processor<Pojo> pp = new MyProcessor(response); pojos.subscribe(pp); return pp;} Processors are

publishers!

Page 30: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Third-party Libraries

30

@GET@Produces(“application/json”)Publisher<Pojo> process( @QueryParam(“predicate”) String predicate) { return DB.get(Pojo.class).filter(predicate);}

Third-party Library

Page 31: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

What about Filters and Interceptors?

•  Need special support for NIO

•  For example, additional methods and contexts

•  Discussion still ongoing

•  May impact how NioBodyReader/NioBodyWriter are defined

31

Page 32: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

And NIO Clients?

•  Will be supported as well

•  Need re-usability of readers and writers for NIO

•  Likely using a new client Invoker

32

Page 33: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

NIO Client

33

WebTarget resource = target(“…”).path(“pojos”);Publisher<Pojo> pojos = resource.request().nio().get(Pojo.class);

pojos.subscribe(new Subscriber<Pojo> { public onNext(Pojo pojo) { // process single pojo } …});

NioBodyReader

Page 34: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Tentative Vocabulary

•  Publisher = Source

•  Subscriber = Sink

•  Does this ring a bell?

34

Page 35: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

SSE is a special case of Flow!

•  Where what flows are SSE protocol messages

•  Initial SSE proposal may be impacted

•  Return a Source instead of injecting a Sink

35

Page 36: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Non-Blocking IO Summary

•  Based on Flows

•  New readers/writers for collections

•  Support for Flows without depending on Java 9

•  Support for Pojos, not just byte streams

•  Publisher<Pojo> and Publisher<ByteArray>

36

Page 37: JAX-RS 2.1 Reloaded€¦ · #DevoxxUS JAX-RS 2.1 Reloaded Santiago Pericas-Geertsen JAX-RS Co-Spec Lead #jax-rs @spericas

#DevoxxUS

Public Release In Progress

•  Support for NIO and Flows

•  Some minor changes to SSE possible

•  Stay tuned!

37