2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 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 package org.onap.aai.util.swagger;
22 import com.fasterxml.jackson.dataformat.yaml.snakeyaml.Yaml;
23 import com.fasterxml.jackson.dataformat.yaml.snakeyaml.constructor.SafeConstructor;
24 import freemarker.template.Configuration;
25 import freemarker.template.Template;
26 import freemarker.template.TemplateException;
28 import org.onap.aai.setup.SchemaVersions;
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 //if the program is run from aai-common, use this directory as default"
41 public static final String ALT_SCHEMA_DIR = "aai-schema";
42 //used to check to see if program is run from aai-core
43 public static final String DEFAULT_RUN_DIR = "aai-core";
45 public static SchemaVersions schemaVersions;
47 public SchemaVersions getSchemaVersions() {
48 return schemaVersions;
53 public static void main(String[] args) throws IOException, TemplateException {
58 // SchemaVersions schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
59 String CURRENT_VERSION = schemaVersions.getDefaultVersion().toString();
60 String schemaDir = System.getProperty("aai.schema.dir");
61 String versionToGenerate = System.getProperty("aai.generate.version");
62 String wikiLink = System.getProperty("aai.wiki.link");
63 String release = System.getProperty("aai.release", "onap");
65 if(schemaDir == null){
66 if(System.getProperty("user.dir") != null && !System.getProperty("user.dir").contains(DEFAULT_RUN_DIR)) {
67 System.out.println("Warning: Schema directory is not set so using default schema dir: " + ALT_SCHEMA_DIR);
68 schemaDir = ALT_SCHEMA_DIR;
71 System.out.println("Warning: Schema directory is not set so using default schema dir: " + DEFAULT_SCHEMA_DIR);
72 schemaDir = DEFAULT_SCHEMA_DIR;
76 if(versionToGenerate == null){
77 System.out.println("Warning: Version to generate is not set so using default versionToGenerate " + CURRENT_VERSION);
78 versionToGenerate = CURRENT_VERSION;
82 System.out.println("Warning: aai.wiki.link property is not set so using default");
83 wikiLink = DEFAULT_WIKI;
86 String yamlFile = schemaDir + "/src/main/resources/" + release + "/aai_swagger_yaml/aai_swagger_" + versionToGenerate + ".yaml";
87 File swaggerYamlFile = new File(yamlFile);
89 if(!swaggerYamlFile.exists()){
90 System.err.println("Unable to find the swagger yaml file: " + swaggerYamlFile);
94 Yaml yaml = new Yaml(new SafeConstructor());
95 Map<String, Object> swaggerMap = null;
97 try (BufferedReader reader = new BufferedReader(new FileReader(swaggerYamlFile))){
98 swaggerMap = (Map<String, Object>) yaml.load(reader);
99 } catch(Exception ex){
100 ex.printStackTrace();
103 if(null == swaggerMap) {
104 throw new IOException();
107 Map<String, Object> map = (Map<String, Object>) swaggerMap.get("paths");
108 Map<String, Object> schemaDefinitionmap = (Map<String, Object>) swaggerMap.get("definitions");
109 Map<String, Object> infoMap = (Map<String, Object>) swaggerMap.get("info");
110 Map<String, List<Api>> tagMap = new LinkedHashMap<>();
112 List<Api> apis = convertToApi(map);
113 apis.forEach((api) -> {
114 if(!tagMap.containsKey(api.getTag())){
115 List<Api> newApis = new ArrayList<>();
117 tagMap.put(api.getTag(), newApis);
119 tagMap.get(api.getTag()).add(api);
123 Map<String, List<Api>> sortedTagMap = new TreeMap<>(tagMap);
124 sortedTagMap.forEach((key, value) -> {
125 value.sort(Comparator.comparing(Api::getPath));
128 Map<String, Object> resultMap = new HashMap<>();
130 List<Definition> definitionList = convertToDefinition(schemaDefinitionmap);
132 definitionList = definitionList
133 .stream().sorted(Comparator.comparing(Definition::getDefinitionName)).collect(Collectors.toList());
135 resultMap.put("aaiApis", tagMap);
136 resultMap.put("sortedAaiApis", sortedTagMap);
137 resultMap.put("wikiLink", wikiLink);
138 resultMap.put("definitions", definitionList);
139 resultMap.put("version", versionToGenerate);
140 if (infoMap.containsKey("description")) {
141 String infoDescription = infoMap.get("description").toString();
143 infoDescription = Arrays.stream(infoDescription.split("\n"))
146 String hyperLink = "";
147 if(line.trim().contains("Differences versus")) {
148 return String.format("");
150 if(line.trim().contains("https://")){
151 int startIndex = line.indexOf("https://");
152 int endIndex = line.lastIndexOf("/");
153 hyperLink = line.substring(startIndex, endIndex);
154 return String.format("<a href=\"%s\">%s</a><br/>", hyperLink, line);
156 return String.format("%s<br/>", line);
159 .collect(Collectors.joining(LINE_SEPARATOR));
161 resultMap.put("description", infoDescription);
164 Configuration configuration = new Configuration();
165 configuration.setClassForTemplateLoading(Api.class, "/");
166 String resourcePath = "src/main/resources";
167 if(System.getProperty("user.dir") != null && !System.getProperty("user.dir").contains(DEFAULT_RUN_DIR)) {
168 configuration.setDirectoryForTemplateLoading(new File(DEFAULT_RUN_DIR + "/" + resourcePath));
171 configuration.setDirectoryForTemplateLoading(new File(resourcePath));
173 Template template = configuration.getTemplate("swagger.html.ftl");
175 String outputDirStr = schemaDir + "/src/main/resources/" + release + "/aai_swagger_html";
177 File outputDir = new File(outputDirStr);
179 if(!outputDir.exists()){
180 boolean resp = outputDir.mkdir();
182 System.err.println("Unable to create the directory: " + outputDirStr);
185 } else if(outputDir.isFile()){
186 System.err.println("Unable to create the directory: " + outputDirStr + " since a filename with that string exists");
190 Writer file = new FileWriter(new File(outputDirStr + "/aai_swagger_" + versionToGenerate + ".html"));
191 template.process(resultMap, file);
194 public static List<Api> convertToApi(Map<String, Object> pathMap){
197 throw new IllegalArgumentException();
199 List<Api> apis = new ArrayList<>();
201 pathMap.forEach( (pathKey, pathValue) -> {
204 Map<String, Object> httpVerbMap = (Map<String, Object>) pathValue;
205 List<Api.HttpVerb> httpVerbs = new ArrayList<>();
207 api.setPath(pathKey);
209 httpVerbMap.forEach((httpVerbKey, httpVerbValue) -> {
211 Api.HttpVerb httpVerb = new Api.HttpVerb();
213 Map<String, Object> httpVerbValueMap = (Map<String,Object>)httpVerbValue;
215 httpVerb.setType(httpVerbKey);
217 if(httpVerbValueMap.containsKey("tags")){
218 httpVerb.setTags((List<String>)httpVerbValueMap.get("tags"));
221 if(httpVerbValueMap.containsKey("summary")){
222 httpVerb.setSummary((String)httpVerbValueMap.get("summary"));
225 if(httpVerbValueMap.containsKey("operationId")){
226 httpVerb.setOperationId((String)httpVerbValueMap.get("operationId"));
229 if(httpVerbValueMap.containsKey("consumes")){
230 httpVerb.setConsumes((List<String>)httpVerbValueMap.get("consumes"));
231 if(httpVerb.getConsumes() != null){
232 httpVerb.setConsumerEnabled(true);
236 if(httpVerbValueMap.containsKey("produces")){
237 httpVerb.setProduces((List<String>)httpVerbValueMap.get("produces"));
240 if(httpVerbValueMap.containsKey("parameters")){
241 List<Map<String, Object>> parameters = (List<Map<String, Object>>) httpVerbValueMap.get("parameters");
242 List<Map<String, Object>> requestParameters = parameters
244 .filter((parameter) -> !parameter.get("name").equals("body"))
245 .collect(Collectors.toList());
246 httpVerb.setParameters(requestParameters);
247 if(httpVerb.getParameters() != null){
248 httpVerb.setParametersEnabled(true);
251 List<Map<String, Object>> requestBodyList = parameters
253 .filter((parameter) -> parameter.get("name").equals("body"))
254 .collect(Collectors.toList());
256 Map<String, Object> requestBody = null;
258 if(requestBodyList != null && requestBodyList.size() == 1){
259 requestBody = requestBodyList.get(0);
260 for(String key : requestBody.keySet()) {
261 //Filter out all the relationship links that appear in the YAML
262 if(key.equals("description")) {
263 String reqBody=(String)requestBody.get(key);
264 if(reqBody.replaceAll("\\[.*.json\\)", "") != reqBody) {
265 requestBody.put(key, reqBody.replaceAll("\\[.*.json\\)", ""));
268 //Filter out all the patchDefinition links that appear in the YAML
269 if(key.equals("schema")) {
270 LinkedHashMap<String,String> reqBody = (LinkedHashMap<String,String>)requestBody.get(key);
271 String schema=reqBody.get("$ref");
272 String schemaNopatch = schema.replace("patchDefinitions", "definitions");
274 if(! schema.equals(schemaNopatch)) {
275 reqBody.put("$ref", schemaNopatch);
276 requestBody.put(key, reqBody);
280 httpVerb.setBodyParametersEnabled(true);
281 httpVerb.setBodyParameters(requestBody);
283 if(requestBody != null && requestBody.containsKey("schema")){
284 Map<String, Object> schemaMap = (Map<String, Object>)requestBody.get("schema");
285 if(schemaMap != null && schemaMap.containsKey("$ref")){
286 String schemaLink = schemaMap.get("$ref").toString();
287 httpVerb.setSchemaLink(schemaLink);
288 int retCode = schemaLink.lastIndexOf('/');
289 if(retCode != -1 && retCode != schemaLink.length()){
290 httpVerb.setSchemaType(schemaLink.substring(retCode));
297 if(httpVerbValueMap.containsKey("responses")){
299 List<Api.HttpVerb.Response> responses = new ArrayList<Api.HttpVerb.Response>();
301 Map<String, Object> responsesMap = (Map<String, Object>) httpVerbValueMap.get("responses");
306 .filter((res) -> !"default".equalsIgnoreCase(res.getKey()))
307 .forEach((responseMap) -> {
309 Map<String, Object> responseValueMap = (Map<String, Object>)responseMap.getValue();
311 Api.HttpVerb.Response response = new Api.HttpVerb.Response();
313 response.setResponseCode(responseMap.getKey());
314 response.setDescription((String) responseValueMap.get("description"));
315 response.setVersion((String) responseValueMap.get("version"));
317 if(responseValueMap != null && responseValueMap.containsKey("schema")){
318 Map<String, Object> schemaMap = (Map<String, Object>)responseValueMap.get("schema");
319 if(schemaMap != null && schemaMap.containsKey("$ref")){
320 String schemaLink = schemaMap.get("$ref").toString();
321 httpVerb.setHasReturnSchema(true);
322 //Filter out all the getDefinition links that appear in the YAML
323 httpVerb.setReturnSchemaLink(schemaLink.replace("getDefinitions", "definitions"));
324 int retCode = schemaLink.lastIndexOf('/');
325 if(retCode != -1 && retCode != schemaLink.length()){
326 httpVerb.setReturnSchemaObject(schemaLink.substring(retCode));
331 responses.add(response);
335 httpVerb.setResponses(responses);
338 httpVerbs.add(httpVerb);
341 api.setHttpMethods(httpVerbs);
348 public static List<Definition> convertToDefinition(Map<String, Object> definitionMap) {
350 if(definitionMap == null)
351 throw new IllegalArgumentException();
353 List<Definition> defintionsList = new ArrayList<>();
357 .forEach((entry) -> {
359 Definition definition = new Definition();
360 String key = entry.getKey();
361 Map<String, Object> valueMap = (Map<String, Object>) entry.getValue();
363 definition.setDefinitionName(key);
365 if(valueMap.containsKey("description")){
366 String description = valueMap.get("description").toString();
367 description = formatDescription(description);
368 definition.setDefinitionDescription(description);
369 definition.setHasDescription(true);
372 List<Definition.Property> definitionProperties = new ArrayList<>();
374 List<String> requiredProperties = (valueMap.get("required") == null) ? new ArrayList<>() : (List<String>) valueMap.get("required");
376 Set<String> requiredPropsSet = requiredProperties.stream().collect(Collectors.toSet());
381 .filter( (e) -> "properties".equals(e.getKey()))
382 .forEach((propertyEntries) -> {
383 Map<String, Object> propertyRealEntries = (Map<String, Object>) propertyEntries.getValue();
386 .forEach((propertyEntry) -> {
387 Definition.Property definitionProperty = new Definition.Property();
388 String propertyKey = propertyEntry.getKey();
389 if(requiredPropsSet.contains(propertyKey)){
390 definitionProperty.setRequired(true);
392 definitionProperty.setPropertyName(propertyKey);
393 Map<String, Object> definitionPropertyMap = (Map<String, Object>) propertyEntry.getValue();
395 if(definitionPropertyMap.containsKey("description")){
396 definitionProperty.setPropertyDescription(definitionPropertyMap.get("description").toString());
397 definitionProperty.setHasPropertyDescription(true);
399 if(definitionPropertyMap.containsKey("type")){
400 String type = definitionPropertyMap.get("type").toString();
401 definitionProperty.setPropertyType(type);
402 definitionProperty.setHasType(true);
403 if ("array".equals(type)) {
404 definitionProperty.setPropertyType("object[]");
405 if(!definitionPropertyMap.containsKey("items")){
406 throw new RuntimeException("Unable to find the property items even though the type is array for " + propertyEntry.getKey());
408 Map<String, Object> itemMap = (Map<String, Object>) definitionPropertyMap.get("items");
409 if(itemMap.containsKey("$ref")){
410 definitionProperty.setHasPropertyReference(true);
411 String refItem = itemMap.get("$ref").toString();
412 int retCode = refItem.lastIndexOf('/');
413 if(retCode != -1 && retCode != refItem.length()){
414 definitionProperty.setPropertyReferenceObjectName(refItem.substring(retCode + 1));
416 definitionProperty.setPropertyReference(refItem);
420 if(definitionPropertyMap.containsKey("$ref")){
421 definitionProperty.setHasPropertyReference(true);
422 String refItem = definitionPropertyMap.get("$ref").toString();
423 int retCode = refItem.lastIndexOf('/');
424 if(retCode != -1 && retCode != refItem.length()){
425 definitionProperty.setPropertyReferenceObjectName(refItem.substring(retCode + 1));
427 definitionProperty.setPropertyReference(refItem);
431 definitionProperties.add(definitionProperty);
435 definition.setPropertyList(definitionProperties);
437 List<Definition.Property> schemaProperties = definitionProperties.
439 .filter((o) -> o.isHasPropertyReference())
440 .collect(Collectors.toList());
442 List<Definition.Property> regularProperties = definitionProperties.
444 .filter((o) -> !o.isHasPropertyReference())
445 .collect(Collectors.toList());
447 definition.setRegularPropertyList(regularProperties);
448 definition.setSchemaPropertyList(schemaProperties);
450 defintionsList.add(definition);
452 return defintionsList;
455 public static String formatDescription(String description){
457 description = Arrays.stream(description.split("\n"))
460 if(line.contains("######")){
461 line = line.replaceAll("#", "");
463 String headerId = line.toLowerCase().replaceAll("\\s", "-");
465 if(line.contains("Related Nodes")){
466 return String.format("<h6 id=\"%s\">%s</h6>%s<ul>", headerId, line, LINE_SEPARATOR);
468 return String.format("<h6 id=\"%s\">%s</h6>", headerId, line);
470 } else if(line.startsWith("-")){
471 line = line.replaceFirst("-", "");
473 return String.format("<li>%s</li>", line);
475 return String.format("<p>%s</p>", line);
478 .collect(Collectors.joining(LINE_SEPARATOR));
480 if(description.contains("<ul>")){
481 description = description + "</ul>";