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=========================================================
21 package org.onap.aai.schemagen.swagger;
23 import com.fasterxml.jackson.dataformat.yaml.snakeyaml.Yaml;
24 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 import org.onap.aai.setup.SchemaVersions;
36 public class GenerateSwagger {
38 public static final String LINE_SEPARATOR = System.getProperty("line.separator");
39 public static final String DEFAULT_WIKI = "";
41 public static final String DEFAULT_SCHEMA_DIR = "../aai-schema";
42 // if the program is run from aai-common, use this directory as default"
43 public static final String ALT_SCHEMA_DIR = "aai-schema";
44 // used to check to see if program is run from aai-schema-gen
45 public static final String DEFAULT_RUN_DIR = "aai-schema-gen";
47 public static SchemaVersions schemaVersions;
49 public SchemaVersions getSchemaVersions() {
50 return schemaVersions;
53 public static void main(String[] args) throws IOException, TemplateException {
55 // SchemaVersions schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
56 String CURRENT_VERSION = schemaVersions.getDefaultVersion().toString();
57 String schemaDir = System.getProperty("aai.schema.dir");
58 String versionToGenerate = System.getProperty("aai.generate.version");
59 String wikiLink = System.getProperty("aai.wiki.link");
60 String release = System.getProperty("aai.release", "onap");
62 if (schemaDir == null) {
63 if (System.getProperty("user.dir") != null
64 && !System.getProperty("user.dir").contains(DEFAULT_RUN_DIR)) {
66 .println("Warning: Schema directory is not set so using default schema dir: "
68 schemaDir = ALT_SCHEMA_DIR;
71 .println("Warning: Schema directory is not set so using default schema dir: "
72 + DEFAULT_SCHEMA_DIR);
73 schemaDir = DEFAULT_SCHEMA_DIR;
77 if (versionToGenerate == null) {
79 "Warning: Version to generate is not set so using default versionToGenerate "
81 versionToGenerate = CURRENT_VERSION;
84 if (wikiLink == null) {
85 System.out.println("Warning: aai.wiki.link property is not set so using default");
86 wikiLink = DEFAULT_WIKI;
89 String yamlFile = schemaDir + "/src/main/resources/" + release
90 + "/aai_swagger_yaml/aai_swagger_" + versionToGenerate + ".yaml";
91 File swaggerYamlFile = new File(yamlFile);
93 if (!swaggerYamlFile.exists()) {
94 System.err.println("Unable to find the swagger yaml file: " + swaggerYamlFile);
98 Yaml yaml = new Yaml(new SafeConstructor());
99 Map<String, Object> swaggerMap = null;
101 try (BufferedReader reader = new BufferedReader(new FileReader(swaggerYamlFile))) {
102 swaggerMap = (Map<String, Object>) yaml.load(reader);
103 } catch (Exception ex) {
105 .println("Unable load yaml file: " + swaggerYamlFile + " : " + ex.getMessage());
106 throw new IOException();
109 Map<String, Object> map = (Map<String, Object>) swaggerMap.get("paths");
110 Map<String, Object> schemaDefinitionmap =
111 (Map<String, Object>) swaggerMap.get("definitions");
112 Map<String, Object> infoMap = (Map<String, Object>) swaggerMap.get("info");
113 Map<String, List<Api>> tagMap = new LinkedHashMap<>();
115 List<Api> apis = convertToApi(map);
116 apis.forEach((api) -> {
117 if (!tagMap.containsKey(api.getTag())) {
118 List<Api> newApis = new ArrayList<>();
120 tagMap.put(api.getTag(), newApis);
122 tagMap.get(api.getTag()).add(api);
126 Map<String, List<Api>> sortedTagMap = new TreeMap<>(tagMap);
127 sortedTagMap.forEach((key, value) -> {
128 value.sort(Comparator.comparing(Api::getPath));
131 Map<String, Object> resultMap = new HashMap<>();
133 List<Definition> definitionList = convertToDefinition(schemaDefinitionmap);
136 definitionList.stream().sorted(Comparator.comparing(Definition::getDefinitionName))
137 .collect(Collectors.toList());
139 resultMap.put("aaiApis", tagMap);
140 resultMap.put("sortedAaiApis", sortedTagMap);
141 resultMap.put("wikiLink", wikiLink);
142 resultMap.put("definitions", definitionList);
143 resultMap.put("version", versionToGenerate);
144 if (infoMap.containsKey("description")) {
145 String infoDescription = infoMap.get("description").toString();
147 infoDescription = Arrays.stream(infoDescription.split("\n")).map(line -> {
149 String hyperLink = "";
150 if (line.trim().contains("Differences versus")) {
153 if (line.trim().contains("https://")) {
154 int startIndex = line.indexOf("https://");
155 int endIndex = line.lastIndexOf("/");
156 hyperLink = line.substring(startIndex, endIndex);
157 return String.format("<a href=\"%s\">%s</a><br/>", hyperLink, line);
159 return String.format("%s<br/>", line);
162 .collect(Collectors.joining(LINE_SEPARATOR));
164 resultMap.put("description", infoDescription);
167 Configuration configuration = new Configuration();
168 configuration.setClassForTemplateLoading(Api.class, "/");
169 String resourcePath = "src/main/resources";
170 if (System.getProperty("user.dir") != null
171 && !System.getProperty("user.dir").contains(DEFAULT_RUN_DIR)) {
173 .setDirectoryForTemplateLoading(new File(DEFAULT_RUN_DIR + "/" + resourcePath));
175 configuration.setDirectoryForTemplateLoading(new File(resourcePath));
177 Template template = configuration.getTemplate("swagger.html.ftl");
179 String outputDirStr = schemaDir + "/src/main/resources/" + release + "/aai_swagger_html";
181 File outputDir = new File(outputDirStr);
183 if (!outputDir.exists()) {
184 boolean resp = outputDir.mkdir();
186 System.err.println("Unable to create the directory: " + outputDirStr);
189 } else if (outputDir.isFile()) {
190 System.err.println("Unable to create the directory: " + outputDirStr
191 + " since a filename with that string exists");
196 new FileWriter(new File(outputDirStr + "/aai_swagger_" + versionToGenerate + ".html"));
197 template.process(resultMap, file);
200 public static List<Api> convertToApi(Map<String, Object> pathMap) {
203 throw new IllegalArgumentException();
205 List<Api> apis = new ArrayList<>();
207 pathMap.forEach((pathKey, pathValue) -> {
210 Map<String, Object> httpVerbMap = (Map<String, Object>) pathValue;
211 List<Api.HttpVerb> httpVerbs = new ArrayList<>();
213 api.setPath(pathKey);
215 httpVerbMap.forEach((httpVerbKey, httpVerbValue) -> {
217 Api.HttpVerb httpVerb = new Api.HttpVerb();
219 Map<String, Object> httpVerbValueMap = (Map<String, Object>) httpVerbValue;
221 httpVerb.setType(httpVerbKey);
223 if (httpVerbValueMap.containsKey("tags")) {
224 httpVerb.setTags((List<String>) httpVerbValueMap.get("tags"));
227 if (httpVerbValueMap.containsKey("summary")) {
228 httpVerb.setSummary((String) httpVerbValueMap.get("summary"));
231 if (httpVerbValueMap.containsKey("operationId")) {
232 httpVerb.setOperationId((String) httpVerbValueMap.get("operationId"));
235 if (httpVerbValueMap.containsKey("consumes")) {
236 httpVerb.setConsumes((List<String>) httpVerbValueMap.get("consumes"));
237 if (httpVerb.getConsumes() != null) {
238 httpVerb.setConsumerEnabled(true);
242 if (httpVerbValueMap.containsKey("produces")) {
243 httpVerb.setProduces((List<String>) httpVerbValueMap.get("produces"));
246 if (httpVerbValueMap.containsKey("parameters")) {
247 List<Map<String, Object>> parameters =
248 (List<Map<String, Object>>) httpVerbValueMap.get("parameters");
249 List<Map<String, Object>> requestParameters = parameters.stream()
250 .filter((parameter) -> !parameter.get("name").equals("body"))
251 .collect(Collectors.toList());
252 httpVerb.setParameters(requestParameters);
253 if (httpVerb.getParameters() != null) {
254 httpVerb.setParametersEnabled(true);
257 List<Map<String, Object>> requestBodyList = parameters.stream()
258 .filter((parameter) -> parameter.get("name").equals("body"))
259 .collect(Collectors.toList());
261 Map<String, Object> requestBody = null;
263 if (requestBodyList != null && requestBodyList.size() == 1) {
264 requestBody = requestBodyList.get(0);
265 for (String key : requestBody.keySet()) {
266 // Filter out all the relationship links that appear in the YAML
267 if (key.equals("description")) {
268 String reqBody = (String) requestBody.get(key);
269 if (!reqBody.replaceAll("\\[.*.json\\)", "").equals(reqBody)) {
270 requestBody.put(key, reqBody.replaceAll("\\[.*.json\\)", ""));
273 // Filter out all the patchDefinition links that appear in the YAML
274 if (key.equals("schema")) {
275 LinkedHashMap<String, String> reqBody =
276 (LinkedHashMap<String, String>) requestBody.get(key);
277 String schema = reqBody.get("$ref");
278 String schemaNopatch =
279 schema.replace("patchDefinitions", "definitions");
281 if (!schema.equals(schemaNopatch)) {
282 reqBody.put("$ref", schemaNopatch);
283 requestBody.put(key, reqBody);
287 httpVerb.setBodyParametersEnabled(true);
288 httpVerb.setBodyParameters(requestBody);
290 if (requestBody != null && requestBody.containsKey("schema")) {
291 Map<String, Object> schemaMap =
292 (Map<String, Object>) requestBody.get("schema");
293 if (schemaMap != null && schemaMap.containsKey("$ref")) {
294 String schemaLink = schemaMap.get("$ref").toString();
295 httpVerb.setSchemaLink(schemaLink);
296 int retCode = schemaLink.lastIndexOf('/');
297 if (retCode != -1 && retCode != schemaLink.length()) {
298 httpVerb.setSchemaType(schemaLink.substring(retCode));
305 if (httpVerbValueMap.containsKey("responses")) {
307 List<Api.HttpVerb.Response> responses = new ArrayList<Api.HttpVerb.Response>();
309 Map<String, Object> responsesMap =
310 (Map<String, Object>) httpVerbValueMap.get("responses");
312 responsesMap.entrySet().stream()
313 .filter((res) -> !"default".equalsIgnoreCase(res.getKey()))
314 .forEach((responseMap) -> {
316 Map<String, Object> responseValueMap =
317 (Map<String, Object>) responseMap.getValue();
319 Api.HttpVerb.Response response = new Api.HttpVerb.Response();
321 response.setResponseCode(responseMap.getKey());
322 response.setDescription((String) responseValueMap.get("description"));
323 response.setVersion((String) responseValueMap.get("version"));
325 if (responseValueMap != null
326 && responseValueMap.containsKey("schema")) {
327 Map<String, Object> schemaMap =
328 (Map<String, Object>) responseValueMap.get("schema");
329 if (schemaMap != null && schemaMap.containsKey("$ref")) {
330 String schemaLink = schemaMap.get("$ref").toString();
331 httpVerb.setHasReturnSchema(true);
332 // Filter out all the getDefinition links that appear in the
334 httpVerb.setReturnSchemaLink(
335 schemaLink.replace("getDefinitions", "definitions"));
336 int retCode = schemaLink.lastIndexOf('/');
337 if (retCode != -1 && retCode != schemaLink.length()) {
339 .setReturnSchemaObject(schemaLink.substring(retCode));
344 responses.add(response);
347 httpVerb.setResponses(responses);
350 httpVerbs.add(httpVerb);
353 api.setHttpMethods(httpVerbs);
360 public static List<Definition> convertToDefinition(Map<String, Object> definitionMap) {
362 if (definitionMap == null)
363 throw new IllegalArgumentException();
365 List<Definition> defintionsList = new ArrayList<>();
367 definitionMap.entrySet().forEach((entry) -> {
369 Definition definition = new Definition();
370 String key = entry.getKey();
371 Map<String, Object> valueMap = (Map<String, Object>) entry.getValue();
373 definition.setDefinitionName(key);
375 if (valueMap.containsKey("description")) {
376 String description = valueMap.get("description").toString();
377 description = formatDescription(description);
378 definition.setDefinitionDescription(description);
379 definition.setHasDescription(true);
382 List<Definition.Property> definitionProperties = new ArrayList<>();
384 List<String> requiredProperties = (valueMap.get("required") == null) ? new ArrayList<>()
385 : (List<String>) valueMap.get("required");
387 Set<String> requiredPropsSet = new HashSet<>(requiredProperties);
389 valueMap.entrySet().stream().filter((e) -> "properties".equals(e.getKey()))
390 .forEach((propertyEntries) -> {
391 Map<String, Object> propertyRealEntries =
392 (Map<String, Object>) propertyEntries.getValue();
393 propertyRealEntries.forEach((propertyKey, value) -> {
394 Definition.Property definitionProperty = new Definition.Property();
395 if (requiredPropsSet.contains(propertyKey)) {
396 definitionProperty.setRequired(true);
398 definitionProperty.setPropertyName(propertyKey);
399 Map<String, Object> definitionPropertyMap = (Map<String, Object>) value;
401 if (definitionPropertyMap.containsKey("description")) {
402 definitionProperty.setPropertyDescription(
403 definitionPropertyMap.get("description").toString());
404 definitionProperty.setHasPropertyDescription(true);
406 if (definitionPropertyMap.containsKey("type")) {
407 String type = definitionPropertyMap.get("type").toString();
408 definitionProperty.setPropertyType(type);
409 definitionProperty.setHasType(true);
410 if ("array".equals(type)) {
411 definitionProperty.setPropertyType("object[]");
412 if (!definitionPropertyMap.containsKey("items")) {
413 throw new RuntimeException(
414 "Unable to find the property items even though the type is array for "
417 Map<String, Object> itemMap =
418 (Map<String, Object>) definitionPropertyMap.get("items");
419 if (itemMap.containsKey("$ref")) {
420 definitionProperty.setHasPropertyReference(true);
421 String refItem = itemMap.get("$ref").toString();
422 int retCode = refItem.lastIndexOf('/');
423 if (retCode != -1 && retCode != refItem.length()) {
424 definitionProperty.setPropertyReferenceObjectName(
425 refItem.substring(retCode + 1));
427 definitionProperty.setPropertyReference(refItem);
431 if (definitionPropertyMap.containsKey("$ref")) {
432 definitionProperty.setHasPropertyReference(true);
433 String refItem = definitionPropertyMap.get("$ref").toString();
434 int retCode = refItem.lastIndexOf('/');
435 if (retCode != -1 && retCode != refItem.length()) {
436 definitionProperty.setPropertyReferenceObjectName(
437 refItem.substring(retCode + 1));
439 definitionProperty.setPropertyReference(refItem);
443 definitionProperties.add(definitionProperty);
447 definition.setPropertyList(definitionProperties);
449 List<Definition.Property> schemaProperties = definitionProperties.stream()
450 .filter(Definition.Property::isHasPropertyReference).collect(Collectors.toList());
452 List<Definition.Property> regularProperties = definitionProperties.stream()
453 .filter((o) -> !o.isHasPropertyReference()).collect(Collectors.toList());
455 definition.setRegularPropertyList(regularProperties);
456 definition.setSchemaPropertyList(schemaProperties);
458 defintionsList.add(definition);
460 return defintionsList;
463 public static String formatDescription(String description) {
465 description = Arrays.stream(description.split("\n")).map((line) -> {
467 if (line.contains("######")) {
468 line = line.replaceAll("#", "");
470 String headerId = line.toLowerCase().replaceAll("\\s", "-");
472 if (line.contains("Related Nodes")) {
473 return String.format("<h6 id=\"%s\">%s</h6>%s<ul>", headerId, line,
476 return String.format("<h6 id=\"%s\">%s</h6>", headerId, line);
478 } else if (line.startsWith("-")) {
479 line = line.replaceFirst("-", "");
481 return String.format("<li>%s</li>", line);
483 return String.format("<p>%s</p>", line);
485 }).collect(Collectors.joining(LINE_SEPARATOR));
487 if (description.contains("<ul>")) {
488 description = description + "</ul>";