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