678842734cb5ae2eee1484486bd9aaae831cad17
[JavaForFun] /
1 package de.spring.webservices.rest.controller;
2
3 import java.util.Map;
4 import java.util.concurrent.CompletableFuture;
5
6 import javax.inject.Inject;
7
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;
25
26 import de.spring.webservices.domain.Car;
27 import de.spring.webservices.rest.business.service.AwesomeBusinessLogic;
28
29 @RestController
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;
35
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 */
39     
40         /**
41          * 
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)
44          * 
45          */
46         
47         private final AwesomeBusinessLogic awesomeBusinessLogic;
48
49         @Inject
50     public DeferrableCarController(AwesomeBusinessLogic awesomeBusinessLogic) {
51                 this.awesomeBusinessLogic = awesomeBusinessLogic;
52         }
53
54         @RequestMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }, method = RequestMethod.GET)
55     @ResponseStatus(HttpStatus.OK)
56     public DeferredResult<Page<Car>> cars() {
57                 
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);
60         CompletableFuture
61                 .supplyAsync(() -> awesomeBusinessLogic.findAll(new PageRequest(PAGE, PAGE_SIZE)))
62                 .thenAcceptAsync(car -> deferredResult.setResult(car))
63                 .exceptionally(exception -> {
64                         LOGGER.error("findAll error: ", exception);
65                         
66                         // DO NOT FORGET THE EXCEPTIONS.
67                         // It will trigger the Spring Exception Handler as you know it :)
68                         deferredResult.setErrorResult(exception);
69                         
70                         return null;
71                 });
72         
73         return deferredResult;
74     }
75
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) {
82                 
83         if (specialHeader != null) {
84                 LOGGER.info("SPECIAL HEADER: " + specialHeader);
85         }
86          
87         if (params.get("mirror") != null) {
88                 LOGGER.info("MIRROR: " + params.get("mirror")); 
89         }
90         
91         if (params.get("window") != null) {
92                 LOGGER.info("WINDOW: " + params.get("window"));
93         }
94         
95         if (wheelParams != null) {
96                 for(String wheel : wheelParams) {
97                         LOGGER.info(wheel);
98                 }
99         }
100         
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);
103         CompletableFuture
104                 .supplyAsync(() -> awesomeBusinessLogic.findById(id))
105                 .thenAcceptAsync(car -> deferredResult.setResult(car))
106                 .exceptionally(exception -> {
107                         
108                         LOGGER.error("findById error: ", exception);
109                         
110                         // DO NOT FORGET THE EXCEPTIONS.
111                         // It will trigger the Spring Exception Handler as you know it :)
112                         deferredResult.setErrorResult(exception);
113                         
114                         return null;
115                 });
116         
117         return deferredResult;
118     }
119     
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) {
124         
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);
127         CompletableFuture
128                 .supplyAsync(() -> {
129                         Car createdCar = awesomeBusinessLogic.create(car);
130                         
131                         HttpHeaders headers = new HttpHeaders();
132                     headers.add(HttpHeaders.LOCATION, "/api/cars/" + createdCar.getId());
133                     return new ResponseEntity<>(createdCar, headers, HttpStatus.CREATED);
134                 })
135                 .thenAcceptAsync(response -> deferredResult.setResult(response))
136                 .exceptionally(exception -> {
137                         
138                         LOGGER.error("create error: ", exception);
139                         
140                         // DO NOT FORGET THE EXCEPTIONS.
141                         // It will trigger the Spring Exception Handler as you know it :)
142                         deferredResult.setErrorResult(exception);
143                         
144                         return null;
145                 });
146         
147                 return deferredResult;
148     }
149
150 }