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