Release dashboard image at version 2.1.0
[portal/ric-dashboard.git] / dashboard / webapp-backend / src / main / java / org / oransc / ric / portal / dashboard / controller / CustomResponseEntityExceptionHandler.java
1 /*-
2  * ========================LICENSE_START=================================
3  * O-RAN-SC
4  * %%
5  * Copyright (C) 2019 AT&T Intellectual Property
6  * %%
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20 package org.oransc.ric.portal.dashboard.controller;
21
22 import java.lang.invoke.MethodHandles;
23
24 import org.oransc.ric.portal.dashboard.exception.InvalidArgumentException;
25 import org.oransc.ric.portal.dashboard.exception.StatsManagerException;
26 import org.oransc.ric.portal.dashboard.exception.UnknownInstanceException;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 import org.springframework.http.HttpStatus;
30 import org.springframework.http.ResponseEntity;
31 import org.springframework.web.bind.annotation.ControllerAdvice;
32 import org.springframework.web.bind.annotation.ExceptionHandler;
33 import org.springframework.web.client.HttpStatusCodeException;
34 import org.springframework.web.client.RestClientResponseException;
35 import org.springframework.web.context.request.WebRequest;
36 import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
37
38 /**
39  * Catches certain exceptions. This controller advice factors out try-catch
40  * blocks in many controller methods.
41  * 
42  * Also see:<br>
43  * https://www.baeldung.com/exception-handling-for-rest-with-spring
44  * https://www.springboottutorial.com/spring-boot-exception-handling-for-rest-services
45  */
46 @ControllerAdvice
47 public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
48
49         // Superclass has "logger" that is exposed here, so use a different name
50         private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
51
52         /**
53          * Generates a message with an upper limit on size.
54          * 
55          * @param t
56          *              Throwable
57          * @return Message
58          */
59         private String getShortExceptionMessage(Throwable t) {
60                 final int enough = 256;
61                 String exString = t.toString();
62                 return exString.length() > enough ? exString.substring(0, enough) : exString;
63         }
64
65         /**
66          * Logs the error and generates a JSON response when a REST controller method
67          * takes a RestClientResponseException. This is thrown by the Http client when a
68          * remote method returns a non-2xx code. All the controller methods are proxies
69          * in that they just forward the request along to a remote system, so if that
70          * remote system fails, return 502 plus some details about the failure, rather
71          * than the generic 500 that Spring-Boot will return on an uncaught exception.
72          * 
73          * Why 502? I quote: <blockquote>HTTP server received an invalid response from a
74          * server it consulted when acting as a proxy or gateway.</blockquote>
75          * 
76          * @param ex
77          *                    The exception
78          * 
79          * @param request
80          *                    The original request
81          * 
82          * @return A response entity with status code 502 and an unstructured message.
83          */
84         @ExceptionHandler({ RestClientResponseException.class })
85         public final ResponseEntity<String> handleRestClientResponse(Exception ex, WebRequest request) {
86                 // Capture the full stack trace in the log.
87                 if (log.isErrorEnabled())
88                         log.error("handleRestClientResponse: request " + request.getDescription(false), ex);
89                 if (ex instanceof HttpStatusCodeException) {
90                         HttpStatusCodeException hsce = (HttpStatusCodeException) ex;
91                         return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(hsce.getResponseBodyAsString());
92                 } else {
93                         return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(getShortExceptionMessage(ex));
94                 }
95         }
96
97         /**
98          * Logs the error and generates a response when a REST controller method takes
99          * an UnknownInstanceException, an invalid RIC instance key was used.
100          * 
101          * @param ex
102          *                    The exception
103          * @param request
104          *                    The original request
105          * @return A response entity with status code 400 and an unstructured message.
106          */
107         @ExceptionHandler({ UnknownInstanceException.class })
108         public final ResponseEntity<String> handleUnknownInstance(Exception ex, WebRequest request) {
109                 log.warn("handleUnknownInstance: request {}, exception {}", request.getDescription(false), ex.toString());
110                 return ResponseEntity.badRequest().body(getShortExceptionMessage(ex));
111         }
112
113         /**
114          * Logs the error and generates a response when a REST controller method takes
115          * an InvalidArgumentException, an invalid JSON was sent.
116          * 
117          * @param ex
118          *                    The exception
119          * @param request
120          *                    The original request
121          * @return A response entity with status code 400 and an unstructured message.
122          */
123         @ExceptionHandler({ InvalidArgumentException.class })
124         public final ResponseEntity<String> handleInvalidArgument(Exception ex, WebRequest request) {
125                 log.warn("handleInvalidArgument: request {}, exception {}", request.getDescription(false), ex.toString());
126                 return ResponseEntity.badRequest().body(getShortExceptionMessage(ex));
127         }
128
129         /**
130          * Logs the error and generates a response when a REST controller method takes
131          * an StatsManagerException.
132          * 
133          * @param ex
134          *                    The exception
135          * @param request
136          *                    The original request
137          * @return A response entity with status code 400 and an unstructured message.
138          */
139         @ExceptionHandler({ StatsManagerException.class })
140         public final ResponseEntity<String> handleStatsManager(Exception ex, WebRequest request) {
141                 log.warn("handleStatsManager: request {}, exception {}", request.getDescription(false), ex.toString());
142                 return ResponseEntity.badRequest().body(getShortExceptionMessage(ex));
143         }
144
145 }