diff --git a/jersey-client-rx/pom.xml b/jersey-client-rx/pom.xml
new file mode 100644
index 0000000000..3857c16730
--- /dev/null
+++ b/jersey-client-rx/pom.xml
@@ -0,0 +1,30 @@
+
+
+ 4.0.0
+ com.baeldung.samples
+ jersey-client-rx
+ 1.0
+ jar
+
+
+ org.glassfish.jersey.core
+ jersey-client
+ 2.27
+
+
+ org.glassfish.jersey.ext.rx
+ jersey-rx-client-rxjava
+ 2.27
+
+
+ org.glassfish.jersey.ext.rx
+ jersey-rx-client-rxjava2
+ 2.27
+
+
+
+ UTF-8
+ 1.8
+ 1.8
+
+
\ No newline at end of file
diff --git a/jersey-client-rx/src/main/java/com/baeldung/samples/jerseyrx/ClientOrchestration.java b/jersey-client-rx/src/main/java/com/baeldung/samples/jerseyrx/ClientOrchestration.java
new file mode 100644
index 0000000000..4adf5e50b8
--- /dev/null
+++ b/jersey-client-rx/src/main/java/com/baeldung/samples/jerseyrx/ClientOrchestration.java
@@ -0,0 +1,203 @@
+package com.baeldung.samples.jerseyrx;
+
+import io.reactivex.Flowable;
+import io.reactivex.disposables.Disposable;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import org.glassfish.jersey.client.rx.rxjava.RxObservableInvokerProvider;
+import org.glassfish.jersey.client.rx.rxjava.RxObservableInvoker;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.InvocationCallback;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.GenericType;
+import org.glassfish.jersey.client.rx.rxjava2.RxFlowableInvoker;
+import org.glassfish.jersey.client.rx.rxjava2.RxFlowableInvokerProvider;
+import rx.Observable;
+
+/**
+ *
+ * @author baeldung
+ */
+public class ClientOrchestration {
+
+ Client client = ClientBuilder.newClient();
+ WebTarget userIdService = client.target("http:localhost:8080/serviceA/id?limit=10");
+ WebTarget nameService = client.target("http:localhost:8080/serviceA/{empId}/name");
+ WebTarget hashService = client.target("http:localhost:8080/serviceA/{comboIDandName}/address");
+
+ Logger logger = Logger.getLogger("ClientOrchestrator");
+
+ public static void main(String[] args) {
+ ClientOrchestration orchestrator = new ClientOrchestration();
+
+ orchestrator.callBackOrchestrate();
+ orchestrator.rxOrchestrate();
+ orchestrator.observableJavaOrchestrate();
+ orchestrator.flowableJavaOrchestrate();
+
+ }
+
+ public void callBackOrchestrate() {
+ logger.info("Orchestrating with the pyramid of doom");
+ userIdService.request()
+ .async()
+ .get(new InvocationCallback>() {
+ @Override
+ public void completed(List empIds) {
+ CountDownLatch completionTracker = new CountDownLatch(empIds.size()); //used to keep track of the progress of the subsequent calls
+ empIds.forEach((id) -> {
+ //for each employee ID, get the name
+ nameService.resolveTemplate("empId", id).request()
+ .async()
+ .get(new InvocationCallback() {
+ @Override
+ public void completed(String response) {
+ completionTracker.countDown();
+ hashService.request().async().get(new InvocationCallback() {
+ @Override
+ public void completed(String response) {
+ logger.log(Level.INFO, "The hash output {0}", response);
+ }
+
+ @Override
+ public void failed(Throwable throwable) {
+ completionTracker.countDown();
+ logger.log(Level.WARNING, "An error has occurred in the hashing request step {0}", throwable.getMessage());
+ }
+ });
+ }
+ @Override
+ public void failed(Throwable throwable) {
+ completionTracker.countDown();
+ logger.log(Level.WARNING, "An error has occurred in the username request step {0}", throwable.getMessage());
+ }
+ });
+ });
+
+ try {
+ if (!completionTracker.await(10, TimeUnit.SECONDS)) { //wait for inner requests to complete in 10 seconds
+ logger.warning("Some requests didn't complete within the timeout");
+ }
+ } catch (InterruptedException ex) {
+ Logger.getLogger(ClientOrchestration.class.getName()).log(Level.SEVERE, null, ex);
+ }
+
+ }
+
+ @Override
+ public void failed(Throwable throwable) {
+ //implement callback
+ }
+ });
+ }
+
+ public void rxOrchestrate() {
+ logger.info("Orchestrating with a CompletionStage");
+ CompletionStage> userIdStage = userIdService.request()
+ .rx()
+ .get(new GenericType>() {
+ })
+ .exceptionally((Throwable throwable) -> {
+ logger.warning("An error has occurred");
+ return null;
+ });
+
+ CompletionStage>> completedNameStage = userIdStage.thenApplyAsync(list -> list.stream().map((Long id) -> {
+ CompletionStage nameStage = nameService.resolveTemplate("empId", id).request().rx().get(String.class);
+ }).collect(Collectors.toList()));
+
+ userIdStage.thenAcceptAsync(listOfIds -> {
+ listOfIds.stream().map((Long id) -> {
+ CompletableFuture completable = nameService.resolveTemplate("empId", id)
+ .request()
+ .rx()
+ .get(String.class)
+ .toCompletableFuture();
+
+ completable.thenAccept((String userName) -> {
+ hashService.resolveTemplate("comboIDandName", userName + id)
+ .request()
+ .rx()
+ .get(String.class)
+ .toCompletableFuture()
+ .thenAcceptAsync(hashValue -> logger.log(Level.INFO, "The hash output {0}", hashValue))
+ .exceptionally((Throwable throwable) -> {
+ logger.log(Level.WARNING, "Hash computation failed for {0}", id);
+ return null;
+ });
+
+ });
+
+ });
+ });
+
+ }
+
+ public void observableJavaOrchestrate() {
+
+ logger.info("Orchestrating with Observables");
+
+ client.register(RxObservableInvokerProvider.class);
+
+ Observable> userIdObservable = userIdService.request()
+ .rx(RxObservableInvoker.class)
+ .get(new GenericType>() {
+ });
+
+ userIdObservable.subscribe((List listOfIds) -> {
+ Observable.from(listOfIds).map(id
+ -> nameService.resolveTemplate("empId", id)
+ .request()
+ .rx(RxObservableInvoker.class)
+ .get(String.class)
+ .asObservable() //gotten the name for the given empId
+ .doOnError(throwable -> logger.log(Level.WARNING, "An error has occurred in the username request step {0}", throwable.getMessage()))
+ .subscribe(userName -> hashService.resolveTemplate("comboIDandName", userName + id)
+ .request()
+ .rx(RxObservableInvoker.class)
+ .get(String.class)
+ .asObservable() //gotten the hash value for empId+username
+ .doOnError(throwable -> logger.log(Level.WARNING, "An error has occurred in the hashing request step {0}", throwable.getMessage()))
+ .subscribe(hashValue -> logger.log(Level.INFO, "The hash output {0}", hashValue))));
+ });
+
+ }
+
+ public void flowableJavaOrchestrate() {
+
+ logger.info("Orchestrating with Flowable");
+
+ client.register(RxFlowableInvokerProvider.class);
+
+ Flowable> userIdObservable = userIdService.request()
+ .rx(RxFlowableInvoker.class)
+ .get(new GenericType>() {
+ });
+
+ Disposable subscribe = userIdObservable.subscribe((List listOfIds) -> {
+ Observable.from(listOfIds).map(id
+ -> nameService.resolveTemplate("empId", id)
+ .request()
+ .rx(RxObservableInvoker.class)
+ .get(String.class)
+ .asObservable() //gotten the name for the given empId
+ .doOnError(throwable -> logger.log(Level.WARNING, "An error has occurred in the username request step {0}", throwable.getMessage()))
+ .subscribe(userName -> hashService.resolveTemplate("comboIDandName", userName + id)
+ .request()
+ .rx(RxObservableInvoker.class)
+ .get(String.class)
+ .asObservable() //gotten the hash value for empId+username
+ .doOnError(throwable -> logger.warning("An error has occurred in the hashing request step " + throwable.getMessage()))
+ .subscribe(hashValue -> logger.log(Level.INFO, "The hash output {0}", hashValue))));
+ });
+
+ }
+
+}