2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.aai.schemagen.genxsd;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.StringReader;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.List;
34 import javax.xml.XMLConstants;
35 import javax.xml.parsers.DocumentBuilder;
36 import javax.xml.parsers.DocumentBuilderFactory;
37 import javax.xml.parsers.ParserConfigurationException;
38 import org.onap.aai.edges.EdgeIngestor;
39 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
40 import org.onap.aai.nodes.NodeIngestor;
41 import org.onap.aai.setup.SchemaVersion;
42 import org.onap.aai.setup.SchemaVersions;
43 import org.w3c.dom.Attr;
44 import org.w3c.dom.Document;
45 import org.w3c.dom.Element;
46 import org.w3c.dom.NamedNodeMap;
47 import org.w3c.dom.Node;
48 import org.w3c.dom.NodeList;
49 import org.xml.sax.InputSource;
50 import org.xml.sax.SAXException;
52 import javax.xml.XMLConstants;
53 import javax.xml.parsers.DocumentBuilder;
54 import javax.xml.parsers.DocumentBuilderFactory;
55 import javax.xml.parsers.ParserConfigurationException;
57 import java.io.FileNotFoundException;
58 import java.io.IOException;
59 import java.io.StringReader;
62 public abstract class OxmFileProcessor {
64 public static final String LINE_SEPARATOR = System.getProperty("line.separator");
65 public static final String DOUBLE_LINE_SEPARATOR =
66 System.getProperty("line.separator") + System.getProperty("line.separator");
67 protected static int annotationsStartVersion = 9; // minimum version to support annotations in
69 protected static int annotationsMinVersion = 6; // lower versions support annotations in xsd
70 protected static int swaggerSupportStartsVersion = 1; // minimum version to support swagger
72 protected static int swaggerDiffStartVersion = 1; // minimum version to support difference
73 protected static int swaggerMinBasepath = 6; // minimum version to support difference
74 static List<String> nodeFilter = createNodeFilter();
75 protected Set<String> namespaceFilter;
76 protected File oxmFile;
78 protected SchemaVersion v;
79 protected Document doc = null;
80 protected String apiVersion = null;
81 protected SchemaVersions schemaVersions;
82 protected Map combinedJavaTypes;
83 protected String apiVersionFmt = null;
84 protected List<String> topLevelPaths = new ArrayList<String>();
85 protected HashMap<String, String> generatedJavaType = new HashMap<String, String>();
86 protected HashMap<String, String> appliedPaths = new HashMap<String, String>();
87 protected NodeList javaTypeNodes = null;
88 protected Map<String, String> javaTypeDefinitions = createJavaTypeDefinitions();
92 public OxmFileProcessor(SchemaVersions schemaVersions, NodeIngestor ni, EdgeIngestor ei) {
93 this.schemaVersions = schemaVersions;
98 private static List<String> createNodeFilter() {
99 return Arrays.asList("search", "actions", "aai-internal", "nodes");
102 private Map<String, String> createJavaTypeDefinitions() {
103 StringBuilder aaiInternal = new StringBuilder();
104 StringBuilder nodes = new StringBuilder();
105 Map<String, String> javaTypeDefinitions = new HashMap<String, String>();
106 // update to use platform portable line separator
107 aaiInternal.append(" aai-internal:").append(LINE_SEPARATOR);
108 aaiInternal.append(" properties:").append(LINE_SEPARATOR);
109 aaiInternal.append(" property-name:").append(LINE_SEPARATOR);
110 aaiInternal.append(" type: string").append(LINE_SEPARATOR);
111 aaiInternal.append(" property-value:").append(LINE_SEPARATOR);
112 aaiInternal.append(" type: string").append(LINE_SEPARATOR);
113 // javaTypeDefinitions.put("aai-internal", aaiInternal.toString());
114 nodes.append(" nodes:").append(LINE_SEPARATOR);
115 nodes.append(" properties:").append(LINE_SEPARATOR);
116 nodes.append(" inventory-item-data:").append(LINE_SEPARATOR);
117 nodes.append(" type: array").append(LINE_SEPARATOR);
118 nodes.append(" items:").append(LINE_SEPARATOR);
119 nodes.append(" $ref: \"#/definitions/inventory-item-data\"")
120 .append(LINE_SEPARATOR);
121 javaTypeDefinitions.put("nodes", nodes.toString());
122 return javaTypeDefinitions;
125 public void setOxmVersion(File oxmFile, SchemaVersion v) {
126 this.oxmFile = oxmFile;
130 public void setXmlVersion(String xml, SchemaVersion v) {
135 public void setVersion(SchemaVersion v) {
140 public void setNodeIngestor(NodeIngestor ni) {
144 public void setEdgeIngestor(EdgeIngestor ei) {
148 public SchemaVersions getSchemaVersions() {
149 return schemaVersions;
152 public void setSchemaVersions(SchemaVersions schemaVersions) {
153 this.schemaVersions = schemaVersions;
156 protected void getTopLevelPaths(XSDElement elem) {
157 NodeList parentNodes;
158 Element parentElement;
159 NodeList xmlElementNodes;
161 parentNodes = elem.getElementsByTagName("java-attributes");
162 if (parentNodes.getLength() == 0) {
165 parentElement = (Element) parentNodes.item(0);
166 xmlElementNodes = parentElement.getElementsByTagName("xml-element");
167 if (xmlElementNodes.getLength() <= 0) {
171 XSDElement xmlElementElement;
173 for (int i = 0; i < xmlElementNodes.getLength(); ++i) {
174 xmlElementElement = new XSDElement((Element) xmlElementNodes.item(i));
175 if (!xmlElementElement.getParentNode().isSameNode(parentElement)) {
178 String topLevel = xmlElementElement.getAttribute("type");
179 topLevel = topLevel.substring(topLevel.lastIndexOf('.') + 1);
180 if (!topLevelPaths.contains(topLevel)) {
181 if ("Nodes".equals(topLevel) || "AaiInternal".equals(topLevel)) {
184 topLevelPaths.add(topLevel);
189 protected boolean checkTopLevel(String topLevel, boolean ignoreActionsSearch) {
190 // when ignoreActionsSearch is set to true, with a topLevel that matches one of the values
191 // to ignore, the logic will handle those values, as if they are not at the top level.
192 // this was done when refactoring checks that may or may not include these top levels.
193 // Using this API allows new top levels to be added to the schema file and
194 // included in the generated yaml without changing this generation logic.
195 if (ignoreActionsSearch) {
196 if ("Actions".equals(topLevel) || "Search".equals(topLevel)) {
200 return topLevelPaths.contains(topLevel);
203 protected void init()
204 throws ParserConfigurationException, SAXException, IOException, EdgeRuleNotFoundException {
205 if (this.xml != null || this.oxmFile != null) {
208 if (this.doc == null) {
209 this.doc = ni.getSchema(v);
211 namespaceFilter = new HashSet<>();
213 NodeList bindingsNodes = doc.getElementsByTagName("xml-bindings");
214 Element bindingElement;
215 NodeList javaTypesNodes;
216 Element javaTypesElement;
218 if (bindingsNodes == null || bindingsNodes.getLength() == 0) {
219 throw new SAXException("OXM file error: missing <binding-nodes> in " + oxmFile);
222 bindingElement = (Element) bindingsNodes.item(0);
223 javaTypesNodes = bindingElement.getElementsByTagName("java-types");
224 if (javaTypesNodes.getLength() < 1) {
225 throw new SAXException(
226 "OXM file error: missing <binding-nodes><java-types> in " + oxmFile);
228 javaTypesElement = (Element) javaTypesNodes.item(0);
230 javaTypeNodes = javaTypesElement.getElementsByTagName("java-type");
231 if (javaTypeNodes.getLength() < 1) {
232 throw new SAXException(
233 "OXM file error: missing <binding-nodes><java-types><java-type> in " + oxmFile);
237 private void createDocument() throws ParserConfigurationException, SAXException, IOException {
238 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
239 dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
240 dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
241 dbFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
242 dbFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
243 dbFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
244 dbFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
245 DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
248 doc = dBuilder.parse(oxmFile);
250 InputSource isInput = new InputSource(new StringReader(xml));
251 doc = dBuilder.parse(isInput);
255 public abstract String getDocumentHeader();
257 public abstract String process() throws ParserConfigurationException, SAXException, IOException,
258 FileNotFoundException, EdgeRuleNotFoundException;
260 public String getXMLRootElementName(Element javaTypeElement) {
261 String xmlRootElementName = null;
262 NamedNodeMap attributes;
264 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
265 Element valElement = (Element) valNodes.item(0);
266 attributes = valElement.getAttributes();
267 for (int i = 0; i < attributes.getLength(); ++i) {
268 Attr attr = (Attr) attributes.item(i);
269 String attrName = attr.getNodeName();
271 String attrValue = attr.getNodeValue();
272 if ("name".equals(attrName)) {
273 xmlRootElementName = attrValue;
276 return xmlRootElementName;
279 public String getXmlRootElementName(String javaTypeName) {
280 String attrName, attrValue;
282 Element javaTypeElement;
283 for (int i = 0; i < javaTypeNodes.getLength(); ++i) {
284 javaTypeElement = (Element) javaTypeNodes.item(i);
285 NamedNodeMap attributes = javaTypeElement.getAttributes();
286 for (int j = 0; j < attributes.getLength(); ++j) {
287 attr = (Attr) attributes.item(j);
288 attrName = attr.getNodeName();
289 attrValue = attr.getNodeValue();
290 if ("name".equals(attrName) && attrValue.equals(javaTypeName)) {
291 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
292 Element valElement = (Element) valNodes.item(0);
293 attributes = valElement.getAttributes();
294 for (int k = 0; k < attributes.getLength(); ++k) {
295 attr = (Attr) attributes.item(k);
296 attrName = attr.getNodeName();
298 attrValue = attr.getNodeValue();
299 if ("name".equals(attrName)) {
309 public Map getCombinedJavaTypes() {
310 return combinedJavaTypes;
313 public void setCombinedJavaTypes(Map combinedJavaTypes) {
314 this.combinedJavaTypes = combinedJavaTypes;
317 public Element getJavaTypeElementSwagger(String javaTypeName) {
319 String attrName, attrValue;
321 Element javaTypeElement;
323 List<Element> combineElementList = new ArrayList<Element>();
324 for (int i = 0; i < javaTypeNodes.getLength(); ++i) {
325 javaTypeElement = (Element) javaTypeNodes.item(i);
326 NamedNodeMap attributes = javaTypeElement.getAttributes();
327 for (int j = 0; j < attributes.getLength(); ++j) {
328 attr = (Attr) attributes.item(j);
329 attrName = attr.getNodeName();
330 attrValue = attr.getNodeValue();
331 if ("name".equals(attrName) && attrValue.equals(javaTypeName)) {
332 combineElementList.add(javaTypeElement);
336 if (combineElementList.size() == 0) {
337 return (Element) null;
338 } else if (combineElementList.size() > 1) {
339 return combineElements(javaTypeName, combineElementList);
341 return combineElementList.get(0);
344 public boolean versionSupportsSwaggerDiff(String version) {
345 int ver = Integer.parseInt(version.substring(1));
346 return ver >= HTMLfromOXM.swaggerDiffStartVersion;
349 public boolean versionSupportsBasePathProperty(String version) {
350 int ver = Integer.parseInt(version.substring(1));
351 return ver <= HTMLfromOXM.swaggerMinBasepath;
354 protected void updateParentXmlElements(Element parentElement, NodeList moreXmlElementNodes) {
359 Node refChild = null;
360 // find childNode with attributes and no children, insert children before that node
361 childNodes = parentElement.getChildNodes();
362 if (childNodes == null || childNodes.getLength() == 0) {
363 // should not happen since the base parent was chosen if it had children
367 for (int i = 0; i < childNodes.getLength(); ++i) {
368 refChild = childNodes.item(i);
369 if (refChild.hasAttributes() && !refChild.hasChildNodes()) {
375 for (int i = 0; i < moreXmlElementNodes.getLength(); ++i) {
376 xmlElement = (Element) moreXmlElementNodes.item(i);
377 childNode = xmlElement.cloneNode(true);
378 parentElement.insertBefore(childNode, refChild);
382 protected Node getXmlPropertiesNode(Element javaTypeElement) {
383 NodeList nl = javaTypeElement.getChildNodes();
385 for (int i = 0; i < nl.getLength(); ++i) {
387 if ("xml-properties".equals(child.getNodeName())) {
394 protected Node merge(NodeList nl, Node mergeNode) {
395 NamedNodeMap nnm = mergeNode.getAttributes();
397 NamedNodeMap childNnm;
399 String mergeName = nnm.getNamedItem("name").getNodeValue();
400 String mergeValue = nnm.getNamedItem("value").getNodeValue();
403 for (int j = 0; j < nl.getLength(); ++j) {
404 childNode = nl.item(j);
405 if ("xml-property".equals(childNode.getNodeName())) {
406 childNnm = childNode.getAttributes();
407 childName = childNnm.getNamedItem("name").getNodeValue();
408 childValue = childNnm.getNamedItem("value").getNodeValue();
409 if (childName.equals(mergeName)) {
411 // keep, replace or update
412 if (childValue.contains(mergeValue)) {
415 if (mergeValue.contains(childValue)) {
416 childNnm.getNamedItem("value").setTextContent(mergeValue);
419 childNnm.getNamedItem("value").setTextContent(mergeValue + "," + childValue);
424 childNode = mergeNode.cloneNode(true);
428 protected void mergeXmlProperties(Node useChildProperties, NodeList propertiesToMerge) {
429 NodeList nl = useChildProperties.getChildNodes();
432 for (int i = 0; i < propertiesToMerge.getLength(); ++i) {
433 childNode = propertiesToMerge.item(i);
434 if ("xml-property".equals(childNode.getNodeName())) {
435 newNode = merge(nl, childNode);
436 if (newNode != null) {
437 useChildProperties.appendChild(newNode);
444 protected void combineXmlProperties(int useElement, List<Element> combineElementList) {
445 // add or update xml-properties to the referenced element from the combined list
446 Element javaTypeElement = combineElementList.get(useElement);
447 NodeList nl = javaTypeElement.getChildNodes();
448 Node useChildProperties = getXmlPropertiesNode(javaTypeElement);
450 Node childProperties;
451 if (useChildProperties == null) {
452 // find xml-properties to clone
453 for (int i = 0; i < combineElementList.size(); ++i) {
454 if (i == useElement) {
457 childProperties = getXmlPropertiesNode(combineElementList.get(i));
458 if (childProperties != null) {
459 useChildProperties = childProperties.cloneNode(true);
460 javaTypeElement.appendChild(useChildProperties);
466 // find other xml-properties
467 for (int i = 0; i < combineElementList.size(); ++i) {
468 if (i == useElement || (cloneChild >= 0 && i <= cloneChild)) {
471 childProperties = getXmlPropertiesNode(combineElementList.get(i));
472 if (childProperties == null) {
475 cnl = childProperties.getChildNodes();
476 mergeXmlProperties(useChildProperties, cnl);
481 protected Element combineElements(String javaTypeName, List<Element> combineElementList) {
482 Element javaTypeElement;
483 NodeList parentNodes;
484 Element parentElement = null;
485 NodeList xmlElementNodes;
488 if (combinedJavaTypes.containsKey(javaTypeName)) {
489 return combineElementList.get((int) combinedJavaTypes.get(javaTypeName));
491 for (int i = 0; i < combineElementList.size(); ++i) {
492 javaTypeElement = combineElementList.get(i);
493 parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
494 if (parentNodes.getLength() == 0) {
497 parentElement = (Element) parentNodes.item(0);
498 xmlElementNodes = parentElement.getElementsByTagName("xml-element");
499 if (xmlElementNodes.getLength() <= 0) {
505 boolean doCombineElements = true;
506 if (useElement < 0) {
508 doCombineElements = false;
509 } else if (useElement == combineElementList.size() - 1) {
510 doCombineElements = false;
512 if (doCombineElements) {
513 // get xml-element from other javaTypeElements
514 Element otherParentElement = null;
515 for (int i = 0; i < combineElementList.size(); ++i) {
516 if (i == useElement) {
519 javaTypeElement = combineElementList.get(i);
520 parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
521 if (parentNodes.getLength() == 0) {
524 otherParentElement = (Element) parentNodes.item(0);
525 xmlElementNodes = otherParentElement.getElementsByTagName("xml-element");
526 if (xmlElementNodes.getLength() <= 0) {
529 // xml-element that are not present
530 updateParentXmlElements(parentElement, xmlElementNodes);
534 // need to combine xml-properties
535 combineXmlProperties(useElement, combineElementList);
536 combinedJavaTypes.put(javaTypeName, useElement);
537 return combineElementList.get(useElement);