1 package de.spring.webservices.rest.controller;
 
   4 import java.util.concurrent.CompletableFuture;
 
   6 import javax.inject.Inject;
 
   8 import org.slf4j.Logger;
 
   9 import org.slf4j.LoggerFactory;
 
  10 import org.springframework.data.domain.Page;
 
  11 import org.springframework.data.domain.PageRequest;
 
  12 import org.springframework.http.HttpHeaders;
 
  13 import org.springframework.http.HttpStatus;
 
  14 import org.springframework.http.MediaType;
 
  15 import org.springframework.http.ResponseEntity;
 
  16 import org.springframework.web.bind.annotation.PathVariable;
 
  17 import org.springframework.web.bind.annotation.RequestBody;
 
  18 import org.springframework.web.bind.annotation.RequestHeader;
 
  19 import org.springframework.web.bind.annotation.RequestMapping;
 
  20 import org.springframework.web.bind.annotation.RequestMethod;
 
  21 import org.springframework.web.bind.annotation.RequestParam;
 
  22 import org.springframework.web.bind.annotation.ResponseStatus;
 
  23 import org.springframework.web.bind.annotation.RestController;
 
  24 import org.springframework.web.context.request.async.DeferredResult;
 
  26 import de.spring.webservices.domain.Car;
 
  27 import de.spring.webservices.rest.business.service.AwesomeBusinessLogic;
 
  30 @RequestMapping("/api/deferrable/cars/")
 
  31 public class DeferrableCarController {
 
  32         private static final Logger LOGGER = LoggerFactory.getLogger(DeferrableCarController.class);
 
  33         private static final int PAGE = 2;
 
  34         private static final int PAGE_SIZE = 10;
 
  36         // With no value, we depend on the Tomcat/Jboss/Jetty/etc timeout value for asynchronous requests.
 
  37         // Spring will answer after 60 secs with an empty response (by default) and HTTP 503 status (by default) when timeout.
 
  38         private static final long ASYNC_TIMEOUT = 60000;  /* milliseconds */
 
  42          * WHEN EXCEPTION IN setErrorResult, Spring WILL TRIGGER THE Spring Exception Handler AS YOU KNOW IT (I HOPE)
 
  43          * SO, YOU COULD HOOK UP THE HANDLER AND RETURN YOUR CUSTOM MESSAGESS (as usual)
 
  47         private final AwesomeBusinessLogic awesomeBusinessLogic;
 
  50     public DeferrableCarController(AwesomeBusinessLogic awesomeBusinessLogic) {
 
  51                 this.awesomeBusinessLogic = awesomeBusinessLogic;
 
  54         @RequestMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }, method = RequestMethod.GET)
 
  55     @ResponseStatus(HttpStatus.OK)
 
  56     public DeferredResult<Page<Car>> cars() {
 
  58         // THIS CODE (I GUESS) SHOULD BE LOCATED IN Service layer. Anyhow this is just an example.
 
  59         DeferredResult<Page<Car>> deferredResult = new DeferredResult<>(ASYNC_TIMEOUT);
 
  61                 .supplyAsync(() -> awesomeBusinessLogic.findAll(new PageRequest(PAGE, PAGE_SIZE)))
 
  62                 .thenAcceptAsync(car -> deferredResult.setResult(car))
 
  63                 .exceptionally(exception -> {
 
  64                         LOGGER.error("findAll error: ", exception);
 
  66                         // DO NOT FORGET THE EXCEPTIONS.
 
  67                         // It will trigger the Spring Exception Handler as you know it :)
 
  68                         deferredResult.setErrorResult(exception);
 
  73         return deferredResult;
 
  76     @RequestMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
 
  77     @ResponseStatus(HttpStatus.OK)
 
  78     public DeferredResult<Car> car(@RequestHeader(value = "MY_HEADER", required = false) String specialHeader,
 
  79                         @PathVariable("id") long id,
 
  80                         @RequestParam Map<String, String> params,
 
  81                         @RequestParam(value = "wheel", required = false) String[] wheelParams) {
 
  83         if (specialHeader != null) {
 
  84                 LOGGER.info("SPECIAL HEADER: " + specialHeader);
 
  87         if (params.get("mirror") != null) {
 
  88                 LOGGER.info("MIRROR: " + params.get("mirror")); 
 
  91         if (params.get("window") != null) {
 
  92                 LOGGER.info("WINDOW: " + params.get("window"));
 
  95         if (wheelParams != null) {
 
  96                 for(String wheel : wheelParams) {
 
 101         // THIS CODE (I GUESS) SHOULD BE LOCATED IN Service layer. Anyhow this is just an example.
 
 102         DeferredResult<Car> deferredResult = new DeferredResult<>(ASYNC_TIMEOUT);
 
 104                 .supplyAsync(() -> awesomeBusinessLogic.findById(id))
 
 105                 .thenAcceptAsync(car -> deferredResult.setResult(car))
 
 106                 .exceptionally(exception -> {
 
 108                         LOGGER.error("findById error: ", exception);
 
 110                         // DO NOT FORGET THE EXCEPTIONS.
 
 111                         // It will trigger the Spring Exception Handler as you know it :)
 
 112                         deferredResult.setErrorResult(exception);
 
 117         return deferredResult;
 
 120     @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
 
 121                 produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
 
 122         @ResponseStatus(HttpStatus.CREATED)
 
 123     public DeferredResult<ResponseEntity<Car>> create(@RequestBody Car car) {
 
 125         // THIS CODE (I GUESS) SHOULD BE LOCATED IN Service layer. Anyhow this is just an example.
 
 126         DeferredResult<ResponseEntity<Car>> deferredResult = new DeferredResult<>(ASYNC_TIMEOUT);
 
 129                         Car createdCar = awesomeBusinessLogic.create(car);
 
 131                         HttpHeaders headers = new HttpHeaders();
 
 132                     headers.add(HttpHeaders.LOCATION, "/api/cars/" + createdCar.getId());
 
 133                     return new ResponseEntity<>(createdCar, headers, HttpStatus.CREATED);
 
 135                 .thenAcceptAsync(response -> deferredResult.setResult(response))
 
 136                 .exceptionally(exception -> {
 
 138                         LOGGER.error("create error: ", exception);
 
 140                         // DO NOT FORGET THE EXCEPTIONS.
 
 141                         // It will trigger the Spring Exception Handler as you know it :)
 
 142                         deferredResult.setErrorResult(exception);
 
 147                 return deferredResult;