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