Merge "AAI-1523 Tweak onap-java-formatter.xml"
[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(),e);
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                         processJavaTypeElementSwagger( javaTypeName, javaTypeElement, pathSb,
142                                 definitionsSb, null, null, null, null, null, null);
143                 }
144                 sb.append(pathSb);
145
146                 sb.append(appendDefinitions());
147                 PutRelationPathSet prp = new PutRelationPathSet(v);
148                 prp.generateRelations(ei);
149                 return sb.toString();
150         }
151         
152         public String appendDefinitions() {
153                 return appendDefinitions(null);
154         }
155         
156         public String appendDefinitions(Set<String> namespaceFilter) {
157                 //append definitions
158                 if ( inventoryDefSb != null ) {
159                         javaTypeDefinitions.put("inventory", inventoryDefSb.toString());
160                 }
161                 StringBuffer sb = new StringBuffer("definitions:\n");
162                 Map<String, String> sortedJavaTypeDefinitions = new TreeMap<String, String>(javaTypeDefinitions);
163                 for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
164 //                  logger.info("Key: "+entry.getKey()+"Value: "+ entry.getValue());
165                     if(namespaceFilter != null && entry.getKey().matches("service-capabilities")) {
166                         for(String tally : namespaceFilter) { logger.debug("Marker: "+tally);}
167                     }
168                         if(namespaceFilter != null && (! namespaceFilter.contains(entry.getKey()))) {
169                                 continue;
170                         }
171                     logger.debug("Key: "+entry.getKey()+"Test: "+ (entry.getKey() == "relationship-dict"));     
172                     if(entry.getKey().matches("relationship-dict")) {
173                             String jb=entry.getValue();
174                         logger.debug("Value: "+jb);
175                             int ndx=jb.indexOf("related-to-property:");
176                             if(ndx > 0) {
177                                 jb=jb.substring(0, ndx);
178                                 jb=jb.replaceAll(" +$", "");
179                             }
180                         logger.debug("Value-after: "+jb);
181                         sb.append(jb);
182                         continue;
183                     }
184                     sb.append(entry.getValue());
185                 }
186                 
187                 sb.append("patchDefinitions:\n");
188                 for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
189                         if(namespaceFilter != null && (! namespaceFilter.contains(entry.getKey()))) {
190                                 continue;
191                         }
192                     String jb=entry.getValue().replaceAll("/definitions/", "/patchDefinitions/");
193                     int ndx=jb.indexOf("relationship-list:");
194                     if(ndx > 0) {
195                         jb=jb.substring(0, ndx);
196                         jb=jb.replaceAll(" +$", "");
197                     }
198                     int ndx1=jb.indexOf("resource-version:");
199                         logger.debug("Key: "+entry.getKey()+" index: " + ndx1);                 
200                         logger.debug("Value: "+jb);                     
201                         if(ndx1 > 0) {
202                             jb=jb.substring(0, ndx1);
203                             jb=jb.replaceAll(" +$", "");
204                     }
205                         logger.debug("Value-after: "+jb);
206                     sb.append(jb);
207                 }
208                     
209                 sb.append("getDefinitions:\n");
210                 for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
211                         if(namespaceFilter != null && (! namespaceFilter.contains(entry.getKey()))) {
212                                 continue;
213                         }
214                     String jb=entry.getValue().replaceAll("/definitions/", "/getDefinitions/");
215                     sb.append(jb);
216                 }
217                 return sb.toString();
218         }
219         
220         private String getDictionary(String resource ) {
221                 StringBuffer dictSb = new StringBuffer();
222                 dictSb.append("  " + resource + ":\n");
223                 dictSb.append("    description: |\n");
224                 dictSb.append("      dictionary of " + resource + "\n" );
225                 dictSb.append("    type: object\n");
226                 dictSb.append("    properties:\n");
227                 dictSb.append("      " + resource + ":\n");
228                 dictSb.append("        type: array\n");
229                 dictSb.append("        items:\n");
230                 dictSb.append("          $ref: \"#/definitions/" + resource + "-dict\"\n");
231                 return dictSb.toString();
232         }
233         
234         private String processJavaTypeElementSwagger( String javaTypeName, Element javaTypeElement,
235                         StringBuffer pathSb, StringBuffer definitionsSb, String path, String tag, String opId,
236                         String getItemName, StringBuffer pathParams, String validEdges) {
237                 
238                 String xmlRootElementName = getXMLRootElementName(javaTypeElement);
239                 StringBuilder definitionsLocalSb = new StringBuilder(256);
240                 
241                 String useTag = null;
242                 String useOpId = null;
243                 logger.debug("tag="+tag);
244                 if ( tag != null ) {
245                         switch ( tag ) {
246                         case "Network":
247                         case "ServiceDesignAndCreation":
248                         case "Business":
249                         case "LicenseManagement":
250                         case "CloudInfrastructure":
251                         case "Common":
252                                 break;
253                         default:
254                                 logger.debug("javaTypeName="+javaTypeName);
255                                 return null;
256                         }
257                 }
258                 
259                 if ( !javaTypeName.equals("Inventory") ) {
260                         if ( javaTypeName.equals("AaiInternal"))
261                                 return null;
262                         if ( opId == null )
263                                 useOpId = javaTypeName;
264                         else
265                                 useOpId = opId + javaTypeName;
266                         if ( tag == null )
267                                 useTag = javaTypeName;
268                 }
269                 path = xmlRootElementName.equals("inventory") ? "" : (path == null) ? "/" + xmlRootElementName : path + "/" + xmlRootElementName;
270                 XSDJavaType javaType = new XSDJavaType(javaTypeElement);
271                 if ( getItemName != null) {
272                 if ( getItemName.equals("array") )
273                         return javaType.getArrayType();
274                 else
275                         return javaType.getItemName();
276                 }
277                         
278                 NodeList parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
279                 if ( parentNodes.getLength() == 0 ) {
280                         logger.debug( "no java-attributes for java-type " + javaTypeName);
281                         return "";
282                 }
283
284                 String pathDescriptionProperty = javaType.getPathDescriptionProperty();
285                 String container = javaType.getContainerProperty();
286                 Vector<String> indexedProps = javaType.getIndexedProps();
287                 Vector<String> containerProps = new Vector<String>();
288                 if(container != null) {
289                         logger.debug("javaTypeName " + javaTypeName + " container:" + container +" indexedProps:"+indexedProps);
290                 }
291                 
292                 Element parentElement = (Element)parentNodes.item(0);
293                 NodeList xmlElementNodes = parentElement.getElementsByTagName("xml-element");
294
295                 StringBuffer sbParameters = new StringBuffer();
296                 StringBuffer sbRequired = new StringBuffer();
297                 int requiredCnt = 0;
298                 int propertyCnt = 0;
299                 StringBuffer sbProperties = new StringBuffer();
300                 
301                 if ( appliedPaths.containsKey(path)) 
302                         return null;
303                 
304                 StringTokenizer st = new StringTokenizer(path, "/");
305                 logger.debug("path: " + path + " st? " + st.toString());
306                 if ( st.countTokens() > 1 && getItemName == null ) {
307                         logger.debug("appliedPaths: " + appliedPaths + " containsKey? " + appliedPaths.containsKey(path));
308                         appliedPaths.put(path, xmlRootElementName);
309                 }
310
311                 Vector<String> addTypeV = null;
312                 for ( int i = 0; i < xmlElementNodes.getLength(); ++i ) {
313                                 XSDElement xmlElementElement = new XSDElement((Element)xmlElementNodes.item(i));
314                                 if ( !xmlElementElement.getParentNode().isSameNode(parentElement))
315                                         continue;
316                                 String elementDescription=xmlElementElement.getPathDescriptionProperty();
317                                 if(getItemName == null) {
318                                         addTypeV = xmlElementElement.getAddTypes(v.toString());
319                                 }
320                     if ( "true".equals(xmlElementElement.getAttribute("xml-key"))) {
321                         path += "/{" + xmlElementElement.getAttribute("name") + "}";
322                     }
323                     logger.debug("path: " + path);
324                 logger.debug( "xmlElementElement.getAttribute(required):"+xmlElementElement.getAttribute("required") );
325                                 
326                                 if ( ("true").equals(xmlElementElement.getAttribute("required"))) {
327                                         if ( requiredCnt == 0 )
328                                                 sbRequired.append("    required:\n");
329                                         ++requiredCnt;
330                                         if ( addTypeV == null || addTypeV.isEmpty()) {
331                                                 sbRequired.append("    - " + xmlElementElement.getAttribute("name") + "\n");
332                                         } else { 
333                                                 for ( int k = 0; k < addTypeV.size(); ++k ) {
334                                                         sbRequired.append("    - " + getXmlRootElementName(addTypeV.elementAt(k)) + ":\n");
335                                                 }
336                                         }
337                                 }
338
339                                 if ( "true".equals(xmlElementElement.getAttribute("xml-key")) )  {
340                                         sbParameters.append(xmlElementElement.getPathParamYAML(elementDescription));
341                                 }
342                                 if (  indexedProps != null
343                                                 && indexedProps.contains(xmlElementElement.getAttribute("name") ) ) {
344                                         containerProps.add(xmlElementElement.getQueryParamYAML());
345                                         GetOperation.addContainerProps(container, containerProps);
346                                 }
347                         if ( xmlElementElement.isStandardType()) {
348                                 sbProperties.append(xmlElementElement.getTypePropertyYAML());
349                                 ++propertyCnt;
350                         }
351                         
352                         StringBuffer newPathParams = new StringBuffer((pathParams == null ? "" : pathParams.toString())+sbParameters.toString()); 
353                 for ( int k = 0; addTypeV != null && k < addTypeV.size(); ++k ) {
354                         String addType = addTypeV.elementAt(k);
355                                 namespaceFilter.add(getXmlRootElementName(addType));
356                                 logger.debug("addType: "+ addType);
357                 
358                         if ( opId == null || !opId.contains(addType)) {
359                                 processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), 
360                                         pathSb, definitionsSb, path,  tag == null ? useTag : tag, useOpId, null,
361                                         newPathParams, validEdges);
362                         }
363                         // need item name of array
364                                 String itemName = processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), 
365                                         pathSb, definitionsSb, path,  tag == null ? useTag : tag, useOpId, 
366                                                         "array", null, null );
367                                         
368                                 if ( itemName != null ) {
369                                         if ( addType.equals("AaiInternal") ) {
370                                                 logger.debug( "addType AaiInternal, skip properties");
371                                                         
372                                         } else if ( getItemName == null) {
373                                                 ++propertyCnt;
374                                                 sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
375                                                 sbProperties.append("        type: array\n        items:\n");
376                                                 sbProperties.append("          $ref: \"#/definitions/" + (itemName == "" ? "inventory-item-data" : itemName) + "\"\n");
377                                                 if ( StringUtils.isNotEmpty(elementDescription) )
378                                                         sbProperties.append("        description: " + elementDescription + "\n");
379                                         }
380                                 } else {
381                                         if ( ("java.util.ArrayList").equals(xmlElementElement.getAttribute("container-type"))) {
382                                                         // need properties for getXmlRootElementName(addType)
383                                                 namespaceFilter.add(getXmlRootElementName(addType));
384                                                 newPathParams = new StringBuffer((pathParams == null ? "" : pathParams.toString())+sbParameters.toString()); 
385                                                 processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), 
386                                                         pathSb, definitionsSb, path,  tag == null ? useTag : tag, useOpId, 
387                                                                         null, newPathParams, validEdges );
388                                                 sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
389                                                 sbProperties.append("        type: array\n        items:          \n");
390                                                 sbProperties.append("          $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n");
391                                                 if ( StringUtils.isNotEmpty(elementDescription) )
392                                                         sbProperties.append("        description: " + elementDescription + "\n");
393
394                                         } else {
395                                                 //Make sure certain types added to the filter don't appear
396                                                 if(nodeFilter.contains(getXmlRootElementName(addType))) {
397                                                         ;
398                                                 } else {
399                                                         sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
400                                                         sbProperties.append("        type: object\n");
401                                                         sbProperties.append("        $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n");
402                                                 }
403                                         }
404                                         if ( StringUtils.isNotEmpty(elementDescription) )
405                                                 sbProperties.append("        description: " + elementDescription + "\n");
406                                         ++propertyCnt;
407                                 }
408                 }
409                 }
410                 
411                 if ( sbParameters.toString().length() > 0 ) {
412                         if ( pathParams == null )
413                                 pathParams = new StringBuffer();
414                         pathParams.append(sbParameters);
415                 }
416                 GetOperation get = new GetOperation(useOpId, xmlRootElementName, tag, path,  pathParams == null ? "" : pathParams.toString());
417             pathSb.append(get.toString());
418             logger.debug("opId vs useOpId:"+opId+" vs "+useOpId+" PathParams="+pathParams);
419                 // add PUT
420                 PutOperation put = new PutOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString(), this.v);
421                 pathSb.append(put.toString());
422                 // add PATCH
423                 PatchOperation patch = new PatchOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString());
424                 pathSb.append(patch.toString());
425                 // add DELETE
426                 DeleteOperation del = new DeleteOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString());
427                 pathSb.append(del.toString());
428                 if ( generatedJavaType.containsKey(xmlRootElementName) ) {
429                         logger.debug("xmlRootElementName(1)="+xmlRootElementName);
430                         return null;
431                 }
432         
433                 boolean processingInventoryDef = false;
434                 String dict = null;
435                 if ( xmlRootElementName.equals("inventory")) {
436                         // inventory properties for each oxm to be concatenated
437                         processingInventoryDef = true;
438                         if ( inventoryDefSb == null ) {
439                                 inventoryDefSb = new StringBuilder();
440                                 definitionsSb.append("  " + xmlRootElementName + ":\n");
441                                 definitionsLocalSb.append("  " + xmlRootElementName + ":\n");
442                                 definitionsLocalSb.append("    properties:\n");
443                         }
444                 } else if ( xmlRootElementName.equals("relationship")) {
445                         definitionsSb.append("  " + "relationship-dict" + ":\n");
446                         definitionsLocalSb.append("  " + "relationship-dict" + ":\n");
447                         dict = getDictionary(xmlRootElementName);
448                 } else {
449                         definitionsSb.append("  " + xmlRootElementName + ":\n");
450                         definitionsLocalSb.append("  " + xmlRootElementName + ":\n");
451                 }
452 //              Collection<EdgeDescription> edges = edgeRuleSet.getEdgeRules(xmlRootElementName );
453                 DeleteFootnoteSet footnotes = new DeleteFootnoteSet(xmlRootElementName);
454                 StringBuffer sbEdge = new StringBuffer();
455                 LinkedHashSet<String> preventDelete = new LinkedHashSet<String>();
456                 String prevent=null;
457                 String nodeCaption = new String("      ###### Related Nodes\n");
458                 try {
459                         EdgeRuleQuery q = new EdgeRuleQuery.Builder(xmlRootElementName).version(v).fromOnly().build();
460                         Multimap<String, EdgeRule> results = ei.getRules(q);
461                         SortedSet<String> ss=new TreeSet<String>(results.keySet());
462                         sbEdge.append(nodeCaption);
463                         nodeCaption="";
464                         for(String key : ss) {
465                                 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())));} );
466                                 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);} );
467                                 results.get(key).stream().filter((i) -> (i.getFrom().equals(xmlRootElementName) && (! i.isPrivateEdge() && i.getPreventDelete().equals("OUT")))).forEach((i) ->{ preventDelete.add(i.getTo().toUpperCase());} );
468                         }
469                 } catch(Exception e) {
470                         logger.debug("xmlRootElementName: "+xmlRootElementName+" from edge exception\n", e);
471                 }
472                 try {
473                         EdgeRuleQuery q1 = new EdgeRuleQuery.Builder(xmlRootElementName).version(v).toOnly().build();
474                         Multimap<String, EdgeRule> results = ei.getRules(q1);
475                         SortedSet<String> ss=new TreeSet<String>(results.keySet());
476                         sbEdge.append(nodeCaption);
477                         for(String key : ss) {
478                                 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);} );
479                                 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())));} );
480                                 results.get(key).stream().filter((i) -> (i.getTo().equals(xmlRootElementName) && (! i.isPrivateEdge() && i.getPreventDelete().equals("IN")))).forEach((i) ->{ preventDelete.add(i.getFrom().toUpperCase());} );
481                         }
482                 } catch(Exception e) {
483                         logger.debug("xmlRootElementName: "+xmlRootElementName+" to edge exception\n", e);
484                 }
485                 if(preventDelete.size() > 0) {
486                         prevent = xmlRootElementName.toUpperCase()+" cannot be deleted if related to "+String.join(",",preventDelete);
487                         logger.debug(prevent);
488                 }
489
490                 if(StringUtils.isNotEmpty(prevent)) {
491                         footnotes.add(prevent);
492                 }
493                 if(footnotes.footnotes.size() > 0) {
494                         sbEdge.append(footnotes.toString());
495                 }                       
496                 validEdges = sbEdge.toString();
497
498                 // Handle description property.  Might have a description OR valid edges OR both OR neither.
499                 // Only put a description: tag if there is at least one.
500                 if (StringUtils.isNotEmpty(pathDescriptionProperty) || StringUtils.isNotEmpty(validEdges) ) {
501                         definitionsSb.append("    description: |\n");
502                         definitionsLocalSb.append("    description: |\n");      
503
504                         if ( pathDescriptionProperty != null ) {
505                                 definitionsSb.append("      " + pathDescriptionProperty + "\n" );
506                                 definitionsLocalSb.append("      " + pathDescriptionProperty    + "\n" );
507                         }
508                         definitionsSb.append(validEdges);
509                         definitionsLocalSb.append(validEdges);
510                 }
511                 
512                 if ( requiredCnt > 0 ) {
513                         definitionsSb.append(sbRequired);
514                         definitionsLocalSb.append(sbRequired);
515                 }
516                         
517                 if ( propertyCnt > 0 ) {
518                         definitionsSb.append("    properties:\n");
519                         definitionsSb.append(sbProperties);
520                         if  ( !processingInventoryDef) {
521                                 definitionsLocalSb.append("    properties:\n");
522                         }
523                         definitionsLocalSb.append(sbProperties);
524                 }
525                 try {
526                         namespaceFilter.add(xmlRootElementName);
527                         if ( xmlRootElementName.equals("inventory") ) {
528                                 //will add to javaTypeDefinitions at end 
529                                 inventoryDefSb.append(definitionsLocalSb.toString());
530                         } else if ( xmlRootElementName.equals("relationship") ){
531                                 javaTypeDefinitions.put(xmlRootElementName, dict);
532                                 javaTypeDefinitions.put(xmlRootElementName+ "-dict", definitionsLocalSb.toString());                    
533                         } else {
534                                 javaTypeDefinitions.put(xmlRootElementName, definitionsLocalSb.toString());
535                         }
536                 } catch (Exception e) {
537                         e.printStackTrace();
538                         logger.error("Exception adding in javaTypeDefinitions",e);
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                 Charset charset = Charset.forName("UTF-8");
572                 Path path = Paths.get(outfileName);
573                 try(BufferedWriter bw = Files.newBufferedWriter(path, charset)){
574                         bw.write(fileContent);
575                 } catch ( IOException e) {
576                         logger.error( "Exception writing output file " + outfileName);
577                         e.printStackTrace();
578                 } 
579         }
580         
581         public boolean validTag(String tag) {
582                 if(tag != null) {
583                         switch ( tag ) {
584                         case "Network":
585 //                      case "Search":
586 //                      case "Actions":
587                         case "ServiceDesignAndCreation":
588                         case "Business":
589                         case "LicenseManagement":
590                         case "CloudInfrastructure":
591                         case "Common":
592                                 return true;
593                         }
594                 }
595                 return false;
596         }
597
598 }