/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= */ package org.onap.aai.schemagen.swagger; import com.fasterxml.jackson.dataformat.yaml.snakeyaml.Yaml; import com.fasterxml.jackson.dataformat.yaml.snakeyaml.constructor.SafeConstructor; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; import org.onap.aai.setup.SchemaConfigVersions; public class GenerateSwagger { public static final String LINE_SEPARATOR = System.getProperty("line.separator"); public static final String DEFAULT_WIKI = ""; public static final String DEFAULT_SCHEMA_DIR = "../aai-schema"; // if the program is run from aai-common, use this directory as default" public static final String ALT_SCHEMA_DIR = "aai-schema"; // used to check to see if program is run from aai-schema-gen public static final String DEFAULT_RUN_DIR = "aai-schema-gen"; public static SchemaConfigVersions schemaConfigVersions; public SchemaConfigVersions getSchemaConfigVersions() { return schemaConfigVersions; } public static void main(String[] args) throws IOException, TemplateException { // SchemaVersions schemaVersions = SpringContextAware.getBean(SchemaVersions.class); String CURRENT_VERSION = schemaConfigVersions.getDefaultVersion().toString(); String schemaDir = System.getProperty("aai.schema.dir"); String versionToGenerate = System.getProperty("aai.generate.version"); String wikiLink = System.getProperty("aai.wiki.link"); String release = System.getProperty("aai.release", "onap"); if (schemaDir == null) { if (System.getProperty("user.dir") != null && !System.getProperty("user.dir").contains(DEFAULT_RUN_DIR)) { System.out .println("Warning: Schema directory is not set so using default schema dir: " + ALT_SCHEMA_DIR); schemaDir = ALT_SCHEMA_DIR; } else { System.out .println("Warning: Schema directory is not set so using default schema dir: " + DEFAULT_SCHEMA_DIR); schemaDir = DEFAULT_SCHEMA_DIR; } } if (versionToGenerate == null) { System.out.println( "Warning: Version to generate is not set so using default versionToGenerate " + CURRENT_VERSION); versionToGenerate = CURRENT_VERSION; } if (wikiLink == null) { System.out.println("Warning: aai.wiki.link property is not set so using default"); wikiLink = DEFAULT_WIKI; } String yamlFile = schemaDir + "/src/main/resources/" + release + "/aai_swagger_yaml/aai_swagger_" + versionToGenerate + ".yaml"; File swaggerYamlFile = new File(yamlFile); if (!swaggerYamlFile.exists()) { System.err.println("Unable to find the swagger yaml file: " + swaggerYamlFile); System.exit(1); } Yaml yaml = new Yaml(new SafeConstructor()); Map swaggerMap = null; try (BufferedReader reader = new BufferedReader(new FileReader(swaggerYamlFile))) { swaggerMap = (Map) yaml.load(reader); } catch (Exception ex) { System.err .println("Unable load yaml file: " + swaggerYamlFile + " : " + ex.getMessage()); throw new IOException(); } Map map = (Map) swaggerMap.get("paths"); Map schemaDefinitionmap = (Map) swaggerMap.get("definitions"); Map infoMap = (Map) swaggerMap.get("info"); Map> tagMap = new LinkedHashMap<>(); List apis = convertToApi(map); apis.forEach((api) -> { if (!tagMap.containsKey(api.getTag())) { List newApis = new ArrayList<>(); newApis.add(api); tagMap.put(api.getTag(), newApis); } else { tagMap.get(api.getTag()).add(api); } }); Map> sortedTagMap = new TreeMap<>(tagMap); sortedTagMap.forEach((key, value) -> { value.sort(Comparator.comparing(Api::getPath)); }); Map resultMap = new HashMap<>(); List definitionList = convertToDefinition(schemaDefinitionmap); definitionList = definitionList.stream().sorted(Comparator.comparing(Definition::getDefinitionName)) .collect(Collectors.toList()); resultMap.put("aaiApis", tagMap); resultMap.put("sortedAaiApis", sortedTagMap); resultMap.put("wikiLink", wikiLink); resultMap.put("definitions", definitionList); resultMap.put("version", versionToGenerate); if (infoMap.containsKey("description")) { String infoDescription = infoMap.get("description").toString(); infoDescription = Arrays.stream(infoDescription.split("\n")).map(line -> { line = line.trim(); String hyperLink = ""; if (line.trim().contains("Differences versus")) { return ""; } if (line.trim().contains("https://")) { int startIndex = line.indexOf("https://"); int endIndex = line.lastIndexOf("/"); hyperLink = line.substring(startIndex, endIndex); return String.format("%s
", hyperLink, line); } return String.format("%s
", line); }) .collect(Collectors.joining(LINE_SEPARATOR)); resultMap.put("description", infoDescription); } Configuration configuration = new Configuration(); configuration.setClassForTemplateLoading(Api.class, "/"); String resourcePath = "src/main/resources"; if (System.getProperty("user.dir") != null && !System.getProperty("user.dir").contains(DEFAULT_RUN_DIR)) { configuration .setDirectoryForTemplateLoading(new File(DEFAULT_RUN_DIR + "/" + resourcePath)); } else { configuration.setDirectoryForTemplateLoading(new File(resourcePath)); } Template template = configuration.getTemplate("swagger.html.ftl"); String outputDirStr = schemaDir + "/src/main/resources/" + release + "/aai_swagger_html"; File outputDir = new File(outputDirStr); if (!outputDir.exists()) { boolean resp = outputDir.mkdir(); if (!resp) { System.err.println("Unable to create the directory: " + outputDirStr); System.exit(1); } } else if (outputDir.isFile()) { System.err.println("Unable to create the directory: " + outputDirStr + " since a filename with that string exists"); System.exit(1); } Writer file = new FileWriter(new File(outputDirStr + "/aai_swagger_" + versionToGenerate + ".html")); template.process(resultMap, file); } public static List convertToApi(Map pathMap) { if (pathMap == null) throw new IllegalArgumentException(); List apis = new ArrayList<>(); pathMap.forEach((pathKey, pathValue) -> { Api api = new Api(); Map httpVerbMap = (Map) pathValue; List httpVerbs = new ArrayList<>(); api.setPath(pathKey); httpVerbMap.forEach((httpVerbKey, httpVerbValue) -> { Api.HttpVerb httpVerb = new Api.HttpVerb(); Map httpVerbValueMap = (Map) httpVerbValue; httpVerb.setType(httpVerbKey); if (httpVerbValueMap.containsKey("tags")) { httpVerb.setTags((List) httpVerbValueMap.get("tags")); } if (httpVerbValueMap.containsKey("summary")) { httpVerb.setSummary((String) httpVerbValueMap.get("summary")); } if (httpVerbValueMap.containsKey("operationId")) { httpVerb.setOperationId((String) httpVerbValueMap.get("operationId")); } if (httpVerbValueMap.containsKey("consumes")) { httpVerb.setConsumes((List) httpVerbValueMap.get("consumes")); if (httpVerb.getConsumes() != null) { httpVerb.setConsumerEnabled(true); } } if (httpVerbValueMap.containsKey("produces")) { httpVerb.setProduces((List) httpVerbValueMap.get("produces")); } if (httpVerbValueMap.containsKey("parameters")) { List> parameters = (List>) httpVerbValueMap.get("parameters"); List> requestParameters = parameters.stream() .filter((parameter) -> !parameter.get("name").equals("body")) .collect(Collectors.toList()); httpVerb.setParameters(requestParameters); if (httpVerb.getParameters() != null) { httpVerb.setParametersEnabled(true); } List> requestBodyList = parameters.stream() .filter((parameter) -> parameter.get("name").equals("body")) .collect(Collectors.toList()); Map requestBody = null; if (requestBodyList != null && requestBodyList.size() == 1) { requestBody = requestBodyList.get(0); for (String key : requestBody.keySet()) { // Filter out all the relationship links that appear in the YAML if (key.equals("description")) { String reqBody = (String) requestBody.get(key); if (!reqBody.replaceAll("\\[.*.json\\)", "").equals(reqBody)) { requestBody.put(key, reqBody.replaceAll("\\[.*.json\\)", "")); } } // Filter out all the patchDefinition links that appear in the YAML if (key.equals("schema")) { LinkedHashMap reqBody = (LinkedHashMap) requestBody.get(key); String schema = reqBody.get("$ref"); String schemaNopatch = schema.replace("patchDefinitions", "definitions"); if (!schema.equals(schemaNopatch)) { reqBody.put("$ref", schemaNopatch); requestBody.put(key, reqBody); } } } httpVerb.setBodyParametersEnabled(true); httpVerb.setBodyParameters(requestBody); if (requestBody != null && requestBody.containsKey("schema")) { Map schemaMap = (Map) requestBody.get("schema"); if (schemaMap != null && schemaMap.containsKey("$ref")) { String schemaLink = schemaMap.get("$ref").toString(); httpVerb.setSchemaLink(schemaLink); int retCode = schemaLink.lastIndexOf('/'); if (retCode != -1 && retCode != schemaLink.length()) { httpVerb.setSchemaType(schemaLink.substring(retCode)); } } } } } if (httpVerbValueMap.containsKey("responses")) { List responses = new ArrayList(); Map responsesMap = (Map) httpVerbValueMap.get("responses"); responsesMap.entrySet().stream() .filter((res) -> !"default".equalsIgnoreCase(res.getKey())) .forEach((responseMap) -> { Map responseValueMap = (Map) responseMap.getValue(); Api.HttpVerb.Response response = new Api.HttpVerb.Response(); response.setResponseCode(responseMap.getKey()); response.setDescription((String) responseValueMap.get("description")); response.setVersion((String) responseValueMap.get("version")); if (responseValueMap != null && responseValueMap.containsKey("schema")) { Map schemaMap = (Map) responseValueMap.get("schema"); if (schemaMap != null && schemaMap.containsKey("$ref")) { String schemaLink = schemaMap.get("$ref").toString(); httpVerb.setHasReturnSchema(true); // Filter out all the getDefinition links that appear in the // YAML httpVerb.setReturnSchemaLink( schemaLink.replace("getDefinitions", "definitions")); int retCode = schemaLink.lastIndexOf('/'); if (retCode != -1 && retCode != schemaLink.length()) { httpVerb .setReturnSchemaObject(schemaLink.substring(retCode)); } } } responses.add(response); }); httpVerb.setResponses(responses); } httpVerbs.add(httpVerb); }); api.setHttpMethods(httpVerbs); apis.add(api); }); return apis; } public static List convertToDefinition(Map definitionMap) { if (definitionMap == null) throw new IllegalArgumentException(); List defintionsList = new ArrayList<>(); definitionMap.entrySet().forEach((entry) -> { Definition definition = new Definition(); String key = entry.getKey(); Map valueMap = (Map) entry.getValue(); definition.setDefinitionName(key); if (valueMap.containsKey("description")) { String description = valueMap.get("description").toString(); description = formatDescription(description); definition.setDefinitionDescription(description); definition.setHasDescription(true); } List definitionProperties = new ArrayList<>(); List requiredProperties = (valueMap.get("required") == null) ? new ArrayList<>() : (List) valueMap.get("required"); Set requiredPropsSet = new HashSet<>(requiredProperties); valueMap.entrySet().stream().filter((e) -> "properties".equals(e.getKey())) .forEach((propertyEntries) -> { Map propertyRealEntries = (Map) propertyEntries.getValue(); propertyRealEntries.forEach((propertyKey, value) -> { Definition.Property definitionProperty = new Definition.Property(); if (requiredPropsSet.contains(propertyKey)) { definitionProperty.setRequired(true); } definitionProperty.setPropertyName(propertyKey); Map definitionPropertyMap = (Map) value; if (definitionPropertyMap.containsKey("description")) { definitionProperty.setPropertyDescription( definitionPropertyMap.get("description").toString()); definitionProperty.setHasPropertyDescription(true); } if (definitionPropertyMap.containsKey("type")) { String type = definitionPropertyMap.get("type").toString(); definitionProperty.setPropertyType(type); definitionProperty.setHasType(true); if ("array".equals(type)) { definitionProperty.setPropertyType("object[]"); if (!definitionPropertyMap.containsKey("items")) { throw new RuntimeException( "Unable to find the property items even though the type is array for " + propertyKey); } else { Map itemMap = (Map) definitionPropertyMap.get("items"); if (itemMap.containsKey("$ref")) { definitionProperty.setHasPropertyReference(true); String refItem = itemMap.get("$ref").toString(); int retCode = refItem.lastIndexOf('/'); if (retCode != -1 && retCode != refItem.length()) { definitionProperty.setPropertyReferenceObjectName( refItem.substring(retCode + 1)); } definitionProperty.setPropertyReference(refItem); } } } else { if (definitionPropertyMap.containsKey("$ref")) { definitionProperty.setHasPropertyReference(true); String refItem = definitionPropertyMap.get("$ref").toString(); int retCode = refItem.lastIndexOf('/'); if (retCode != -1 && retCode != refItem.length()) { definitionProperty.setPropertyReferenceObjectName( refItem.substring(retCode + 1)); } definitionProperty.setPropertyReference(refItem); } } } definitionProperties.add(definitionProperty); }); }); definition.setPropertyList(definitionProperties); List schemaProperties = definitionProperties.stream() .filter(Definition.Property::isHasPropertyReference).collect(Collectors.toList()); List regularProperties = definitionProperties.stream() .filter((o) -> !o.isHasPropertyReference()).collect(Collectors.toList()); definition.setRegularPropertyList(regularProperties); definition.setSchemaPropertyList(schemaProperties); defintionsList.add(definition); }); return defintionsList; } public static String formatDescription(String description) { description = Arrays.stream(description.split("\n")).map((line) -> { line = line.trim(); if (line.contains("######")) { line = line.replaceAll("#", ""); line = line.trim(); String headerId = line.toLowerCase().replaceAll("\\s", "-"); if (line.contains("Related Nodes")) { return String.format("
%s
%s
    ", headerId, line, LINE_SEPARATOR); } else { return String.format("
    %s
    ", headerId, line); } } else if (line.startsWith("-")) { line = line.replaceFirst("-", ""); line = line.trim(); return String.format("
  • %s
  • ", line); } else { return String.format("

    %s

    ", line); } }).collect(Collectors.joining(LINE_SEPARATOR)); if (description.contains("
      ")) { description = description + "
    "; } return description; } }