3092943cb9d560241d2a85a2016965b2bb3379ac
[JavaForFun] /
1 package de.spring.webservices.rest.controller;
2
3 import java.util.Map;
4 import java.util.concurrent.Callable;
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.WebAsyncTask;
25
26 import de.spring.webservices.domain.Car;
27 import de.spring.webservices.rest.business.service.AwesomeBusinessLogic;
28
29 @RestController
30 @RequestMapping("/api/callable/cars/")
31 public class CallableCarController {
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          * 
43          * WHEN EXCEPTION FROM CALLABLE, Spring WILL TRIGGER THE Spring Exception Handler AS YOU KNOW IT.
44          * See: https://spring.io/blog/2012/05/10/spring-mvc-3-2-preview-making-a-controller-method-asynchronous/
45          * 
46          * When an Exception is raised by a Callable, it is handled through the
47          * HandlerExceptionResolver mechanism just like exceptions raised by any
48          * other controller method. The more detailed explanation is that the
49          * exception is caught and saved, and the request is dispatched to the
50          * Servlet container where processing resumes and the
51          * HandlerExceptionResolver chain invoked. This also means
52          * that @ExceptionHandler methods will be invoked as usual.
53          * 
54          * 
55          * SO, YOU COULD HOOK UP THE HANDLER AND RETURN YOUR CUSTOM MESSAGESS (as
56          * usual)
57          * 
58          */
59         
60         
61         private final AwesomeBusinessLogic awesomeBusinessLogic;
62         
63         @Inject
64         public CallableCarController(AwesomeBusinessLogic awesomeBusinessLogic) {
65                 this.awesomeBusinessLogic = awesomeBusinessLogic;
66         }
67
68     @RequestMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }, method = RequestMethod.GET)
69     @ResponseStatus(HttpStatus.OK)
70     public Callable<Page<Car>> cars() {
71         
72         // Relying on the timeout given by Tomcat/Jboss/Jetty/etc. WebAsyncTask if you want to control your timeout (see below)
73         
74 //      return new Callable<Page<Car>>() {
75 //                      @Override
76 //                      public Page<Car> call() throws Exception {
77 //                              return awesomeBusinessLogic.findAll(new PageRequest(PAGE, PAGE_SIZE));
78 //                      }
79 //              };
80         
81         // lambda way :)
82         return () -> awesomeBusinessLogic.findAll(new PageRequest(PAGE, PAGE_SIZE));
83         
84     }
85
86     @RequestMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
87     @ResponseStatus(HttpStatus.OK)
88     public WebAsyncTask<Car> car(@RequestHeader(value = "MY_HEADER", required = false) String specialHeader,
89                 @PathVariable("id") long id,
90                 @RequestParam Map<String, String> params,
91                 @RequestParam(value = "wheel", required = false) String[] wheelParams) {
92                 
93         if (specialHeader != null) {
94                 LOGGER.info("SPECIAL HEADER: " + specialHeader);
95         }
96          
97         if (params.get("mirror") != null) {
98                 LOGGER.info("MIRROR: " + params.get("mirror")); 
99         }
100         
101         if (params.get("window") != null) {
102                 LOGGER.info("WINDOW: " + params.get("window"));
103         }
104         
105         if (wheelParams != null) {
106                 for(String wheel : wheelParams) {
107                         LOGGER.info(wheel);
108                 }
109         }
110         
111         
112         // If you want to control stuff like timeout you must use WebAsyncTask + Callable :)
113         
114 //      Callable<Car> callable = new Callable<Car>() {
115 //                      @Override
116 //                      public Car call() throws Exception {
117 //                              return awesomeBusinessLogic.findById(id);
118 //                      }
119 //              };
120 //              return new WebAsyncTask<>(ASYNC_TIMEOUT, callable);
121         
122         // lambda way :)
123         return new WebAsyncTask<>(ASYNC_TIMEOUT, () -> awesomeBusinessLogic.findById(id));
124     }
125     
126     @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
127                 produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
128         @ResponseStatus(HttpStatus.CREATED)
129     public WebAsyncTask<ResponseEntity<Car>> create(@RequestBody Car car) {
130
131         // If you want to control stuff like timeout you must use WebAsyncTask + Callable :)
132
133 //      Callable<ResponseEntity<Car>> callable = new Callable<ResponseEntity<Car>>() {
134 //                      @Override
135 //                      public ResponseEntity<Car> call() throws Exception {
136 //                              Car createdCar = awesomeBusinessLogic.create(car);
137 //                      
138 //                      HttpHeaders headers = new HttpHeaders();
139 //                      headers.add(HttpHeaders.LOCATION, "/api/cars/" + createdCar.getId());
140 //                      return new ResponseEntity<>(createdCar, headers, HttpStatus.CREATED);
141 //                      }
142 //              };
143                 
144         // lambda way
145                 Callable<ResponseEntity<Car>> callable = () -> {
146                         Car createdCar = awesomeBusinessLogic.create(car);
147                 
148                 HttpHeaders headers = new HttpHeaders();
149                 headers.add(HttpHeaders.LOCATION, "/api/cars/" + createdCar.getId());
150                 return new ResponseEntity<>(createdCar, headers, HttpStatus.CREATED);
151                 };
152                 
153                 return new WebAsyncTask<>(ASYNC_TIMEOUT, callable);
154     }
155
156 }