No repeat yourself :)
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Fri, 9 Dec 2016 23:50:14 +0000 (00:50 +0100)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Sat, 10 Dec 2016 00:00:18 +0000 (01:00 +0100)
Adapter for DeferredResult <-> CompletableFuture

SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/DeferrableCarController.java
SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/adapters/CompletableFutureAdapter.java [new file with mode: 0644]

index 6788427..ad92446 100644 (file)
@@ -25,6 +25,7 @@ import org.springframework.web.context.request.async.DeferredResult;
 
 import de.spring.webservices.domain.Car;
 import de.spring.webservices.rest.business.service.AwesomeBusinessLogic;
+import de.spring.webservices.rest.controller.adapters.CompletableFutureAdapter;
 
 @RestController
 @RequestMapping("/api/deferrable/cars/")
@@ -32,18 +33,7 @@ public class DeferrableCarController {
        private static final Logger LOGGER = LoggerFactory.getLogger(DeferrableCarController.class);
        private static final int PAGE = 2;
        private static final int PAGE_SIZE = 10;
-
-       // With no value, we depend on the Tomcat/Jboss/Jetty/etc timeout value for asynchronous requests.
-       // Spring will answer after 60 secs with an empty response (by default) and HTTP 503 status (by default) when timeout.
-       private static final long ASYNC_TIMEOUT = 60000;  /* milliseconds */
-    
-       /**
-        * 
-        * WHEN EXCEPTION IN setErrorResult, Spring WILL TRIGGER THE Spring Exception Handler AS YOU KNOW IT (I HOPE)
-        * SO, YOU COULD HOOK UP THE HANDLER AND RETURN YOUR CUSTOM MESSAGESS (as usual)
-        * 
-        */
-       
+       
        private final AwesomeBusinessLogic awesomeBusinessLogic;
 
        @Inject
@@ -54,23 +44,9 @@ public class DeferrableCarController {
        @RequestMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }, method = RequestMethod.GET)
     @ResponseStatus(HttpStatus.OK)
     public DeferredResult<Page<Car>> cars() {
-               
-       // THIS CODE (I GUESS) SHOULD BE LOCATED IN Service layer. Anyhow this is just an example.
-       DeferredResult<Page<Car>> deferredResult = new DeferredResult<>(ASYNC_TIMEOUT);
-       CompletableFuture
-               .supplyAsync(() -> awesomeBusinessLogic.findAll(new PageRequest(PAGE, PAGE_SIZE)))
-               .thenAcceptAsync(car -> deferredResult.setResult(car))
-               .exceptionally(exception -> {
-                       LOGGER.error("findAll error: ", exception);
-                       
-                       // DO NOT FORGET THE EXCEPTIONS.
-                       // It will trigger the Spring Exception Handler as you know it :)
-                       deferredResult.setErrorResult(exception);
-                       
-                       return null;
-               });
-       
-        return deferredResult;
+                       
+       return CompletableFutureAdapter.callAdapter(() ->
+               awesomeBusinessLogic.findAll(new PageRequest(PAGE, PAGE_SIZE)));
     }
 
     @RequestMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
@@ -97,54 +73,24 @@ public class DeferrableCarController {
                        LOGGER.info(wheel);
                }
        }
