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;