Add RFC 8040 compliant error handler
[ccsdk/apps.git] / ms / sliboot / src / main / java / org / onap / ccsdk / apps / ms / sliboot / controllers / RestconfApiController.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - CCSDK
4  * ================================================================================
5  * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
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
21 package org.onap.ccsdk.apps.ms.sliboot.controllers;
22
23 import com.fasterxml.jackson.core.JsonProcessingException;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.google.gson.Gson;
26 import com.google.gson.JsonObject;
27 import org.onap.ccsdk.apps.ms.sliboot.swagger.ConfigApi;
28 import org.onap.ccsdk.apps.ms.sliboot.swagger.OperationalApi;
29 import org.onap.ccsdk.apps.ms.sliboot.swagger.OperationsApi;
30 import org.onap.ccsdk.apps.ms.sliboot.data.TestResultsOperationalRepository;
31 import org.onap.ccsdk.apps.ms.sliboot.swagger.model.*;
32 import org.onap.ccsdk.apps.services.RestApplicationException;
33 import org.onap.ccsdk.apps.services.RestException;
34 import org.onap.ccsdk.apps.services.RestProtocolException;
35 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
36 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
37 import org.onap.ccsdk.sli.core.sli.provider.base.SvcLogicServiceBase;
38 import org.onap.ccsdk.apps.ms.sliboot.data.TestResultConfig;
39 import org.onap.ccsdk.apps.ms.sliboot.data.TestResultsConfigRepository;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42 import org.springframework.beans.factory.annotation.Autowired;
43 import org.springframework.boot.autoconfigure.domain.EntityScan;
44 import org.springframework.context.annotation.ComponentScan;
45 import org.springframework.http.HttpStatus;
46 import org.springframework.http.ResponseEntity;
47 import org.springframework.stereotype.Controller;
48 import org.springframework.web.bind.annotation.RestController;
49
50 import javax.servlet.http.HttpServletRequest;
51 import javax.validation.Valid;
52 import java.util.*;
53
54 @javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2020-02-20T12:50:11.207-05:00")
55
56 @RestController
57 @ComponentScan(basePackages = {"org.onap.ccsdk.apps.ms.sliboot.*", "org.onap.ccsdk.apps.services"})
58 @EntityScan("org.onap.ccsdk.apps.ms.sliboot.*")
59 public class RestconfApiController implements ConfigApi, OperationalApi, OperationsApi {
60
61         private final ObjectMapper objectMapper;
62         private final HttpServletRequest request;
63
64     @Autowired
65     protected SvcLogicServiceBase svc;
66
67     @Autowired
68         private TestResultsConfigRepository testResultsConfigRepository;
69
70     @Autowired
71         private TestResultsOperationalRepository testResultsOperationalRepository;
72
73         private static final Logger log = LoggerFactory.getLogger(RestconfApiController.class);
74
75         @org.springframework.beans.factory.annotation.Autowired
76         public RestconfApiController(ObjectMapper objectMapper, HttpServletRequest request) {
77                 this.objectMapper = objectMapper;
78                 this.request = request;
79         }
80
81
82         @Override
83         public Optional<ObjectMapper> getObjectMapper() {
84                 return Optional.ofNullable(objectMapper);
85         }
86
87         @Override
88         public Optional<HttpServletRequest> getRequest() {
89                 return Optional.ofNullable(request);
90         }
91         @Override
92         public Optional<String> getAcceptHeader() {
93                 return ConfigApi.super.getAcceptHeader();
94         }
95
96         @Override
97         public ResponseEntity<SliApiHealthcheck> operationsSLIAPIhealthcheckPost() {
98
99                 SliApiResponseFields respFields = new SliApiResponseFields();
100                 HttpStatus httpStatus = HttpStatus.OK;
101
102                 try {
103                         log.info("Calling SLI-API:healthcheck DG");
104                         SvcLogicContext ctxIn = new SvcLogicContext();
105                         SvcLogicContext ctxOut = svc.execute("sli", "healthcheck", null, "sync", ctxIn);
106                         Properties respProps = ctxOut.toProperties();
107
108                         respFields.setAckFinalIndicator(respProps.getProperty("ack-final-indicator", "Y"));
109                         respFields.setResponseCode(respProps.getProperty("error-code", "200"));
110                         respFields.setResponseMessage(respProps.getProperty("error-message", "Success"));
111                         respFields.setContextMemoryJson(propsToJson(respProps, "context-memory"));
112
113                 } catch (Exception e) {
114                         respFields.setAckFinalIndicator("true");
115                         respFields.setResponseCode("500");
116                         respFields.setResponseMessage(e.getMessage());
117                         httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
118                         log.error("Error calling healthcheck directed graph", e);
119
120                 }
121
122                 SliApiHealthcheck resp = new SliApiHealthcheck();
123                 resp.setOutput(respFields);
124                 return (new ResponseEntity<>(resp, httpStatus));
125         }
126
127         @Override
128         public ResponseEntity<SliApiVlbcheck> operationsSLIAPIvlbcheckPost() {
129
130                 SliApiResponseFields respFields = new SliApiResponseFields();
131                 HttpStatus httpStatus = HttpStatus.OK;
132
133                 try {
134                         log.info("Calling SLI-API:vlbcheck DG");
135                         SvcLogicContext ctxIn = new SvcLogicContext();
136                         SvcLogicContext ctxOut = svc.execute("sli", "vlbcheck", null, "sync", ctxIn);
137                         Properties respProps = ctxOut.toProperties();
138                         respFields.setAckFinalIndicator(respProps.getProperty("ack-final-indicator", "Y"));
139                         respFields.setResponseCode(respProps.getProperty("error-code", "200"));
140                         respFields.setResponseMessage(respProps.getProperty("error-message", "Success"));
141                         respFields.setContextMemoryJson(propsToJson(respProps, "context-memory"));
142
143                 } catch (Exception e) {
144                         respFields.setAckFinalIndicator("true");
145                         respFields.setResponseCode("500");
146                         respFields.setResponseMessage(e.getMessage());
147                         httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
148                         log.error("Error calling vlbcheck directed graph", e);
149
150                 }
151
152                 SliApiVlbcheck resp = new SliApiVlbcheck();
153                 resp.setOutput(respFields);
154                 return (new ResponseEntity<>(resp, httpStatus));
155         }
156
157         @Override
158         public ResponseEntity<SliApiExecuteGraph> operationsSLIAPIexecuteGraphPost(@Valid SliApiExecutegraphInputBodyparam executeGraphInput) {
159
160                 SvcLogicContext ctxIn = new SvcLogicContext();
161                 SliApiExecuteGraph resp = new SliApiExecuteGraph();
162                 SliApiResponseFields respFields = new SliApiResponseFields();
163                 String executeGraphInputJson = null;
164
165                 try {
166                          executeGraphInputJson = objectMapper.writeValueAsString(executeGraphInput);
167                          log.info("Input as JSON is "+executeGraphInputJson);
168                 } catch (JsonProcessingException e) {
169
170                         respFields.setAckFinalIndicator("true");
171                         respFields.setResponseCode("500");
172                         respFields.setResponseMessage(e.getMessage());
173                         log.error("Cannot create JSON from input object", e);
174                         resp.setOutput(respFields);
175                         return (new ResponseEntity<>(resp, HttpStatus.INTERNAL_SERVER_ERROR));
176
177                 }
178                 JsonObject jsonInput = new Gson().fromJson(executeGraphInputJson, JsonObject.class);
179                 JsonObject passthroughObj = jsonInput.get("input").getAsJsonObject();
180
181                 ctxIn.mergeJson("input", passthroughObj.toString());
182
183                 try {
184                         // Any of these can throw a nullpointer exception
185                         String calledModule = executeGraphInput.getInput().getModuleName();
186                         String calledRpc = executeGraphInput.getInput().getRpcName();
187                         String modeStr = executeGraphInput.getInput().getMode().toString();
188                         // execute should only throw a SvcLogicException
189                         SvcLogicContext ctxOut = svc.execute(calledModule, calledRpc, null, modeStr, ctxIn);
190                         Properties respProps = ctxOut.toProperties();
191
192                         respFields.setAckFinalIndicator(respProps.getProperty("ack-final-indicator", "Y"));
193                         respFields.setResponseCode(respProps.getProperty("error-code", "200"));
194                         respFields.setResponseMessage(respProps.getProperty("error-message", "SUCCESS"));
195                         respFields.setContextMemoryJson(propsToJson(respProps, "context-memory"));
196                         resp.setOutput(respFields);
197                         return (new ResponseEntity<>(resp, HttpStatus.valueOf(Integer.parseInt(respFields.getResponseCode()))));
198
199                 } catch (NullPointerException npe) {
200                         respFields.setAckFinalIndicator("true");
201                         respFields.setResponseCode("500");
202                         respFields.setResponseMessage("Check that you populated module, rpc and or mode correctly.");
203
204                         resp.setOutput(respFields);
205                         return (new ResponseEntity<>(resp, HttpStatus.INTERNAL_SERVER_ERROR));
206                 } catch (SvcLogicException e) {
207                         respFields.setAckFinalIndicator("true");
208                         respFields.setResponseCode("500");
209                         respFields.setResponseMessage(e.getMessage());
210                         resp.setOutput(respFields);
211                         return (new ResponseEntity<>(resp, HttpStatus.INTERNAL_SERVER_ERROR));
212                 }
213         }
214
215         @Override
216         public ResponseEntity<Void> configSLIAPItestResultsSLIAPItestResultTestIdentifierDelete(String testIdentifier) {
217
218                 List<TestResultConfig> testResultConfigs = testResultsConfigRepository.findByTestIdentifier(testIdentifier);
219
220                 if (testResultConfigs != null) {
221                         Iterator<TestResultConfig> testResultConfigIterator = testResultConfigs.iterator();
222                         while (testResultConfigIterator.hasNext()) {
223                                 testResultsConfigRepository.delete(testResultConfigIterator.next());
224                         }
225                 }
226
227                 return (new ResponseEntity<>(HttpStatus.OK));
228         }
229
230         @Override
231         public ResponseEntity<Void> configSLIAPItestResultsDelete() {
232
233                 testResultsConfigRepository.deleteAll();
234
235                 return (new ResponseEntity<>(HttpStatus.OK));
236         }
237
238         @Override
239         public ResponseEntity<SliApiTestResults> operationalSLIAPItestResultsGet() {
240
241                 SliApiTestResults results = new SliApiTestResults();
242
243                 testResultsOperationalRepository.findAll().forEach(testResult -> {
244                         SliApiTestresultsTestResult item = null;
245                         try {
246                                 item = objectMapper.readValue(testResult.getResults(), SliApiTestresultsTestResult.class);
247                                 results.addTestResultItem(item);
248                         } catch (JsonProcessingException e) {
249                                 log.error("Could not convert testResult", e);
250                         }
251                 });
252
253
254                 return new ResponseEntity<>(results, HttpStatus.OK);
255         }
256
257         @Override
258         public ResponseEntity<SliApiTestresultsTestResult> configSLIAPItestResultsSLIAPItestResultTestIdentifierGet(String testIdentifier) {
259
260                 List<TestResultConfig> testResultConfigs = testResultsConfigRepository.findByTestIdentifier(testIdentifier);
261
262                 if ((testResultConfigs == null) || (testResultConfigs.size() == 0)) {
263                         return new ResponseEntity<>(HttpStatus.NOT_FOUND);
264                 } else {
265                         TestResultConfig testResultConfig = testResultConfigs.get(0);
266                         SliApiTestresultsTestResult testResult = null;
267                         try {
268                                 testResult = objectMapper.readValue(testResultConfig.getResults(), SliApiTestresultsTestResult.class);
269                         } catch (JsonProcessingException e) {
270                                 log.error("Cannot convert test result", e);
271                                 return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
272                         }
273
274
275                         return new ResponseEntity<>(testResult, HttpStatus.OK);
276                 }
277         }
278
279         @Override
280         public ResponseEntity<SliApiTestResults> configSLIAPItestResultsGet() throws RestException {
281
282                 if(getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {
283                 } else {
284                         log.warn("ObjectMapper or HttpServletRequest not configured in default RestconfApi interface so no example is generated");
285                 }
286
287                 SliApiTestResults results = new SliApiTestResults();
288
289                 if (testResultsConfigRepository.count() == 0) {
290                         throw new RestApplicationException("data-missing", "Request could not be completed because the relevant data model content does not exist", 404);
291                 }
292
293                 testResultsConfigRepository.findAll().forEach(testResult -> {
294                         SliApiTestresultsTestResult item = null;
295                         try {
296                                 item = objectMapper.readValue(testResult.getResults(), SliApiTestresultsTestResult.class);
297                                 results.addTestResultItem(item);
298                         } catch (JsonProcessingException e) {
299                                 log.error("Could not convert testResult", e);
300                         }
301                 });
302
303
304                 return new ResponseEntity<>(results, HttpStatus.OK);
305         }
306
307         @Override
308         public ResponseEntity<Void> configSLIAPItestResultsSLIAPItestResultTestIdentifierPut(String testIdentifier, @Valid SliApiTestresultsTestResult testResult) {
309
310                 if(getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {
311                 } else {
312                         log.warn("ObjectMapper or HttpServletRequest not configured in default RestconfApi interface so no example is generated");
313                 }
314
315                 List<TestResultConfig> testResultConfigs = testResultsConfigRepository.findByTestIdentifier(testIdentifier);
316                 Iterator<TestResultConfig> testResultIter = testResultConfigs.iterator();
317                 while (testResultIter.hasNext()) {
318                         testResultsConfigRepository.delete(testResultIter.next());
319                 }
320
321                 TestResultConfig testResultConfig = null;
322                 try {
323                         testResultConfig = new TestResultConfig(testResult.getTestIdentifier(), objectMapper.writeValueAsString(testResult));
324                         testResultsConfigRepository.save(testResultConfig);
325                 } catch (JsonProcessingException e) {
326                         log.error("Could not save test result", e);
327                         return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
328                 }
329
330                 return new ResponseEntity<>(HttpStatus.OK);
331         }
332
333         @Override
334         public ResponseEntity<Void> configSLIAPItestResultsPost(@Valid SliApiTestResults testResults) {
335
336                 List<SliApiTestresultsTestResult> resultList = testResults.getTestResult();
337
338                 if (resultList == null) {
339                         log.error("Invalid input - no test results list");
340                         return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
341                 }
342                 Iterator<SliApiTestresultsTestResult> resultIterator = resultList.iterator();
343
344                 while (resultIterator.hasNext()) {
345                         SliApiTestresultsTestResult curResult = resultIterator.next();
346                         try {
347                                 testResultsConfigRepository.save(new TestResultConfig(curResult.getTestIdentifier(), objectMapper.writeValueAsString(curResult)));
348                         } catch (JsonProcessingException e) {
349                                 log.error("Could not save test result", e);
350                                 return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
351                         }
352                 }
353
354                 return new ResponseEntity<>(HttpStatus.OK);
355         }
356
357         @Override
358         public ResponseEntity<Void> configSLIAPItestResultsPut(@Valid SliApiTestResults testResults) {
359
360                 testResultsConfigRepository.deleteAll();
361
362                 List<SliApiTestresultsTestResult> resultList = testResults.getTestResult();
363
364                 Iterator<SliApiTestresultsTestResult> resultIterator = resultList.iterator();
365
366
367                 while (resultIterator.hasNext()) {
368                         SliApiTestresultsTestResult curResult = resultIterator.next();
369                         try {
370                                 testResultsConfigRepository.save(new TestResultConfig(curResult.getTestIdentifier(), objectMapper.writeValueAsString(curResult)));
371                         } catch (JsonProcessingException e) {
372                                 log.error("Could not save test result", e);
373                                 return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
374                         }
375                 }
376
377                 return new ResponseEntity<>(HttpStatus.OK);
378         }
379
380         public static String propsToJson(Properties props, String root)
381         {
382                 StringBuffer sbuff = new StringBuffer();
383
384                 sbuff.append("{ \""+root+"\" : { ");
385                 boolean needComma = false;
386                 for (Map.Entry<Object, Object> prop : props.entrySet()) {
387                         sbuff.append("\""+(String) prop.getKey()+"\" : \""+(String)prop.getValue()+"\"");
388                         if (needComma) {
389                                 sbuff.append(" , ");
390                         } else {
391                                 needComma = true;
392                         }
393                 }
394                 sbuff.append(" } }");
395
396                 return(sbuff.toString());
397         }
398
399 }