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.schemagen.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;
27 import org.onap.aai.setup.SchemaVersions;
31 import java.util.stream.Collectors;
33 public class GenerateSwagger {
35 public static final String LINE_SEPARATOR = System.getProperty("line.separator");
36 public static final String DEFAULT_WIKI = "";
38 public static final String DEFAULT_SCHEMA_DIR = "../aai-schema";
39 //if the program is run from aai-common, use this directory as default"
40 public static final String ALT_SCHEMA_DIR = "aai-schema";
41 //used to check to see if program is run from aai-schema-gen
42 public static final String DEFAULT_RUN_DIR = "aai-schema-gen";
44 public static SchemaVersions schemaVersions;
46 public SchemaVersions getSchemaVersions() {
47 return schemaVersions;
52 public static void main(String[] args) throws IOException, TemplateException {
57 // SchemaVersions schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
58 String CURRENT_VERSION = schemaVersions.getDefaultVersion().toString();
59 String schemaDir = System.getProperty("aai.schema.dir");
60 String versionToGenerate = System.getProperty("aai.generate.version");
61 String wikiLink = System.getProperty("aai.wiki.link");
62 String release = System.getProperty("aai.release", "onap");
64 if(schemaDir == null){
65 if(System.getProperty("user.dir") != null && !System.getProperty("user.dir").contains(DEFAULT_RUN_DIR)) {
66 System.out.println("Warning: Schema directory is not set so using default schema dir: " + ALT_SCHEMA_DIR);
67 schemaDir = ALT_SCHEMA_DIR;
70 System.out.println("Warning: Schema directory is not set so using default schema dir: " + DEFAULT_SCHEMA_DIR);
71 schemaDir = DEFAULT_SCHEMA_DIR;
75 if(versionToGenerate == null){
76 System.out.println("Warning: Version to generate is not set so using default versionToGenerate " + CURRENT_VERSION);
77 versionToGenerate = CURRENT_VERSION;
81 System.out.println("Warning: aai.wiki.link property is not set so using default");
82 wikiLink = DEFAULT_WIKI;
85 String yamlFile = schemaDir + "/src/main/resources/" + release + "/aai_swagger_yaml/aai_swagger_" + versionToGenerate + ".yaml";
86 File swaggerYamlFile = new File(yamlFile);
88 if(!swaggerYamlFile.exists()){
89 System.err.println("Unable to find the swagger yaml file: " + swaggerYamlFile);
93 Yaml yaml = new Yaml(new SafeConstructor());
94 Map<String, Object> swaggerMap = null;
96 try (BufferedReader reader = new BufferedReader(new FileReader(swaggerYamlFile))){
97 swaggerMap = (Map<String, Object>) yaml.load(reader);
98 } catch(Exception ex){
99 System.err.println("Unable load yaml file: " + swaggerYamlFile + " : " + ex.getMessage());
100 throw new IOException();
103 Map<String, Object> map = (Map<String, Object>) swaggerMap.get("paths");
104 Map<String, Object> schemaDefinitionmap = (Map<String, Object>) swaggerMap.get("definitions");
105 Map<String, Object> infoMap = (Map<String, Object>) swaggerMap.get("info");
106 Map<String, List<Api>> tagMap = new LinkedHashMap<>();
108 List<Api> apis = convertToApi(map);
109 apis.forEach((api) -> {
110 if(!tagMap.containsKey(api.getTag())){
111 List<Api> newApis = new ArrayList<>();
113 tagMap.put(api.getTag(), newApis);
115 tagMap.get(api.getTag()).add(api);
119 Map<String, List<Api>> sortedTagMap = new TreeMap<>(tagMap);
120 sortedTagMap.forEach((key, value) -> {
121 value.sort(Comparator.comparing(Api::getPath));
124 Map<String, Object> resultMap = new HashMap<>();
126 List<Definition> definitionList = convertToDefinition(schemaDefinitionmap);
128 definitionList = definitionList
129 .stream().sorted(Comparator.comparing(Definition::getDefinitionName)).collect(Collectors.toList());
131 resultMap.put("aaiApis", tagMap);
132 resultMap.put("sortedAaiApis", sortedTagMap);
133 resultMap.put("wikiLink", wikiLink);
134 resultMap.put("definitions", definitionList);
135 resultMap.put("version", versionToGenerate);
136 if (infoMap.containsKey("description")) {
137 String infoDescription = infoMap.get("description").toString();
139 infoDescription = Arrays.stream(infoDescription.split("\n"))
142 String hyperLink = "";
143 if(line.trim().contains("Differences versus")) {
146 if(line.trim().contains("https://")){
147 int startIndex = line.indexOf("https://");
148 int endIndex = line.lastIndexOf("/");
149 hyperLink = line.substring(startIndex, endIndex);
150 return String.format("<a href=\"%s\">%s</a><br/>", hyperLink, line);
152 return String.format("%s<br/>", line);
155 .collect(Collectors.joining(LINE_SEPARATOR));
157 resultMap.put("description", infoDescription);
160 Configuration configuration = new Configuration();
161 configuration.setClassForTemplateLoading(Api.class, "/");
162 String resourcePath = "src/main/resources";
163 if(System.getProperty("user.dir") != null && !System.getProperty("user.dir").contains(DEFAULT_RUN_DIR)) {
164 configuration.setDirectoryForTemplateLoading(new File(DEFAULT_RUN_DIR + "/" + resourcePath));
167 configuration.setDirectoryForTemplateLoading(new File(resourcePath));
169 Template template = configuration.getTemplate("swagger.html.ftl");
171 String outputDirStr = schemaDir + "/src/main/resources/" + release + "/aai_swagger_html";
173 File outputDir = new File(outputDirStr);
175 if(!outputDir.exists()){
176 boolean resp = outputDir.mkdir();
178 System.err.println("Unable to create the directory: " + outputDirStr);
181 } else if(outputDir.isFile()){
182 System.err.println("Unable to create the directory: " + outputDirStr + " since a filename with that string exists");
186 Writer file = new FileWriter(new File(outputDirStr + "/aai_swagger_" + versionToGenerate + ".html"));
187 template.process(resultMap, file);
190 public static List<Api> convertToApi(Map<String, Object> pathMap){
193 throw new IllegalArgumentException();
195 List<Api> apis = new ArrayList<>();
197 pathMap.forEach( (pathKey, pathValue) -> {
200 Map<String, Object> httpVerbMap = (Map<String, Object>) pathValue;
201 List<Api.HttpVerb> httpVerbs = new ArrayList<>();
203 api.setPath(pathKey);
205 httpVerbMap.forEach((httpVerbKey, httpVerbValue) -> {
207 Api.HttpVerb httpVerb = new Api.HttpVerb();
209 Map<String, Object> httpVerbValueMap = (Map<String,Object>)httpVerbValue;
211 httpVerb.setType(httpVerbKey);
213 if(httpVerbValueMap.containsKey("tags")){
214 httpVerb.setTags((List<String>)httpVerbValueMap.get("tags"));
217 if(httpVerbValueMap.containsKey("summary")){
218 httpVerb.setSummary((String)httpVerbValueMap.get("summary"));
221 if(httpVerbValueMap.containsKey("operationId")){
222 httpVerb.setOperationId((String)httpVerbValueMap.get("operationId"));
225 if(httpVerbValueMap.containsKey("consumes")){
226 httpVerb.setConsumes((List<String>)httpVerbValueMap.get("consumes"));
227 if(httpVerb.getConsumes() != null){
228 httpVerb.setConsumerEnabled(true);
232 if(httpVerbValueMap.containsKey("produces")){
233 httpVerb.setProduces((List<String>)httpVerbValueMap.get("produces"));
236 if(httpVerbValueMap.containsKey("parameters")){
237 List<Map<String, Object>> parameters = (List<Map<String, Object>>) httpVerbValueMap.get("parameters");
238 List<Map<String, Object>> requestParameters = parameters
240 .filter((parameter) -> !parameter.get("name").equals("body"))
241 .collect(Collectors.toList());
242 httpVerb.setParameters(requestParameters);
243 if(httpVerb.getParameters() != null){
244 httpVerb.setParametersEnabled(true);
247 List<Map<String, Object>> requestBodyList = parameters
249 .filter((parameter) -> parameter.get("name").equals("body"))
250 .collect(Collectors.toList());
252 Map<String, Object> requestBody = null;
254 if(requestBodyList != null && requestBodyList.size() == 1){
255 requestBody = requestBodyList.get(0);
256 for(String key : requestBody.keySet()) {
257 //Filter out all the relationship links that appear in the YAML
258 if(key.equals("description")) {
259 String reqBody=(String)requestBody.get(key);
260 if(!reqBody.replaceAll("\\[.*.json\\)", "").equals(reqBody)) {
261 requestBody.put(key, reqBody.replaceAll("\\[.*.json\\)", ""));
264 //Filter out all the patchDefinition links that appear in the YAML
265 if(key.equals("schema")) {
266 LinkedHashMap<String,String> reqBody = (LinkedHashMap<String,String>)requestBody.get(key);
267 String schema=reqBody.get("$ref");
268 String schemaNopatch = schema.replace("patchDefinitions", "definitions");
270 if(! schema.equals(schemaNopatch)) {
271 reqBody.put("$ref", schemaNopatch);
272 requestBody.put(key, reqBody);
276 httpVerb.setBodyParametersEnabled(true);
277 httpVerb.setBodyParameters(requestBody);
279 if(requestBody != null && requestBody.containsKey("schema")){
280 Map<String, Object> schemaMap = (Map<String, Object>)requestBody.get("schema");
281 if(schemaMap != null && schemaMap.containsKey("$ref")){
282 String schemaLink = schemaMap.get("$ref").toString();
283 httpVerb.setSchemaLink(schemaLink);
284 int retCode = schemaLink.lastIndexOf('/');
285 if(retCode != -1 && retCode != schemaLink.length()){
286 httpVerb.setSchemaType(schemaLink.substring(retCode));
293 if(httpVerbValueMap.containsKey("responses")){
295 List<Api.HttpVerb.Response> responses = new ArrayList<Api.HttpVerb.Response>();
297 Map<String, Object> responsesMap = (Map<String, Object>) httpVerbValueMap.get("responses");
302 .filter((res) -> !"default".equalsIgnoreCase(res.getKey()))
303 .forEach((responseMap) -> {
305 Map<String, Object> responseValueMap = (Map<String, Object>)responseMap.getValue();
307 Api.HttpVerb.Response response = new Api.HttpVerb.Response();
309 response.setResponseCode(responseMap.getKey());
310 response.setDescription((String) responseValueMap.get("description"));
311 response.setVersion((String) responseValueMap.get("version"));
313 if(responseValueMap != null && responseValueMap.containsKey("schema")){
314 Map<String, Object> schemaMap = (Map<String, Object>)responseValueMap.get("schema");
315 if(schemaMap != null && schemaMap.containsKey("$ref")){
316 String schemaLink = schemaMap.get("$ref").toString();
317 httpVerb.setHasReturnSchema(true);
318 //Filter out all the getDefinition links that appear in the YAML
319 httpVerb.setReturnSchemaLink(schemaLink.replace("getDefinitions", "definitions"));
320 int retCode = schemaLink.lastIndexOf('/');
321 if(retCode != -1 && retCode != schemaLink.length()){
322 httpVerb.setReturnSchemaObject(schemaLink.substring(retCode));
327 responses.add(response);
331 httpVerb.setResponses(responses);
334 httpVerbs.add(httpVerb);
337 api.setHttpMethods(httpVerbs);
344 public static List<Definition> convertToDefinition(Map<String, Object> definitionMap) {
346 if(definitionMap == null)
347 throw new IllegalArgumentException();
349 List<Definition> defintionsList = new ArrayList<>();
353 .forEach((entry) -> {
355 Definition definition = new Definition();
356 String key = entry.getKey();
357 Map<String, Object> valueMap = (Map<String, Object>) entry.getValue();
359 definition.setDefinitionName(key);
361 if(valueMap.containsKey("description")){
362 String description = valueMap.get("description").toString();
363 description = formatDescription(description);
364 definition.setDefinitionDescription(description);
365 definition.setHasDescription(true);
368 List<Definition.Property> definitionProperties = new ArrayList<>();
370 List<String> requiredProperties = (valueMap.get("required") == null) ? new ArrayList<>() : (List<String>) valueMap.get("required");
372 Set<String> requiredPropsSet = new HashSet<>(requiredProperties);
377 .filter( (e) -> "properties".equals(e.getKey()))
378 .forEach((propertyEntries) -> {
379 Map<String, Object> propertyRealEntries = (Map<String, Object>) propertyEntries.getValue();
381 .forEach((propertyKey, value) -> {
382 Definition.Property definitionProperty = new Definition.Property();
383 if (requiredPropsSet.contains(propertyKey)) {
384 definitionProperty.setRequired(true);
386 definitionProperty.setPropertyName(propertyKey);
387 Map<String, Object> definitionPropertyMap =
388 (Map<String, Object>) value;
390 if (definitionPropertyMap.containsKey("description")) {
391 definitionProperty.setPropertyDescription(
392 definitionPropertyMap.get("description").toString());
393 definitionProperty.setHasPropertyDescription(true);
395 if (definitionPropertyMap.containsKey("type")) {
396 String type = definitionPropertyMap.get("type").toString();
397 definitionProperty.setPropertyType(type);
398 definitionProperty.setHasType(true);
399 if ("array".equals(type)) {
400 definitionProperty.setPropertyType("object[]");
401 if (!definitionPropertyMap.containsKey("items")) {
402 throw new RuntimeException(
403 "Unable to find the property items even though the type is array for " +
406 Map<String, Object> itemMap =
407 (Map<String, Object>) definitionPropertyMap
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()) {
415 .setPropertyReferenceObjectName(
416 refItem.substring(retCode + 1));
418 definitionProperty.setPropertyReference(refItem);
422 if (definitionPropertyMap.containsKey("$ref")) {
423 definitionProperty.setHasPropertyReference(true);
425 definitionPropertyMap.get("$ref").toString();
426 int retCode = refItem.lastIndexOf('/');
427 if (retCode != -1 && retCode != refItem.length()) {
428 definitionProperty.setPropertyReferenceObjectName(
429 refItem.substring(retCode + 1));
431 definitionProperty.setPropertyReference(refItem);
435 definitionProperties.add(definitionProperty);
439 definition.setPropertyList(definitionProperties);
441 List<Definition.Property> schemaProperties = definitionProperties.
443 .filter(Definition.Property::isHasPropertyReference)
444 .collect(Collectors.toList());
446 List<Definition.Property> regularProperties = definitionProperties.
448 .filter((o) -> !o.isHasPropertyReference())
449 .collect(Collectors.toList());
451 definition.setRegularPropertyList(regularProperties);
452 definition.setSchemaPropertyList(schemaProperties);
454 defintionsList.add(definition);
456 return defintionsList;
459 public static String formatDescription(String description){
461 description = Arrays.stream(description.split("\n"))
464 if(line.contains("######")){
465 line = line.replaceAll("#", "");
467 String headerId = line.toLowerCase().replaceAll("\\s", "-");
469 if(line.contains("Related Nodes")){
470 return String.format("<h6 id=\"%s\">%s</h6>%s<ul>", headerId, line, LINE_SEPARATOR);
472 return String.format("<h6 id=\"%s\">%s</h6>", headerId, line);
474 } else if(line.startsWith("-")){
475 line = line.replaceFirst("-", "");
477 return String.format("<li>%s</li>", line);
479 return String.format("<p>%s</p>", line);
482 .collect(Collectors.joining(LINE_SEPARATOR));
484 if(description.contains("<ul>")){
485 description = description + "</ul>";