2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
20 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 package org.onap.aai.util.swagger;
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;
32 import java.util.stream.Collectors;
34 public class GenerateSwagger {
36 public static final String LINE_SEPARATOR = System.getProperty("line.separator");
37 public static final String DEFAULT_WIKI = "";
39 public static final String DEFAULT_SCHEMA_DIR = "../aai-schema";
40 public static final String CURRENT_VERSION = "v11";
42 public static void main(String[] args) throws IOException, TemplateException {
44 String schemaDir = System.getProperty("aai.schema.dir");
45 String versionToGenerate = System.getProperty("aai.generate.version");
46 String wikiLink = System.getProperty("aai.wiki.link");
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;
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;
59 System.out.println("Warning: aai.wiki.link property is not set so using default");
60 wikiLink = DEFAULT_WIKI;
63 String yamlFile = schemaDir + "/src/main/resources/aai_swagger_yaml/aai_swagger_" + versionToGenerate + ".yaml";
64 File swaggerYamlFile = new File(yamlFile);
66 if(!swaggerYamlFile.exists()){
67 System.err.println("Unable to find the swagger yaml file: " + swaggerYamlFile);
71 Yaml yaml = new Yaml(new SafeConstructor());
72 Map<String, Object> swaggerMap = null;
74 try (BufferedReader reader = new BufferedReader(new FileReader(swaggerYamlFile))){
75 swaggerMap = (Map<String, Object>) yaml.load(reader);
76 } catch(IOException ex){
80 if(null == swaggerMap) {
81 throw new IOException();
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<>();
89 List<Api> apis = convertToApi(map);
90 apis.forEach((api) -> {
91 if(!tagMap.containsKey(api.getTag())){
92 List<Api> newApis = new ArrayList<>();
94 tagMap.put(api.getTag(), newApis);
96 tagMap.get(api.getTag()).add(api);
100 Map<String, List<Api>> sortedTagMap = new TreeMap<>(tagMap);
101 sortedTagMap.forEach((key, value) -> {
102 value.sort(Comparator.comparing(Api::getPath));
105 Map<String, Object> resultMap = new HashMap<>();
107 List<Definition> definitionList = convertToDefinition(schemaDefinitionmap);
109 definitionList = definitionList
110 .stream().sorted(Comparator.comparing(Definition::getDefinitionName)).collect(Collectors.toList());
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();
119 infoDescription = Arrays.stream(infoDescription.split("\n"))
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);
129 return String.format("%s<br/>", line);
132 .collect(Collectors.joining(LINE_SEPARATOR));
134 resultMap.put("description", infoDescription);
137 Configuration configuration = new Configuration();
138 configuration.setClassForTemplateLoading(Api.class, "/");
139 configuration.setDirectoryForTemplateLoading(new File("src/main/resources/"));
141 Template template = configuration.getTemplate("swagger.html.ftl");
143 String outputDirStr = schemaDir + "/src/main/resources/aai_swagger_html";
145 File outputDir = new File(outputDirStr);
147 if(!outputDir.exists()){
148 boolean resp = outputDir.mkdir();
150 System.err.println("Unable to create the directory: " + outputDirStr);
153 } else if(outputDir.isFile()){
154 System.err.println("Unable to create the directory: " + outputDirStr + " since a filename with that string exists");
158 Writer file = new FileWriter(new File(outputDirStr + "/aai_swagger_" + versionToGenerate + ".html"));
159 template.process(resultMap, file);
162 public static List<Api> convertToApi(Map<String, Object> pathMap){
165 throw new IllegalArgumentException();
167 List<Api> apis = new ArrayList<>();
169 pathMap.forEach( (pathKey, pathValue) -> {
172 Map<String, Object> httpVerbMap = (Map<String, Object>) pathValue;
173 List<Api.HttpVerb> httpVerbs = new ArrayList<>();
175 api.setPath(pathKey);
177 httpVerbMap.forEach((httpVerbKey, httpVerbValue) -> {
179 Api.HttpVerb httpVerb = new Api.HttpVerb();
181 Map<String, Object> httpVerbValueMap = (Map<String,Object>)httpVerbValue;
183 httpVerb.setType(httpVerbKey);
185 if(httpVerbValueMap.containsKey("tags")){
186 httpVerb.setTags((List<String>)httpVerbValueMap.get("tags"));
189 if(httpVerbValueMap.containsKey("summary")){
190 httpVerb.setSummary((String)httpVerbValueMap.get("summary"));
193 if(httpVerbValueMap.containsKey("operationId")){
194 httpVerb.setOperationId((String)httpVerbValueMap.get("operationId"));
197 if(httpVerbValueMap.containsKey("consumes")){
198 httpVerb.setConsumes((List<String>)httpVerbValueMap.get("consumes"));
199 if(httpVerb.getConsumes() != null){
200 httpVerb.setConsumerEnabled(true);
204 if(httpVerbValueMap.containsKey("produces")){
205 httpVerb.setProduces((List<String>)httpVerbValueMap.get("produces"));
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
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);
219 List<Map<String, Object>> requestBodyList = parameters
221 .filter((parameter) -> parameter.get("name").equals("body"))
222 .collect(Collectors.toList());
224 Map<String, Object> requestBody = null;
226 if(requestBodyList != null && requestBodyList.size() == 1){
227 requestBody = requestBodyList.get(0);
228 httpVerb.setBodyParametersEnabled(true);
229 httpVerb.setBodyParameters(requestBody);
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));
245 if(httpVerbValueMap.containsKey("responses")){
247 List<Api.HttpVerb.Response> responses = new ArrayList<Api.HttpVerb.Response>();
249 Map<String, Object> responsesMap = (Map<String, Object>) httpVerbValueMap.get("responses");
254 .filter((res) -> !"default".equalsIgnoreCase(res.getKey()))
255 .forEach((responseMap) -> {
257 Map<String, Object> responseValueMap = (Map<String, Object>)responseMap.getValue();
259 Api.HttpVerb.Response response = new Api.HttpVerb.Response();
261 response.setResponseCode(responseMap.getKey());
262 response.setDescription((String) responseValueMap.get("description"));
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));
277 responses.add(response);
281 httpVerb.setResponses(responses);
284 httpVerbs.add(httpVerb);
287 api.setHttpMethods(httpVerbs);
294 public static List<Definition> convertToDefinition(Map<String, Object> definitionMap) {
296 if(definitionMap == null)
297 throw new IllegalArgumentException();
299 List<Definition> defintionsList = new ArrayList<>();
303 .forEach((entry) -> {
305 Definition definition = new Definition();
306 String key = entry.getKey();
307 Map<String, Object> valueMap = (Map<String, Object>) entry.getValue();
309 definition.setDefinitionName(key);
311 if(valueMap.containsKey("description")){
312 String description = valueMap.get("description").toString();
313 description = formatDescription(description);
314 definition.setDefinitionDescription(description);
315 definition.setHasDescription(true);
318 List<Definition.Property> definitionProperties = new ArrayList<>();
320 List<String> requiredProperties = (valueMap.get("required") == null) ? new ArrayList<>() : (List<String>) valueMap.get("required");
322 Set<String> requiredPropsSet = requiredProperties.stream().collect(Collectors.toSet());
327 .filter( (e) -> "properties".equals(e.getKey()))
328 .forEach((propertyEntries) -> {
329 Map<String, Object> propertyRealEntries = (Map<String, Object>) propertyEntries.getValue();
332 .forEach((propertyEntry) -> {
333 Definition.Property definitionProperty = new Definition.Property();
334 String propertyKey = propertyEntry.getKey();
335 if(requiredPropsSet.contains(propertyKey)){
336 definitionProperty.setRequired(true);
338 definitionProperty.setPropertyName(propertyKey);
339 Map<String, Object> definitionPropertyMap = (Map<String, Object>) propertyEntry.getValue();
341 if(definitionPropertyMap.containsKey("description")){
342 definitionProperty.setPropertyDescription(definitionPropertyMap.get("description").toString());
343 definitionProperty.setHasPropertyDescription(true);
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());
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));
362 definitionProperty.setPropertyReference(refItem);
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));
373 definitionProperty.setPropertyReference(refItem);
377 definitionProperties.add(definitionProperty);
381 definition.setPropertyList(definitionProperties);
383 List<Definition.Property> schemaProperties = definitionProperties.
385 .filter((o) -> o.isHasPropertyReference())
386 .collect(Collectors.toList());
388 List<Definition.Property> regularProperties = definitionProperties.
390 .filter((o) -> !o.isHasPropertyReference())
391 .collect(Collectors.toList());
393 definition.setRegularPropertyList(regularProperties);
394 definition.setSchemaPropertyList(schemaProperties);
396 defintionsList.add(definition);
398 return defintionsList;
401 public static String formatDescription(String description){
403 description = Arrays.stream(description.split("\n"))
406 if(line.contains("######")){
407 line = line.replaceAll("#", "");
409 String headerId = line.toLowerCase().replaceAll("\\s", "-");
411 if(line.contains("Related Nodes")){
412 return String.format("<h6 id=\"%s\">%s</h6>%s<ul>", headerId, line, LINE_SEPARATOR);
414 return String.format("<h6 id=\"%s\">%s</h6>", headerId, line);
416 } else if(line.startsWith("-")){
417 line = line.replaceFirst("-", "");
419 return String.format("<li>%s</li>", line);
421 return String.format("<p>%s</p>", line);
424 .collect(Collectors.joining(LINE_SEPARATOR));
426 if(description.contains("<ul>")){
427 description = description + "</ul>";