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