REST in an Async World
-
Upload
david-delabassee -
Category
Software
-
view
493 -
download
4
Transcript of REST in an Async World
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
DavidDelabassee@delabasseeOracle
RESTinanAsyncWorldIsrael–July2017
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 2
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 3
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
SafeHarborStatementThefollowingisintendedtooutlineourgeneralproductdirecPon.ItisintendedforinformaPonpurposesonly,andmaynotbeincorporatedintoanycontract.Itisnotacommitmenttodeliveranymaterial,code,orfuncPonality,andshouldnotberelieduponinmakingpurchasingdecisions.Thedevelopment,release,andPmingofanyfeaturesorfuncPonalitydescribedforOracle’sproductsremainsatthesolediscrePonofOracle.
4
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
Agenda
• REST&JAX-RS• Synchronousvs.Asynchronous• Client-sidevs.Server-side
5
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
Client-sideREST
ConfidenPal–OracleInternal/Restricted/HighlyRestricted 6
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS
• JavaAPIforRESTfulWebServices– JAX-RS2.0–JSR339(*)– JAX-RS2.1–JSR370
• StandardbasedRESTfulframework– Server-sideandclient-side– Jersey,JBossRESTEasy,Restlet,ApacheCXF,ApacheWink,IBMJAX-RS,…
• JavaSEandJavaEE
7
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 8
Clientclient=ClientBuilder.newClient();WebTargettarget=client.target("http://weath.er/api").queryParam("city","Paris”);Forecastforecast=target.request().get(Forecast.class);…client.close();
JAX-RSClientAPI
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPI
• Client– Clientsidecontainer– Customizable&tunable• E.g.executorService()(newinJAX-RS2.1!)
• WebTarget– TargetremoteURI– Buildfromaclient– path()+resolveTemplates(),queryParam(),matrixParam()
javax.ws.rs.client.Clientinterface
9
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPI
• RequestinvocaPonbuilder– BuildfromaWebTarget– acceptXXX(),cookie(),header(),cacheControl()…– HTTPmethods
javax.ws.rs.client.Clientinterface
10
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPI
• FluentAPI– ClientBuilderèClientèWebTargetèRequestbuildingèResponse
javax.ws.rs.client.Clientinterface
11
List<Forecast>forecast=ClientBuilder.newClient().target("http://weath.er/cities").request().accept("application/json").header("Foo","bar").get(newGenericType<List<Forecast>>(){});
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPI
• Synchronousinvoker
• Asynchronousinvoker
12
Stringcity=client.target("http://locati.on/api").queryParam("city","Paris").request().get(String.class);
Future<String>fCity=client.target("http://locati.on/api").queryParam("city","Paris").request().async().get(String.class);
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPIAsynchronousinvoca.on
13
Future<String>fCity=client.target("http://locati.on/api")…
.request().async().get(String.class);Stringcity=future.get();
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPIAsynchronousinvoca.on
14
Future<String>fCity=client.target("http://locati.on/api")…
.request().async().get(String.class);
try{
Stringcity=future.get(4,TimeUnit.SECONDS);
}catch(TimeoutExceptiontimeout){…}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPIAsynchronousinvoca.on
15
Future<String>future=client.target("http://locati.on/api")…
.request().async().get(String.class);
while(!future.isDone()){//responsehasn'tbeenreceivedyet…}
Stringcity=f.get();…
//SetClientProperties.CONNECT_TIMEOUT&READ_TIMEOUT
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPI
• InvocaPonCallbackInterface– javax.ws.rs.client.InvocaPonCallback<RESPONSE>
• ContainerwillreceiveasynchronousprocessingeventsfromaninvocaPon– completed(RESPONSEresponse)– failed(Throwablethrowable)
16
Asynchronousinvoca.on
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPI
17
Invoca.onCallback…WebTargetmyResource=client.target("http://examp.le/api/read");Future<Customer>future=myResource.request(MediaType.TEXT_PLAIN).async().get(newInvocationCallback<Customer>(){
@Overridepublicvoidcompleted(Customercustomer){//dosomethingwiththegivencustomer}
@Overridepublicvoidfailed(Throwablethrowable){//Oops!}
});
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 18
TheTravelService
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService-Synchronous• Customerdetails:150ms• RecommendeddesPnaPons:250ms• PricecalculaPonforacustomeranddesPnaPon:170ms(each)• WeatherforecastforadesPnaPon:330ms(each)
19
5400ms
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService-Asynchronous
20
730ms
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 21
TheTravelService
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 22
TheTravelServicedestination.path("recommended").request().header("Rx-User","Async").async().get(newInvocationCallback<List<Destination>>(){@Overridepublicvoidcompleted(finalList<Destination>recommended){finalCountDownLatchinnerLatch=newCountDownLatch(recommended.size());finalMap<String,Forecast>forecasts=Collections.synchronizedMap(newHashMap<>());for(finalDestinationdest:recommended){forecast.resolveTemplate("dest",dest.getDestination()).request().async().get(newInvocationCallback<Forecast>(){@Overridepublicvoidcompleted(finalForecastforecast){forecasts.put(dest.getDestination(),forecast);innerLatch.countDown();}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 23
JAX-RS2.0
@Overridepublicvoidfailed(finalThrowablethrowable){innerLatch.countDown();}});}
try{if(!innerLatch.await(10,TimeUnit.SECONDS)){//timeout}}catch(finalInterruptedExceptione){//Ooops,interrupted!}
//Continuewithprocessing…}
@Overridepublicvoidfailed(finalThrowablethrowable){//Recommendationerror}});
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 24
JAX-RS2.1
//JAX-RS2.1CompletionStage<Response>csResponse=ClientBuilder.newClient().target("http://example.com/api").request().rx().get();
Future<Response>fResponse=ClientBuilder.newClient().target("http://example.com/api").request().async().get();
Responseresponse=ClientBuilder.newClient().target("http://example.com/api").request().get();
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
ComplePonStageinterface
• “AstageofapossiblyasynchronouscomputaPon,thatperformsanac.onorcomputesavalue”• “Ontermina.onastagemayinturntriggerotherdependentstages.”• StageexecuPontriggeredbycomplePonof– “then”-asinglestage– “combine”-bothoftwostages– “either”-eitheroftwostages
25
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
ComplePonStageinterface
• ComputaPontakesanargumentandreturnsaresult?– “apply”–Func.ontakeresultofthepreviousstageasargument,returnaresult– “accept”–Consumeronlytakeanargument– “run”–Runnablenoargumentanddoesn’treturnaresult
• HowtheexecuPonofthecomputaPonisarranged?– Doesn'tendwith“async”–executeusingthestage’sdefaultexecuPonfacility– Endwith“async”-usethestage’sdefaultasynchronousexecuPonfacility
• …
26
hsps://docs.oracle.com/javase/8/docs/api/java/uPl/concurrent/ComplePonStage.html
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 27
JAX-RS2.1
CompletionStage<Number>csPrice=client.target("price/{destination}").resolveTemplate("destination","Paris").request().rx().get(Number.class);CompletionStage<String>csForecast=client.target("forecast/{destination}").resolveTemplate("destination","Paris").request().rx().get(String.class);csPrice.thenCombine(csForecast,(price,forecast)->book(price,forecast));
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 28
DemoTheTravelService
hsps://github.com/jersey/jersey/tree/master/examples/rx-client-webapp
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPI
• RESTClientSidecontainer• Synchronousinvoker– Defaultinvoker-javax.ws.rs.client.SyncInvoker
• Asynchronousinvokers– async()invoker-javax.ws.rs.client.AsyncInvoker• Mightblock->InvocaPonCallback
– ReacPverx()invoker-javax.ws.rs.client.RxInvoker• NewinJAX-RS2.1!• ComplePonStageAPI+otherReacPvelibrary(opt.)
29
Summary
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
Server-sideREST
ConfidenPal–OracleInternal/Restricted/HighlyRestricted 30
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 31
Server-side@Path("/Item")publicclassItemResource{@Path("{id}")@Produces(MediaType.APPLICATION_XML)publicItemResourcegetItemResource(@PathParam("id")Stringid){returnItemResource.getInstance(id);}@POST@Consumes(MediaType.APPLICATION_XML)@Produces(MediaType.APPLICATION_XML)publicResponsecreateItem(@QueryParam("name")Stringname){//...returnResponse.status(Status.OK).entity(…).build();}}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 32
Server-sideAsync@Path("/Async")publicclassItemResource{
@GETpublicvoidheavyResource(@SuspendedAsyncResponsear){
mes.execute(newRunnable(){@Overridepublicvoidrun(){try{//longrunningcomputation...ar.resume(Response.ok(...).build());}catch(InterruptedExceptionex){//Ooops!}}});...
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
Server-sideAsync
• Providesmeansforasynchronousserversideresponseprocessing– Injectablevia@SuspendedOR– ResourcemethodcanreturnaComplePonStage<T>instance(newinJAX-RS2.1!)
• Boundtotherequest– Suspend– Resume– Configure– Cancel
33
AsyncResponseinterface
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
Server-sideAsync
34
Client Server
@Suspended
AsyncResponse.resume(…)
LongrunningoperaPon…
Request
Response
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
LongrunningRESToperaPons
è POST...longrunningoperaPon...ç ‘201Created’+LocaPon
35
è POSTç ‘202Accepted’+TempLocaPon
è GETTempLocaPonç ‘200OK’(+ETA)…è GETTempLocaPonç ‘303SeeOther’+FinalLocaPon
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
Server-sentEvents
• Persistent,one-waycommunicaPonchannel• Textprotocol,specialmediatype"text/event-stream"• ServercansendmulPplemessages(events)toaclient• Cancontainid,name,commentretryinterval• Supportedinallmodernbrowsers
36
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS2.1
37
SSE
• SseEvent– ID,Name,Comment,…
• OutboundSseEvent– Server-siderepresentaPonofaServer-sentevent– OutboundSseEvent.Builder()
• InboundSseEvent– Client-siderepresentaPonofaServer-sentevent
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS2.1
38
SSE–Serverside
• SseEventSink– OutboundServer-SentEventsstream– SseBroadcaster
@GET@Path("sse")@Produces(MediaType.SERVER_SENT_EVENTS)publicvoideventStream(@ContextSseEventSinkeventSink,@ContextSSEsse){...eventSink.send(sse.newEvent("anevent"));eventSink.send(sse.newEvent("anotherevent"));...eventSink.close();}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS2.1
39
SSE–Clientside
• SseEventSource– ClientforprocessingincomingServer-SentEvents
SseEventSourcees=SseEventSource.target(SSE_target).reconnectingEvery(5,SECONDS).build();es.register(System.out::println);//InboundSseEventconsumeres.register(...);//Throwableconsumeres.open();...es.close();
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
Wrap-up
ConfidenPal–OracleInternal/Restricted/HighlyRestricted 40
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS
• JavaAPIforRESTfulWebServices– JAX-RS2.0–JSR339(*)– JAX-RS2.1–JSR370
• StandardbasedRESTfulframework– Server-sideandclient-side– JavaSEandJavaEE– Jersey,JBossRESTEasy,Restlet,ApacheCXF,ApacheWink,IBMJAX-RS,…
41
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS–Client-side
• RESTClientSidecontainer• Invokers– Synchronous• javax.ws.rs.client.SyncInvoker• Default
– Asynchronous• javax.ws.rs.client.AsyncInvoker
– ReacPve• NewinJAX-RS2.1!• javax.ws.rs.client.AsyncInvoker
42
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS–Client-side
43
Sync Async RXPerformanceandscalability ✗✗ ✔ ✔Easytodevelopandmaintain ✔ ✗ ✔
…complexworkflow ✗ ✗ ✔…errorhandling ✗ ✗ ✔
LeveragenewJavaSEfeature ✗ ✗ ✔
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS–ReacPveClientAPI• JavaSE8ComplePonStage– Asmandatedbythespec.
• Jersey– RxJava-rx.Observable– RxJava2-io.reacPvex.Flowable– Guava-ListenableFuture
44
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS–Server-side
• AsyncResponse– ResumeexecuPononadifferentthread– @Suspended– ResourcemethodreturningaComplePonStage<T>instance
• LongrunningoperaPonpasern• Server-sentEvents
45
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JavaEE8
46
BeanValida.on
CDI2.0
JSON-B1.0
Security1.0
BeanValida.on2.0
JSF2.3
Servlet4.0
JSON-P1.1
JAX-RS2.1 ReacPveclientAPI,Server-sentevents,…
HTTP/2,serverpush,…
Java<->JSONbinding
UpdatestoJSONstandards,JSONCollectors,…
Asyncevent,eventpriority,SEsupport,…
EmbraceJavaSE8,newconstraints
ImprovedCDI,WebSocket,SE8integraPon,…
StandardizedIdenPtyStore,AuthenPcaPon,SecurityContext
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JavaEE8• Workinprogress– FinalRelease-Summer2017(plan)
• OpenSourceReferenceImplementaPons– hsps://github.com/jersey
– hsps://github.com/javaee
• Staytuned…– hsps://blogs.oracle.com/theaquarium/
47
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
תודה רבה.
ConfidenPal–OracleInternal/Restricted/HighlyRestricted 48
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
Resources
• JAX-RSspecificaPon– hsps://github.com/jax-rs/api
• Jersey–AsynchronousServicesandClients– hsps://jersey.java.net/documentaPon/latest/async.html#d0e8611– hsps://github.com/jersey/jersey/tree/master/examples/rx-client-webapp
• ComplePonStage– hsps://docs.oracle.com/javase/8/docs/api/java/uPl/concurrent/ComplePonStage.html
• JavaEETutorial– hsps://docs.oracle.com/javaee/7/tutorial/
49