| [//]: # " 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) |