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