Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSandCDIBikethe(ReacIve)BridgeCON2549
DavidDelabassée(@delabassee)-OracleJoséPaumard(@josepaumard)-ConsultantOctober,2017
2
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 3
@delabassee
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 4
@JosePaumard
@JosePaumard
https://github.com/JosePaumard
https://www.slideshare.net/jpaumard
https://www.youtube.com/user/JPaumard
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
SafeHarborStatementThefollowingisintendedtooutlineourgeneralproductdirecIon.ItisintendedforinformaIonpurposesonly,andmaynotbeincorporatedintoanycontract.Itisnotacommitmenttodeliveranymaterial,code,orfuncIonality,andshouldnotberelieduponinmakingpurchasingdecisions.Thedevelopment,release,andImingofanyfeaturesorfuncIonalitydescribedforOracle’sproductsremainsatthesolediscreIonofOracle.
5
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 6
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.| 7
reacIve
adjecIve|re·ac·Ive|\rē-ˈak-Iv\
1:of,relaIngto,ormarkedbyreacIonorreactance2a:readilyresponsivetoasImulus
h`ps://www.merriam-webster.com/dicIonary/reacIve
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS
8
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RS2.1
• JSR370– JavaEE8
• Async– NewReacIveClientAPI– Newmethodforpausingresquestprocessing,etc.
• Server-SentEventsupport• JSON-P&JSON-Bsupport• …
JavaAPIforRESTfulWebServices
9
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
//JAX-RS2.0Clientclient=ClientBuilder.newClient();WebTargettarget=client.target("http://weath.er/api").queryParam("city","Paris");Forecastforecast=target.request().get(Forecast.class);//…client.close();
JAX-RSClientAPI
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
JAX-RS2.0Invokers
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-RSClientAPIAsynchronousinvocaJon
13
Future<String>fCity=client.target("http://locati.on/api").queryParam("city","Paris").request().async().get(String.class);
Stringcity=fCity.get();
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPIAsynchronousinvocaJon
14
Future<String>fCity=client.target("http://locati.on/api").queryParam("city","Paris").request().async().get(String.class);try{
Stringcity=fCity.get(5,TimeUnit.SECONDS);
}catch(TimeoutExceptiontimeout){
//…
}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPIAsynchronousinvocaJon
15
//SetClientProperties.CONNECT_TIMEOUT&READ_TIMEOUTFuture<String>fCity=client.target("http://locati.on/api").queryParam("city","Paris").request().async().get(String.class);while(!fCity.isDone()){
//responsehasn'tbeenreceivedyet
}
Stringcity=fCity.get();
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPI
• InvocaIonCallbackInterface– javax.ws.rs.client.InvocationCallback<RESPONSE>
• ContainerwillreceiveasyncprocessingeventsfromaninvocaIon– completed(RESPONSEresponse)– failed(Throwablethrowable)
AsynchronousinvocaJon
16
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSClientAPI
WebTargetmyResource=client.target("http://examp.le/api/read");Future<Customer>future=myResource.request(MediaType.TEXT_PLAIN)
.async().get(newInvocationCallback<Customer>(){ @Override publicvoidcompleted(Customercustomer){ //dosomethingwiththecustomer } @Override publicvoidfailed(Throwablethrowable){ //Oops! }});
…
InvocaJonCallback
17
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService
18
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService
• Customerdetails:150ms• RecommendeddesInaIons:250ms• PricecalculaIonforacustomeranddesInaIon:170ms(each)• WeatherforecastforadesInaIon:330ms(each)
Synchronous
19
5400ms
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelServiceAsynchronous
20
730ms
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService
21
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService
22
destination.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.|
TheTravelService
23
//cont.@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.|
JAX-RSClientAPI
NewJAX-RSReacJveInvoker
24
//JAX-RS2.0Responseresponse=client.target(recommandationService).request().get();
Future<Response>futureResponse=client.target(recommandationService).request().async().get();//JAX-RS2.1CompletionStage<Response>completionStageResp=client.target(recommandationService).request().rx().get();
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
CompleIonStageAPI
• AmodelforaTask– ThatperformsanacIonandmayreturnavalue– Thatcanbetriggeredbyanothertask– Thatmaytriggeranothertask– Thatcanbeexecutedinadifferentthread
• ACompleJonStageisanelementofanasynchronouschain
25
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
CompleIonStagePipeline
26
CS1 CS21
CS22
CS31 CS41
CS32
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService
27
CompletionStage<JsonObject>queryForecastCS=client.target("forecast") .queryParam("format","json").request() .rx() .get(JsonObject.class);
Function<JsonObject,Forecast>unmarshallForecast=jsonObject->JsonBuilder.create().fromJson(jsonObject.toString(),Forecast.class);
Function<Destination,CompletionStage<Void>>populateWithForecast=destination->queryForecastCS.thenApply(unmarshallForecast).thenAccept(forecast->destination.setForecast(forecast));
Function<Destination,CompletionStage<Void>>populateWithQuotation=destination->queryQuotationCS.thenApply(unmarshallQuotation).thenAccept(quotation->destination.setQuotation(quotation));
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService
28
Function<Destination,CompletableFuture<Void>>populateDestination=destination->CompletableFuture.allOf(populateWithForecast.apply(destination).toCompletableFuture(),populateWithQuotation.apply(destination).toCompletableFuture()).toCompletableFuture();
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService
29
Function<Destination,CompletableFuture<Void>>populateDestination=destination->CompletableFuture.allOf(populateWithForecast.apply(destination).toCompletableFuture(),populateWithQuotation.apply(destination).toCompletableFuture()).toCompletableFuture();Function<List<Destination>,CompletableFuture<?>[]>populateDestinations=destinations->destinations.stream().map(populateDestination).toArray(CompletableFuture[]::new);
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService
30
@GETpublicvoidpopulateDestination(@SuspendedfinalAsyncResponseasyncResponse){CompletionStage<List<Destination>>destinationCS=client.target("destination") .queryParam("format","json").request() .rx()
.get(/*someJSONBcode*/);CompletionStage<List<Destination>>updatedDestinationsCS=destinationCS.thenCompose(CompletableFuture.allOf(populateDestinations));asyncResponse.resume(updatedDestinationsCS.toCompletableFuture().get());}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
TheTravelService
31
@GETpublicCompletionStage<Destination>populateDestination(){CompletionStage<List<Destination>>destinationCS=client.target("destination") .queryParam("format","json").request() .rx()
.get(/*someJSONBcode*/);CompletionStage<List<Destination>>updatedDestinationsCS=destinationCS.thenCompose(CompletableFuture.allOf(populateDestinations));returnupdatedDestinationsCS;}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
ExcepIonHandling
32
CS1 CS21
CS22
CS31 CS41
CS32
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
ExcepIonHandling
ReturnsanewCompleJonStage• ThatcompleteswhentheCScompletes• Eitherwiththesameresult(normalcompleIon)• OrwiththetransformedexcepIon
33
excepJonaly()
stage.exceptionaly(//Functionexception->doSomethingNotTooStupidWith(exception));
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
ExcepIonHandling
ReturnsanewCompleJonStage• ThatcompleteswhentheCScompletes• CallstheBiFuncJonwithanullasresultorexcepIon
34
handle()
stage.handle(//BiFunction(result,exception)->doSomethingWith(result,exception));
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
ExcepIonHandling
ReturnsanewCompleJonStage• WiththesameresultorexcepIonasthisstage• ThatexecutesthegivenacIonwhenthisstagecompletes
35
whenComplete()
stage.whenComplete(//BiConsumer+asyncversion(result,exception)->doSomethingWith(result,exception));
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
ExcepIonHandling
36
CompletionStage<Void>quotation=client.target("quotation").request().rx().get(JsonObject.class).thenApply(unmarshallQuotation).exceptionnaly(throwable->null).thenAccept(destination::setQuotation);
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
ExcepIonHandling
37
CompletionStage<Void>quotation=client.target("quotation").request().rx().get(JsonObject.class).thenApply(unmarshallQuotation).handle(((quotation,throwable)->{
if(throwable==null){ destination.setQuotation(quotation); }else{ //trytodosomethingsmartwiththeexception } }
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSReacIveExtensions
• SupportedonallHTTPMethodsoftheClientAPI– DELETE– GET– HEAD– OPTIONS– POST– PUT– TRACE
38
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JAX-RSReacIveExtensions
• ImplementaIonsMUSTsupportaninvokerforCompleJonStage• ImplementaIonsMAYsupportotherreacIveAPIs• Jersey
– CompleIonStageRxInvoker(Default)– RxListenableFutureInvoker–Guava
39
h`ps://github.com/jersey/jersey/tree/master/ext/rx
client.register(RxFlowableInvokerProvider.class);client.target(...)....rx(RxFlowableInvoker.class).get();
– RxObservableInvoker–RxJava– RxFlowableInvoker–RxJava2
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
CDI
40
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
CDI2.0
• JSR365– JavaEE8
• JavaSEfocus– ModularspecificaIon– CDIContainerbootstraping
• OberseversOrdering• AsynchronousEvents• …
ContextandDependencyInjecJon
41
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
AsynchronousEvents
42
//Producer@InjectEvent<Payload>event;
publicvoidaCriticalBusinessMethod(){
CompletionStage<Payload>cs=event.fireAsync(newPayload());}//ConsumerpublicvoidanOberser(@ObservesAsyncPayloadevent){//dosomethingwiththepayload}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
AsynchronousEvents
43
//Producer@InjectEvent<Payload>event;
publicvoidaCriticalBusinessMethod(){
CompletionStage<Payload>cs=event.fireAsync(newPayload(),executor);}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
AsynchronousEvents
44
//Producer@InjectEvent<Payload>event;
publicvoidaCriticalBusinessMethod(){
CompletionStage<Payload>cs=event.fireAsync(newPayload(),SwingUtilities::invokeLater);}
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
Wrap-up
45
Copyright©2017,Oracleand/oritsaffiliates.Allrightsreserved.|
JavaEE8–ModernizaIon&SimplificaIon
46
CDI2.0
JSON-B1.0(*)
Security1.0(*)
BeanValidaJon2.0
JSF2.3
Servlet4.0
JSON-P1.1
JAX-RS2.1 ReacIveClientAPI,Server-SentEvents,…
HTTP/2,ServerPush,…
Java<->JSONbinding
UpdatestoJSONstandards,JSONCollectors,…
AsyncEvent,Observersordering,SEsupport,…
EmbraceJavaSE8,newconstraints,…
ImprovedCDI,WebSocket,SE8integraIon,…
PortableIdenItyStore,AuthenIcaIon&SecurityContext