Move the aai-schema, annotations and
[aai/schema-service.git] / aai-schema-gen / src / main / java / org / onap / aai / schemagen / genxsd / OxmFileProcessor.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *    http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.onap.aai.schemagen.genxsd;
21
22 import org.onap.aai.edges.EdgeIngestor;
23 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
24 import org.onap.aai.nodes.NodeIngestor;
25 import org.onap.aai.setup.SchemaVersion;
26 import org.onap.aai.setup.SchemaVersions;
27 import org.w3c.dom.*;
28 import org.xml.sax.InputSource;
29 import org.xml.sax.SAXException;
30
31 import javax.xml.XMLConstants;
32 import javax.xml.parsers.DocumentBuilder;
33 import javax.xml.parsers.DocumentBuilderFactory;
34 import javax.xml.parsers.ParserConfigurationException;
35 import java.io.File;
36 import java.io.FileNotFoundException;
37 import java.io.IOException;
38 import java.io.StringReader;
39 import java.util.*;
40
41 public abstract class OxmFileProcessor {
42
43         public static final String LINE_SEPARATOR = System.getProperty("line.separator");
44         public static final String DOUBLE_LINE_SEPARATOR = System.getProperty("line.separator") + System.getProperty("line.separator");
45
46         EdgeIngestor ei;
47         NodeIngestor ni;
48         protected Set<String> namespaceFilter;
49         protected File oxmFile;
50         protected String xml;
51         protected SchemaVersion v;
52         protected Document doc = null;
53         protected String apiVersion = null;
54         protected SchemaVersions schemaVersions;
55
56
57         protected static int annotationsStartVersion = 9; // minimum version to support annotations in xsd
58         protected static int annotationsMinVersion = 6; // lower versions support annotations in xsd
59         protected static int swaggerSupportStartsVersion = 1; // minimum version to support swagger documentation
60         protected static int swaggerDiffStartVersion = 1; // minimum version to support difference
61         protected static int swaggerMinBasepath = 6; // minimum version to support difference
62
63         protected Map combinedJavaTypes;
64
65
66         protected String apiVersionFmt = null;
67         protected HashMap<String, String> generatedJavaType = new HashMap<String, String>();
68         protected HashMap<String, String> appliedPaths = new HashMap<String, String>();
69         protected NodeList javaTypeNodes = null;
70
71         protected Map<String,String> javaTypeDefinitions = createJavaTypeDefinitions();
72     private Map<String, String> createJavaTypeDefinitions()
73     {
74         StringBuffer aaiInternal = new StringBuffer();
75         StringBuffer nodes = new StringBuffer();
76         Map<String,String> javaTypeDefinitions = new HashMap<String, String>();
77         aaiInternal.append("  aai-internal:\n");
78         aaiInternal.append("    properties:\n");
79         aaiInternal.append("      property-name:\n");
80         aaiInternal.append("        type: string\n");
81         aaiInternal.append("      property-value:\n");
82         aaiInternal.append("        type: string\n");
83 //      javaTypeDefinitions.put("aai-internal", aaiInternal.toString());
84               nodes.append("  nodes:\n");
85               nodes.append("    properties:\n");
86               nodes.append("      inventory-item-data:\n");
87               nodes.append("        type: array\n");
88               nodes.append("        items:\n");
89               nodes.append("          $ref: \"#/definitions/inventory-item-data\"\n");
90         javaTypeDefinitions.put("nodes", nodes.toString());
91         return javaTypeDefinitions;
92     }
93         static List<String> nodeFilter = createNodeFilter();
94     private static List<String> createNodeFilter()
95     {
96         List<String> list = Arrays.asList("search", "actions", "aai-internal", "nodes");
97         return list;
98     }
99
100     public OxmFileProcessor(SchemaVersions schemaVersions, NodeIngestor ni, EdgeIngestor ei){
101         this.schemaVersions = schemaVersions;
102         this.ni = ni;
103                 this.ei = ei;
104         }
105
106
107
108         public void setOxmVersion(File oxmFile, SchemaVersion v) {
109                 this.oxmFile = oxmFile;
110                 this.v = v;
111         }
112
113         public void setXmlVersion(String xml, SchemaVersion v) {
114                 this.xml = xml;
115                 this.v = v;
116         }
117
118         public void setVersion(SchemaVersion v) {
119                 this.oxmFile = null;
120                 this.v = v;
121         }
122
123         public void setNodeIngestor(NodeIngestor ni) {
124                     this.ni = ni;
125         }
126
127     public void setEdgeIngestor(EdgeIngestor ei) {
128             this.ei = ei;
129         }
130
131     public SchemaVersions getSchemaVersions() {
132                 return schemaVersions;
133         }
134
135         public void setSchemaVersions(SchemaVersions schemaVersions) {
136                 this.schemaVersions = schemaVersions;
137         }
138
139         protected void init() throws ParserConfigurationException, SAXException, IOException, EdgeRuleNotFoundException  {
140                 if(this.xml != null || this.oxmFile != null ) {
141                         createDocument();
142                 }
143                 if(this.doc == null) {
144                         this.doc = ni.getSchema(v);
145                 }
146                 namespaceFilter = new HashSet<>();
147
148             NodeList bindingsNodes = doc.getElementsByTagName("xml-bindings");
149                 Element bindingElement;
150                 NodeList javaTypesNodes;
151                 Element javaTypesElement;
152
153                 if ( bindingsNodes == null || bindingsNodes.getLength() == 0 ) {
154                         throw new SAXException("OXM file error: missing <binding-nodes> in " + oxmFile);
155                 }
156
157                 bindingElement = (Element) bindingsNodes.item(0);
158                 javaTypesNodes = bindingElement.getElementsByTagName("java-types");
159                 if ( javaTypesNodes.getLength() < 1 ) {
160                         throw new SAXException("OXM file error: missing <binding-nodes><java-types> in " + oxmFile);
161                 }
162                 javaTypesElement = (Element) javaTypesNodes.item(0);
163
164                 javaTypeNodes = javaTypesElement.getElementsByTagName("java-type");
165                 if ( javaTypeNodes.getLength() < 1 ) {
166                         throw new SAXException("OXM file error: missing <binding-nodes><java-types><java-type> in " + oxmFile );
167                 }
168         }
169
170         private void createDocument() throws ParserConfigurationException, SAXException, IOException {
171                 DocumentBuilder dBuilder = null;
172                 try {
173                     DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
174                     dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
175                     dBuilder = dbFactory.newDocumentBuilder();
176                 } catch (ParserConfigurationException e) {
177                         throw e;
178                 }
179                 try {
180                     if ( xml == null ) {
181                         doc = dBuilder.parse(oxmFile);
182                     } else {
183                             InputSource isInput = new InputSource(new StringReader(xml));
184                             doc = dBuilder.parse(isInput);
185                     }
186                 } catch (SAXException e) {
187                         throw e;
188                 } catch (IOException e) {
189                         throw e;
190                 }
191                 return;
192         }
193         public abstract String getDocumentHeader();
194         public abstract String process() throws ParserConfigurationException, SAXException, IOException, FileNotFoundException, EdgeRuleNotFoundException ;
195
196         public String getXMLRootElementName(Element javaTypeElement) {
197                 String xmlRootElementName=null;
198                 NamedNodeMap attributes;
199
200                 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
201                 Element valElement = (Element) valNodes.item(0);
202                 attributes = valElement.getAttributes();
203                 for ( int i = 0; i < attributes.getLength(); ++i ) {
204             Attr attr = (Attr) attributes.item(i);
205             String attrName = attr.getNodeName();
206
207             String attrValue = attr.getNodeValue();
208             if ( attrName.equals("name"))
209                 xmlRootElementName = attrValue;
210                 }
211                 return xmlRootElementName;
212         }
213
214         public String getXmlRootElementName( String javaTypeName )
215         {
216                 String attrName, attrValue;
217                 Attr attr;
218                 Element javaTypeElement;
219                 for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
220                         javaTypeElement = (Element) javaTypeNodes.item(i);
221                         NamedNodeMap attributes = javaTypeElement.getAttributes();
222                         for ( int j = 0; j < attributes.getLength(); ++j ) {
223                     attr = (Attr) attributes.item(j);
224                     attrName = attr.getNodeName();
225                     attrValue = attr.getNodeValue();
226                     if ( attrName.equals("name") && attrValue.equals(javaTypeName)) {
227                                 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
228                                 Element valElement = (Element) valNodes.item(0);
229                                 attributes = valElement.getAttributes();
230                                 for ( int k = 0; k < attributes.getLength(); ++k ) {
231                             attr = (Attr) attributes.item(k);
232                             attrName = attr.getNodeName();
233
234                             attrValue = attr.getNodeValue();
235                             if ( attrName.equals("name"))
236                                 return (attrValue);
237                                 }
238                     }
239                         }
240                 }
241                 return null;
242         }
243
244         public Map getCombinedJavaTypes() {
245                 return combinedJavaTypes;
246         }
247
248         public void setCombinedJavaTypes(Map combinedJavaTypes) {
249                 this.combinedJavaTypes = combinedJavaTypes;
250         }
251
252         public Element getJavaTypeElementSwagger( String javaTypeName )
253         {
254
255                 String attrName, attrValue;
256                 Attr attr;
257                 Element javaTypeElement;
258
259                 List<Element> combineElementList = new ArrayList<Element>();
260                 for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
261                         javaTypeElement = (Element) javaTypeNodes.item(i);
262                         NamedNodeMap attributes = javaTypeElement.getAttributes();
263                         for ( int j = 0; j < attributes.getLength(); ++j ) {
264                     attr = (Attr) attributes.item(j);
265                     attrName = attr.getNodeName();
266                     attrValue = attr.getNodeValue();
267                     if ( attrName.equals("name") && attrValue.equals(javaTypeName)) {
268                         combineElementList.add(javaTypeElement);
269                     }
270                         }
271                 }
272                 if ( combineElementList.size() == 0 ) {
273                         return (Element) null;
274                 } else if ( combineElementList.size() > 1 ) {
275                         return combineElements( javaTypeName, combineElementList);
276                 }
277                 return combineElementList.get(0);
278         }
279
280         public boolean versionSupportsSwaggerDiff( String version) {
281                 int ver = new Integer(version.substring(1)).intValue();
282                 if ( ver >= HTMLfromOXM.swaggerDiffStartVersion ) {
283                         return true;
284                 }
285                 return false;
286         }
287
288         public boolean versionSupportsBasePathProperty( String version) {
289                 int ver = new Integer(version.substring(1)).intValue();
290                 if ( ver <= HTMLfromOXM.swaggerMinBasepath ) {
291                         return true;
292                 }
293                 return false;
294         }
295
296         protected void updateParentXmlElements(Element parentElement, NodeList moreXmlElementNodes) {
297                 Element xmlElement;
298                 NodeList childNodes;
299                 Node childNode;
300
301                 Node refChild = null;
302                 // find childNode with attributes and no children, insert children before that node
303                 childNodes = parentElement.getChildNodes();
304                 if ( childNodes == null || childNodes.getLength() == 0 ) {
305                         // should not happen since the base parent was chosen if it had children
306                         return;
307                 }
308
309                 for ( int i = 0; i < childNodes.getLength(); ++i ) {
310                         refChild = childNodes.item(i);
311                         if ( refChild.hasAttributes() && !refChild.hasChildNodes()) {
312                                 break;
313                         }
314
315                 }
316
317                 for ( int i = 0; i < moreXmlElementNodes.getLength(); ++i ) {
318                         xmlElement = (Element)moreXmlElementNodes.item(i);
319                         childNode = xmlElement.cloneNode(true);
320                         parentElement.insertBefore(childNode, refChild);
321                 }
322         }
323
324         protected Node getXmlPropertiesNode(Element javaTypeElement ) {
325                 NodeList nl = javaTypeElement.getChildNodes();
326                 Node child;
327                 for ( int i = 0; i < nl.getLength(); ++i ) {
328                         child = nl.item(i);
329                         if ( "xml-properties".equals(child.getNodeName())) {
330                                 return child;
331                         }
332                 }
333                 return null;
334         }
335
336         protected Node merge( NodeList nl, Node mergeNode ) {
337                 NamedNodeMap nnm = mergeNode.getAttributes();
338                 Node childNode;
339                 NamedNodeMap childNnm;
340
341                 String mergeName = nnm.getNamedItem("name").getNodeValue();
342                 String mergeValue = nnm.getNamedItem("value").getNodeValue();
343                 String childName;
344                 String childValue;
345                 for ( int j = 0; j < nl.getLength(); ++j ) {
346                         childNode = nl.item(j);
347                         if ( "xml-property".equals(childNode.getNodeName())) {
348                                 childNnm = childNode.getAttributes();
349                                 childName = childNnm.getNamedItem("name").getNodeValue();
350                                 childValue = childNnm.getNamedItem("value").getNodeValue();
351                                 if ( childName.equals(mergeName)) {
352                                         // attribute exists
353                                         // keep, replace or update
354                                         if ( childValue.contains(mergeValue) ) {
355                                                 return null;
356                                         }
357                                         if ( mergeValue.contains(childValue) ) {
358                                                 childNnm.getNamedItem("value").setTextContent(mergeValue);
359                                                 return null;
360                                         }
361                                         childNnm.getNamedItem("value").setTextContent(mergeValue + "," + childValue);
362                                         return null;
363                                 }
364                         }
365                 }
366                 childNode = mergeNode.cloneNode(true);
367                 return childNode;
368         }
369
370         protected void mergeXmlProperties(Node useChildProperties, NodeList propertiesToMerge ) {
371                 NodeList nl = useChildProperties.getChildNodes();
372                 Node childNode;
373                 Node newNode;
374                 for ( int i = 0; i < propertiesToMerge.getLength(); ++i ) {
375                         childNode = propertiesToMerge.item(i);
376                         if ( "xml-property".equals(childNode.getNodeName()) ) {
377                                 newNode = merge(nl, childNode);
378                                 if ( newNode != null ) {
379                                         useChildProperties.appendChild(newNode);
380                                 }
381                         }
382
383                 }
384         }
385
386         protected void combineXmlProperties(int useElement, List<Element> combineElementList) {
387                 // add or update xml-properties to the referenced element from the combined list
388                 Element javaTypeElement = combineElementList.get(useElement);
389                 NodeList nl = javaTypeElement.getChildNodes();
390                 Node useChildProperties = getXmlPropertiesNode( javaTypeElement);
391                 int cloneChild = -1;
392                 Node childProperties;
393                 if ( useChildProperties == null ) {
394                         // find xml-properties to clone
395                         for ( int i = 0; i < combineElementList.size(); ++i ) {
396                                 if ( i == useElement ) {
397                                         continue;
398                                 }
399                                 childProperties = getXmlPropertiesNode(combineElementList.get(i));
400                                 if ( childProperties != null ) {
401                                         useChildProperties = childProperties.cloneNode(true);
402                                         javaTypeElement.appendChild(useChildProperties);
403                                         cloneChild = i;
404                                 }
405                         }
406                 }
407                 NodeList cnl;
408                 // find other xml-properties
409                 for ( int i = 0; i < combineElementList.size(); ++i ) {
410                         if ( i == useElement|| ( cloneChild >= 0 && i <= cloneChild )) {
411                                 continue;
412                         }
413                         childProperties = getXmlPropertiesNode(combineElementList.get(i));
414                         if ( childProperties == null ) {
415                                 continue;
416                         }
417                         cnl = childProperties.getChildNodes();
418                         mergeXmlProperties( useChildProperties, cnl);
419                 }
420
421         }
422
423         protected Element combineElements( String javaTypeName, List<Element> combineElementList ) {
424                 Element javaTypeElement;
425                 NodeList parentNodes;
426                 Element parentElement = null;
427                 NodeList xmlElementNodes;
428
429                 int useElement = -1;
430                 if ( combinedJavaTypes.containsKey( javaTypeName) ) {
431                         return combineElementList.get((int)combinedJavaTypes.get(javaTypeName));
432                 }
433                 for ( int i = 0; i < combineElementList.size(); ++i ) {
434                         javaTypeElement = combineElementList.get(i);
435                         parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
436                         if ( parentNodes.getLength() == 0 ) {
437                                 continue;
438                         }
439                         parentElement = (Element)parentNodes.item(0);
440                         xmlElementNodes = parentElement.getElementsByTagName("xml-element");
441                         if ( xmlElementNodes.getLength() <= 0 ) {
442                                 continue;
443                         }
444                         useElement = i;
445                         break;
446                 }
447                 boolean doCombineElements = true;
448                 if ( useElement < 0 ) {
449                         useElement = 0;
450                         doCombineElements = false;
451                 } else if ( useElement == combineElementList.size() - 1) {
452                         doCombineElements = false;
453                 }
454                 if ( doCombineElements ) {
455                         // get xml-element from other javaTypeElements
456                         Element otherParentElement = null;
457                         for ( int i = 0; i < combineElementList.size(); ++i ) {
458                                 if ( i == useElement ) {
459                                         continue;
460                                 }
461                                 javaTypeElement = combineElementList.get(i);
462                                 parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
463                                 if ( parentNodes.getLength() == 0 ) {
464                                         continue;
465                                 }
466                                 otherParentElement = (Element)parentNodes.item(0);
467                                 xmlElementNodes = otherParentElement.getElementsByTagName("xml-element");
468                                 if ( xmlElementNodes.getLength() <= 0 ) {
469                                         continue;
470                                 }
471                                 // xml-element that are not present
472                                 updateParentXmlElements( parentElement, xmlElementNodes);
473
474                         }
475                 }
476                 // need to combine xml-properties
477                 combineXmlProperties(useElement, combineElementList );
478                 combinedJavaTypes.put( javaTypeName, useElement);
479                 return combineElementList.get(useElement);
480         }
481 }