Merge "Replace relationship array with object in generated swagger"
[aai/schema-service.git] / aai-schema-gen / src / main / java / org / onap / aai / schemagen / genxsd / YAMLfromOXM.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
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
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20 package org.onap.aai.schemagen.genxsd;
21
22 import com.google.common.collect.Multimap;
23 import org.apache.commons.lang3.StringUtils;
24 import org.onap.aai.edges.EdgeIngestor;
25 import org.onap.aai.edges.EdgeRule;
26 import org.onap.aai.edges.EdgeRuleQuery;
27 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
28 import org.onap.aai.nodes.NodeIngestor;
29 import org.onap.aai.setup.SchemaVersion;
30 import org.onap.aai.setup.SchemaVersions;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.w3c.dom.Element;
34 import org.w3c.dom.NodeList;
35 import org.xml.sax.SAXException;
36
37 import javax.xml.parsers.ParserConfigurationException;
38 import java.io.BufferedWriter;
39 import java.io.File;
40 import java.io.FileNotFoundException;
41 import java.io.IOException;
42 import java.nio.charset.Charset;
43 import java.nio.file.Files;
44 import java.nio.file.Path;
45 import java.nio.file.Paths;
46 import java.util.*;
47
48 public class YAMLfromOXM extends OxmFileProcessor {
49     private static final Logger logger = LoggerFactory.getLogger("YAMLfromOXM.class");
50     // private static StringBuffer totalPathSbAccumulator = new StringBuffer();
51     private static final String root = "../aai-schema/src/main/resources";
52     private static final String autoGenRoot = "aai-schema/src/main/resources";
53     private static final String generateTypeYAML = "yaml";
54     private static final String normalStartDir = "aai-schema-gen";
55     private static final String yaml_dir = (((System.getProperty("user.dir") != null)
56         && (!System.getProperty("user.dir").contains(normalStartDir))) ? autoGenRoot : root)
57         + "/aai_swagger_yaml";
58     private StringBuilder inventoryDefSb = null;
59
60     private String basePath;
61
62     public YAMLfromOXM(String basePath, SchemaVersions schemaVersions, NodeIngestor ni,
63         EdgeIngestor ei) {
64         super(schemaVersions, ni, ei);
65         this.basePath = basePath;
66     }
67
68     public void setOxmVersion(File oxmFile, SchemaVersion v) {
69         super.setOxmVersion(oxmFile, v);
70     }
71
72     public void setXmlVersion(String xml, SchemaVersion v) {
73         super.setXmlVersion(xml, v);
74     }
75
76     public void setVersion(SchemaVersion v) {
77         super.setVersion(v);
78     }
79
80     @Override
81     public String getDocumentHeader() {
82         StringBuffer sb = new StringBuffer();
83         sb.append("swagger: \"2.0\"\ninfo:" + LINE_SEPARATOR + "  ");
84         sb.append("description: |");
85         if (versionSupportsSwaggerDiff(v.toString())) {
86             sb.append("\n\n    [Differences versus the previous schema version]("
87                 + "apidocs/aai_swagger_" + v.toString() + ".diff)");
88         }
89         sb.append(
90             DOUBLE_LINE_SEPARATOR + "    Copyright © 2017-18 AT&T Intellectual Property. All rights reserved." + DOUBLE_LINE_SEPARATOR + "    Licensed under the Creative Commons License, Attribution 4.0 Intl. (the "License"); you may not use this documentation except in compliance with the License.\n\n    You may obtain a copy of the License at\n\n    (https://creativecommons.org/licenses/by/4.0/)\n\n    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." + DOUBLE_LINE_SEPARATOR + "    This document is best viewed with Firefox or Chrome. Nodes can be found by appending /#/definitions/node-type-to-find to the path to this document. Edge definitions can be found with the node definitions." + LINE_SEPARATOR + "  version: \""
91                 + v.toString() + "\"" + LINE_SEPARATOR );
92         sb.append("  title: Active and Available Inventory REST API" + LINE_SEPARATOR);
93         sb.append(
94             "  license:" + LINE_SEPARATOR + "    name: Apache 2.0\n    url: http://www.apache.org/licenses/LICENSE-2.0.html" + LINE_SEPARATOR);
95         sb.append("  contact:" + LINE_SEPARATOR + "    name:" + LINE_SEPARATOR + "    url:" + LINE_SEPARATOR + "    email:" + LINE_SEPARATOR);
96         sb.append("host:" + LINE_SEPARATOR + "basePath: " + basePath + "/" + v.toString() + LINE_SEPARATOR);
97         sb.append("schemes:" + LINE_SEPARATOR + "  - https\npaths:" + LINE_SEPARATOR);
98         return sb.toString();
99     }
100
101     protected void init() throws ParserConfigurationException, SAXException, IOException,
102         FileNotFoundException, EdgeRuleNotFoundException {
103         super.init();
104     }
105
106     @Override
107     public String process() throws ParserConfigurationException, SAXException, IOException,
108         FileNotFoundException, EdgeRuleNotFoundException {
109         StringBuffer sb = new StringBuffer();
110         StringBuffer pathSb = new StringBuffer();
111         try {
112             init();
113         } catch (Exception e) {
114             logger.error("Error initializing " + this.getClass(), e);
115             throw e;
116         }
117         pathSb.append(getDocumentHeader());
118         StringBuffer definitionsSb = new StringBuffer();
119         Element elem;
120         String javaTypeName;
121         combinedJavaTypes = new HashMap();
122         for (int i = 0; i < javaTypeNodes.getLength(); ++i) {
123             elem = (Element) javaTypeNodes.item(i);
124             javaTypeName = elem.getAttribute("name");
125             boolean processInventory = false;
126             if (!"Inventory".equals(javaTypeName)) {
127                 if (generatedJavaType.containsKey(getXmlRootElementName(javaTypeName))) {
128                     continue;
129                 }
130                 // will combine all matching java-types
131                 elem = getJavaTypeElementSwagger(javaTypeName);
132             } else {
133                 processInventory = true;
134             }
135
136             XSDElement javaTypeElement = new XSDElement(elem);
137
138             if (processInventory) {
139                 getTopLevelPaths(javaTypeElement);
140             }
141
142             if (javaTypeName == null) {
143                 String msg = "Invalid OXM file: <java-type> has no name attribute in " + oxmFile;
144                 logger.error(msg);
145                 throw new SAXException(msg);
146             }
147             namespaceFilter.add(getXmlRootElementName(javaTypeName));
148             processJavaTypeElementSwagger(javaTypeName, javaTypeElement, pathSb, definitionsSb,
149                 null, null, null, null, null, null);
150         }
151         sb.append(pathSb);
152
153         sb.append(appendDefinitions());
154         PutRelationPathSet prp = new PutRelationPathSet(v);
155         prp.generateRelations(ei);
156         return sb.toString();
157     }
158
159     public String appendDefinitions() {
160         return appendDefinitions(null);
161     }
162
163     public String appendDefinitions(Set<String> namespaceFilter) {
164         // append definitions
165         if (inventoryDefSb != null) {
166             javaTypeDefinitions.put("inventory", inventoryDefSb.toString());
167         }
168         StringBuffer sb = new StringBuffer("definitions:\n");
169         Map<String, String> sortedJavaTypeDefinitions =
170             new TreeMap<String, String>(javaTypeDefinitions);
171         for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
172             // logger.info("Key: "+entry.getKey()+"Value: "+ entry.getValue());
173             if (namespaceFilter != null && entry.getKey().matches("service-capabilities")) {
174                 for (String tally : namespaceFilter) {
175                     logger.debug("Marker: " + tally);
176                 }
177             }
178             if (namespaceFilter != null && (!namespaceFilter.contains(entry.getKey()))) {
179                 continue;
180             }
181             logger.debug(
182                 "Key: " + entry.getKey() + "Test: " + (entry.getKey() == "relationship-dict"));
183             if (entry.getKey().matches("relationship-dict")) {
184                 String jb = entry.getValue();
185                 logger.debug("Value: " + jb);
186                 int ndx = jb.indexOf("related-to-property:");
187                 if (ndx > 0) {
188                     jb = jb.substring(0, ndx);
189                     jb = jb.replaceAll(" +$", "");
190                 }
191                 logger.debug("Value-after: " + jb);
192                 sb.append(jb);
193                 continue;
194             }
195             sb.append(entry.getValue());
196         }
197
198         sb.append("patchDefinitions:\n");
199         for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
200             if (namespaceFilter != null && (!namespaceFilter.contains(entry.getKey()))) {
201                 continue;
202             }
203             String jb = entry.getValue().replaceAll("/definitions/", "/patchDefinitions/");
204             int ndx = jb.indexOf("relationship-list:");
205             if (ndx > 0) {
206                 jb = jb.substring(0, ndx);
207                 jb = jb.replaceAll(" +$", "");
208             }
209             int ndx1 = jb.indexOf("resource-version:");
210             logger.debug("Key: " + entry.getKey() + " index: " + ndx1);
211             logger.debug("Value: " + jb);
212             if (ndx1 > 0) {
213                 jb = jb.substring(0, ndx1);
214                 jb = jb.replaceAll(" +$", "");
215             }
216             logger.debug("Value-after: " + jb);
217             sb.append(jb);
218         }
219
220         sb.append("getDefinitions:\n");
221         for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
222             if (namespaceFilter != null && (!namespaceFilter.contains(entry.getKey()))) {
223                 continue;
224             }
225             String jb = entry.getValue().replaceAll("/definitions/", "/getDefinitions/");
226             sb.append(jb);
227         }
228         return sb.toString();
229     }
230
231     private String getDictionary(String resource) {
232         StringBuffer dictSb = new StringBuffer();
233         dictSb.append("  " + resource + ":\n");
234         dictSb.append("    description: |\n");
235         dictSb.append("      dictionary of " + resource + "\n");
236         dictSb.append("    type: object\n");
237         dictSb.append("    properties:\n");
238         dictSb.append("      " + resource + ":\n");
239         dictSb.append("        type: array\n");
240         dictSb.append("        items:\n");
241         dictSb.append("          $ref: \"#/definitions/" + resource + "-dict\"\n");
242         return dictSb.toString();
243     }
244
245     private String processJavaTypeElementSwagger(String javaTypeName, Element javaTypeElement,
246         StringBuffer pathSb, StringBuffer definitionsSb, String path, String tag, String opId,
247         String getItemName, StringBuffer pathParams, String validEdges) {
248
249         String xmlRootElementName = getXMLRootElementName(javaTypeElement);
250         StringBuilder definitionsLocalSb = new StringBuilder(256);
251
252         String useTag = null;
253         String useOpId = null;
254         logger.debug("tag=" + tag);
255         if (tag != null) {
256          // set ignore to true to skip Actions and Search
257             boolean topCheck = checkTopLevel(tag, true);
258             if (!topCheck) {
259                 return null;
260             }
261         }
262
263         if (!javaTypeName.equals("Inventory")) {
264             if (javaTypeName.equals("AaiInternal")) {
265                 return null;
266             }
267             if (opId == null) {
268                 useOpId = javaTypeName;
269             } else {
270                 useOpId = opId + javaTypeName;
271             }
272             if (tag == null) {
273                 useTag = javaTypeName;
274             }
275         }
276         path = xmlRootElementName.equals("inventory") ? ""
277             : (path == null) ? "/" + xmlRootElementName : path + "/" + xmlRootElementName;
278         XSDJavaType javaType = new XSDJavaType(javaTypeElement);
279         if (getItemName != null) {
280             if (getItemName.equals("array")) {
281                 return javaType.getArrayType();
282             } else {
283                 return javaType.getItemName();
284             }
285         }
286
287         NodeList parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
288         if (parentNodes.getLength() == 0) {
289             logger.debug("no java-attributes for java-type " + javaTypeName);
290             return "";
291         }
292
293         String pathDescriptionProperty = javaType.getPathDescriptionProperty();
294         String container = javaType.getContainerProperty();
295         Vector<String> indexedProps = javaType.getIndexedProps();
296         Vector<String> containerProps = new Vector<String>();
297         if (container != null) {
298             logger.debug("javaTypeName " + javaTypeName + " container:" + container
299                 + " indexedProps:" + indexedProps);
300         }
301
302         Element parentElement = (Element) parentNodes.item(0);
303         NodeList xmlElementNodes = parentElement.getElementsByTagName("xml-element");
304
305         StringBuffer sbParameters = new StringBuffer();
306         StringBuffer sbRequired = new StringBuffer();
307         int requiredCnt = 0;
308         int propertyCnt = 0;
309         StringBuffer sbProperties = new StringBuffer();
310
311         if (appliedPaths.containsKey(path)) {
312             return null;
313         }
314
315         StringTokenizer st = new StringTokenizer(path, "/");
316         logger.debug("path: " + path + " st? " + st.toString());
317         if (st.countTokens() > 1 && getItemName == null) {
318             logger.debug("appliedPaths: " + appliedPaths + " containsKey? "
319                 + appliedPaths.containsKey(path));
320             appliedPaths.put(path, xmlRootElementName);
321         }
322         
323         Vector<String> addTypeV = null;
324         for (int i = 0; i < xmlElementNodes.getLength(); ++i) {
325             XSDElement xmlElementElement = new XSDElement((Element) xmlElementNodes.item(i));
326             if (!xmlElementElement.getParentNode().isSameNode(parentElement)) {
327                 continue;
328             }
329             String elementDescription = xmlElementElement.getPathDescriptionProperty();
330             if (getItemName == null) {
331                 addTypeV = xmlElementElement.getAddTypes(v.toString());
332             }
333             if ("true".equals(xmlElementElement.getAttribute("xml-key"))) {
334                 path += "/{" + xmlElementElement.getAttribute("name") + "}";
335             }
336             logger.debug("path: " + path);
337             logger.debug("xmlElementElement.getAttribute(required):"
338                 + xmlElementElement.getAttribute("required"));
339
340             if (("true").equals(xmlElementElement.getAttribute("required"))) {
341                 if (requiredCnt == 0) {
342                     sbRequired.append("    required:\n");
343                 }
344                 ++requiredCnt;
345                 if (addTypeV == null || addTypeV.isEmpty()) {
346                     sbRequired.append("    - " + xmlElementElement.getAttribute("name") + "\n");
347                 } else {
348                     for (int k = 0; k < addTypeV.size(); ++k) {
349                         sbRequired.append(
350                             "    - " + getXmlRootElementName(addTypeV.elementAt(k)) + ":\n");
351                     }
352                 }
353             }
354
355             if ("true".equals(xmlElementElement.getAttribute("xml-key"))) {
356                 sbParameters.append(xmlElementElement.getPathParamYAML(elementDescription));
357             }
358             if (indexedProps != null
359                 && indexedProps.contains(xmlElementElement.getAttribute("name"))) {
360                 containerProps.add(xmlElementElement.getQueryParamYAML());
361                 GetOperation.addContainerProps(container, containerProps);
362             }
363             if (xmlElementElement.isStandardType()) {
364                 sbProperties.append(xmlElementElement.getTypePropertyYAML());
365                 ++propertyCnt;
366             }
367
368             StringBuffer newPathParams = new StringBuffer(
369                 (pathParams == null ? "" : pathParams.toString()) + sbParameters.toString());
370             String useName;
371             for (int k = 0; addTypeV != null && k < addTypeV.size(); ++k) {
372                 String addType = addTypeV.elementAt(k);
373                 namespaceFilter.add(getXmlRootElementName(addType));
374                 logger.debug("addType: " + addType);
375
376                 if (opId == null || !opId.contains(addType)) {
377                     processJavaTypeElementSwagger(addType, getJavaTypeElementSwagger(addType),
378                         pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId, null,
379                         newPathParams, validEdges);
380                 }
381                 // need item name of array
382                 String itemName = processJavaTypeElementSwagger(addType,
383                     getJavaTypeElementSwagger(addType), pathSb, definitionsSb, path,
384                     tag == null ? useTag : tag, useOpId, "array", null, null);
385
386                 if (itemName != null) {
387                     if (addType.equals("AaiInternal")) {
388                         logger.debug("addType AaiInternal, skip properties");
389
390                     } else if (getItemName == null) {
391                         ++propertyCnt;
392                         sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
393                         if ( "RelationshipList".equals(addType)) {
394                             sbProperties.append("        type: object\n");
395                             sbProperties.append("        $ref: \"#/definitions/"
396                                 + itemName + "\"\n");
397                         } else {
398                                 if ( "relationship".equals(itemName) ) {
399                                         System.out.println(v + "-relationship added as array for getItemName null");
400                                 }
401                                 sbProperties.append("        type: array\n        items:\n");
402                                 sbProperties.append("          $ref: \"#/definitions/"
403                             + (itemName == "" ? "inventory-item-data" : itemName) + "\"\n");
404                         }
405                         if (StringUtils.isNotEmpty(elementDescription)) {
406                             sbProperties
407                                 .append("        description: " + elementDescription + "\n");
408                         }
409                     }
410                 } else {
411                     if (("java.util.ArrayList")
412                         .equals(xmlElementElement.getAttribute("container-type"))) {
413                         // need properties for getXmlRootElementName(addType)
414                         namespaceFilter.add(getXmlRootElementName(addType));
415                         newPathParams =
416                             new StringBuffer((pathParams == null ? "" : pathParams.toString())
417                                 + sbParameters.toString());
418                         processJavaTypeElementSwagger(addType, getJavaTypeElementSwagger(addType),
419                             pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId, null,
420                             newPathParams, validEdges);
421                         useName = getXmlRootElementName(addType);
422                         sbProperties.append("      " + useName + ":\n");
423                         if ( "relationship".equals(useName)) {
424                             sbProperties.append("        type: object\n");
425                             sbProperties.append("        $ref: \"#/definitions/relationship\"\n");
426                         } else {
427                                     sbProperties.append("        type: array\n        items:          \n");
428                                     sbProperties.append("          $ref: \"#/definitions/"
429                                         + getXmlRootElementName(addType) + "\"\n");
430                                     if (StringUtils.isNotEmpty(elementDescription)) {
431                                         sbProperties
432                                             .append("        description: " + elementDescription + "\n");
433                                     }
434                         }
435
436                     } else {
437                         // Make sure certain types added to the filter don't appear
438                         if (nodeFilter.contains(getXmlRootElementName(addType))) {
439                             ;
440                         } else {
441                             sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
442                             sbProperties.append("        type: object\n");
443                             sbProperties.append("        $ref: \"#/definitions/"
444                                 + getXmlRootElementName(addType) + "\"\n");
445                         }
446                     }
447                     if (StringUtils.isNotEmpty(elementDescription)) {
448                         sbProperties.append("        description: " + elementDescription + "\n");
449                     }
450                     ++propertyCnt;
451                 }
452             }
453         }
454
455         if (sbParameters.toString().length() > 0) {
456             if (pathParams == null) {
457                 pathParams = new StringBuffer();
458             }
459             pathParams.append(sbParameters);
460         }
461         GetOperation get = new GetOperation(useOpId, xmlRootElementName, tag, path,
462             pathParams == null ? "" : pathParams.toString());
463         pathSb.append(get.toString());
464         logger.debug("opId vs useOpId:" + opId + " vs " + useOpId + " PathParams=" + pathParams);
465         // add PUT
466         PutOperation put = new PutOperation(useOpId, xmlRootElementName, tag, path,
467             pathParams == null ? "" : pathParams.toString(), this.v);
468         pathSb.append(put.toString());
469         // add PATCH
470         PatchOperation patch = new PatchOperation(useOpId, xmlRootElementName, tag, path,
471             pathParams == null ? "" : pathParams.toString());
472         pathSb.append(patch.toString());
473         // add DELETE
474         DeleteOperation del = new DeleteOperation(useOpId, xmlRootElementName, tag, path,
475             pathParams == null ? "" : pathParams.toString());
476         pathSb.append(del.toString());
477         if (generatedJavaType.containsKey(xmlRootElementName)) {
478             logger.debug("xmlRootElementName(1)=" + xmlRootElementName);
479             return null;
480         }
481
482         boolean processingInventoryDef = false;
483         String dict = null;
484         if (xmlRootElementName.equals("inventory")) {
485             // inventory properties for each oxm to be concatenated
486             processingInventoryDef = true;
487             if (inventoryDefSb == null) {
488                 inventoryDefSb = new StringBuilder();
489                 definitionsSb.append("  " + xmlRootElementName + ":\n");
490                 definitionsLocalSb.append("  " + xmlRootElementName + ":\n");
491                 definitionsLocalSb.append("    properties:\n");
492             }
493         } else if (xmlRootElementName.equals("relationship")) {
494             definitionsSb.append("  " + "relationship-dict" + ":\n");
495             definitionsLocalSb.append("  " + "relationship-dict" + ":\n");
496             dict = getDictionary(xmlRootElementName);
497         } else {
498             definitionsSb.append("  " + xmlRootElementName + ":\n");
499             definitionsLocalSb.append("  " + xmlRootElementName + ":\n");
500         }
501         // Collection<EdgeDescription> edges = edgeRuleSet.getEdgeRules(xmlRootElementName );
502         DeleteFootnoteSet footnotes = new DeleteFootnoteSet(xmlRootElementName);
503         StringBuffer sbEdge = new StringBuffer();
504         LinkedHashSet<String> preventDelete = new LinkedHashSet<String>();
505         String prevent = null;
506         String nodeCaption = new String("      ###### Related Nodes\n");
507         try {
508             EdgeRuleQuery q =
509                 new EdgeRuleQuery.Builder(xmlRootElementName).version(v).fromOnly().build();
510             Multimap<String, EdgeRule> results = ei.getRules(q);
511             SortedSet<String> ss = new TreeSet<String>(results.keySet());
512             sbEdge.append(nodeCaption);
513             nodeCaption = "";
514             for (String key : ss) {
515                 results.get(key).stream()
516                     .filter((i) -> (i.getFrom().equals(xmlRootElementName) && (!i.isPrivateEdge())))
517                     .forEach((i) -> {
518                         logger.info(new String(new StringBuffer("      - TO ").append(i.getTo())
519                             .append(i.getDirection().toString()).append(i.getContains())));
520                     });
521                 results.get(key).stream()
522                     .filter((i) -> (i.getFrom().equals(xmlRootElementName) && (!i.isPrivateEdge())))
523                     .forEach((i) -> {
524                         sbEdge.append("      - TO " + i.getTo());
525                         EdgeDescription ed = new EdgeDescription(i);
526                         String footnote = ed.getAlsoDeleteFootnote(xmlRootElementName);
527                         sbEdge.append(ed.getRelationshipDescription("TO", xmlRootElementName)
528                             + footnote + "\n");
529                         if (StringUtils.isNotEmpty(footnote)) {
530                             footnotes.add(footnote);
531                         }
532                     });
533                 results.get(key).stream()
534                     .filter((i) -> (i.getFrom().equals(xmlRootElementName)
535                         && (!i.isPrivateEdge() && i.getPreventDelete().equals("OUT"))))
536                     .forEach((i) -> {
537                         preventDelete.add(i.getTo().toUpperCase());
538                     });
539             }
540         } catch (Exception e) {
541             logger.debug("xmlRootElementName: " + xmlRootElementName + " from edge exception\n", e);
542         }
543         try {
544             EdgeRuleQuery q1 =
545                 new EdgeRuleQuery.Builder(xmlRootElementName).version(v).toOnly().build();
546             Multimap<String, EdgeRule> results = ei.getRules(q1);
547             SortedSet<String> ss = new TreeSet<String>(results.keySet());
548             sbEdge.append(nodeCaption);
549             for (String key : ss) {
550                 results.get(key).stream()
551                     .filter((i) -> (i.getTo().equals(xmlRootElementName) && (!i.isPrivateEdge())))
552                     .forEach((i) -> {
553                         sbEdge.append("      - FROM " + i.getFrom());
554                         EdgeDescription ed = new EdgeDescription(i);
555                         String footnote = ed.getAlsoDeleteFootnote(xmlRootElementName);
556                         sbEdge.append(ed.getRelationshipDescription("FROM", xmlRootElementName)
557                             + footnote + "\n");
558                         if (StringUtils.isNotEmpty(footnote)) {
559                             footnotes.add(footnote);
560                         }
561                     });
562                 results.get(key).stream()
563                     .filter((i) -> (i.getTo().equals(xmlRootElementName) && (!i.isPrivateEdge())))
564                     .forEach((i) -> {
565                         logger.info(new String(new StringBuffer("      - FROM ").append(i.getFrom())
566                             .append(i.getDirection().toString()).append(i.getContains())));
567                     });
568                 results.get(key).stream()
569                     .filter((i) -> (i.getTo().equals(xmlRootElementName)
570                         && (!i.isPrivateEdge() && i.getPreventDelete().equals("IN"))))
571                     .forEach((i) -> {
572                         preventDelete.add(i.getFrom().toUpperCase());
573                     });
574             }
575         } catch (Exception e) {
576             logger.debug("xmlRootElementName: " + xmlRootElementName + " to edge exception\n", e);
577         }
578         if (preventDelete.size() > 0) {
579             prevent = xmlRootElementName.toUpperCase() + " cannot be deleted if related to "
580                 + String.join(",", preventDelete);
581             logger.debug(prevent);
582         }
583
584         if (StringUtils.isNotEmpty(prevent)) {
585             footnotes.add(prevent);
586         }
587         if (footnotes.footnotes.size() > 0) {
588             sbEdge.append(footnotes.toString());
589         }
590         validEdges = sbEdge.toString();
591
592         // Handle description property. Might have a description OR valid edges OR both OR neither.
593         // Only put a description: tag if there is at least one.
594         if (StringUtils.isNotEmpty(pathDescriptionProperty) || StringUtils.isNotEmpty(validEdges)) {
595             definitionsSb.append("    description: |\n");
596             definitionsLocalSb.append("    description: |\n");
597
598             if (pathDescriptionProperty != null) {
599                 definitionsSb.append("      " + pathDescriptionProperty + "\n");
600                 definitionsLocalSb.append("      " + pathDescriptionProperty + "\n");
601             }
602             definitionsSb.append(validEdges);
603             definitionsLocalSb.append(validEdges);
604         }
605
606         if (requiredCnt > 0) {
607             definitionsSb.append(sbRequired);
608             definitionsLocalSb.append(sbRequired);
609         }
610
611         if (propertyCnt > 0) {
612             definitionsSb.append("    properties:\n");
613             definitionsSb.append(sbProperties);
614             if (!processingInventoryDef) {
615                 definitionsLocalSb.append("    properties:\n");
616             }
617             definitionsLocalSb.append(sbProperties);
618         }
619         try {
620             namespaceFilter.add(xmlRootElementName);
621             if (xmlRootElementName.equals("inventory")) {
622                 // will add to javaTypeDefinitions at end
623                 inventoryDefSb.append(definitionsLocalSb.toString());
624             } else if (xmlRootElementName.equals("relationship")) {
625                 javaTypeDefinitions.put(xmlRootElementName, dict);
626                 javaTypeDefinitions.put(xmlRootElementName + "-dict",
627                     definitionsLocalSb.toString());
628             } else {
629                 javaTypeDefinitions.put(xmlRootElementName, definitionsLocalSb.toString());
630             }
631         } catch (Exception e) {
632             e.printStackTrace();
633             logger.error("Exception adding in javaTypeDefinitions", e);
634         }
635         if (xmlRootElementName.equals("inventory")) {
636             logger.trace("skip xmlRootElementName(2)=" + xmlRootElementName);
637             return null;
638         }
639         generatedJavaType.put(xmlRootElementName, null);
640         /*
641          * if( validTag(javaTypeName) && javaTypeName == useTag && tag == null) {
642          * String nameSpaceResult =
643          * getDocumentHeader()+pathSb.toString()+appendDefinitions(namespaceFilter);
644          * writeYAMLfile(javaTypeName, nameSpaceResult);
645          * totalPathSbAccumulator.append(pathSb);
646          * pathSb.delete(0, pathSb.length());
647          * namespaceFilter.clear();
648          * }
649          */
650         logger.trace("xmlRootElementName(2)=" + xmlRootElementName);
651         return null;
652     }
653
654     private void writeYAMLfile(String outfileName, String fileContent) {
655         outfileName = (StringUtils.isEmpty(outfileName)) ? "aai_swagger" : outfileName;
656         outfileName = (outfileName.lastIndexOf(File.separator) == -1)
657             ? yaml_dir + File.separator + outfileName + "_" + v.toString() + "." + generateTypeYAML
658             : outfileName;
659         File outfile = new File(outfileName);
660         File parentDir = outfile.getParentFile();
661         if (parentDir != null && !parentDir.exists()) {
662             parentDir.mkdirs();
663         }
664         try {
665             outfile.createNewFile();
666         } catch (IOException e) {
667             logger.error("Exception creating output file " + outfileName);
668             e.printStackTrace();
669         }
670         try {
671             Charset charset = Charset.forName("UTF-8");
672             Path path = Paths.get(outfileName);
673             try (BufferedWriter bw = Files.newBufferedWriter(path, charset)) {
674                 bw.write(fileContent);
675             }
676         } catch (IOException e) {
677             logger.error("Exception writing output file " + outfileName);
678             e.printStackTrace();
679         }
680     }
681
682     public boolean validTag(String tag) {
683         if (tag != null) {
684             // set ignore to true to skip Actions and Search
685             boolean topCheck = checkTopLevel(tag, true);
686             if (topCheck) {
687                 return true;
688             }
689         }
690         return false;
691     }
692
693 }