-       
-       // THIS CODE (I GUESS) SHOULD BE LOCATED IN Service layer. Anyhow this is just an example.
-       DeferredResult<Car> deferredResult = new DeferredResult<>(ASYNC_TIMEOUT);
-       CompletableFuture
-               .supplyAsync(() -> awesomeBusinessLogic.findById(id))
-               .thenAcceptAsync(car -> deferredResult.setResult(car))
-               .exceptionally(exception -> {
-                       
-                       LOGGER.error("findById error: ", exception);
-                       
-                       // DO NOT FORGET THE EXCEPTIONS.
-                       // It will trigger the Spring Exception Handler as you know it :)
-                       deferredResult.setErrorResult(exception);
-                       
-                       return null;
-               });
-       
-        return deferredResult;
+               
+       return CompletableFutureAdapter.callAdapter(() -> awesomeBusinessLogic.findById(id));
     }
     
     @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
                produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
        @ResponseStatus(HttpStatus.CREATED)
     public DeferredResult<ResponseEntity<Car>> create(@RequestBody Car car) {
-       
-       // THIS CODE (I GUESS) SHOULD BE LOCATED IN Service layer. Anyhow this is just an example.
-       DeferredResult<ResponseEntity<Car>> deferredResult = new DeferredResult<>(ASYNC_TIMEOUT);
-       CompletableFuture
-               .supplyAsync(() -> {
-                       Car createdCar = awesomeBusinessLogic.create(car);
-                       
-                       HttpHeaders headers = new HttpHeaders();
-                   headers.add(HttpHeaders.LOCATION, "/api/cars/" + createdCar.getId());
-                   return new ResponseEntity<>(createdCar, headers, HttpStatus.CREATED);
-               })
-               .thenAcceptAsync(response -> deferredResult.setResult(response))
-               .exceptionally(exception -> {
-                       
-                       LOGGER.error("create error: ", exception);
-                       
-                       // DO NOT FORGET THE EXCEPTIONS.
-                       // It will trigger the Spring Exception Handler as you know it :)
-                       deferredResult.setErrorResult(exception);
-                       
-                       return null;
-               });
-       
-               return deferredResult;
+               
+       return CompletableFutureAdapter.callAdapter(() -> createResponseCar(car));
     }
 
+    
+    private ResponseEntity<Car> createResponseCar(Car car) {
+               Car createdCar = awesomeBusinessLogic.create(car);
+               
+               HttpHeaders headers = new HttpHeaders();
+           headers.add(HttpHeaders.LOCATION, "/api/cars/" + createdCar.getId());
+           return new ResponseEntity<>(createdCar, headers, HttpStatus.CREATED);
+    }
 }
diff --git a/SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/adapters/CompletableFutureAdapter.java b/SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/adapters/CompletableFutureAdapter.java
new file mode 100644 (file)
index 0000000..094d5f0
--- /dev/null
@@ -0,0 +1,49 @@
+package de.spring.webservices.rest.controller.adapters;
+
+import java.util.concurrent.CompletableFuture;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.context.request.async.DeferredResult;
+
+public class CompletableFutureAdapter {
+       private static final Logger LOGGER = LoggerFactory.getLogger(CompletableFutureAdapter.class);
+
+       /**
+        * 
+        * WHEN EXCEPTION IN setErrorResult, Spring WILL TRIGGER THE Spring Exception Handler AS YOU KNOW IT (I HOPE)
+        * SO, YOU COULD HOOK UP THE HANDLER AND RETURN YOUR CUSTOM MESSAGESS (as usual)
+        * 
+        */
+       
+       // With no value, we depend on the Tomcat/Jboss/Jetty/etc timeout value for asynchronous requests.
+       // Spring will answer after 60 secs with an empty response (by default) and HTTP 503 status (by default) when timeout.
+       private static final long ASYNC_TIMEOUT = 60000;  /* milliseconds */
+
+       
+       @FunctionalInterface
+       public interface DeferredCall<T> {
+               
+               public T doCall();
+       }
+       
+       
+       public static final <T> DeferredResult<T> callAdapter(DeferredCall<T> deferredCall) {
+               
+       DeferredResult<T> deferredResult = new DeferredResult<>(ASYNC_TIMEOUT);
+       CompletableFuture
+               .supplyAsync(deferredCall::doCall)
+               .thenAcceptAsync(deferredResult::setResult)
+               .exceptionally(exception -> {
+                       
+                       LOGGER.error("findById error: ", exception);
+                       
+                       deferredResult.setErrorResult(exception);
+                       
+                       return null;
+               });
+       
+        return deferredResult; 
+       }
+       
+}