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