Fix Blocker and Critical Sonar issues/bugs.
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / util / swagger / GenerateSwagger.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.openecomp.aai
4  * ================================================================================
5  * Copyright (C) 2017 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.openecomp.aai.util.swagger;
22
23 import com.fasterxml.jackson.dataformat.yaml.snakeyaml.Yaml;
24 import com.fasterxml.jackson.dataformat.yaml.snakeyaml.constructor.SafeConstructor;
25 import freemarker.template.Configuration;
26 import freemarker.template.Template;
27 import freemarker.template.TemplateException;
28
29 import java.io.*;
30 import java.util.*;
31 import java.util.stream.Collectors;
32
33 public class GenerateSwagger {
34
35     public static final String LINE_SEPARATOR = System.getProperty("line.separator");
36     public static final String DEFAULT_WIKI = "";
37
38     public static final String DEFAULT_SCHEMA_DIR = "../aai-schema";
39     public static final String CURRENT_VERSION = "v11";
40
41     public static void main(String[] args) throws IOException, TemplateException {
42
43         String schemaDir         = System.getProperty("aai.schema.dir");
44         String versionToGenerate = System.getProperty("aai.generate.version");
45         String wikiLink = System.getProperty("aai.wiki.link");
46
47         if(schemaDir == null){
48             System.out.println("Warning: Schema directory is not set so using default schema dir: " + DEFAULT_SCHEMA_DIR);
49             schemaDir = DEFAULT_SCHEMA_DIR;
50         }
51
52         if(versionToGenerate == null){
53             System.out.println("Warning: Version to generate is not set so using default version: " + CURRENT_VERSION);
54             versionToGenerate = CURRENT_VERSION;
55         }
56
57         if(wikiLink == null){
58             System.out.println("Warning: aai.wiki.link property is not set so using default");
59             wikiLink = DEFAULT_WIKI;
60         }
61
62         String yamlFile = schemaDir + "/src/main/resources/aai_swagger_yaml/aai_swagger_" + versionToGenerate + ".yaml";
63         File swaggerYamlFile = new File(yamlFile);
64
65         if(!swaggerYamlFile.exists()){
66             System.err.println("Unable to find the swagger yaml file: " + swaggerYamlFile);
67             System.exit(1);
68         }
69
70         Yaml yaml = new Yaml(new SafeConstructor());
71         Map<String, Object> swaggerMap = null;
72
73         try (BufferedReader reader = new BufferedReader(new FileReader(swaggerYamlFile))){
74             swaggerMap = (Map<String, Object>) yaml.load(reader);
75         } catch(IOException ex){
76             ex.printStackTrace();
77         }
78
79         if(null == swaggerMap) {
80             throw new IOException();
81         }
82
83         Map<String, Object> map = (Map<String, Object>) swaggerMap.get("paths");
84         Map<String, Object> schemaDefinitionmap = (Map<String, Object>) swaggerMap.get("definitions");
85         Map<String, Object> infoMap = (Map<String, Object>) swaggerMap.get("info");
86         Map<String, List<Api>> tagMap = new LinkedHashMap<>();
87
88         List<Api> apis = convertToApi(map);
89         apis.forEach((api) -> {
90             if(!tagMap.containsKey(api.getTag())){
91                 List<Api> newApis = new ArrayList<>();
92                 newApis.add(api);
93                 tagMap.put(api.getTag(), newApis);
94             } else {
95                 tagMap.get(api.getTag()).add(api);
96             }
97         });
98
99         Map<String, List<Api>> sortedTagMap = new TreeMap<>(tagMap);
100         sortedTagMap.forEach((key, value) -> {
101             value.sort(Comparator.comparing(Api::getPath));
102         });
103
104         Map<String, Object> resultMap = new HashMap<>();
105
106         List<Definition> definitionList = convertToDefinition(schemaDefinitionmap);
107
108         definitionList = definitionList
109             .stream().sorted(Comparator.comparing(Definition::getDefinitionName)).collect(Collectors.toList());
110
111         resultMap.put("aaiApis", tagMap);
112         resultMap.put("sortedAaiApis", sortedTagMap);
113         resultMap.put("wikiLink", wikiLink);
114         resultMap.put("definitions", definitionList);
115         if (infoMap.containsKey("description")) {
116             String infoDescription = infoMap.get("description").toString();
117
118             infoDescription = Arrays.stream(infoDescription.split("\n"))
119                     .map(line -> {
120                         line = line.trim();
121                         String hyperLink = "";
122                         if(line.trim().contains("https://")){
123                             int startIndex = line.indexOf("https://");
124                             int endIndex = line.lastIndexOf("/");
125                             hyperLink = line.substring(startIndex, endIndex);
126                             return String.format("<a href=\"%s\">%s</a><br/>", hyperLink, line);
127                         }
128                         return String.format("%s<br/>", line);
129                     })
130
131                     .collect(Collectors.joining(LINE_SEPARATOR));
132
133             resultMap.put("description", infoDescription);
134         }
135
136         Configuration configuration = new Configuration();
137         configuration.setClassForTemplateLoading(Api.class, "/");
138         configuration.setDirectoryForTemplateLoading(new File("src/main/resources/"));
139
140         Template template = configuration.getTemplate("swagger.html.ftl");
141
142         String outputDirStr = schemaDir + "/src/main/resources/aai_swagger_html";
143
144         File outputDir = new File(outputDirStr);
145
146         if(!outputDir.exists()){
147             boolean resp = outputDir.mkdir();
148             if(!resp){
149                 System.err.println("Unable to create the directory: " + outputDirStr);
150                 System.exit(1);
151             }
152         } else if(outputDir.isFile()){
153             System.err.println("Unable to create the directory: " + outputDirStr + " since a filename with that string exists");
154             System.exit(1);
155         }
156
157         Writer file = new FileWriter(new File(outputDirStr +  "/aai_swagger_" + versionToGenerate + ".html"));
158         template.process(resultMap, file);
159     }
160
161     public static List<Api> convertToApi(Map<String, Object> pathMap){
162
163         if(pathMap == null)
164             throw new IllegalArgumentException();
165
166         List<Api> apis = new ArrayList<>();
167
168         pathMap.forEach( (pathKey, pathValue) -> {
169
170             Api api = new Api();
171             Map<String, Object> httpVerbMap = (Map<String, Object>) pathValue;
172             List<Api.HttpVerb> httpVerbs = new ArrayList<>();
173
174             api.setPath(pathKey);
175
176             httpVerbMap.forEach((httpVerbKey, httpVerbValue) -> {
177
178                 Api.HttpVerb httpVerb = new Api.HttpVerb();
179
180                 Map<String, Object> httpVerbValueMap = (Map<String,Object>)httpVerbValue;
181
182                 httpVerb.setType(httpVerbKey);
183
184                 if(httpVerbValueMap.containsKey("tags")){
185                     httpVerb.setTags((List<String>)httpVerbValueMap.get("tags"));
186                 }
187
188                 if(httpVerbValueMap.containsKey("summary")){
189                     httpVerb.setSummary((String)httpVerbValueMap.get("summary"));
190                 }
191
192                 if(httpVerbValueMap.containsKey("operationId")){
193                     httpVerb.setOperationId((String)httpVerbValueMap.get("operationId"));
194                 }
195
196                 if(httpVerbValueMap.containsKey("consumes")){
197                     httpVerb.setConsumes((List<String>)httpVerbValueMap.get("consumes"));
198                     if(httpVerb.getConsumes() != null){
199                         httpVerb.setConsumerEnabled(true);
200                     }
201                 }
202
203                 if(httpVerbValueMap.containsKey("produces")){
204                     httpVerb.setProduces((List<String>)httpVerbValueMap.get("produces"));
205                 }
206
207                 if(httpVerbValueMap.containsKey("parameters")){
208                     List<Map<String, Object>> parameters = (List<Map<String, Object>>) httpVerbValueMap.get("parameters");
209                     List<Map<String, Object>> requestParameters = parameters
210                             .stream()
211                             .filter((parameter) -> !parameter.get("name").equals("body"))
212                             .collect(Collectors.toList());
213                     httpVerb.setParameters(requestParameters);
214                     if(httpVerb.getParameters() != null){
215                         httpVerb.setParametersEnabled(true);
216                     }
217
218                     List<Map<String, Object>> requestBodyList = parameters
219                             .stream()
220                             .filter((parameter) -> parameter.get("name").equals("body"))
221                             .collect(Collectors.toList());
222
223                     Map<String, Object> requestBody = null;
224
225                     if(requestBodyList != null && requestBodyList.size() == 1){
226                         requestBody = requestBodyList.get(0);
227                         httpVerb.setBodyParametersEnabled(true);
228                         httpVerb.setBodyParameters(requestBody);
229
230                         if(requestBody != null && requestBody.containsKey("schema")){
231                             Map<String, Object> schemaMap = (Map<String, Object>)requestBody.get("schema");
232                             if(schemaMap != null && schemaMap.containsKey("$ref")){
233                                 String schemaLink = schemaMap.get("$ref").toString();
234                                 httpVerb.setSchemaLink(schemaLink);
235                                 int retCode = schemaLink.lastIndexOf('/');
236                                 if(retCode != -1 && retCode != schemaLink.length()){
237                                     httpVerb.setSchemaType(schemaLink.substring(retCode));
238                                 }
239                             }
240                         }
241                     }
242                 }
243
244                 if(httpVerbValueMap.containsKey("responses")){
245
246                     List<Api.HttpVerb.Response> responses = new ArrayList<Api.HttpVerb.Response>();
247
248                     Map<String, Object> responsesMap = (Map<String, Object>) httpVerbValueMap.get("responses");
249
250                     responsesMap
251                         .entrySet()
252                         .stream()
253                         .filter((res) -> !"default".equalsIgnoreCase(res.getKey()))
254                         .forEach((responseMap) -> {
255
256                             Map<String, Object> responseValueMap = (Map<String, Object>)responseMap.getValue();
257
258                             Api.HttpVerb.Response response = new Api.HttpVerb.Response();
259
260                             response.setResponseCode(responseMap.getKey());
261                             response.setDescription((String) responseValueMap.get("description"));
262
263                             if(responseValueMap != null && responseValueMap.containsKey("schema")){
264                                 Map<String, Object> schemaMap = (Map<String, Object>)responseValueMap.get("schema");
265                                 if(schemaMap != null && schemaMap.containsKey("$ref")){
266                                     String schemaLink = schemaMap.get("$ref").toString();
267                                     httpVerb.setHasReturnSchema(true);
268                                     httpVerb.setReturnSchemaLink(schemaLink);
269                                     int retCode = schemaLink.lastIndexOf('/');
270                                     if(retCode != -1 && retCode != schemaLink.length()){
271                                         httpVerb.setReturnSchemaObject(schemaLink.substring(retCode));
272                                     }
273                                 }
274                             }
275
276                             responses.add(response);
277                         }
278                     );
279
280                     httpVerb.setResponses(responses);
281                 }
282
283                 httpVerbs.add(httpVerb);
284             });
285
286             api.setHttpMethods(httpVerbs);
287             apis.add(api);
288         });
289
290         return apis;
291     }
292
293     public static List<Definition> convertToDefinition(Map<String, Object> definitionMap) {
294
295         if(definitionMap == null)
296             throw new IllegalArgumentException();
297
298         List<Definition> defintionsList = new ArrayList<>();
299
300         definitionMap
301             .entrySet()
302             .forEach((entry) -> {
303
304                 Definition definition = new Definition();
305                 String key = entry.getKey();
306                 Map<String, Object> valueMap = (Map<String, Object>) entry.getValue();
307
308                 definition.setDefinitionName(key);
309
310                 if(valueMap.containsKey("description")){
311                     String description = valueMap.get("description").toString();
312                     description = formatDescription(description);
313                     definition.setDefinitionDescription(description);
314                     definition.setHasDescription(true);
315                 }
316
317                 List<Definition.Property> definitionProperties = new ArrayList<>();
318
319                 List<String> requiredProperties = (valueMap.get("required") == null) ? new ArrayList<>() : (List<String>) valueMap.get("required");
320
321                 Set<String> requiredPropsSet = requiredProperties.stream().collect(Collectors.toSet());
322
323                 valueMap
324                     .entrySet()
325                     .stream()
326                     .filter( (e) -> "properties".equals(e.getKey()))
327                     .forEach((propertyEntries) -> {
328                         Map<String, Object> propertyRealEntries = (Map<String, Object>) propertyEntries.getValue();
329                         propertyRealEntries
330                             .entrySet()
331                             .forEach((propertyEntry) -> {
332                                 Definition.Property definitionProperty = new Definition.Property();
333                                 String propertyKey = propertyEntry.getKey();
334                                 if(requiredPropsSet.contains(propertyKey)){
335                                     definitionProperty.setRequired(true);
336                                 }
337                                 definitionProperty.setPropertyName(propertyKey);
338                                 Map<String, Object> definitionPropertyMap = (Map<String, Object>) propertyEntry.getValue();
339
340                                 if(definitionPropertyMap.containsKey("description")){
341                                     definitionProperty.setPropertyDescription(definitionPropertyMap.get("description").toString());
342                                     definitionProperty.setHasPropertyDescription(true);
343                                 }
344                                 if(definitionPropertyMap.containsKey("type")){
345                                     String type = definitionPropertyMap.get("type").toString();
346                                     definitionProperty.setPropertyType(type);
347                                     definitionProperty.setHasType(true);
348                                     if ("array".equals(type)) {
349                                         definitionProperty.setPropertyType("object[]");
350                                         if(!definitionPropertyMap.containsKey("items")){
351                                             throw new RuntimeException("Unable to find the property items even though the type is array for " + propertyEntry.getKey());
352                                         } else {
353                                             Map<String, Object> itemMap = (Map<String, Object>) definitionPropertyMap.get("items");
354                                             if(itemMap.containsKey("$ref")){
355                                                 definitionProperty.setHasPropertyReference(true);
356                                                 String refItem = itemMap.get("$ref").toString();
357                                                 int retCode = refItem.lastIndexOf('/');
358                                                 if(retCode != -1 && retCode != refItem.length()){
359                                                     definitionProperty.setPropertyReferenceObjectName(refItem.substring(retCode + 1));
360                                                 }
361                                                 definitionProperty.setPropertyReference(refItem);
362                                             }
363                                         }
364                                     } else {
365                                         if(definitionPropertyMap.containsKey("$ref")){
366                                             definitionProperty.setHasPropertyReference(true);
367                                             String refItem = definitionPropertyMap.get("$ref").toString();
368                                             int retCode = refItem.lastIndexOf('/');
369                                             if(retCode != -1 && retCode != refItem.length()){
370                                                 definitionProperty.setPropertyReferenceObjectName(refItem.substring(retCode + 1));
371                                             }
372                                             definitionProperty.setPropertyReference(refItem);
373                                         }
374                                     }
375                                 }
376                                 definitionProperties.add(definitionProperty);
377                             });
378                     });
379
380                 definition.setPropertyList(definitionProperties);
381
382                 List<Definition.Property> schemaProperties = definitionProperties.
383                         stream()
384                         .filter((o) -> o.isHasPropertyReference())
385                         .collect(Collectors.toList());
386
387                 List<Definition.Property> regularProperties = definitionProperties.
388                         stream()
389                         .filter((o) -> !o.isHasPropertyReference())
390                         .collect(Collectors.toList());
391
392                 definition.setRegularPropertyList(regularProperties);
393                 definition.setSchemaPropertyList(schemaProperties);
394
395                 defintionsList.add(definition);
396             });
397         return defintionsList;
398     }
399
400     public static String formatDescription(String description){
401
402         description = Arrays.stream(description.split("\n"))
403             .map((line) -> {
404                 line = line.trim();
405                 if(line.contains("######")){
406                     line = line.replaceAll("#", "");
407                     line = line.trim();
408                     String headerId = line.toLowerCase().replaceAll("\\s", "-");
409
410                     if(line.contains("Related Nodes")){
411                         return String.format("<h6 id=\"%s\">%s</h6>%s<ul>", headerId, line, LINE_SEPARATOR);
412                     } else {
413                         return String.format("<h6 id=\"%s\">%s</h6>", headerId, line);
414                     }
415                 } else if(line.startsWith("-")){
416                     line = line.replaceFirst("-", "");
417                     line = line.trim();
418                     return String.format("<li>%s</li>", line);
419                 } else {
420                     return String.format("<p>%s</p>", line);
421                 }
422             })
423             .collect(Collectors.joining(LINE_SEPARATOR));
424
425         if(description.contains("<ul>")){
426             description = description + "</ul>";
427         }
428
429         return description;
430     }
431
432 }