a14a6977408f413ad43eb8b1e4deae13ce2c1441
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / util / genxsd / YAMLfromOXM.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *    http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.onap.aai.util.genxsd;
21
22 import java.io.BufferedWriter;
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.nio.charset.Charset;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.util.HashMap;
31 import java.util.LinkedHashSet;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.SortedSet;
35 import java.util.StringTokenizer;
36 import java.util.TreeMap;
37 import java.util.TreeSet;
38 import java.util.Vector;
39
40 import javax.xml.parsers.ParserConfigurationException;
41
42 import org.apache.commons.lang3.StringUtils;
43 import org.onap.aai.edges.EdgeIngestor;
44 import org.onap.aai.edges.EdgeRule;
45 import org.onap.aai.edges.EdgeRuleQuery;
46 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
47 import org.onap.aai.exceptions.AAIException;
48 import org.onap.aai.setup.SchemaVersion;
49 import org.onap.aai.setup.SchemaVersions;
50 import org.onap.aai.nodes.NodeIngestor;
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 import com.google.common.collect.Multimap;
57
58
59 public class YAMLfromOXM extends OxmFileProcessor {
60         private static final Logger logger = LoggerFactory.getLogger("YAMLfromOXM.class");
61 //      private static StringBuffer totalPathSbAccumulator = new StringBuffer();
62         private static final String root = "../aai-schema/src/main/resources";
63         private static final String autoGenRoot = "aai-schema/src/main/resources";
64         private static final String generateTypeYAML = "yaml";
65         private static final String normalStartDir = "aai-core";
66         private static final String yaml_dir = (((System.getProperty("user.dir") != null) && (!System.getProperty("user.dir").contains(normalStartDir))) ? autoGenRoot : root) + "/aai_swagger_yaml";
67         private StringBuilder inventoryDefSb = null;
68         
69
70         private String basePath;
71         
72         public YAMLfromOXM(String basePath, SchemaVersions schemaVersions, NodeIngestor ni, EdgeIngestor ei){
73                 super(schemaVersions, ni,ei);
74                 this.basePath = basePath;
75         }
76         public void setOxmVersion(File oxmFile, SchemaVersion v) {
77                 super.setOxmVersion(oxmFile, v);
78         }
79         public void setXmlVersion(String xml, SchemaVersion v){
80                 super.setXmlVersion(xml, v);
81         }
82         
83         public void setVersion(SchemaVersion v) {
84                 super.setVersion(v);
85         }
86
87         @Override
88         public String getDocumentHeader() {
89                 StringBuffer sb = new StringBuffer();
90                 sb.append("swagger: \"2.0\"\ninfo:\n  ");
91                 sb.append("description: |");
92         if ( versionSupportsSwaggerDiff(v.toString())) {
93             sb.append("\n\n    [Differences versus the previous schema version](" + "apidocs/aai_swagger_" + v.toString() + ".diff)");
94         }
95                 sb.append("\n\n    Copyright © 2017-18 AT&T Intellectual Property. All rights reserved.\n\n    Licensed under the Creative Commons License, Attribution 4.0 Intl. (the "License"); you may not use this documentation except in compliance with the License.\n\n    You may obtain a copy of the License at\n\n    (https://creativecommons.org/licenses/by/4.0/)\n\n    Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n\n    This document is best viewed with Firefox or Chrome. Nodes can be found by appending /#/definitions/node-type-to-find to the path to this document. Edge definitions can be found with the node definitions.\n  version: \"" + v.toString() +"\"\n");
96                 sb.append("  title: Active and Available Inventory REST API\n");
97                 sb.append("  license:\n    name: Apache 2.0\n    url: http://www.apache.org/licenses/LICENSE-2.0.html\n");
98                 sb.append("  contact:\n    name:\n    url:\n    email:\n");
99                 sb.append("host:\nbasePath: " + basePath + "/" + v.toString() + "\n");
100                 sb.append("schemes:\n  - https\npaths:\n");
101                 return sb.toString();
102         }
103         
104         protected void init() throws ParserConfigurationException, SAXException, IOException, AAIException, FileNotFoundException, EdgeRuleNotFoundException {
105                 super.init();
106         }
107
108         @Override
109         public String process() throws ParserConfigurationException, SAXException, IOException, AAIException, FileNotFoundException, EdgeRuleNotFoundException {
110                 StringBuffer sb = new StringBuffer();
111                 StringBuffer pathSb = new StringBuffer();
112                 try {
113                         init();
114                 } catch(Exception e) {
115                         logger.error( "Error initializing " + this.getClass());
116                         throw e;
117                 }               
118                 pathSb.append(getDocumentHeader());
119                 StringBuffer definitionsSb = new StringBuffer();
120                 Element elem;
121                 String javaTypeName;
122                 combinedJavaTypes = new HashMap();
123                 for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
124                         elem = (Element)javaTypeNodes.item(i);
125                         javaTypeName = elem.getAttribute("name");
126                         if ( !"Inventory".equals(javaTypeName ) ) {
127                                 if ( generatedJavaType.containsKey(getXmlRootElementName(javaTypeName) ) ) {
128                                         continue;
129                                 }
130                                 // will combine all matching java-types
131                                 elem = getJavaTypeElementSwagger(javaTypeName );
132                         }                       
133                         
134                         XSDElement javaTypeElement = new XSDElement(elem);
135                         if ( javaTypeName == null ) {
136                                 String msg = "Invalid OXM file: <java-type> has no name attribute in " + oxmFile; 
137                                 logger.error(msg);
138                                 throw new AAIException(msg);
139                         }
140                         namespaceFilter.add(getXmlRootElementName(javaTypeName));
141
142                         processJavaTypeElementSwagger( javaTypeName, javaTypeElement, pathSb,
143                                 definitionsSb, null, null, null, null, null, null);
144                 }
145                 sb.append(pathSb);
146
147                 sb.append(appendDefinitions());
148                 PutRelationPathSet prp = new PutRelationPathSet(v);
149                 prp.generateRelations(ei);
150                 return sb.toString();
151         }
152         
153         public String appendDefinitions() {
154                 return appendDefinitions(null);
155         }
156         
157         public String appendDefinitions(Set<String> namespaceFilter) {
158                 //append definitions
159                 if ( inventoryDefSb != null ) {
160                         javaTypeDefinitions.put("inventory", inventoryDefSb.toString());
161                 }
162                 StringBuffer sb = new StringBuffer("definitions:\n");
163                 Map<String, String> sortedJavaTypeDefinitions = new TreeMap<String, String>(javaTypeDefinitions);
164                 for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
165 //                  logger.info("Key: "+entry.getKey()+"Value: "+ entry.getValue());
166                     if(namespaceFilter != null && entry.getKey().matches("service-capabilities")) {
167                         for(String tally : namespaceFilter) { logger.debug("Marker: "+tally);}
168                     }
169                         if(namespaceFilter != null && (! namespaceFilter.contains(entry.getKey()))) {
170                                 continue;
171                         }
172                     logger.debug("Key: "+entry.getKey()+"Test: "+ (entry.getKey() == "relationship-dict"));     
173                     if(entry.getKey().matches("relationship-dict")) {
174                             String jb=entry.getValue();
175                         logger.debug("Value: "+jb);
176                             int ndx=jb.indexOf("related-to-property:");
177                             if(ndx > 0) {
178                                 jb=jb.substring(0, ndx);
179                                 jb=jb.replaceAll(" +$", "");
180                             }
181                         logger.debug("Value-after: "+jb);
182                         sb.append(jb);
183                         continue;
184                     }
185                     sb.append(entry.getValue());
186                 }
187                 
188                 sb.append("patchDefinitions:\n");
189                 for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
190                         if(namespaceFilter != null && (! namespaceFilter.contains(entry.getKey()))) {
191                                 continue;
192                         }
193                     String jb=entry.getValue().replaceAll("/definitions/", "/patchDefinitions/");
194                     int ndx=jb.indexOf("relationship-list:");
195                     if(ndx > 0) {
196                         jb=jb.substring(0, ndx);
197                         jb=jb.replaceAll(" +$", "");
198                     }
199                     int ndx1=jb.indexOf("resource-version:");
200                         logger.debug("Key: "+entry.getKey()+" index: " + ndx1);                 
201                         logger.debug("Value: "+jb);                     
202                         if(ndx1 > 0) {
203                             jb=jb.substring(0, ndx1);
204                             jb=jb.replaceAll(" +$", "");
205                     }
206                         logger.debug("Value-after: "+jb);
207                     sb.append(jb);
208                 }
209                     
210                 sb.append("getDefinitions:\n");
211                 for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
212                         if(namespaceFilter != null && (! namespaceFilter.contains(entry.getKey()))) {
213                                 continue;
214                         }
215                     String jb=entry.getValue().replaceAll("/definitions/", "/getDefinitions/");
216                     sb.append(jb);
217                 }
218                 return sb.toString();
219         }
220         
221         private String getDictionary(String resource ) {
222                 StringBuffer dictSb = new StringBuffer();
223                 dictSb.append("  " + resource + ":\n");
224                 dictSb.append("    description: |\n");
225                 dictSb.append("      dictionary of " + resource + "\n" );
226                 dictSb.append("    type: object\n");
227                 dictSb.append("    properties:\n");
228                 dictSb.append("      " + resource + ":\n");
229                 dictSb.append("        type: array\n");
230                 dictSb.append("        items:\n");
231                 dictSb.append("          $ref: \"#/definitions/" + resource + "-dict\"\n");
232                 return dictSb.toString();
233         }
234         
235         private String processJavaTypeElementSwagger( String javaTypeName, Element javaTypeElement,
236                         StringBuffer pathSb, StringBuffer definitionsSb, String path, String tag, String opId,
237                         String getItemName, StringBuffer pathParams, String validEdges) {
238
239                 String xmlRootElementName = getXMLRootElementName(javaTypeElement);
240                 StringBuilder definitionsLocalSb = new StringBuilder(256);
241                 
242                 String useTag = null;
243                 String useOpId = null;
244                 logger.debug("tag="+tag);
245                 if ( tag != null ) {
246                         switch ( tag ) {
247                         case "Network":
248                         case "ServiceDesignAndCreation":
249                         case "Business":
250                         case "LicenseManagement":
251                         case "CloudInfrastructure":
252                         case "Common":
253                                 break;
254                         default:
255                                 logger.debug("javaTypeName="+javaTypeName);
256                                 return null;
257                         }
258                 }
259                 
260                 if ( !javaTypeName.equals("Inventory") ) {
261                         if ( javaTypeName.equals("AaiInternal"))
262                                 return null;
263                         if ( opId == null )
264                                 useOpId = javaTypeName;
265                         else
266                                 useOpId = opId + javaTypeName;
267                         if ( tag == null )
268                                 useTag = javaTypeName;
269                 }
270                 path = xmlRootElementName.equals("inventory") ? "" : (path == null) ? "/" + xmlRootElementName : path + "/" + xmlRootElementName;
271                 XSDJavaType javaType = new XSDJavaType(javaTypeElement);
272                 if ( getItemName != null) {
273                 if ( getItemName.equals("array") )
274                         return javaType.getArrayType();
275                 else
276                         return javaType.getItemName();
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> containerProps = new Vector<String>();
289                 if(container != null) {
290                         logger.debug("javaTypeName " + javaTypeName + " container:" + container +" indexedProps:"+indexedProps);
291                 }
292                 
293                 Element parentElement = (Element)parentNodes.item(0);
294                 NodeList xmlElementNodes = parentElement.getElementsByTagName("xml-element");
295
296                 StringBuffer sbParameters = new StringBuffer();
297                 StringBuffer sbRequired = new StringBuffer();
298                 int requiredCnt = 0;
299                 int propertyCnt = 0;
300                 StringBuffer sbProperties = new StringBuffer();
301                 
302                 if ( appliedPaths.containsKey(path)) 
303                         return null;
304                 
305                 StringTokenizer st = new StringTokenizer(path, "/");
306                 logger.debug("path: " + path + " st? " + st.toString());
307                 if ( st.countTokens() > 1 && getItemName == null ) {
308                         logger.debug("appliedPaths: " + appliedPaths + " containsKey? " + appliedPaths.containsKey(path));
309                         appliedPaths.put(path, xmlRootElementName);
310                 }
311
312                 Vector<String> addTypeV = null;
313                 for ( int i = 0; i < xmlElementNodes.getLength(); ++i ) {
314                                 XSDElement xmlElementElement = new XSDElement((Element)xmlElementNodes.item(i));
315                                 if ( !xmlElementElement.getParentNode().isSameNode(parentElement))
316                                         continue;
317                                 String elementDescription=xmlElementElement.getPathDescriptionProperty();
318                                 if(getItemName == null) {
319                                         addTypeV = xmlElementElement.getAddTypes(v.toString());
320                                 }
321                     if ( "true".equals(xmlElementElement.getAttribute("xml-key"))) {
322                         path += "/{" + xmlElementElement.getAttribute("name") + "}";
323                     }
324                     logger.debug("path: " + path);
325                 logger.debug( "xmlElementElement.getAttribute(required):"+xmlElementElement.getAttribute("required") );
326                                 
327                                 if ( ("true").equals(xmlElementElement.getAttribute("required"))) {
328                                         if ( requiredCnt == 0 )
329                                                 sbRequired.append("    required:\n");
330                                         ++requiredCnt;
331                                         if ( addTypeV == null || addTypeV.isEmpty()) {
332                                                 sbRequired.append("    - " + xmlElementElement.getAttribute("name") + "\n");
333                                         } else { 
334                                                 for ( int k = 0; k < addTypeV.size(); ++k ) {
335                                                         sbRequired.append("    - " + getXmlRootElementName(addTypeV.elementAt(k)) + ":\n");
336                                                 }
337                                         }
338                                 }
339
340                                 if ( "true".equals(xmlElementElement.getAttribute("xml-key")) )  {
341                                         sbParameters.append(xmlElementElement.getPathParamYAML(elementDescription));
342                                 }
343                                 if (  indexedProps != null
344                                                 && indexedProps.contains(xmlElementElement.getAttribute("name") ) ) {
345                                         containerProps.add(xmlElementElement.getQueryParamYAML());
346                                         GetOperation.addContainerProps(container, containerProps);
347                                 }
348                         if ( xmlElementElement.isStandardType()) {
349                                 sbProperties.append(xmlElementElement.getTypePropertyYAML());
350                                 ++propertyCnt;
351                         }
352                         
353                         StringBuffer newPathParams = new StringBuffer((pathParams == null ? "" : pathParams.toString())+sbParameters.toString()); 
354                 for ( int k = 0; addTypeV != null && k < addTypeV.size(); ++k ) {
355                         String addType = addTypeV.elementAt(k);
356                                 namespaceFilter.add(getXmlRootElementName(addType));
357                                 logger.debug("addType: "+ addType);
358                 
359                         if ( opId == null || !opId.contains(addType)) {
360                                 processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), 
361                                         pathSb, definitionsSb, path,  tag == null ? useTag : tag, useOpId, null,
362                                         newPathParams, validEdges);
363                         }
364                         // need item name of array
365                                 String itemName = processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), 
366                                         pathSb, definitionsSb, path,  tag == null ? useTag : tag, useOpId, 
367                                                         "array", null, null );
368                                         
369                                 if ( itemName != null ) {
370                                         if ( addType.equals("AaiInternal") ) {
371                                                 logger.debug( "addType AaiInternal, skip properties");
372                                                         
373                                         } else if ( getItemName == null) {
374                                                 ++propertyCnt;
375                                                 sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
376                                                 sbProperties.append("        type: array\n        items:\n");
377                                                 sbProperties.append("          $ref: \"#/definitions/" + (itemName == "" ? "inventory-item-data" : itemName) + "\"\n");
378                                                 if ( StringUtils.isNotEmpty(elementDescription) )
379                                                         sbProperties.append("        description: " + elementDescription + "\n");
380                                         }
381                                 } else {
382                                         if ( ("java.util.ArrayList").equals(xmlElementElement.getAttribute("container-type"))) {
383                                                         // need properties for getXmlRootElementName(addType)
384                                                 namespaceFilter.add(getXmlRootElementName(addType));
385                                                 newPathParams = new StringBuffer((pathParams == null ? "" : pathParams.toString())+sbParameters.toString()); 
386                                                 processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), 
387                                                         pathSb, definitionsSb, path,  tag == null ? useTag : tag, useOpId, 
388                                                                         null, newPathParams, validEdges );
389                                                 sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
390                                                 sbProperties.append("        type: array\n        items:          \n");
391                                                 sbProperties.append("          $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n");
392                                                 if ( StringUtils.isNotEmpty(elementDescription) )
393                                                         sbProperties.append("        description: " + elementDescription + "\n");
394
395                                         } else {
396                                                 //Make sure certain types added to the filter don't appear
397                                                 if(nodeFilter.contains(getXmlRootElementName(addType))) {
398                                                         ;
399                                                 } else {
400                                                         sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
401                                                         sbProperties.append("        type: object\n");
402                                                         sbProperties.append("        $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n");
403                                                 }
404                                         }
405                                         if ( StringUtils.isNotEmpty(elementDescription) )
406                                                 sbProperties.append("        description: " + elementDescription + "\n");
407                                         ++propertyCnt;
408                                 }
409                 }
410                 }
411                 
412                 if ( sbParameters.toString().length() > 0 ) {
413                         if ( pathParams == null )
414                                 pathParams = new StringBuffer();
415                         pathParams.append(sbParameters);
416                 }
417                 GetOperation get = new GetOperation(useOpId, xmlRootElementName, tag, path,  pathParams == null ? "" : pathParams.toString());
418             pathSb.append(get.toString());
419             logger.debug("opId vs useOpId:"+opId+" vs "+useOpId+" PathParams="+pathParams);
420                 // add PUT
421                 PutOperation put = new PutOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString(), this.v);
422                 pathSb.append(put.toString());
423                 // add PATCH
424                 PatchOperation patch = new PatchOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString());
425                 pathSb.append(patch.toString());
426                 // add DELETE
427                 DeleteOperation del = new DeleteOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString());
428                 pathSb.append(del.toString());
429                 if ( generatedJavaType.containsKey(xmlRootElementName) ) {
430                         logger.debug("xmlRootElementName(1)="+xmlRootElementName);
431                         return null;
432                 }
433         
434                 boolean processingInventoryDef = false;
435                 String dict = null;
436                 if ( xmlRootElementName.equals("inventory")) {
437                         // inventory properties for each oxm to be concatenated
438                         processingInventoryDef = true;
439                         if ( inventoryDefSb == null ) {
440                                 inventoryDefSb = new StringBuilder();
441                                 definitionsSb.append("  " + xmlRootElementName + ":\n");
442                                 definitionsLocalSb.append("  " + xmlRootElementName + ":\n");
443                                 definitionsLocalSb.append("    properties:\n");
444                         }
445                 } else if ( xmlRootElementName.equals("relationship")) {
446                         definitionsSb.append("  " + "relationship-dict" + ":\n");
447                         definitionsLocalSb.append("  " + "relationship-dict" + ":\n");
448                         dict = getDictionary(xmlRootElementName);
449                 } else {
450                         definitionsSb.append("  " + xmlRootElementName + ":\n");
451                         definitionsLocalSb.append("  " + xmlRootElementName + ":\n");
452                 }
453 //              Collection<EdgeDescription> edges = edgeRuleSet.getEdgeRules(xmlRootElementName );
454                 DeleteFootnoteSet footnotes = new DeleteFootnoteSet(xmlRootElementName);
455                 StringBuffer sbEdge = new StringBuffer();
456                 LinkedHashSet<String> preventDelete = new LinkedHashSet<String>();
457                 String prevent=null;
458                 String nodeCaption = new String("      ###### Related Nodes\n");
459                 try {
460                         EdgeRuleQuery q = new EdgeRuleQuery.Builder(xmlRootElementName).version(v).fromOnly().build();
461                         Multimap<String, EdgeRule> results = ei.getRules(q);
462                         SortedSet<String> ss=new TreeSet<String>(results.keySet());
463                         sbEdge.append(nodeCaption);
464                         nodeCaption="";
465                         for(String key : ss) {
466                                 results.get(key).stream().filter((i) -> (i.getFrom().equals(xmlRootElementName) && (! i.isPrivateEdge()))).forEach((i) ->{ logger.info(new String(new StringBuffer("      - TO ").append(i.getTo()).append(i.getDirection().toString()).append(i.getContains())));} );
467                                 results.get(key).stream().filter((i) -> (i.getFrom().equals(xmlRootElementName) && (! i.isPrivateEdge()))).forEach((i) ->{ sbEdge.append("      - TO "+i.getTo()); EdgeDescription ed = new EdgeDescription(i);  String footnote = ed.getAlsoDeleteFootnote(xmlRootElementName); sbEdge.append(ed.getRelationshipDescription("TO", xmlRootElementName)+footnote+"\n"); if(StringUtils.isNotEmpty(footnote)) footnotes.add(footnote);} );
468                                 results.get(key).stream().filter((i) -> (i.getFrom().equals(xmlRootElementName) && (! i.isPrivateEdge() && i.getPreventDelete().equals("OUT")))).forEach((i) ->{ preventDelete.add(i.getTo().toUpperCase());} );
469                         }
470                 } catch(Exception e) {
471                         logger.debug("xmlRootElementName: "+xmlRootElementName+"\n"+e);
472                 }
473                 try {
474                         EdgeRuleQuery q1 = new EdgeRuleQuery.Builder(xmlRootElementName).version(v).toOnly().build();
475                         Multimap<String, EdgeRule> results = ei.getRules(q1);
476                         SortedSet<String> ss=new TreeSet<String>(results.keySet());
477                         sbEdge.append(nodeCaption);
478                         for(String key : ss) {
479                                 results.get(key).stream().filter((i) -> (i.getTo().equals(xmlRootElementName) && (! i.isPrivateEdge()))).forEach((i) ->{ sbEdge.append("      - FROM "+i.getFrom()); EdgeDescription ed = new EdgeDescription(i);  String footnote = ed.getAlsoDeleteFootnote(xmlRootElementName); sbEdge.append(ed.getRelationshipDescription("FROM", xmlRootElementName)+footnote+"\n"); if(StringUtils.isNotEmpty(footnote)) footnotes.add(footnote);} );
480                                 results.get(key).stream().filter((i) -> (i.getTo().equals(xmlRootElementName) && (! i.isPrivateEdge()))).forEach((i) ->{ logger.info(new String(new StringBuffer("      - FROM ").append(i.getFrom()).append(i.getDirection().toString()).append(i.getContains())));} );
481                                 results.get(key).stream().filter((i) -> (i.getTo().equals(xmlRootElementName) && (! i.isPrivateEdge() && i.getPreventDelete().equals("IN")))).forEach((i) ->{ preventDelete.add(i.getFrom().toUpperCase());} );
482                         }
483                 } catch(Exception e) {
484                         logger.debug("xmlRootElementName: "+xmlRootElementName+"\n"+e);
485                 }
486                 if(preventDelete.size() > 0) {
487                         prevent = xmlRootElementName.toUpperCase()+" cannot be deleted if related to "+String.join(",",preventDelete);
488                         logger.debug(prevent);
489                 }
490
491                 if(StringUtils.isNotEmpty(prevent)) {
492                         footnotes.add(prevent);
493                 }
494                 if(footnotes.footnotes.size() > 0) {
495                         sbEdge.append(footnotes.toString());
496                 }                       
497                 validEdges = sbEdge.toString();
498
499                 // Handle description property.  Might have a description OR valid edges OR both OR neither.
500                 // Only put a description: tag if there is at least one.
501                 if (StringUtils.isNotEmpty(pathDescriptionProperty) || StringUtils.isNotEmpty(validEdges) ) {
502                         definitionsSb.append("    description: |\n");
503                         definitionsLocalSb.append("    description: |\n");      
504
505                         if ( pathDescriptionProperty != null ) {
506                                 definitionsSb.append("      " + pathDescriptionProperty + "\n" );
507                                 definitionsLocalSb.append("      " + pathDescriptionProperty    + "\n" );
508                         }
509                         definitionsSb.append(validEdges);
510                         definitionsLocalSb.append(validEdges);
511                 }
512                 
513                 if ( requiredCnt > 0 ) {
514                         definitionsSb.append(sbRequired);
515                         definitionsLocalSb.append(sbRequired);
516                 }
517                         
518                 if ( propertyCnt > 0 ) {
519                         definitionsSb.append("    properties:\n");
520                         definitionsSb.append(sbProperties);
521                         if  ( !processingInventoryDef) {
522                                 definitionsLocalSb.append("    properties:\n");
523                         }
524                         definitionsLocalSb.append(sbProperties);
525                 }
526                 try {
527                         namespaceFilter.add(xmlRootElementName);
528                         if ( xmlRootElementName.equals("inventory") ) {
529                                 //will add to javaTypeDefinitions at end 
530                                 inventoryDefSb.append(definitionsLocalSb.toString());
531                         } else if ( xmlRootElementName.equals("relationship") ){
532                                 javaTypeDefinitions.put(xmlRootElementName, dict);
533                                 javaTypeDefinitions.put(xmlRootElementName+ "-dict", definitionsLocalSb.toString());                    
534                         } else {
535                                 javaTypeDefinitions.put(xmlRootElementName, definitionsLocalSb.toString());
536                         }
537                 } catch (Exception e) {
538                         e.printStackTrace();
539                 }
540                 if ( xmlRootElementName.equals("inventory") ) {
541                         logger.trace("skip xmlRootElementName(2)="+xmlRootElementName);
542                         return null;
543                 }               
544                 generatedJavaType.put(xmlRootElementName, null);
545 /*
546                 if( validTag(javaTypeName) && javaTypeName == useTag && tag == null) {
547                         String nameSpaceResult = getDocumentHeader()+pathSb.toString()+appendDefinitions(namespaceFilter);
548                         writeYAMLfile(javaTypeName, nameSpaceResult);
549                         totalPathSbAccumulator.append(pathSb);
550                         pathSb.delete(0, pathSb.length());
551                         namespaceFilter.clear();
552                 }
553 */
554                 logger.trace("xmlRootElementName(2)="+xmlRootElementName);
555                 return null;
556         }
557         
558         private void writeYAMLfile(String outfileName, String fileContent) {
559                 outfileName = (StringUtils.isEmpty(outfileName)) ? "aai_swagger" : outfileName;
560                 outfileName = (outfileName.lastIndexOf(File.separator) == -1) ? yaml_dir + File.separator +outfileName+"_" + v.toString() + "." + generateTypeYAML : outfileName;
561                 File outfile = new File(outfileName);
562                 File parentDir = outfile.getParentFile();
563                 if(parentDir != null && ! parentDir.exists()) 
564                         parentDir.mkdirs();
565                 try {
566                         outfile.createNewFile();
567                 } catch (IOException e) {
568                         logger.error( "Exception creating output file " + outfileName);
569                         e.printStackTrace();
570                 }
571                 BufferedWriter bw = null;
572                 Charset charset = Charset.forName("UTF-8");
573                 Path path = Paths.get(outfileName);
574                 try {
575                         bw = Files.newBufferedWriter(path, charset);
576                         bw.write(fileContent);
577                         if ( bw != null ) {
578                                 bw.close();
579                         }
580                 } catch ( IOException e) {
581                         logger.error( "Exception writing output file " + outfileName);
582                         e.printStackTrace();
583                 } 
584         }
585         
586         public boolean validTag(String tag) {
587                 if(tag != null) {
588                         switch ( tag ) {
589                         case "Network":
590 //                      case "Search":
591 //                      case "Actions":
592                         case "ServiceDesignAndCreation":
593                         case "Business":
594                         case "LicenseManagement":
595                         case "CloudInfrastructure":
596                         case "Common":
597                                 return true;
598                         }
599                 }
600                 return false;
601         }
602
603 }