/** * ============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 org.onap.aai.setup.SchemaVersions; import java.io.*; import java.util.*; import java.util.stream.Collectors; 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 SchemaVersions schemaVersions; public SchemaVersions getSchemaVersions() { return schemaVersions; } public static void main(String[] args) throws IOException, TemplateException { // SchemaVersions schemaVersions = SpringContextAware.getBean(SchemaVersions.class); String CURRENT_VERSION = schemaVersions.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; } }