Update the license for 2017-2018 license
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / util / GenerateXsd.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;
21
22 import com.google.common.base.Joiner;
23 import com.jayway.jsonpath.JsonPath;
24 import org.apache.commons.lang3.StringUtils;
25 import org.apache.commons.text.similarity.LevenshteinDistance;
26
27 import org.onap.aai.introspection.Version;
28 import org.onap.aai.serialization.db.EdgeProperty;
29 import org.w3c.dom.*;
30 import org.xml.sax.InputSource;
31
32 import javax.xml.XMLConstants;
33 import javax.xml.parsers.DocumentBuilder;
34 import javax.xml.parsers.DocumentBuilderFactory;
35 import javax.xml.xpath.*;
36 import java.io.*;
37 import java.nio.charset.Charset;
38 import java.nio.file.Files;
39 import java.nio.file.Path;
40 import java.nio.file.Paths;
41 import java.util.*;
42
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 public class GenerateXsd {
47         
48         private static final Logger logger = LoggerFactory.getLogger("GenerateXsd.class");
49         
50         static String apiVersion = null;
51         static String apiVersionFmt = null;
52         static boolean useAnnotationsInXsd = false;
53         static String responsesUrl = null;
54         static String responsesLabel = null;
55         static String jsonEdges = null;
56
57         static Map<String, String> generatedJavaType;
58         static Map<String, String> appliedPaths;
59         static Map<String, String> deletePaths;
60         static Map<String, String> putRelationPaths;
61         static NodeList javaTypeNodes;
62         static Map<String,String> javaTypeDefinitions = createJavaTypeDefinitions();
63     private static Map<String, String> createJavaTypeDefinitions()
64     {
65         StringBuffer aaiInternal = new StringBuffer();
66         Map<String,String> javaTypeDefinitions = new HashMap<String, String>();
67         aaiInternal.append("  aai-internal:\n");
68         aaiInternal.append("    properties:\n");
69         aaiInternal.append("      property-name:\n");
70         aaiInternal.append("        type: string\n");
71         aaiInternal.append("      property-value:\n");
72         aaiInternal.append("        type: string\n");
73         javaTypeDefinitions.put("aai-internal", aaiInternal.toString());
74         return javaTypeDefinitions;
75     }
76
77         public static final int VALUE_NONE = 0;
78         public static final int VALUE_DESCRIPTION = 1;
79         public static final int VALUE_INDEXED_PROPS = 2;
80         
81         private static final String generateTypeXSD = "xsd";
82         private static final String generateTypeYAML = "yaml";
83         
84         private static final String root = "../aai-schema/src/main/resources";
85         private static final String xsd_dir = root + "/aai_schema";
86         private static final String yaml_dir = root + "/aai_swagger_yaml";
87         
88         /* These three strings are for yaml auto-generation from aai-common class*/
89         private static final String normalStartDir = "aai-core";
90         private static final String autoGenRoot = "aai-schema/src/main/resources";
91         private static final String alt_yaml_dir = autoGenRoot + "/aai_swagger_yaml";
92
93         private static int annotationsStartVersion = 9; // minimum version to support annotations in xsd
94         private static int swaggerSupportStartsVersion = 7; // minimum version to support swagger documentation
95         
96         private static XPath xpath = XPathFactory.newInstance().newXPath();
97
98
99         private enum LineageType {
100                 PARENT, CHILD, UNRELATED;
101         }
102         private class EdgeDescription {
103                 
104                 private String ruleKey;
105                 private String to;
106                 private String from;
107                 private LineageType type = LineageType.UNRELATED;
108                 private String direction;
109                 private String multiplicity;
110                 private String preventDelete;
111                 private String deleteOtherV;
112                 private boolean hasDelTarget = false;
113                 private String label;
114                 private String description;
115                 /**
116                  * @return the deleteOtherV
117                  */
118                 public String getDeleteOtherV() {
119                         return deleteOtherV;
120                 }
121                 /**
122                  * @param deleteOtherV the deleteOtherV to set
123                  */
124                 public void setDeleteOtherV(String deleteOtherV) {
125                         logger.debug("Edge: "+this.getRuleKey());
126                         logger.debug("Truth: "+(("${direction}".equals(deleteOtherV)) ? "true" : "false"));
127                         logger.debug("Truth: "+(("!${direction}".equals(deleteOtherV)) ? "true" : "false"));
128
129                         if("${direction}".equals(deleteOtherV) ) {
130                                 this.deleteOtherV = this.direction;
131                         } else if("!${direction}".equals(deleteOtherV) ) {
132                                 this.deleteOtherV = this.direction.equals("IN") ? "OUT" : ((this.direction.equals("OUT")) ? "IN" : deleteOtherV);
133                         } else {
134                                 this.deleteOtherV = deleteOtherV;
135                         }
136                         logger.debug("DeleteOtherV="+deleteOtherV+"/"+this.direction+"="+this.deleteOtherV);
137                 }
138                 /**
139                  * @return the preventDelete
140                  */
141                 public String getPreventDelete() {
142                         return preventDelete;
143                 }
144                 /**
145                  * @param preventDelete the preventDelete to set
146                  */
147                 public void setPreventDelete(String preventDelete) {
148                         if(this.getTo().equals("flavor") || this.getFrom().equals("flavor") ){
149                                 logger.debug("Edge: "+this.getRuleKey());
150                                 logger.debug("Truth: "+(("${direction}".equals(preventDelete)) ? "true" : "false"));
151                                 logger.debug("Truth: "+(("!${direction}".equals(preventDelete)) ? "true" : "false"));
152                         }
153
154                         if("${direction}".equals(preventDelete) ) {
155                                 this.preventDelete = this.direction;
156                         } else if("!${direction}".equals(preventDelete) ) {
157                                 this.preventDelete = this.direction.equals("IN") ? "OUT" : ((this.direction.equals("OUT")) ? "IN" : preventDelete);
158                         } else {
159                                 this.preventDelete = preventDelete;
160                         }
161                         if(this.getTo().equals("flavor") || this.getFrom().equals("flavor")) {
162                                 logger.debug("PreventDelete="+preventDelete+"/"+this.direction+"="+this.preventDelete);
163                         }
164                 }
165                 /**
166                  * @return the to
167                  */
168                 public String getTo() {
169                         return to;
170                 }
171                 /**
172                  * @param to the to to set
173                  */
174                 public void setTo(String to) {
175                         this.to = to;
176                 }
177                 /**
178                  * @return the from
179                  */
180                 public String getFrom() {
181                         return from;
182                 }
183                 /**
184                  * @param from the from to set
185                  */
186                 public void setFrom(String from) {
187                         this.from = from;
188                 }
189
190
191                 public String getRuleKey() {
192                         return ruleKey;
193                 }
194                 public String getMultiplicity() {
195                         return multiplicity;
196                 }
197                 public String getDirection() {
198                         return direction;
199                 }
200                 public String getDescription() {
201                         return this.description;
202                 }
203                 public void setRuleKey(String val) {
204                         this.ruleKey=val;
205                 }
206                 public void setType(LineageType val) {
207                         this.type=val;
208                 }
209                 public void setDirection(String val) {
210                         this.direction = val;
211                 }
212                 public void setMultiplicity(String val) {
213                         this.multiplicity=val;
214                 }
215                 public void setHasDelTarget(String val) {
216                         hasDelTarget = Boolean.parseBoolean(val);
217                 }
218                 public void setDescription(String val) {
219                         this.description = val;
220                 }
221
222                 public String getRelationshipDescription(String fromTo, String otherNodeName) {
223                         
224                         String result = "";             
225
226                         if ("FROM".equals(fromTo)) {
227                                 if ("OUT".equals(direction)) {
228                                         if (LineageType.PARENT == type) {
229                                                 result = " (PARENT of "+otherNodeName;
230                                                 result = String.join(" ", result+",", this.from, this.getLabel(), this.to);
231                                         } 
232                                 } 
233                                 else {
234                                         if (LineageType.CHILD == type) {
235                                                 result = " (CHILD of "+otherNodeName;
236                                                 result = String.join(" ", result+",",  this.from, this.getLabel(), this.to);
237                                         } 
238                                         else if (LineageType.PARENT == type) {
239                                                 result = " (PARENT of "+otherNodeName;
240                                                 result = String.join(" ", result+",", this.from, this.getLabel(), this.to);
241                                         }
242                                 }
243                                 if (result.length() == 0) result = String.join(" ", "(", this.from, this.getLabel(), this.to+",", this.getMultiplicity());
244                         } else {
245                         //if ("TO".equals(fromTo)
246                                 if ("OUT".equals(direction)) {
247                                         if (LineageType.PARENT == type) {
248                                                 result = " (CHILD of "+otherNodeName;
249                                                 result = String.join(" ", result+",", this.from, this.getLabel(), this.to+",", this.getMultiplicity());
250                                         } 
251                                 } else {
252                                         if (LineageType.PARENT == type) {
253                                                 result = " (PARENT of "+otherNodeName;
254                                                 result = String.join(" ", result+",", this.from, this.getLabel(), this.to+",", this.getMultiplicity());
255                                         }
256                                 }
257                                 if (result.length() == 0) result = String.join(" ", "(", this.from, this.getLabel(), this.to+",", this.getMultiplicity());
258
259                         }
260
261                         if (hasDelTarget) result = result + ", will delete target node";
262
263                         if (result.length() > 0) result = result + ")";
264                         
265                         if (description != null && description.length() > 0) result = result + "\n      "+ description; // 6 spaces is important for yaml
266                         
267                         return result;
268                 }
269
270                 /**
271                  * @return the hasDelTarget
272                  */
273                 @SuppressWarnings("unused")
274                 public boolean isHasDelTarget() {
275                         return hasDelTarget;
276                 }
277                 /**
278                  * @param hasDelTarget the hasDelTarget to set
279                  */
280                 @SuppressWarnings("unused")
281                 public void setHasDelTarget(boolean hasDelTarget) {
282                         this.hasDelTarget = hasDelTarget;
283                 }
284                 /**
285                  * @return the type
286                  */
287                 @SuppressWarnings("unused")
288                 public LineageType getType() {
289                         return type;
290                 }
291                 /**
292                  * @return the label
293                  */
294                 public String getLabel() {
295                         return label;
296                 }
297                 public void setLabel(String string) {
298                         this.label=string;
299                 }
300         }
301         
302         private static class PutRelationPathSet {
303                 String apiPath;
304                 String opId;
305                 ArrayList<String> relations = new ArrayList<String>();
306                 String objectName = "";
307                 String currentAPIVersion = "";
308                 public PutRelationPathSet(String opId, String path) {
309                         super();
310                         this.apiPath = path.replace("/relationship-list/relationship", "");
311                         this.opId = opId;
312                         objectName = GenerateXsd.deletePaths.get(apiPath);
313                         currentAPIVersion = GenerateXsd.apiVersion;
314                 }
315                 public void process() {
316                         this.toRelations();
317                         this.fromRelations();
318                         this.writeRelationsFile();
319
320                 }
321                 public void toRelations() {
322                         logger.debug("{“comment”: “Valid TO Relations that can be added”},");
323                         logger.debug("apiPath: "+apiPath+"\nopId="+opId+"\nobjectName="+objectName);
324                         Collection<EdgeDescription> toEdges = GenerateXsd.getEdgeRulesTO(objectName);
325                         
326                         if(toEdges.size() > 0) {
327                                 relations.add("{\"comment\": \"Valid TO Relations that can be added\"}\n");
328                         }
329                         for (EdgeDescription ed : toEdges) {
330                                 logger.debug(ed.getRuleKey()+"Type="+ed.type);
331                                 String obj = ed.getRuleKey().replace(objectName,"").replace("|","");
332                                 String selectedRelation = "";
333                                 if(ed.type == LineageType.UNRELATED) {
334                                         String selectObj = getUnrelatedObjectPaths(obj, apiPath);
335                                         logger.debug("SelectedObj:"+selectObj);
336                                         selectedRelation = formatObjectRelationSet(obj,selectObj);
337                                         logger.trace("ObjectRelationSet"+selectedRelation);
338                                 } else {
339                                         String selectObj = getKinObjectPath(obj, apiPath);
340                                         logger.debug("SelectedObj:"+selectObj);
341                                         selectedRelation = formatObjectRelation(obj,selectObj);
342                                         logger.trace("ObjectRelationSet"+selectedRelation);
343                                 }
344                                 relations.add(selectedRelation);
345                                 logger.trace(selectedRelation);
346                         }
347                 }
348                 
349                 public void fromRelations() {
350                         logger.debug("“comment”: “Valid FROM Relations that can be added”");
351                         Collection<EdgeDescription> fromEdges = getEdgeRulesFROM(objectName);
352                         if(fromEdges.size() > 0) {
353                                 relations.add("{\"comment\": \"Valid FROM Relations that can be added\"}\n");
354                         }
355                         for (EdgeDescription ed : fromEdges) {
356                                 logger.debug(ed.getRuleKey()+"Type="+ed.type);
357                                 String obj = ed.getRuleKey().replace(objectName,"").replace("|","");
358                                 String selectedRelation = "";
359                                 if(ed.type == LineageType.UNRELATED) {
360                                         String selectObj = getUnrelatedObjectPaths(obj, apiPath);
361                                         logger.debug("SelectedObj"+selectObj);
362                                         selectedRelation = formatObjectRelationSet(obj,selectObj);
363                                         logger.trace("ObjectRelationSet"+selectedRelation);
364                                 } else {
365                                         String selectObj = getKinObjectPath(obj, apiPath);
366                                         logger.debug("SelectedObj"+selectObj);
367                                         selectedRelation = formatObjectRelation(obj,selectObj);
368                                         logger.trace("ObjectRelationSet"+selectedRelation);
369                                 }
370                                 relations.add(selectedRelation);
371                                 logger.trace(selectedRelation);
372                         }
373                 }
374                 public void writeRelationsFile() {
375                         File examplefilePath = new File(yaml_dir + "/relations/" + currentAPIVersion+"/"+opId.replace("RelationshipListRelationship", "") + ".json");
376
377                         logger.debug(String.join("exampleFilePath: ", examplefilePath.toString()));
378                         FileOutputStream fop = null;
379                         try {
380                                 if (!examplefilePath.exists()) {
381                                         examplefilePath.getParentFile().mkdirs();
382                                         examplefilePath.createNewFile();
383                                 }
384                                 fop = new FileOutputStream(examplefilePath);
385                         } catch(Exception e) {
386                                 e.printStackTrace();
387                                 return;
388                         }
389                         try {
390                                 if(relations.size() > 0) {fop.write("[\n".getBytes());}
391                                 fop.write(String.join(",\n", relations).getBytes());
392                                 if(relations.size() > 0) {fop.write("\n]\n".getBytes());}
393                                 fop.flush();
394                                 fop.close();
395                         } catch (Exception e) {
396                                 e.printStackTrace();
397                                 return;
398                         }
399                         logger.debug(String.join(",\n", relations));
400                         return;
401                 }
402                 
403                 private static String formatObjectRelationSet(String obj, String selectObj) {
404                         StringBuffer pathSb = new StringBuffer();
405                         String[] paths = selectObj.split("[|]");
406                         for (String s: paths) {
407                                 logger.trace("SelectOBJ"+s);
408                                 pathSb.append(formatObjectRelation(obj, s)+",\n");
409                         }
410                         pathSb.deleteCharAt(pathSb.length()-2);
411                         return pathSb.toString();
412                 }
413
414                 private static String formatObjectRelation(String obj, String selectObj) {
415                         StringBuffer pathSb = new StringBuffer();
416                         pathSb.append("{\n");
417                         pathSb.append("\"related-to\" : \""+obj+"\",\n");
418                         pathSb.append("\"related-link\" : \""+selectObj+"\"\n");
419                         pathSb.append("}");
420                         return pathSb.toString();
421                 }
422
423                 private static String getKinObjectPath(String obj, String apiPath) {
424                         LevenshteinDistance proximity = new LevenshteinDistance();
425                         String targetPath = "";
426                         int targetScore = Integer.MAX_VALUE;
427                         int targetMaxScore = 0;
428                         for (Map.Entry<String, String> p : deletePaths.entrySet()) {
429                                         if(p.getValue().equals(obj)) {
430                                                 targetScore = (targetScore >= proximity.apply(apiPath, p.getKey())) ? proximity.apply(apiPath, p.getKey()) : targetScore;
431                                                 targetPath = (targetScore >= proximity.apply(apiPath, p.getKey())) ? p.getKey() : targetPath;
432                                                 targetMaxScore = (targetMaxScore <= proximity.apply(apiPath, p.getKey())) ? proximity.apply(apiPath, p.getKey()) : targetScore;
433                                                 logger.trace(proximity.apply(apiPath, p.getKey())+":"+p.getKey());
434                                                 logger.trace(proximity.apply(apiPath, p.getKey())+":"+apiPath);
435                                         }
436                         }
437                         return targetPath;
438                 }
439
440                 private static String getUnrelatedObjectPaths(String obj, String apiPath) {
441                         String targetPath = "";
442                         logger.trace("Obj:"+obj +"\n" + apiPath);
443                         for (Map.Entry<String, String> p : deletePaths.entrySet()) {
444                                         if(p.getValue().equals(obj)) {
445                                                 logger.trace("p.getvalue:"+p.getValue()+"p.getkey:"+p.getKey());
446                                                 targetPath +=  ((targetPath.length() == 0 ? "" : "|") + p.getKey());
447                                                 logger.trace("Match:"+apiPath +"\n" + targetPath);
448                                         }
449                         }
450                         return targetPath;
451                 }
452         }
453         
454         private static class PatchOperation {
455                 String useOpId;
456                 String xmlRootElementName;
457                 String tag;
458                 String path;
459                 String pathParams;
460
461                 public PatchOperation(String useOpId, String xmlRootElementName, String tag, String path, String pathParams) {
462                         super();
463                         this.useOpId = useOpId;
464                         this.xmlRootElementName = xmlRootElementName;
465                         this.tag = tag;
466                         this.path = path;
467                         this.pathParams = pathParams;
468                 }
469
470                 @Override
471                 public String toString() {
472                         StringBuffer pathSb = new StringBuffer();
473                         pathSb.append("    patch:\n");
474                         pathSb.append("      tags:\n");
475                         pathSb.append("        - " + tag + "\n");
476
477                         pathSb.append("      summary: update an existing " + xmlRootElementName + "\n");
478                         pathSb.append("      description: update an existing " + xmlRootElementName + "\n");
479                         pathSb.append("      operationId: Update" + useOpId + "\n");
480                         pathSb.append("      consumes:\n");
481                         pathSb.append("        - application/json\n");
482                         pathSb.append("        - application/xml\n");                                   
483                         pathSb.append("      produces:\n");
484                         pathSb.append("        - application/json\n");
485                         pathSb.append("        - application/xml\n");
486                         pathSb.append("      responses:\n");
487                         pathSb.append("        \"default\":\n");
488                         pathSb.append("          " + responsesUrl);
489                                         
490                         pathSb.append("      parameters:\n");
491                         pathSb.append(pathParams); // for nesting
492                         pathSb.append("        - name: body\n");
493                         pathSb.append("          in: body\n");
494                         pathSb.append("          description: " + xmlRootElementName + " object that needs to be created or updated\n");
495                         pathSb.append("          required: true\n");
496                         pathSb.append("          schema:\n");
497                         pathSb.append("            $ref: \"patchSchema.yaml#/definitions/" + xmlRootElementName + "\"\n");
498                 
499                         return pathSb.toString();
500                 }
501                 public String toString1() {
502                         StringBuffer pathSb = new StringBuffer();
503                         StringBuffer relationshipExamplesSb = new StringBuffer();
504                         if ( path.endsWith("/relationship") ) {
505                                 pathSb.append("  " + path + ":\n" );
506                         }
507                         pathSb.append("    patch:\n");
508                         pathSb.append("      tags:\n");
509                         pathSb.append("        - " + tag + "\n");
510
511                         if ( path.endsWith("/relationship") ) {
512                                 pathSb.append("      summary: see node definition for valid relationships\n");
513                                 relationshipExamplesSb.append("[See Examples](apidocs/relations/"+GenerateXsd.apiVersion+"/"+useOpId+".json)");
514                         } else {
515                                 pathSb.append("      summary: update an existing " + xmlRootElementName + "\n");
516                                 pathSb.append("      description: |\n");
517                                 pathSb.append("        Update an existing " + xmlRootElementName + "\n");
518                                 pathSb.append("        #\n");                           
519                                 pathSb.append("        Note:  Endpoints that are not devoted to object relationships support both PUT and PATCH operations.\n");
520                                 pathSb.append("        The PUT operation will entirely replace an existing object.\n"); 
521                                 pathSb.append("        The PATCH operation sends a \"description of changes\" for an existing object.  The entire set of changes must be applied.  An error result means no change occurs.\n");                         
522                                 pathSb.append("        #\n");                           
523                                 pathSb.append("        Other differences between PUT and PATCH are:\n");
524                                 pathSb.append("        #\n");
525                                 pathSb.append("        - For PATCH, you can send any of the values shown in sample REQUEST body.  There are no required values.\n");
526                                 pathSb.append("        - For PATCH, resource-id which is a required REQUEST body element for PUT, must not be sent.\n");
527                                 pathSb.append("        - PATCH cannot be used to update relationship elements; there are dedicated PUT operations for this.\n");
528                         }
529                         pathSb.append("      operationId: Update" + useOpId + "\n");
530                         pathSb.append("      consumes:\n");
531                         pathSb.append("        - application/json\n");
532                         pathSb.append("        - application/xml\n");                                   
533                         pathSb.append("      produces:\n");
534                         pathSb.append("        - application/json\n");
535                         pathSb.append("        - application/xml\n");
536                         pathSb.append("      responses:\n");
537                         pathSb.append("        \"default\":\n");
538                         pathSb.append("          " + responsesUrl);
539                         pathSb.append("      parameters:\n");
540                         pathSb.append(pathParams); // for nesting
541                         pathSb.append("        - name: body\n");
542                         pathSb.append("          in: body\n");
543                         pathSb.append("          description: " + xmlRootElementName + " object that needs to be created or updated. "+relationshipExamplesSb.toString()+"\n");
544                         pathSb.append("          required: true\n");
545                         pathSb.append("          schema:\n");
546                         pathSb.append("            $ref: \"#/patchDefinitions/" + xmlRootElementName + "\"\n");
547                         return pathSb.toString();
548                 }               
549         }
550         private static class PutOperation {
551                 String useOpId;
552                 String xmlRootElementName;
553                 String tag;
554                 String path;
555                 String pathParams;
556                 
557                 public PutOperation(String useOpId, String xmlRootElementName, String tag, String path, String pathParams) {
558                         super();
559                         this.useOpId = useOpId;
560                         this.xmlRootElementName = xmlRootElementName;
561                         this.tag = tag;
562                         this.path = path;
563                         this.pathParams = pathParams;
564                 }
565
566                 @Override
567                 public String toString() {
568                         StringBuffer pathSb = new StringBuffer();
569                         StringBuffer relationshipExamplesSb = new StringBuffer();
570                         if ( path.endsWith("/relationship") ) {
571                                 pathSb.append("  " + path + ":\n" );
572                         }
573                         pathSb.append("    put:\n");
574                         pathSb.append("      tags:\n");
575                         pathSb.append("        - " + tag + "\n");
576
577                         if ( path.endsWith("/relationship") ) {
578                                 pathSb.append("      summary: see node definition for valid relationships\n");
579                         } else {
580                                 pathSb.append("      summary: create or update an existing " + xmlRootElementName + "\n");
581                                 pathSb.append("      description: |\n        Create or update an existing " + xmlRootElementName + ".\n        #\n        Note! This PUT method has a corresponding PATCH method that can be used to update just a few of the fields of an existing object, rather than a full object replacement.  An example can be found in the [PATCH section] below\n");
582                         }
583                         relationshipExamplesSb.append("[Valid relationship examples shown here](apidocs/relations/"+GenerateXsd.apiVersion+"/"+useOpId.replace("RelationshipListRelationship", "")+".json)");
584                         pathSb.append("      operationId: createOrUpdate" + useOpId + "\n");
585                         pathSb.append("      consumes:\n");
586                         pathSb.append("        - application/json\n");
587                         pathSb.append("        - application/xml\n");                                   
588                         pathSb.append("      produces:\n");
589                         pathSb.append("        - application/json\n");
590                         pathSb.append("        - application/xml\n");
591                         pathSb.append("      responses:\n");
592                         pathSb.append("        \"default\":\n");
593                         pathSb.append("          " + responsesUrl);
594                 
595                         pathSb.append("      parameters:\n");
596                         pathSb.append(pathParams); // for nesting
597                         pathSb.append("        - name: body\n");
598                         pathSb.append("          in: body\n");
599                         pathSb.append("          description: " + xmlRootElementName + " object that needs to be created or updated. "+relationshipExamplesSb.toString()+"\n");
600                         pathSb.append("          required: true\n");
601                         pathSb.append("          schema:\n");
602                         pathSb.append("            $ref: \"#/definitions/" + xmlRootElementName + "\"\n");
603                         return pathSb.toString();
604                 }
605                 public String tagRelationshipPathMapEntry() {
606                         if ( path.endsWith("/relationship") ) {
607                                 putRelationPaths.put(useOpId, path);
608                         }
609                         return "";
610                 }
611                 
612         }
613         
614         private static class GetOperation {
615                 String useOpId;
616                 String xmlRootElementName;
617                 String tag;
618                 String path;
619                 @SuppressWarnings("unused")
620                 String pathParams;
621                 public GetOperation(String useOpId, String xmlRootElementName, String tag, String path, String pathParams) {
622                         super();
623                         this.useOpId = useOpId;
624                         this.xmlRootElementName = xmlRootElementName;
625                         this.tag = tag;
626                         this.path = path;
627                         this.pathParams = pathParams;
628                 }
629                 @Override
630                 public String toString() {
631                         StringBuffer pathSb = new StringBuffer();
632                         pathSb.append("  " + path + ":\n" );
633                         pathSb.append("    get:\n");
634                         pathSb.append("      tags:\n");
635                         pathSb.append("        - " + tag + "\n");
636                         pathSb.append("      summary: returns " + xmlRootElementName + "\n");
637
638                         pathSb.append("      description: returns " + xmlRootElementName + "\n");
639                         pathSb.append("      operationId: get" + useOpId + "\n");
640                         pathSb.append("      produces:\n");
641                         pathSb.append("        - application/json\n");
642                         pathSb.append("        - application/xml\n");
643                         
644                         pathSb.append("      responses:\n");
645                         pathSb.append("        \"200\":\n");
646                         pathSb.append("          description: successful operation\n");
647                         pathSb.append("          schema:\n");
648                         pathSb.append("              $ref: \"#/getDefinitions/" + xmlRootElementName + "\"\n");
649                         pathSb.append("        \"default\":\n");
650                         pathSb.append("          " + responsesUrl);
651
652                         return pathSb.toString();
653                 }
654                 
655         }
656         private static class DeleteOperation {
657                 String useOpId;
658                 String xmlRootElementName;
659                 String tag;
660                 String path;
661                 String pathParams;
662                 public DeleteOperation(String useOpId, String xmlRootElementName, String tag, String path, String pathParams) {
663                         super();
664                         this.useOpId = useOpId;
665                         this.xmlRootElementName = xmlRootElementName;
666                         this.tag = tag;
667                         this.path = path;
668                         this.pathParams = pathParams;
669                 }
670                 @Override
671                 public String toString() {
672                         StringBuffer pathSb = new StringBuffer();
673                         pathSb.append("    delete:\n");
674                         pathSb.append("      tags:\n");
675                         pathSb.append("        - " + tag + "\n");
676                         pathSb.append("      summary: delete an existing " + xmlRootElementName + "\n");
677                         
678                         pathSb.append("      description: delete an existing " + xmlRootElementName + "\n");
679                         
680                         pathSb.append("      operationId: delete" + useOpId + "\n");
681                         pathSb.append("      consumes:\n");
682                         pathSb.append("        - application/json\n");
683                         pathSb.append("        - application/xml\n");                                   
684                         pathSb.append("      produces:\n");
685                         pathSb.append("        - application/json\n");
686                         pathSb.append("        - application/xml\n");
687                         pathSb.append("      responses:\n");
688                         pathSb.append("        \"default\":\n");
689                         pathSb.append("          " + responsesUrl);
690                         pathSb.append("      parameters:\n");
691
692                         pathSb.append(pathParams); // for nesting
693                         if ( !path.endsWith("/relationship") ) {
694                                 pathSb.append("        - name: resource-version\n");
695
696                                 pathSb.append("          in: query\n");
697                                 pathSb.append("          description: resource-version for concurrency\n");
698                                 pathSb.append("          required: true\n");
699                                 pathSb.append("          type: string\n");
700                         }
701                         return pathSb.toString();
702                 }
703                 public String objectPathMapEntry() {
704                         if (! path.endsWith("/relationship") ) {
705                                 deletePaths.put(path, xmlRootElementName);
706                         }
707                         return (xmlRootElementName+":"+path);
708                 }
709                 
710         }
711         
712         private static boolean validVersion(String versionToGen) {
713                 
714                 if ("ALL".equalsIgnoreCase(versionToGen)) {
715                         return true;
716                 }
717                 
718                 for (Version v : Version.values()) {
719                 if (v.name().equals(versionToGen)) {
720                     return true;
721                 }
722             }
723
724             return false;
725         }
726         
727         private static boolean versionUsesAnnotations( String version) {
728                 if (new Integer(version.substring(1)).intValue() >= annotationsStartVersion ) {
729                         return true;
730                 }
731                 return false;
732         }
733         
734         private static boolean versionSupportsSwagger( String version) {
735                 if (new Integer(version.substring(1)).intValue() >= swaggerSupportStartsVersion ) {
736                         return true;
737                 }
738                 return false;
739         }
740         
741         public static void main(String[] args) throws IOException {
742                 String versionToGen = System.getProperty("gen_version").toLowerCase();
743                 String fileTypeToGen = System.getProperty("gen_type").toLowerCase();
744                 if ( fileTypeToGen == null ) {
745                         fileTypeToGen = generateTypeXSD;
746                 }
747                 
748                 if ( !fileTypeToGen.equals( generateTypeXSD ) && !fileTypeToGen.equals( generateTypeYAML )) {
749                         System.err.println("Invalid gen_type passed. " + fileTypeToGen);
750                         System.exit(1);
751                 }
752                 
753                 
754                 String responsesLabel = System.getProperty("yamlresponses_url");
755                 responsesUrl = responsesLabel;
756                 
757                 List<Version> versionsToGen = new ArrayList<>();
758                 if ( versionToGen == null ) {
759                         System.err.println("Version is required, ie v<n> or ALL.");
760                         System.exit(1);                 
761                 }
762                 else if (!"ALL".equalsIgnoreCase(versionToGen) && !versionToGen.matches("v\\d+") && !validVersion(versionToGen)) {
763                         System.err.println("Invalid version passed. " + versionToGen);
764                         System.exit(1);
765                 }
766                 else if ("ALL".equalsIgnoreCase(versionToGen)) {
767                         versionsToGen = Arrays.asList(Version.values());
768                         Collections.sort(versionsToGen);
769                         Collections.reverse(versionsToGen);
770                 } else {
771                         versionsToGen.add(Version.valueOf(versionToGen));
772                 }
773                 
774                 //process file type System property
775                 fileTypeToGen = (fileTypeToGen == null ? generateTypeXSD : fileTypeToGen.toLowerCase());
776                 if ( !fileTypeToGen.equals( generateTypeXSD ) && !fileTypeToGen.equals( generateTypeYAML )) {
777                         System.err.println("Invalid gen_type passed. " + fileTypeToGen);
778                         System.exit(1);
779                 } else if ( fileTypeToGen.equals(generateTypeYAML) ) {
780                         if ( responsesUrl == null || responsesUrl.length() < 1 
781                                         || responsesLabel == null || responsesLabel.length() < 1 ) {
782                                 System.err.println("generating swagger yaml file requires yamlresponses_url and yamlresponses_label properties" );
783                                 System.exit(1);
784                         } else {
785                                 responsesUrl = "description: "+ "Response codes found in [response codes]("+responsesLabel+ ").\n";
786                         }
787                 }
788                 String oxmPath;
789                 if(System.getProperty("user.dir") != null && !System.getProperty("user.dir").contains(normalStartDir)) {
790                         oxmPath = autoGenRoot + "/oxm/";
791                 }
792                 else {
793                         oxmPath = root + "/oxm/";
794                 }
795
796                 String outfileName;
797                 File outfile;
798                 String fileContent;
799                 
800                 for (Version v : versionsToGen) {
801                         apiVersion = v.toString();
802                         logger.info("Generating " + apiVersion + " " + fileTypeToGen);
803                         File oxm_file = new File(oxmPath + "aai_oxm_" + apiVersion + ".xml");
804                         apiVersionFmt = "." + apiVersion + ".";
805                         generatedJavaType = new HashMap<String, String>();
806                         appliedPaths = new HashMap<String, String>();
807                         putRelationPaths = new HashMap<String, String>();
808                         deletePaths = new HashMap<String, String>();
809
810                         if ( fileTypeToGen.equals(generateTypeXSD) ) {
811                                 useAnnotationsInXsd = versionUsesAnnotations(apiVersion);
812                                 outfileName = xsd_dir + "/aai_schema_" + apiVersion + "." + generateTypeXSD;
813                                 fileContent = processOxmFile(oxm_file, v, null);
814                         } else if ( versionSupportsSwagger(apiVersion )) {
815                                 if(System.getProperty("user.dir") != null && !System.getProperty("user.dir").contains(normalStartDir)) {
816                                         outfileName = alt_yaml_dir;
817                                 }
818                                 else {
819                                         outfileName = yaml_dir;
820                                 }
821                                 outfileName = outfileName + "/aai_swagger_" + apiVersion + "." + generateTypeYAML;
822                                 fileContent = generateSwaggerFromOxmFile( oxm_file, null);
823                         } else {
824                                 continue;
825                         }
826                         outfile = new File(outfileName);
827                         File parentDir = outfile.getParentFile();
828                         if(! parentDir.exists()) 
829                               parentDir.mkdirs();
830                 
831                     try {
832                         outfile.createNewFile();
833                     } catch (IOException e) {
834                         logger.error( "Exception creating output file " + outfileName);
835                         e.printStackTrace();
836                     }
837                     BufferedWriter bw = null;
838                 try {
839                         Charset charset = Charset.forName("UTF-8");
840                         Path path = Paths.get(outfileName);
841                         bw = Files.newBufferedWriter(path, charset);
842                         bw.write(fileContent);
843                 } catch ( IOException e) {
844                         logger.error( "Exception writing output file " + outfileName);
845                         e.printStackTrace();
846                 } finally {
847                         if ( bw != null ) {
848                                 bw.close();
849                         }
850                 }
851                         logger.info( "GeneratedXSD successful, saved in " + outfileName);
852                 }
853                 
854         }
855
856
857         public static String processJavaTypeElement( String javaTypeName, Element javaTypeElement) {
858                 
859                 String xmlRootElementName = null;
860
861                 NodeList parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
862                 StringBuffer sb = new StringBuffer();
863                 if ( parentNodes.getLength() == 0 ) {
864                         logger.trace( "no java-attributes for java-type " + javaTypeName);
865                         return "";
866
867                 }
868                 
869                 NamedNodeMap attributes;
870                 
871                 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
872                 Element valElement = (Element) valNodes.item(0);
873                 attributes = valElement.getAttributes();
874                 for ( int i = 0; i < attributes.getLength(); ++i ) {
875             Attr attr = (Attr) attributes.item(i);
876             String attrName = attr.getNodeName();
877
878             String attrValue = attr.getNodeValue();
879             logger.trace("Found xml-root-element attribute: " + attrName + " with value: " + attrValue);
880             if ( attrName.equals("name"))
881                 xmlRootElementName = attrValue;
882                 }
883                 
884                 Element parentElement = (Element)parentNodes.item(0);
885                 NodeList xmlElementNodes = parentElement.getElementsByTagName("xml-element");
886                 NodeList childNodes;
887                 Element childElement;
888                 String xmlElementWrapper;
889
890                 Element xmlElementElement;
891                 String addType;
892                 String elementName, elementType, elementIsKey, elementIsRequired, elementContainerType;
893                 StringBuffer sb1 = new StringBuffer();
894                 if ( xmlElementNodes.getLength() > 0 ) {
895                         sb1.append("  <xs:element name=\"" + xmlRootElementName + "\">\n");
896                         sb1.append("    <xs:complexType>\n");
897                         NodeList properties = GenerateXsd.locateXmlProperties(javaTypeElement);
898                         if (properties != null && useAnnotationsInXsd) {
899                                 logger.trace("properties found for: " + xmlRootElementName);
900                                 sb1.append("      <xs:annotation>\r\n");
901                                 insertAnnotation(properties, false, "class", sb1, "      ");
902                                 
903                                 sb1.append("      </xs:annotation>\r\n");
904                         } else {
905                                 logger.trace("no properties found for: " + xmlRootElementName);
906                         }
907                         sb1.append("      <xs:sequence>\n");
908                         for ( int i = 0; i < xmlElementNodes.getLength(); ++i ) {
909                                 
910                                 xmlElementElement = (Element)xmlElementNodes.item(i);
911                                 childNodes = xmlElementElement.getElementsByTagName("xml-element-wrapper");
912                                 
913                                 xmlElementWrapper = null;
914                                 if ( childNodes.getLength() > 0 ) {
915                                         childElement = (Element)childNodes.item(0);
916                                         // get name
917                                         attributes = childElement.getAttributes();
918                                         for ( int k = 0; k < attributes.getLength(); ++k ) {
919                                                 Attr attr = (Attr) attributes.item(k);
920                                                 String attrName = attr.getNodeName();
921                                                 String attrValue = attr.getNodeValue();
922                                                 if ( attrName.equals("name")) {
923                                                         xmlElementWrapper = attrValue;
924                                                         logger.trace("found xml-element-wrapper " + xmlElementWrapper);
925                                                 }
926                                         }
927
928                                 }
929                                 attributes = xmlElementElement.getAttributes();
930                                 addType = null;
931         
932          
933                                 elementName = elementType = elementIsKey = elementIsRequired = elementContainerType = null;
934                                 for ( int j = 0; j < attributes.getLength(); ++j ) {
935                             Attr attr = (Attr) attributes.item(j);
936                             String attrName = attr.getNodeName();
937         
938                             String attrValue = attr.getNodeValue();
939                             logger.trace("For " + xmlRootElementName + " Found xml-element attribute: " + attrName + " with value: " + attrValue);
940                             if ( attrName.equals("name")) {
941                                 elementName = attrValue;
942                             }
943                             if ( attrName.equals("type")) {
944                                 elementType = attrValue;
945                                 if ( attrValue.contains(apiVersionFmt) ) {
946                                         addType = attrValue.substring(attrValue.lastIndexOf('.')+1);
947                                         if ( !generatedJavaType.containsKey(addType) ) {
948                                                 generatedJavaType.put(addType, attrValue);
949                                                 sb.append(processJavaTypeElement( addType, getJavaTypeElement(addType) ));      
950                                         }
951                                 }
952                                         
953                             }
954
955                             if ( attrName.equals("xml-key")) {
956                                 elementIsKey = attrValue;
957                             }
958                             if ( attrName.equals("required")) {
959                                 elementIsRequired = attrValue;
960                             }
961                             if ( attrName.equals("container-type")) {
962                                 elementContainerType = attrValue;
963                             }   
964                                 }
965         
966                                 if ( xmlElementWrapper != null ) {
967                                         sb1.append("        <xs:element name=\"" + xmlElementWrapper +"\"");
968                                         if ( elementIsRequired == null || !elementIsRequired.equals("true")||addType != null) { 
969                                                 sb1.append(" minOccurs=\"0\""); 
970                                         } 
971                                         sb1.append(">\n");
972                                         sb1.append("          <xs:complexType>\n");
973                                         properties = GenerateXsd.locateXmlProperties(javaTypeElement);
974                                         if (properties != null && useAnnotationsInXsd) {
975                                                 sb1.append("            <xs:annotation>\r\n");
976                                                 insertAnnotation(properties, false, "class", sb1, "            ");
977                                                 sb1.append("            </xs:annotation>\r\n");
978                                         } else {
979                                                 logger.trace("no properties found for: " + xmlElementWrapper);
980                                         }
981                                         sb1.append("            <xs:sequence>\n");
982                                         sb1.append("      ");
983                                 }
984                 if ("Nodes".equals(addType)) {
985                         logger.trace("Skipping nodes, temporary testing");
986                         continue;
987                 }
988                                 if ( addType != null ) {
989                                         sb1.append("        <xs:element ref=\"tns:" + getXmlRootElementName(addType) +"\"");
990                                 } else {
991                                         sb1.append("        <xs:element name=\"" + elementName +"\"");
992                                 }
993                                 if ( elementType.equals("java.lang.String"))
994                                         sb1.append(" type=\"xs:string\"");
995                                 if ( elementType.equals("java.lang.Long"))
996                                         sb1.append(" type=\"xs:unsignedInt\"");
997                                 if ( elementType.equals("java.lang.Integer"))
998                                         sb1.append(" type=\"xs:int\"");
999                                 if ( elementType.equals("java.lang.Boolean"))
1000                                         sb1.append(" type=\"xs:boolean\"");
1001                                 if ( elementIsRequired == null || !elementIsRequired.equals("true")||addType != null) { 
1002                                         sb1.append(" minOccurs=\"0\"");
1003                                 } 
1004                                 if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) {
1005                                         sb1.append(" maxOccurs=\"unbounded\"");
1006                                 }
1007                                 properties = GenerateXsd.locateXmlProperties(xmlElementElement);
1008                                 if (properties != null || elementIsKey != null) {
1009                                         sb1.append(">\n");
1010                                         if ( useAnnotationsInXsd ) {
1011                                                 sb1.append("          <xs:annotation>\r\n");
1012                                                 insertAnnotation(properties, elementIsKey != null, "field", sb1, "          ");
1013                                                 sb1.append("          </xs:annotation>\r\n");
1014                                         }
1015                                         if (xmlElementWrapper== null) {
1016                                                 sb1.append("        </xs:element>\n");
1017                                         }
1018                                 } else {
1019                                         sb1.append("/>\n");
1020                                 }
1021                                 if ( xmlElementWrapper != null ) {
1022                                         sb1.append("            </xs:sequence>\n");
1023                                         sb1.append("          </xs:complexType>\n");
1024                                         sb1.append("        </xs:element>\n");
1025                                 }
1026                         }
1027                 sb1.append("      </xs:sequence>\n");
1028                 sb1.append("    </xs:complexType>\n");
1029                 sb1.append("  </xs:element>\n");
1030                 }
1031                 
1032                 if ( xmlElementNodes.getLength() < 1 ) {
1033                         sb.append("  <xs:element name=\"" + xmlRootElementName + "\">\n");
1034                         sb.append("    <xs:complexType>\n");
1035                         sb.append("      <xs:sequence/>\n");
1036                         sb.append("    </xs:complexType>\n");
1037                         sb.append("  </xs:element>\n");
1038                         generatedJavaType.put(javaTypeName, null);
1039                         return sb.toString();                   
1040                 }
1041                 sb.append( sb1 );
1042                 return sb.toString();
1043         }
1044         
1045         private static void insertAnnotation(NodeList items, boolean isKey, String target, StringBuffer sb1, String indentation) {
1046                 if (items != null || isKey) {
1047                         List<String> metadata = new ArrayList<>();
1048                         
1049                         String name = "";
1050                         String value = "";
1051                         Element item = null;
1052                         if (isKey) {
1053                                 metadata.add("isKey=true");
1054                         }
1055                         if (items != null) {
1056                                 for (int i = 0; i < items.getLength(); i++) {
1057                                         item = (Element)items.item(i);
1058                                         name = item.getAttribute("name");
1059                                         value = item.getAttribute("value");
1060                                         if (name.equals("abstract")) {
1061                                                 name = "isAbstract";
1062                                         } else if (name.equals("extends")) {
1063                                                 name = "extendsFrom";
1064                                         }
1065                                         metadata.add(name + "=\"" + value.replaceAll("&",  "&amp;") + "\"");
1066                                 }
1067                         }
1068                         sb1.append(
1069                                         indentation + "  <xs:appinfo>\r\n" + 
1070                                                         indentation + "    <annox:annotate target=\""+target+"\">@org.onap.aai.annotations.Metadata(" + Joiner.on(",").join(metadata) + ")</annox:annotate>\r\n" +
1071                                                         indentation + "  </xs:appinfo>\r\n");
1072                 }
1073
1074         }
1075
1076         private static Element getJavaTypeElement( String javaTypeName )
1077         {
1078                 
1079                 String attrName, attrValue;
1080                 Attr attr;
1081                 Element javaTypeElement;
1082                 for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
1083                         javaTypeElement = (Element) javaTypeNodes.item(i);
1084                         NamedNodeMap attributes = javaTypeElement.getAttributes();
1085                         for ( int j = 0; j < attributes.getLength(); ++j ) {
1086                     attr = (Attr) attributes.item(j);
1087                     attrName = attr.getNodeName();
1088                     attrValue = attr.getNodeValue();
1089                     if ( attrName.equals("name") && attrValue.equals(javaTypeName))
1090                         return javaTypeElement;
1091                         }
1092                 }
1093                 logger.error( "oxm file format error, missing java-type " + javaTypeName);
1094                 return (Element) null;
1095         }
1096         
1097         private static Element getJavaTypeElementSwagger( String javaTypeName )
1098         {
1099                 
1100                 String attrName, attrValue;
1101                 Attr attr;
1102                 Element javaTypeElement;
1103                 for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
1104                         javaTypeElement = (Element) javaTypeNodes.item(i);
1105                         NamedNodeMap attributes = javaTypeElement.getAttributes();
1106                         for ( int j = 0; j < attributes.getLength(); ++j ) {
1107                     attr = (Attr) attributes.item(j);
1108                     attrName = attr.getNodeName();
1109                     attrValue = attr.getNodeValue();
1110                     if ( attrName.equals("name") && attrValue.equals(javaTypeName))
1111                         return javaTypeElement;
1112                         }
1113                 }
1114                 logger.error( "oxm file format error, missing java-type " + javaTypeName);
1115                 return (Element) null;
1116         }
1117         private static String getXmlRootElementName( String javaTypeName )
1118         {
1119                 
1120                 String attrName, attrValue;
1121                 Attr attr;
1122                 Element javaTypeElement;
1123                 for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
1124                         javaTypeElement = (Element) javaTypeNodes.item(i);
1125                         NamedNodeMap attributes = javaTypeElement.getAttributes();
1126                         for ( int j = 0; j < attributes.getLength(); ++j ) {
1127                     attr = (Attr) attributes.item(j);
1128                     attrName = attr.getNodeName();
1129                     attrValue = attr.getNodeValue();
1130                     if ( attrName.equals("name") && attrValue.equals(javaTypeName)) {
1131                                 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
1132                                 Element valElement = (Element) valNodes.item(0);
1133                                 attributes = valElement.getAttributes();
1134                                 for ( int k = 0; k < attributes.getLength(); ++k ) {
1135                             attr = (Attr) attributes.item(k);
1136                             attrName = attr.getNodeName();
1137
1138                             attrValue = attr.getNodeValue();
1139                             if ( attrName.equals("name"))
1140                                 return (attrValue);
1141                                 }
1142                     }
1143                         }
1144                 }
1145                 logger.error( "oxm file format error, missing java-type " + javaTypeName);
1146                 return null;
1147         }       
1148         
1149         
1150         public static String processOxmFile( File oxmFile, Version v, String xml )
1151         {
1152                 if ( xml != null ){
1153                     apiVersion = v.toString();
1154                     useAnnotationsInXsd = true;
1155                     apiVersionFmt = "." + apiVersion + ".";
1156                     generatedJavaType = new HashMap<>();
1157                         appliedPaths = new HashMap<>();
1158                 }
1159                 StringBuilder sb = new StringBuilder();
1160                 logger.trace("processing starts");
1161                 sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
1162                 String namespace = "org.onap";
1163                 if (v.compareTo(Version.v11) < 0) {
1164                         namespace = "org.openecomp";
1165                 }
1166                 if ( useAnnotationsInXsd ) {
1167                         sb.append("<xs:schema elementFormDefault=\"qualified\" version=\"1.0\" targetNamespace=\"http://" + namespace + ".aai.inventory/" 
1168                                 + apiVersion + "\" xmlns:tns=\"http://" + namespace + ".aai.inventory/" + apiVersion + "\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
1169                                                 + "\n"
1170                                                 + "xmlns:jaxb=\"http://java.sun.com/xml/ns/jaxb\"\r\n" + 
1171                                                 "    jaxb:version=\"2.1\" \r\n" + 
1172                                                 "    xmlns:annox=\"http://annox.dev.java.net\" \r\n" + 
1173                                                 "    jaxb:extensionBindingPrefixes=\"annox\">\n\n");
1174                 } else {
1175                 
1176                         sb.append("<xs:schema elementFormDefault=\"qualified\" version=\"1.0\" targetNamespace=\"http://" + namespace + ".aai.inventory/" 
1177                                         + apiVersion + "\" xmlns:tns=\"http://" + namespace + ".aai.inventory/" + apiVersion + "\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n\n");
1178                 }
1179
1180                 try {
1181                     
1182                     DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
1183                     dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
1184                     DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
1185                     Document doc;
1186                     
1187                     if ( xml == null ){
1188                         doc = dBuilder.parse(oxmFile);
1189                     } else {
1190                             InputSource is = new InputSource(new StringReader(xml));
1191                             doc = dBuilder.parse(is);
1192                     } 
1193                     NodeList bindingsNodes = doc.getElementsByTagName("xml-bindings");
1194                         Element bindingElement;
1195                         NodeList javaTypesNodes;
1196                         Element javaTypesElement;
1197                         
1198                         Element javaTypeElement;
1199
1200                         
1201                         if ( bindingsNodes == null || bindingsNodes.getLength() == 0 ) {
1202                                 logger.error( "missing <binding-nodes> in " + oxmFile );
1203                                 return null;
1204                         }           
1205                         
1206                         bindingElement = (Element) bindingsNodes.item(0);
1207                         javaTypesNodes = bindingElement.getElementsByTagName("java-types");
1208                         if ( javaTypesNodes.getLength() < 1 ) {
1209                                 logger.error( "missing <binding-nodes><java-types> in " + oxmFile );
1210                                 return null;
1211                         }
1212                         javaTypesElement = (Element) javaTypesNodes.item(0);
1213                         javaTypeNodes = javaTypesElement.getElementsByTagName("java-type");
1214                         if ( javaTypeNodes.getLength() < 1 ) {
1215                                 logger.error( "missing <binding-nodes><java-types><java-type> in " + oxmFile );
1216                                 return null;
1217                         }
1218
1219                         String javaTypeName;
1220                         String attrName, attrValue;
1221                         Attr attr;
1222                         for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
1223                                 javaTypeElement = (Element) javaTypeNodes.item(i);
1224                                 NamedNodeMap attributes = javaTypeElement.getAttributes();
1225                                 javaTypeName = null;
1226                                 for ( int j = 0; j < attributes.getLength(); ++j ) {
1227                             attr = (Attr) attributes.item(j);
1228                             attrName = attr.getNodeName();
1229                             attrValue = attr.getNodeValue();
1230                             if ( attrName.equals("name"))
1231                                 javaTypeName = attrValue;
1232                                 }
1233                                 if ( javaTypeName == null ) {
1234                                         logger.error( "<java-type> has no name attribute in " + oxmFile );
1235                                         return null;
1236                                 }
1237                                 if ("Nodes".equals(javaTypeName)) {
1238                                         logger.debug("skipping Nodes entry (temporary feature)");
1239                                         continue;
1240                                 }
1241                                 if ( !generatedJavaType.containsKey(javaTypeName) ) {
1242                                         generatedJavaType.put(javaTypeName, null);
1243                                         sb.append(processJavaTypeElement( javaTypeName, javaTypeElement ));
1244                                 }
1245                         }
1246                                 
1247                 } catch (Exception e) {
1248                         e.printStackTrace();
1249                         return null;
1250                 }
1251                 sb.append("</xs:schema>\n");
1252                 return sb.toString();
1253         }
1254         
1255         public static String toDeleteRules(String objectName) {
1256                 Collection<EdgeDescription> toEdges = GenerateXsd.getEdgeRulesTO(objectName);
1257                 logger.debug("TO Edges count: "+toEdges.size()+" Object: "+objectName);
1258                 String prevent=null;
1259                 String also=null;
1260                 LinkedHashSet<String> preventDelete = new LinkedHashSet<String>();
1261                 LinkedHashSet<String> alsoDelete = new LinkedHashSet<String>();
1262                 for (EdgeDescription ed : toEdges) {
1263                         logger.debug("{“comment”: From = "+ed.getFrom()+" To: "+ed.getTo()+" Object: "+objectName);
1264                         logger.debug("{“comment”: Direction = "+ed.getDirection()+" PreventDelete: "+ed.getPreventDelete()+" DeleteOtherV: "+ed.getDeleteOtherV()+" Object: "+objectName);
1265                         if(ed.getPreventDelete().equals("IN") && ed.getTo().equals(objectName)) {
1266                                 preventDelete.add(ed.getFrom().toUpperCase());
1267                         }
1268                         if(ed.getDeleteOtherV().equals("IN") && ed.getTo().equals(objectName) ) {
1269                                 alsoDelete.add(ed.getFrom().toUpperCase());
1270                         }
1271                 }
1272                 if(preventDelete.size() > 0) {
1273                         prevent = "      - "+objectName.toUpperCase()+" cannot be deleted if linked to "+String.join(",",preventDelete);
1274                         logger.info(prevent);
1275                 }
1276                 if(alsoDelete.size() > 0) {
1277                         also = "      - "+objectName.toUpperCase()+" is DELETED when these are DELETED "+String.join(",",alsoDelete);
1278                         // This commented out line is better (gets who deletes what correct) but still not accurate.
1279                         //also = "      - Deletion of an instance of "+objectName.toUpperCase()+" causes instances of these directly related types to be DELETED ["+String.join(",",alsoDelete)+"]";
1280                         logger.info(also);
1281                 }
1282                 return String.join((prevent == null || also == null) ? "" : "\n", prevent == null ? "" : prevent, also == null ? "" : also)+((prevent == null && also == null) ? "" : "\n");
1283         }
1284         
1285         public static String fromDeleteRules(String objectName) {
1286                 Collection<EdgeDescription> fromEdges = GenerateXsd.getEdgeRulesFROM(objectName);
1287                 LinkedHashSet<String> preventDelete = new LinkedHashSet <String>();
1288                 LinkedHashSet<String> alsoDelete = new LinkedHashSet <String>();
1289                 String prevent=null;
1290                 String also=null;
1291                 for (EdgeDescription ed : fromEdges) {
1292                         logger.debug("{“comment”: From = "+ed.getFrom()+" To: "+ed.getTo()+" Object: "+objectName);
1293                         logger.debug("{“comment”: Direction = "+ed.getDirection()+" PreventDelete: "+ed.getPreventDelete()+" DeleteOtherV: "+ed.getDeleteOtherV()+" Object: "+objectName);
1294                         if(ed.getPreventDelete().equals("OUT") && ed.getFrom().equals(objectName)) {
1295                                 preventDelete.add(ed.getTo().toUpperCase());
1296                         }
1297                         if(ed.getDeleteOtherV().equals("OUT") && ed.getFrom().equals(objectName) ) {
1298                                 alsoDelete.add(ed.getTo().toUpperCase());
1299                         }
1300                 }
1301                 if(preventDelete.size() > 0) {
1302                         prevent = "      - "+objectName.toUpperCase()+" cannot be deleted if linked to "+String.join(",",preventDelete);
1303                         logger.info(prevent);
1304                 }
1305                 if(alsoDelete.size() > 0) {
1306                         also = "      - "+objectName.toUpperCase()+" deletion means associated objects of these types are also DELETED:"+String.join(",",alsoDelete);
1307                         // This commented out line is better (gets who deletes what correct) but still not accurate.
1308                         //also = "      - Deletion of an instance of "+objectName.toUpperCase()+" causes instances of these directly related types to be DELETED ["+String.join(",",alsoDelete)+"]";
1309                         logger.info(also);
1310                 }
1311                 return String.join((prevent == null || also == null) ? "" : "\n", prevent == null ? "" : prevent, also == null ? "" : also)+((prevent == null && also == null) ? "" : "\n");
1312         }
1313
1314
1315         private static boolean isStandardType( String elementType )
1316         {
1317                 switch ( elementType ) {
1318                 case "java.lang.String":
1319                 case "java.lang.Long":
1320                 case "java.lang.Integer":
1321                 case"java.lang.Boolean":
1322                         return true;
1323                 }
1324                 return false;
1325         }
1326         
1327         private static Vector<String> getIndexedProps( String attrValue )
1328         {
1329                 if ( attrValue == null )
1330                         return null;
1331                 StringTokenizer st = new StringTokenizer( attrValue, ",");
1332                 if ( st.countTokens() ==  0 )
1333                         return null;
1334                 Vector<String> result = new Vector<String>();
1335                 while ( st.hasMoreTokens()) {
1336                         result.add(st.nextToken());
1337                 }
1338                 return result;
1339         }
1340                 
1341         /**
1342          * Guaranteed to at least return non null but empty collection of edge descriptions
1343          * @param nodeName name of the vertex whose edge relationships to return
1344          * @return collection of node neighbors based on DbEdgeRules
1345         **/
1346         private static Collection<EdgeDescription> getEdgeRulesFromJson( String path, boolean skipMatch ) 
1347         {
1348
1349                 ArrayList<EdgeDescription> result = new ArrayList<>();
1350                 Iterator<Map<String, Object>> edgeRulesIterator;
1351                 try {
1352
1353                         GenerateXsd x = new GenerateXsd();
1354                         
1355                         List<Map<String, Object>> inEdges = JsonPath.parse(jsonEdges).read(path);
1356                         
1357                         edgeRulesIterator = inEdges.iterator();
1358                         Map<String, Object> edgeMap;
1359                         String fromNode;
1360                         String toNode;
1361                         String direction;
1362                         String multiplicity;
1363                         String isParent;
1364                         String hasDelTarget;
1365                         String deleteOtherV;
1366                         String preventDelete;
1367                         String description;
1368                         EdgeDescription edgeDes;
1369                         
1370                         while( edgeRulesIterator.hasNext() ){
1371                                 edgeMap = edgeRulesIterator.next();
1372                                 fromNode = (String)edgeMap.get("from");
1373                                 toNode = (String)edgeMap.get("to");
1374                                 if ( skipMatch ) { 
1375                                         if ( fromNode.equals(toNode)) {
1376                                                 continue;
1377                                         }
1378                                 }
1379                                 edgeDes = x.new EdgeDescription();
1380                                 edgeDes.setRuleKey(fromNode + "|" + toNode);
1381                                 edgeDes.setLabel((String)edgeMap.get("label"));
1382                                 edgeDes.setTo((String)edgeMap.get("to"));
1383                                 edgeDes.setFrom((String)edgeMap.get("from"));
1384                                 direction = (String)edgeMap.get("direction");
1385                                 edgeDes.setDirection(direction);
1386                                 multiplicity = (String)edgeMap.get("multiplicity");
1387                                 edgeDes.setMultiplicity(multiplicity);
1388                                 isParent = (String)edgeMap.get(EdgeProperty.CONTAINS.toString());
1389                                 if ( "${direction}".equals(isParent))  {
1390                                         edgeDes.setType(LineageType.PARENT);
1391                                 } else {
1392                                         edgeDes.setType(LineageType.UNRELATED);
1393                                 }
1394                                 hasDelTarget = (String)edgeMap.get(EdgeProperty.DELETE_OTHER_V.toString());
1395                                 deleteOtherV = (String)edgeMap.get(EdgeProperty.DELETE_OTHER_V.toString());
1396                                 edgeDes.setDeleteOtherV(deleteOtherV);
1397                                 edgeDes.setHasDelTarget(hasDelTarget);
1398                                 preventDelete = (String)edgeMap.get(EdgeProperty.PREVENT_DELETE.toString());
1399                                 edgeDes.setPreventDelete(preventDelete);
1400                                 description = (String)edgeMap.get(EdgeProperty.DESCRIPTION.toString());
1401                                 edgeDes.setDescription(description);
1402                                 
1403                                 result.add(edgeDes);
1404                                 logger.debug("Edge: "+edgeDes.getRuleKey());
1405                         }
1406                 } catch (Exception ex) {
1407                         ex.printStackTrace();
1408                 }
1409                 return result;
1410                 
1411         }
1412         
1413         /**
1414          * Guaranteed to at least return non null but empty collection of edge descriptions
1415          * @param nodeName name of the vertex whose edge relationships to return
1416          * @return collection of node neighbors based on DbEdgeRules
1417         **/
1418         private static Collection<EdgeDescription> getEdgeRules( String nodeName ) 
1419         {               
1420                 String fromRulesPath = "$['rules'][?(@['from']=='" + nodeName + "')]";
1421                 String toRulesPath = "$['rules'][?(@['to']=='" + nodeName + "')]";
1422                 Collection<EdgeDescription> fromEdges = getEdgeRulesFromJson( fromRulesPath, false );
1423                 Collection<EdgeDescription> edges = getEdgeRulesFromJson( toRulesPath, true );
1424                 edges.addAll(fromEdges);
1425                 return edges;
1426         }
1427         
1428         private static Collection<EdgeDescription> getEdgeRulesTO( String nodeName ) 
1429         {               
1430                 String toRulesPath = "$['rules'][?(@['to']=='" + nodeName + "')]";
1431                 Collection<EdgeDescription> edges = getEdgeRulesFromJson( toRulesPath, true );
1432                 return edges;
1433         }
1434         
1435         private static Collection<EdgeDescription> getEdgeRulesFROM( String nodeName ) 
1436         {               
1437                 String fromRulesPath = "$['rules'][?(@['from']=='" + nodeName + "')]";
1438                 Collection<EdgeDescription> edges = getEdgeRulesFromJson( fromRulesPath, true );
1439                 return edges;
1440         }       
1441         public static String processJavaTypeElementSwagger( String javaTypeName, Element javaTypeElement,
1442                         StringBuffer pathSb, StringBuffer definitionsSb, String path, String tag, String opId,
1443                         String getItemName, StringBuffer pathParams, String queryParams, String validEdges) {
1444                 
1445                 String xmlRootElementName = null;
1446                 StringBuilder definitionsLocalSb = new StringBuilder(256);
1447                 
1448                 String useTag = null;
1449                 String useOpId = null;
1450                 
1451                 if ( tag != null ) {
1452                         switch ( tag ) {
1453                         case "Network":
1454                         case "ServiceDesignAndCreation":
1455                         case "Business":
1456                         case "LicenseManagement":
1457                         case "CloudInfrastructure":
1458                                 break;
1459                         default:
1460                                 return null;
1461                         }
1462                 }
1463                 
1464                 if ( !javaTypeName.equals("Inventory") ) {
1465                         if ( javaTypeName.equals("AaiInternal"))
1466                                 return null;
1467                         if ( opId == null )
1468                                 useOpId = javaTypeName;
1469                         else
1470                                 useOpId = opId + javaTypeName;
1471                         if ( tag == null )
1472                                 useTag = javaTypeName;
1473                 }
1474                 
1475                 NodeList parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
1476
1477                 if ( parentNodes.getLength() == 0 ) {
1478                         logger.trace( "no java-attributes for java-type " + javaTypeName);
1479                         return "";
1480                 }
1481                 
1482                 NamedNodeMap attributes;
1483                 
1484                 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
1485                 Element valElement = (Element) valNodes.item(0);
1486                 attributes = valElement.getAttributes();
1487                 for ( int i = 0; i < attributes.getLength(); ++i ) {
1488             Attr attr = (Attr) attributes.item(i);
1489             String attrName = attr.getNodeName();
1490
1491             String attrValue = attr.getNodeValue();
1492             logger.trace("Found xml-root-element attribute: " + attrName + " with value: " + attrValue);
1493             if ( attrName.equals("name"))
1494                 xmlRootElementName = attrValue;
1495                 }
1496
1497                 NodeList childNodes;
1498                 Element childElement;
1499                 NodeList xmlPropNodes = javaTypeElement.getElementsByTagName("xml-properties");
1500                 Element xmlPropElement;
1501                 String pathDescriptionProperty = null;
1502                 
1503                 
1504                 Vector<String> indexedProps = null;
1505                 
1506                 if ( xmlPropNodes.getLength() > 0 ) {
1507
1508                         for ( int i = 0; i < xmlPropNodes.getLength(); ++i ) {
1509                                 xmlPropElement = (Element)xmlPropNodes.item(i);
1510                                 if ( !xmlPropElement.getParentNode().isSameNode(javaTypeElement))
1511                                         continue;
1512                                 childNodes = xmlPropElement.getElementsByTagName("xml-property");
1513                                 
1514                                 if ( childNodes.getLength() > 0 ) {
1515                                         for ( int j = 0; j < childNodes.getLength(); ++j ) {
1516                                                 childElement = (Element)childNodes.item(j);
1517                                                 // get name
1518                                                 int useValue = VALUE_NONE;
1519                                                 attributes = childElement.getAttributes();
1520                                                 for ( int k = 0; k < attributes.getLength(); ++k ) {
1521                                                         Attr attr = (Attr) attributes.item(k);
1522                                                         String attrName = attr.getNodeName();
1523                                                         String attrValue = attr.getNodeValue();
1524                                                         if ( attrName == null || attrValue == null )
1525                                                                 continue;
1526                                                         if ( attrName.equals("name") && attrValue.equals("description")) {
1527                                                                 useValue = VALUE_DESCRIPTION;
1528                                                         }
1529                                                         if ( useValue == VALUE_DESCRIPTION && attrName.equals("value")) {
1530                                                                 pathDescriptionProperty = attrValue;
1531                                                         }
1532                                                         if ( attrValue.equals("indexedProps")) {
1533                                                                 useValue = VALUE_INDEXED_PROPS;
1534                                                         }
1535                                                         if ( useValue == VALUE_INDEXED_PROPS && attrName.equals("value")) {
1536                                                                 indexedProps = getIndexedProps( attrValue );
1537                                                         }
1538                                                 }
1539                                         }
1540                                 }
1541                         }
1542                 }
1543                 logger.trace("javaTypeName " + javaTypeName + " description " + pathDescriptionProperty);
1544                 
1545                 Element parentElement = (Element)parentNodes.item(0);
1546                 NodeList xmlElementNodes = parentElement.getElementsByTagName("xml-element");
1547
1548         
1549                 String attrDescription = null;
1550
1551                 Element xmlElementElement;
1552                 String addType = null;
1553                 String elementType = null, elementIsKey = null, elementIsRequired, elementContainerType = null;
1554                 String elementName = null;
1555                 StringBuffer sbParameters = new StringBuffer();
1556
1557                 StringBuffer sbRequired = new StringBuffer();
1558                 int requiredCnt = 0;
1559                 int propertyCnt = 0;
1560                 StringBuffer sbProperties = new StringBuffer();
1561                 StringBuffer sbIndexedParams = new StringBuffer();
1562
1563                 
1564                 StringTokenizer st;
1565                 if ( xmlRootElementName.equals("inventory"))
1566                         path = "";
1567                 else if ( path == null )
1568                         path = "/" + xmlRootElementName;
1569                 else
1570                         path += "/" + xmlRootElementName;
1571                 st = new StringTokenizer(path, "/");
1572                 boolean genPath = false;
1573
1574                 if ( st.countTokens() > 1 && getItemName == null ) {
1575                         if ( appliedPaths.containsKey(path)) 
1576                                 return null;
1577                         appliedPaths.put(path, xmlRootElementName);
1578                         genPath = true;
1579                         if ( path.contains("/relationship/") ) { // filter paths with relationship-list
1580                                 genPath = false;
1581                         }
1582                         if ( path.endsWith("/relationship-list")) {
1583                                 genPath = false;
1584                         }
1585                                         
1586                 }
1587                 
1588                 Vector<String> addTypeV = null;
1589                 if (  xmlElementNodes.getLength() > 0 ) {
1590                         
1591                         for ( int i = 0; i < xmlElementNodes.getLength(); ++i ) {
1592                                 xmlElementElement = (Element)xmlElementNodes.item(i);
1593                                 if ( !xmlElementElement.getParentNode().isSameNode(parentElement))
1594                                         continue;
1595
1596                                 valNodes = xmlElementElement.getElementsByTagName("xml-properties");
1597                                 attrDescription = null;
1598                                 if ( valNodes.getLength() > 0 ) {
1599                                         for ( int j = 0; j < valNodes.getLength(); ++j ) {
1600                                                 valElement = (Element)valNodes.item(j);
1601                                                 if ( !valElement.getParentNode().isSameNode(xmlElementElement))
1602                                                         continue;
1603                                                 childNodes = valElement.getElementsByTagName("xml-property");
1604                                                 if ( childNodes.getLength() > 0 ) {
1605                                                         childElement = (Element)childNodes.item(0);
1606                                                         // get name
1607                                                         attributes = childElement.getAttributes();
1608                                                         attrDescription = null;
1609                                                         boolean useValue = false;
1610                                                         for ( int k = 0; k < attributes.getLength(); ++k ) {
1611                                                                 Attr attr = (Attr) attributes.item(k);
1612                                                                 String attrName = attr.getNodeName();
1613                                                                 String attrValue = attr.getNodeValue();
1614                                                                 if ( attrName.equals("name") && attrValue.equals("description")) {
1615                                                                         useValue = true;
1616                                                                 }
1617                                                                 if ( useValue && attrName.equals("value")) {
1618                                                                         attrDescription = attrValue;
1619                                                                 }
1620                                                         }
1621
1622                                                 }
1623                                         }
1624                                 }
1625                                 
1626                                 attributes = xmlElementElement.getAttributes();
1627                                 addTypeV = null; // vector of 1
1628                                 addType = null;
1629                                 
1630                                 elementName = elementType = elementIsKey = elementIsRequired = elementContainerType = null;
1631                                 for ( int j = 0; j < attributes.getLength(); ++j ) {
1632                             Attr attr = (Attr) attributes.item(j);
1633                             String attrName = attr.getNodeName();
1634         
1635                             String attrValue = attr.getNodeValue();
1636                             logger.trace("For " + xmlRootElementName + " Found xml-element attribute: " + attrName + " with value: " + attrValue);
1637                             if ( attrName.equals("name")) {
1638                                 elementName = attrValue;
1639
1640                             }
1641                             if ( attrName.equals("type") && getItemName == null ) {
1642                                 elementType = attrValue;
1643                                 if ( attrValue.contains(apiVersionFmt) ) {
1644                                         addType = attrValue.substring(attrValue.lastIndexOf('.')+1);
1645                                         if ( addTypeV == null ) 
1646                                                 addTypeV = new Vector<String>();
1647                                         addTypeV.add(addType);
1648                                 }
1649                                         
1650                             }
1651                             if ( attrName.equals("xml-key")) {
1652                                 elementIsKey = attrValue;
1653                                 path += "/{" + elementName + "}";
1654                             }
1655                             if ( attrName.equals("required")) {
1656                                 elementIsRequired = attrValue;
1657                             }
1658                             if ( attrName.equals("container-type")) {
1659                                 elementContainerType = attrValue;
1660                             }   
1661                                 }
1662                 if ( getItemName != null ) {
1663                         if ( getItemName.equals("array") ) {
1664                                 if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) {
1665                                         logger.trace( " returning array " + elementName );
1666                                         return elementName;
1667                                 }
1668                                 
1669                         } else { // not an array check
1670                                 if ( elementContainerType == null || !elementContainerType.equals("java.util.ArrayList")) {
1671                                         logger.trace( " returning object " + elementName );
1672                                         return elementName;
1673                                 }
1674                                 
1675                         }
1676                         logger.trace( " returning null" );
1677                         return null;
1678                 }
1679                                 if ( elementIsRequired != null ) {
1680                                         if ( requiredCnt == 0 )
1681                                                 sbRequired.append("    required:\n");
1682                                         ++requiredCnt;
1683                                         if ( addTypeV != null ) {
1684                                                 for ( int k = 0; k < addTypeV.size(); ++i ) {
1685                                                         sbRequired.append("    - " + getXmlRootElementName(addTypeV.elementAt(k)) + ":\n");
1686                                                 }
1687                                         } else 
1688                                                 sbRequired.append("    - " + elementName + "\n");
1689
1690                                 }
1691
1692                                 if (  elementIsKey != null )  {
1693                                         sbParameters.append(("        - name: " + elementName + "\n"));
1694                                         sbParameters.append(("          in: path\n"));
1695                                         if ( attrDescription != null && attrDescription.length() > 0 )
1696                                                 sbParameters.append(("          description: " + attrDescription + "\n"));
1697                                         sbParameters.append(("          required: true\n"));
1698                                         if ( elementType.equals("java.lang.String"))
1699                                                 sbParameters.append("          type: string\n");
1700                                         if ( elementType.equals("java.lang.Long")) {
1701                                                 sbParameters.append("          type: integer\n");
1702                                                 sbParameters.append("          format: int64\n");
1703                                         }
1704                                         if ( elementType.equals("java.lang.Integer")) {
1705                                                 sbParameters.append("          type: integer\n");
1706                                                 sbParameters.append("          format: int32\n");
1707                                         }
1708                                         if ( elementType.equals("java.lang.Boolean")) {
1709                                                 sbParameters.append("          type: boolean\n");
1710                                         }
1711                                         if(StringUtils.isNotBlank(elementName)) {
1712                                                 sbParameters.append("          example: "+"__"+elementName.toUpperCase()+"__"+"\n");
1713                                         }
1714                                 } else if (  indexedProps != null
1715                                                 && indexedProps.contains(elementName ) ) {
1716                                         sbIndexedParams.append(("        - name: " + elementName + "\n"));
1717                                         sbIndexedParams.append(("          in: query\n"));
1718                                         if ( attrDescription != null && attrDescription.length() > 0 )
1719                                                 sbIndexedParams.append(("          description: " + attrDescription + "\n"));
1720                                         sbIndexedParams.append(("          required: false\n"));
1721                                         if ( elementType.equals("java.lang.String"))
1722                                                 sbIndexedParams.append("          type: string\n");
1723                                         if ( elementType.equals("java.lang.Long")) {
1724                                                 sbIndexedParams.append("          type: integer\n");
1725                                                 sbIndexedParams.append("          format: int64\n");
1726                                         }
1727                                         if ( elementType.equals("java.lang.Integer")) {
1728                                                 sbIndexedParams.append("          type: integer\n");
1729                                                 sbIndexedParams.append("          format: int32\n");
1730                                         }
1731                                         if ( elementType.equals("java.lang.Boolean"))
1732                                                 sbIndexedParams.append("          type: boolean\n");
1733                                 }
1734                         if ( isStandardType(elementType)) {
1735                                 sbProperties.append("      " + elementName + ":\n");
1736                                 ++propertyCnt;
1737                                 sbProperties.append("        type: ");
1738
1739                                 if ( elementType.equals("java.lang.String"))
1740                                         sbProperties.append("string\n");
1741                                 else if ( elementType.equals("java.lang.Long")) {
1742                                         sbProperties.append("integer\n");
1743                                         sbProperties.append("        format: int64\n");
1744                                 }
1745                                 else if ( elementType.equals("java.lang.Integer")){
1746                                         sbProperties.append("integer\n");
1747                                         sbProperties.append("        format: int32\n");
1748                                 }
1749                                 else if ( elementType.equals("java.lang.Boolean"))
1750                                         sbProperties.append("boolean\n");
1751                                 if ( attrDescription != null && attrDescription.length() > 0 )
1752                                         sbProperties.append("        description: " + attrDescription + "\n");
1753                         }
1754
1755                 if ( addTypeV !=  null ) {
1756                         StringBuffer newPathParams = null;
1757                         if ( pathParams != null  ) {
1758                                 newPathParams = new StringBuffer();
1759                                 newPathParams.append(pathParams);
1760                         }
1761                     if ( sbParameters.toString().length() > 0 ) {
1762                                         if ( newPathParams == null )
1763                                                 newPathParams = new StringBuffer();
1764                                         newPathParams.append(sbParameters);
1765                     }
1766                     String newQueryParams = null;
1767                     if ( sbIndexedParams.toString().length() > 0 ) {
1768                         if ( queryParams == null )
1769                                 newQueryParams = sbIndexedParams.toString();
1770                         else
1771                                 newQueryParams = queryParams + sbIndexedParams.toString();
1772                     } else {
1773                         newQueryParams = queryParams;
1774                     }
1775                         for ( int k = 0; k < addTypeV.size(); ++k ) {
1776                                 addType = addTypeV.elementAt(k);
1777                 
1778                                 if ( opId == null || !opId.contains(addType)) {
1779                                         processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), 
1780                                                 pathSb, definitionsSb, path,  tag == null ? useTag : tag, useOpId, null,
1781                                                 newPathParams, newQueryParams, validEdges);
1782                                 }
1783                                 // need item name of array
1784                                         String itemName = processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), 
1785                                                 pathSb, definitionsSb, path,  tag == null ? useTag : tag, useOpId, 
1786                                                                 "array", null, null, null );
1787                                         
1788                                         if ( itemName != null ) {
1789                                                 if ( addType.equals("AaiInternal") ) {
1790                                                         logger.debug( "addType AaiInternal, skip properties");
1791                                                         
1792                                                 } else if ( getItemName == null) {
1793                                                         ++propertyCnt;
1794                                                         sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
1795                                                         sbProperties.append("        type: array\n        items:\n");
1796                                                         sbProperties.append("          $ref: \"#/definitions/" + (itemName == "" ? "aai-internal" : itemName) + "\"\n");
1797                                                         if ( attrDescription != null && attrDescription.length() > 0 )
1798                                                                 sbProperties.append("        description: " + attrDescription + "\n");
1799                                                 }
1800                                         } else {
1801                                                 if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) {
1802                                                         // need properties for getXmlRootElementName(addType)
1803                                                 newPathParams = null;
1804                                                 if ( pathParams != null  ) {
1805                                                         newPathParams = new StringBuffer();
1806                                                         newPathParams.append(pathParams);
1807                                                 }
1808                                             if ( sbParameters.toString().length() > 0 ) {
1809                                                                 if ( newPathParams == null )
1810                                                                         newPathParams = new StringBuffer();
1811                                                                 newPathParams.append(sbParameters);
1812                                             }
1813                                             newQueryParams = null;
1814                                             if ( sbIndexedParams.toString().length() > 0 ) {
1815                                                 if ( queryParams == null )
1816                                                         newQueryParams = sbIndexedParams.toString();
1817                                                 else
1818                                                         newQueryParams = queryParams + sbIndexedParams.toString();
1819                                             } else {
1820                                                 newQueryParams = queryParams;
1821                                             }
1822                                                         processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType), 
1823                                                                 pathSb, definitionsSb, path,  tag == null ? useTag : tag, useOpId, 
1824                                                                                 null, newPathParams, newQueryParams, validEdges );
1825                                                         sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
1826                                                         sbProperties.append("        type: array\n        items:          \n");
1827                                                         sbProperties.append("          $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n");
1828                                                 } else {
1829                                                         sbProperties.append("      " + getXmlRootElementName(addType) + ":\n");
1830                                                         sbProperties.append("        type: object\n");
1831                                                         sbProperties.append("        $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n");
1832                                                 }
1833                                                 if ( attrDescription != null && attrDescription.length() > 0 )
1834                                                         sbProperties.append("        description: " + attrDescription + "\n");
1835                                                 ++propertyCnt;
1836                                         }
1837                         }
1838                 }
1839                 }
1840         }       
1841                 if ( genPath ) {
1842                         if ( !path.endsWith("/relationship") ) {
1843                                 GetOperation get = new GetOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString());
1844                                 pathSb.append(get.toString());
1845 //                              if ( path.indexOf('{') > 0 ) {
1846                                 
1847                             if ( sbParameters.toString().length() > 0 ) {
1848                                                 if ( pathParams == null )
1849                                                         pathParams = new StringBuffer();
1850                                                 pathParams.append(sbParameters);
1851                             }
1852                                         if ( pathParams != null) {
1853                                                 pathSb.append("      parameters:\n");
1854                                                 pathSb.append(pathParams);
1855                                         } else
1856                                                 logger.trace( "null pathParams for " + useOpId);
1857                                         if ( sbIndexedParams.toString().length() > 0 ) {
1858                                                 if ( queryParams == null )
1859                                                         queryParams = sbIndexedParams.toString();
1860                                                 else
1861                                                         queryParams = queryParams + sbIndexedParams.toString();
1862                                         }
1863                                         if ( queryParams != null ) {
1864                                                 if ( pathParams == null ) {
1865                                                         pathSb.append("      parameters:\n");
1866                                                 }
1867                                                 pathSb.append(queryParams);
1868                                         }
1869 //                              }
1870                         }
1871                         boolean skipPutDelete = false; // no put or delete for "all" 
1872                         if ( !path.endsWith("/relationship") ) {                                
1873                                 if ( !path.endsWith("}") ){
1874                                                 skipPutDelete = true;
1875                                 }
1876                                         
1877                         }
1878                         if ( path.indexOf('{') > 0 && !opId.startsWith("Search") &&!skipPutDelete) {
1879                                 // add PUT
1880                                 PutOperation put = new PutOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString());
1881                                 pathSb.append(put.toString());
1882                                 if ( !path.endsWith("/relationship") ) {
1883                                         PatchOperation patch = new PatchOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString());
1884                                         pathSb.append(patch.toString1());
1885                                 }
1886                                 logger.debug(put.tagRelationshipPathMapEntry());
1887
1888                                 // add DELETE
1889                                 DeleteOperation del = new DeleteOperation(useOpId, xmlRootElementName, tag, path, pathParams == null ? "" : pathParams.toString());
1890                                 pathSb.append(del.toString());
1891                                 logger.debug(del.objectPathMapEntry());
1892                         }
1893                         
1894                 }
1895                 if ( generatedJavaType.containsKey(xmlRootElementName) ) {
1896                         return null;
1897                 }
1898         
1899                 definitionsSb.append("  " + xmlRootElementName + ":\n");
1900                 definitionsLocalSb.append("  " + xmlRootElementName + ":\n");
1901                 Collection<EdgeDescription> edges = getEdgeRules(xmlRootElementName );
1902                 
1903                 if ( edges.size() > 0 ) {
1904                         StringBuffer sbEdge = new StringBuffer();
1905                         sbEdge.append("      ###### Related Nodes\n");
1906                         for (EdgeDescription ed : edges) {
1907                                 if ( ed.getRuleKey().startsWith(xmlRootElementName)) {
1908                                     sbEdge.append("      - TO ").append(ed.getRuleKey().substring(ed.getRuleKey().indexOf("|")+1));
1909                                     sbEdge.append(ed.getRelationshipDescription("TO", xmlRootElementName));
1910                                     sbEdge.append("\n");
1911                                 }
1912                         }
1913                         for (EdgeDescription ed : edges) { 
1914                                 if ( ed.getRuleKey().endsWith(xmlRootElementName)) {
1915                                     sbEdge.append("      - FROM ").append(ed.getRuleKey().substring(0, ed.getRuleKey().indexOf("|")));
1916                                     sbEdge.append(ed.getRelationshipDescription("FROM", xmlRootElementName));
1917                                     sbEdge.append("\n");
1918                                 }
1919                         }
1920                         // Delete rule processing is incorrect.  One cannot express the delete rules in isolation from the
1921                         // specific edge.  Take the case of allotted-resource and service-instance.  When the service-instance owns the
1922                         // allotted-resource, yes, it deletes it.  But when the service-instance only uses the allotted-resource, the deletion
1923                         // of the service instance does not cause the deletion of the allotted-resource.
1924                         // I put some lines into the toDeleteRules and fromDeleteRules to correct things to an extent, but it's still
1925                         // not right.
1926                         sbEdge.append(toDeleteRules(xmlRootElementName));
1927                         sbEdge.append(fromDeleteRules(xmlRootElementName));
1928                         validEdges = sbEdge.toString();
1929                 }
1930
1931                 // Handle description property.  Might have a description OR valid edges OR both OR neither.
1932                 // Only put a description: tag if there is at least one.
1933                 if (pathDescriptionProperty != null || validEdges != null) {
1934                         definitionsSb.append("    description: |\n");
1935                         definitionsLocalSb.append("    description: |\n");      
1936
1937                         if ( pathDescriptionProperty != null ) {
1938                                 definitionsSb.append("      " + pathDescriptionProperty + "\n" );
1939                                 definitionsLocalSb.append("      " + pathDescriptionProperty    + "\n" );
1940                         }
1941                         if (validEdges != null) {
1942                                 definitionsSb.append(validEdges);
1943                                 definitionsLocalSb.append(validEdges);
1944                         }
1945                 }
1946                 
1947                 if ( requiredCnt > 0 ) {
1948                         definitionsSb.append(sbRequired);
1949                         definitionsLocalSb.append(sbRequired);
1950                 }
1951                         
1952                 if ( propertyCnt > 0 ) {
1953                         definitionsSb.append("    properties:\n");
1954                         definitionsSb.append(sbProperties);
1955                         definitionsLocalSb.append("    properties:\n");
1956                         definitionsLocalSb.append(sbProperties);
1957                 }
1958                 try {
1959                         javaTypeDefinitions.put(xmlRootElementName, definitionsLocalSb.toString());
1960                 } catch (Exception e) {
1961                         e.printStackTrace();
1962                 }
1963                 generatedJavaType.put(xmlRootElementName, null);
1964                 return null;
1965         }
1966         
1967         public static void generateRelations() {
1968                 if(putRelationPaths == null)
1969                         return;
1970                 putRelationPaths.forEach((k,v)->{
1971                         logger.trace("k="+k+"\n"+"v="+v+v.equals("/business/customers/customer/{global-customer-id}/service-subscriptions/service-subscription/{service-type}/service-instances/service-instance/{service-instance-id}/allotted-resources/allotted-resource/{id}/relationship-list/relationship"));
1972                         logger.debug("apiPath(Operation): "+v);
1973                         logger.debug("Target object: "+v.replace("/relationship-list/relationship", ""));
1974                         logger.debug("Relations: ");
1975                         PutRelationPathSet prp = new PutRelationPathSet(k, v);
1976                         prp.process();
1977                 });
1978         }
1979
1980         public static String generateSwaggerFromOxmFile( File oxmFile, String xml )
1981         {
1982                 if ( xml != null ){
1983                         apiVersion = Version.getLatest().toString();
1984                     apiVersionFmt = "." + apiVersion + ".";
1985                     generatedJavaType = new HashMap<>();
1986                         appliedPaths = new HashMap<>();
1987                         responsesUrl = "Description: response-label\n";
1988                 }
1989                 StringBuffer sb = new StringBuffer();
1990                 sb.append("swagger: \"2.0\"\ninfo:\n  ");
1991                 sb.append("description: |");
1992                 sb.append("\n\n    [Differences versus the previous schema version]("+"apidocs/aai_swagger_" + apiVersion + ".diff)");
1993                 sb.append("\n\n    Copyright &copy; 2017 AT&amp;T Intellectual Property. All rights reserved.\n\n    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.\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 &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.\n\n    ECOMP and OpenECOMP are trademarks and service marks of AT&amp;T Intellectual Property.\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: \"" + apiVersion +"\"\n");
1994                 sb.append("  title: Active and Available Inventory REST API\n");
1995                 sb.append("  license:\n    name: Apache 2.0\n    url: http://www.apache.org/licenses/LICENSE-2.0.html\n");
1996                 sb.append("  contact:\n    name:\n    url:\n    email:\n");
1997                 sb.append("host:\nbasePath: /aai/" + apiVersion + "\n");
1998                 sb.append("schemes:\n  - https\npaths:\n");
1999
2000                 try {
2001                         File initialFile;
2002                         if(System.getProperty("user.dir") != null && !System.getProperty("user.dir").contains(normalStartDir)) {
2003                                 initialFile = new File(normalStartDir + "/src/main/resources/dbedgerules/DbEdgeRules_" + apiVersion + ".json");
2004                         }
2005                         else {
2006                                 initialFile = new File("src/main/resources/dbedgerules/DbEdgeRules_" + apiVersion + ".json");
2007                         }
2008                     InputStream is = new FileInputStream(initialFile);
2009
2010                         Scanner scanner = new Scanner(is);
2011                         jsonEdges = scanner.useDelimiter("\\Z").next();
2012                         scanner.close();
2013                         is.close();
2014                         
2015                     DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
2016                     dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
2017                     DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
2018                     Document doc;
2019                     
2020                     if ( xml == null ) {
2021                         doc = dBuilder.parse(oxmFile);
2022                     } else {
2023                             InputSource isInput = new InputSource(new StringReader(xml));
2024                             doc = dBuilder.parse(isInput);
2025                     }
2026
2027                     NodeList bindingsNodes = doc.getElementsByTagName("xml-bindings");
2028                         Element bindingElement;
2029                         NodeList javaTypesNodes;
2030                         Element javaTypesElement;
2031                         
2032                         Element javaTypeElement;
2033
2034                         
2035                         if ( bindingsNodes == null || bindingsNodes.getLength() == 0 ) {
2036                                 logger.error( "missing <binding-nodes> in " + oxmFile );
2037                                 return null;
2038                         }           
2039                         
2040                         bindingElement = (Element) bindingsNodes.item(0);
2041                         javaTypesNodes = bindingElement.getElementsByTagName("java-types");
2042                         if ( javaTypesNodes.getLength() < 1 ) {
2043                                 logger.error( "missing <binding-nodes><java-types> in " + oxmFile );
2044                                 return null;
2045                         }
2046                         javaTypesElement = (Element) javaTypesNodes.item(0);
2047
2048                         javaTypeNodes = javaTypesElement.getElementsByTagName("java-type");
2049                         if ( javaTypeNodes.getLength() < 1 ) {
2050                                 logger.error( "missing <binding-nodes><java-types><java-type> in " + oxmFile );
2051                                 return null;
2052                         }
2053
2054                         String javaTypeName;
2055                         String attrName, attrValue;
2056                         Attr attr;
2057                         StringBuffer pathSb = new StringBuffer();
2058                         
2059                         StringBuffer definitionsSb = new StringBuffer();
2060                         for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
2061                                 javaTypeElement = (Element) javaTypeNodes.item(i);
2062                                 NamedNodeMap attributes = javaTypeElement.getAttributes();
2063                                 javaTypeName = null;
2064                                 for ( int j = 0; j < attributes.getLength(); ++j ) {
2065                             attr = (Attr) attributes.item(j);
2066                             attrName = attr.getNodeName();
2067                             attrValue = attr.getNodeValue();
2068                             if ( attrName.equals("name"))
2069                                 javaTypeName = attrValue;
2070                                 }
2071                                 if ( javaTypeName == null ) {
2072                                         logger.error( "<java-type> has no name attribute in " + oxmFile );
2073                                         return null;
2074                                 }
2075                                 if ( !generatedJavaType.containsKey(getXmlRootElementName(javaTypeName)) ) {
2076                                         
2077                                         processJavaTypeElementSwagger( javaTypeName, javaTypeElement, pathSb,
2078                                                         definitionsSb, null, null, null, null, null, null, null);
2079                                 }
2080                         }
2081                         sb.append(pathSb);
2082                 } catch (Exception e) {
2083                         e.printStackTrace();
2084                         return null;
2085                 }
2086                 //append definitions
2087                 sb.append("definitions:\n");
2088                 Map<String, String> sortedJavaTypeDefinitions = new TreeMap<String, String>(javaTypeDefinitions);
2089                 for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
2090                     logger.debug("Key: "+entry.getKey()+"Test: "+ (entry.getKey() == "relationship"));  
2091                     if(entry.getKey().matches("relationship")) {
2092                             String jb=entry.getValue();
2093                         logger.debug("Value: "+jb);
2094                             int ndx=jb.indexOf("related-to-property:");
2095                             if(ndx > 0) {
2096                                 jb=jb.substring(0, ndx);
2097                                 jb=jb.replaceAll(" +$", "");
2098                             }
2099                         logger.debug("Value-after: "+jb);
2100                         sb.append(jb);
2101                         continue;
2102                     }
2103                     sb.append(entry.getValue());
2104                 }
2105                     
2106                 sb.append("patchDefinitions:\n");
2107                 for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
2108                     String jb=entry.getValue().replaceAll("/definitions/", "/patchDefinitions/");
2109                     int ndx=jb.indexOf("relationship-list:");
2110                     if(ndx > 0) {
2111                         jb=jb.substring(0, ndx);
2112                         jb=jb.replaceAll(" +$", "");
2113                     }
2114                     int ndx1=jb.indexOf("resource-version:");
2115                         logger.debug("Key: "+entry.getKey()+" index: " + ndx1);                 
2116                         logger.debug("Value: "+jb);                     
2117                         if(ndx1 > 0) {
2118                             jb=jb.substring(0, ndx1);
2119                             jb=jb.replaceAll(" +$", "");
2120                     }
2121                         logger.debug("Value-after: "+jb);
2122                     sb.append(jb);
2123                 }
2124                     
2125                 sb.append("getDefinitions:\n");
2126                 for (Map.Entry<String, String> entry : sortedJavaTypeDefinitions.entrySet()) {
2127                     String jb=entry.getValue().replaceAll("/definitions/", "/getDefinitions/");
2128                     sb.append(jb);
2129                 }
2130
2131                 logger.debug("generated " + sb.toString());
2132                 generateRelations();
2133                 return sb.toString();
2134         }
2135         
2136         private static NodeList locateXmlProperties(Element element) {
2137                 XPathExpression expr;
2138                 NodeList result = null;
2139                 try {
2140                         expr = xpath.compile("xml-properties");
2141                         if (expr != null) {
2142                                 Object nodeset = expr.evaluate(element, XPathConstants.NODESET);
2143                                 if (nodeset != null) {
2144                                         NodeList nodes = (NodeList) nodeset;
2145                                         if (nodes != null && nodes.getLength() > 0) {
2146                                                 Element xmlProperty = (Element)nodes.item(0);
2147                                                 result = xmlProperty.getElementsByTagName("xml-property");
2148                                         }
2149                                 }
2150                         }
2151                 } catch (XPathExpressionException e) {
2152                         e.printStackTrace();
2153                 }
2154                 return result;
2155                 
2156         }
2157 }