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