| [//]: # " Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved. " |
| [//]: # " " |
| [//]: # " This program and the accompanying materials are made available under the " |
| [//]: # " terms of the Eclipse Distribution License v. 1.0, which is available at " |
| [//]: # " http://www.eclipse.org/org/documents/edl-v10.php. " |
| [//]: # " " |
| [//]: # " SPDX-License-Identifier: BSD-3-Clause " |
| |
| Reactive Clients Jersey Reactive Client Extensions Example |
| ========================================================== |
| |
| This example demonstrates how data from multiple resources and in |
| various formats (json, xml) can be combined into a form suitable to ones |
| requirements. The example show and compares usage of standard JAX-RS |
| sync client, JAX-RS async client, Jersey's Observable (RxJava) client |
| extension, Jersey's CompletionStage (Java 8) client extension and |
| Jersey's ListenableFuture (Guava) client extension. |
| |
| The application consists of two parts: |
| |
| - **"Remote"**, that can be considered to be deployed on a |
| remote machine. In fact each resource from |
| `org.glassfish.jersey.examples.rx.remote` package can be deployed on |
| a separate remote machine as every resource represents a service of |
| it's own. |
| |
| - **Note:** `DestinationResource` returns response entities as `JSON` |
| while `CalculationResource` and `ForecastResource` as `XML`. |
| |
| - **"Agent"**, which is a synchronization/orchestration layer. This |
| layer, also deployed as a server application, fetches data from all |
| needed resources (using JAX-RS Client API) and combine |
| them together. The combined result is then sent to the client that |
| invoked the original request on the orchestration layer. |
| |
| Every "agent" resource (package `org.glassfish.jersey.examples.rx.agent`) |
| invokes the following requests to the "remote" resource: |
| |
| - Obtain **visited** destinations for a user. (User identification is |
| propagated via request header and basically everything about a user |
| maximally simplified since it's out of scope of this example) |
| |
| - Obtain **recommended** destinations for a user. Requests obtaining |
| **visited** and **recommended** destinations are independent and can |
| be run in parallel. |
| |
| - Obtain weather **forecasts** for recommended destinations. New |
| client request is invoked for every recommended destination. |
| Obtaining weather **forecasts** depend on actual |
| **recommended** destinations. |
| |
| - Obtain trip **calculations** (prices) for recommended destinations. |
| New client request is invoked for every recommended destination. |
| Obtaining trip **calculations** depend on actual |
| **recommended** destinations. **forecast** and **calculation** |
| requests are independent on each other and can be invoked |
| in parallel. |
| |
| Contents |
| -------- |
| |
| > Please note that the example is not fully implemented right now. |
| > |
| > Available "agent" resources are _/rx/agent/sync_, _/rx/agent/async_ and _/rx/agent/completion_. |
| |
| The mapping of the URI path space is presented in the following table: |
| |
| URI path | Resource class | HTTP methods | Allowed values |
| -------------------------------------------------- | ------------------------------- | -------------- | ------------------------------------------------------------------------------ |
| **_/rx/agent/sync_** | SyncAgentResource | GET | returns JSON |
| **_/rx/agent/async_** | AsyncAgentResource | GET | returns JSON |
| **_/rx/agent/observable_** **(temporarily n/a)** | ObservableAgentResource | GET | returns JSON |
| **_/rx/agent/completion_** | CompletionStageAgentResource | GET | returns JSON |
| **_/rx/agent/listenable_** **(temporarily n/a)** | ListenableFutureAgentResource | GET | returns JSON |
| **_/rx/remote/destination/visited_** | DestinationResource | GET | returns JSON |
| **_/rx/remote/destination/recommended_** | DestinationResource | GET | returns JSON |
| **_/rx/remote/forecast/{destination}_** | ForecastResource | GET | destination - name of a country; returns XML (random value) |
| **_/rx/remote/calculation/from/{from}/to/{to}_** | CalculationResource | GET | from - name of a country, to - name of a country; returns XML (random value) |
| |
| Application is Servlet 3 based, web.xml-less. Everything needed (resources/providers) is registered in `RxApplication`. |
| |
| Sample Response |
| --------------- |
| |
| Agent responses look similar to the following one: |
| |
| ```javascript |
| { |
| "visited" : [ { |
| "destination" : "Antigua & Barbuda" |
| }, { |
| "destination" : "Guinea" |
| }, { |
| "destination" : "Malta" |
| }, { |
| "destination" : "Denmark" |
| }, { |
| "destination" : "Tajikistan" |
| } ], |
| "recommended" : [ { |
| "destination" : "Bolivia", |
| "forecast" : "Showers", |
| "price" : 1359 |
| }, { |
| "destination" : "Yemen", |
| "forecast" : "Haze", |
| "price" : 8032 |
| }, { |
| "destination" : "Dominican Republic", |
| "forecast" : "Cloudy", |
| "price" : 1141 |
| }, { |
| "destination" : "Korea South", |
| "forecast" : "Mostly Sunny", |
| "price" : 9853 |
| }, { |
| "destination" : "Saudi Arabia", |
| "forecast" : "Fog", |
| "price" : 9063 |
| } ], |
| "processingTime" : 877 |
| } |
| ``` |
| |
| As can be seen the response entity contains 3 main elements: **visited** |
| (list of visited destinations), **recommended** (list of recommended |
| destinations + weather forecast and price calculation) and |
| **processingTime** (describing how long it took to obtain previous two |
| elements). |
| |
| Running the Example |
| ------------------- |
| |
| Run the example as follows: |
| |
| > mvn clean package jetty:run |
| |
| This deploys current example using Jetty. You can access the application at: |
| |
| - <http://localhost:8080/rx/agent/sync> |
| - <http://localhost:8080/rx/agent/async> |
| - <http://localhost:8080/rx/agent/listenable> **(temporarily n/a)** |
| - <http://localhost:8080/rx/agent/observable> **(temporarily n/a)** |
| - <http://localhost:8080/rx/agent/completion> |
| |
| Resources |
| --------- |
| |
| This examples is using the following (3-rd party) libraries: |
| |
| **RxJava** by Netflix |
| - [GitHub](https://github.com/ReactiveX/RxJava) |
| - [GitHub.Wiki](https://github.com/ReactiveX/RxJava/wiki) |
| - [JavaDoc](http://reactivex.io/RxJava/javadoc/) |
| |
| **Guava** by Google |
| - [Homepage](https://code.google.com/p/guava-libraries/) |
| - [ListenableFuture |
| Explained](https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained) |
| - [JavaDoc](http://docs.guava-libraries.googlecode.com/git/javadoc/index.html?overview-summary.html) |