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=========================================================
20 package org.onap.aai.schemagen.genxsd;
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;
28 import org.xml.sax.InputSource;
29 import org.xml.sax.SAXException;
31 import javax.xml.XMLConstants;
32 import javax.xml.parsers.DocumentBuilder;
33 import javax.xml.parsers.DocumentBuilderFactory;
34 import javax.xml.parsers.ParserConfigurationException;
36 import java.io.FileNotFoundException;
37 import java.io.IOException;
38 import java.io.StringReader;
41 public abstract class OxmFileProcessor {
43 public static final String LINE_SEPARATOR = System.getProperty("line.separator");
44 public static final String DOUBLE_LINE_SEPARATOR =
45 System.getProperty("line.separator") + System.getProperty("line.separator");
46 protected static int annotationsStartVersion = 9; // minimum version to support annotations in
48 protected static int annotationsMinVersion = 6; // lower versions support annotations in xsd
49 protected static int swaggerSupportStartsVersion = 1; // minimum version to support swagger
51 protected static int swaggerDiffStartVersion = 1; // minimum version to support difference
52 protected static int swaggerMinBasepath = 6; // minimum version to support difference
53 static List<String> nodeFilter = createNodeFilter();
54 protected Set<String> namespaceFilter;
55 protected File oxmFile;
57 protected SchemaVersion v;
58 protected Document doc = null;
59 protected String apiVersion = null;
60 protected SchemaVersions schemaVersions;
61 protected Map combinedJavaTypes;
62 protected String apiVersionFmt = null;
63 protected List<String> topLevelPaths = new ArrayList<String>();
64 protected HashMap<String, String> generatedJavaType = new HashMap<String, String>();
65 protected HashMap<String, String> appliedPaths = new HashMap<String, String>();
66 protected NodeList javaTypeNodes = null;
67 protected Map<String, String> javaTypeDefinitions = createJavaTypeDefinitions();
71 public OxmFileProcessor(SchemaVersions schemaVersions, NodeIngestor ni, EdgeIngestor ei) {
72 this.schemaVersions = schemaVersions;
77 private static List<String> createNodeFilter() {
78 List<String> list = Arrays.asList("search", "actions", "aai-internal", "nodes");
82 private Map<String, String> createJavaTypeDefinitions() {
83 StringBuffer aaiInternal = new StringBuffer();
84 StringBuffer nodes = new StringBuffer();
85 Map<String, String> javaTypeDefinitions = new HashMap<String, String>();
86 // update to use platform portable line separator
87 aaiInternal.append(" aai-internal:" + LINE_SEPARATOR);
88 aaiInternal.append(" properties:" + LINE_SEPARATOR);
89 aaiInternal.append(" property-name:" + LINE_SEPARATOR);
90 aaiInternal.append(" type: string" + LINE_SEPARATOR);
91 aaiInternal.append(" property-value:" + LINE_SEPARATOR);
92 aaiInternal.append(" type: string" + LINE_SEPARATOR);
93 // javaTypeDefinitions.put("aai-internal", aaiInternal.toString());
94 nodes.append(" nodes:" + LINE_SEPARATOR);
95 nodes.append(" properties:" + LINE_SEPARATOR);
96 nodes.append(" inventory-item-data:" + LINE_SEPARATOR);
97 nodes.append(" type: array" + LINE_SEPARATOR);
98 nodes.append(" items:" + LINE_SEPARATOR);
99 nodes.append(" $ref: \"#/definitions/inventory-item-data\"" + LINE_SEPARATOR);
100 javaTypeDefinitions.put("nodes", nodes.toString());
101 return javaTypeDefinitions;
104 public void setOxmVersion(File oxmFile, SchemaVersion v) {
105 this.oxmFile = oxmFile;
109 public void setXmlVersion(String xml, SchemaVersion v) {
114 public void setVersion(SchemaVersion v) {
119 public void setNodeIngestor(NodeIngestor ni) {
123 public void setEdgeIngestor(EdgeIngestor ei) {
127 public SchemaVersions getSchemaVersions() {
128 return schemaVersions;
131 public void setSchemaVersions(SchemaVersions schemaVersions) {
132 this.schemaVersions = schemaVersions;
135 protected void getTopLevelPaths(XSDElement elem) {
136 NodeList parentNodes;
137 Element parentElement;
138 NodeList xmlElementNodes;
140 parentNodes = elem.getElementsByTagName("java-attributes");
141 if (parentNodes.getLength() == 0) {
144 parentElement = (Element) parentNodes.item(0);
145 xmlElementNodes = parentElement.getElementsByTagName("xml-element");
146 if (xmlElementNodes.getLength() <= 0) {
150 XSDElement xmlElementElement;
152 for (int i = 0; i < xmlElementNodes.getLength(); ++i) {
153 xmlElementElement = new XSDElement((Element) xmlElementNodes.item(i));
154 if (!xmlElementElement.getParentNode().isSameNode(parentElement)) {
157 String topLevel = xmlElementElement.getAttribute("type");
158 topLevel = topLevel.substring(topLevel.lastIndexOf('.') + 1);
159 if (!topLevelPaths.contains(topLevel)) {
160 if ("Nodes".equals(topLevel) || "AaiInternal".equals(topLevel)) {
163 topLevelPaths.add(topLevel);
168 protected boolean checkTopLevel(String topLevel, boolean ignoreActionsSearch) {
169 // when ignoreActionsSearch is set to true, with a topLevel that matches one of the values
170 // to ignore, the logic will handle those values, as if they are not at the top level.
171 // this was done when refactoring checks that may or may not include these top levels.
172 // Using this API allows new top levels to be added to the schema file and
173 // included in the generated yaml without changing this generation logic.
174 if (ignoreActionsSearch) {
175 if ("Actions".equals(topLevel) || "Search".equals(topLevel)) {
179 if (topLevelPaths.contains(topLevel)) {
185 protected void init()
186 throws ParserConfigurationException, SAXException, IOException, EdgeRuleNotFoundException {
187 if (this.xml != null || this.oxmFile != null) {
190 if (this.doc == null) {
191 this.doc = ni.getSchema(v);
193 namespaceFilter = new HashSet<>();
195 NodeList bindingsNodes = doc.getElementsByTagName("xml-bindings");
196 Element bindingElement;
197 NodeList javaTypesNodes;
198 Element javaTypesElement;
200 if (bindingsNodes == null || bindingsNodes.getLength() == 0) {
201 throw new SAXException("OXM file error: missing <binding-nodes> in " + oxmFile);
204 bindingElement = (Element) bindingsNodes.item(0);
205 javaTypesNodes = bindingElement.getElementsByTagName("java-types");
206 if (javaTypesNodes.getLength() < 1) {
207 throw new SAXException(
208 "OXM file error: missing <binding-nodes><java-types> in " + oxmFile);
210 javaTypesElement = (Element) javaTypesNodes.item(0);
212 javaTypeNodes = javaTypesElement.getElementsByTagName("java-type");
213 if (javaTypeNodes.getLength() < 1) {
214 throw new SAXException(
215 "OXM file error: missing <binding-nodes><java-types><java-type> in " + oxmFile);
219 private void createDocument() throws ParserConfigurationException, SAXException, IOException {
220 DocumentBuilder dBuilder = null;
222 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
223 dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
224 dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
225 dbFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
226 dbFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
227 dbFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
228 dbFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
229 dBuilder = dbFactory.newDocumentBuilder();
230 } catch (ParserConfigurationException e) {
235 doc = dBuilder.parse(oxmFile);
237 InputSource isInput = new InputSource(new StringReader(xml));
238 doc = dBuilder.parse(isInput);
240 } catch (SAXException e) {
242 } catch (IOException e) {
248 public abstract String getDocumentHeader();
250 public abstract String process() throws ParserConfigurationException, SAXException, IOException,
251 FileNotFoundException, EdgeRuleNotFoundException;
253 public String getXMLRootElementName(Element javaTypeElement) {
254 String xmlRootElementName = null;
255 NamedNodeMap attributes;
257 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
258 Element valElement = (Element) valNodes.item(0);
259 attributes = valElement.getAttributes();
260 for (int i = 0; i < attributes.getLength(); ++i) {
261 Attr attr = (Attr) attributes.item(i);
262 String attrName = attr.getNodeName();
264 String attrValue = attr.getNodeValue();
265 if (attrName.equals("name")) {
266 xmlRootElementName = attrValue;
269 return xmlRootElementName;
272 public String getXmlRootElementName(String javaTypeName) {
273 String attrName, attrValue;
275 Element javaTypeElement;
276 for (int i = 0; i < javaTypeNodes.getLength(); ++i) {
277 javaTypeElement = (Element) javaTypeNodes.item(i);
278 NamedNodeMap attributes = javaTypeElement.getAttributes();
279 for (int j = 0; j < attributes.getLength(); ++j) {
280 attr = (Attr) attributes.item(j);
281 attrName = attr.getNodeName();
282 attrValue = attr.getNodeValue();
283 if (attrName.equals("name") && attrValue.equals(javaTypeName)) {
284 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
285 Element valElement = (Element) valNodes.item(0);
286 attributes = valElement.getAttributes();
287 for (int k = 0; k < attributes.getLength(); ++k) {
288 attr = (Attr) attributes.item(k);
289 attrName = attr.getNodeName();
291 attrValue = attr.getNodeValue();
292 if (attrName.equals("name")) {
302 public Map getCombinedJavaTypes() {
303 return combinedJavaTypes;
306 public void setCombinedJavaTypes(Map combinedJavaTypes) {
307 this.combinedJavaTypes = combinedJavaTypes;
310 public Element getJavaTypeElementSwagger(String javaTypeName) {
312 String attrName, attrValue;
314 Element javaTypeElement;
316 List<Element> combineElementList = new ArrayList<Element>();
317 for (int i = 0; i < javaTypeNodes.getLength(); ++i) {
318 javaTypeElement = (Element) javaTypeNodes.item(i);
319 NamedNodeMap attributes = javaTypeElement.getAttributes();
320 for (int j = 0; j < attributes.getLength(); ++j) {
321 attr = (Attr) attributes.item(j);
322 attrName = attr.getNodeName();
323 attrValue = attr.getNodeValue();
324 if (attrName.equals("name") && attrValue.equals(javaTypeName)) {
325 combineElementList.add(javaTypeElement);
329 if (combineElementList.size() == 0) {
330 return (Element) null;
331 } else if (combineElementList.size() > 1) {
332 return combineElements(javaTypeName, combineElementList);
334 return combineElementList.get(0);
337 public boolean versionSupportsSwaggerDiff(String version) {
338 int ver = new Integer(version.substring(1)).intValue();
339 if (ver >= HTMLfromOXM.swaggerDiffStartVersion) {
345 public boolean versionSupportsBasePathProperty(String version) {
346 int ver = new Integer(version.substring(1)).intValue();
347 if (ver <= HTMLfromOXM.swaggerMinBasepath) {
353 protected void updateParentXmlElements(Element parentElement, NodeList moreXmlElementNodes) {
358 Node refChild = null;
359 // find childNode with attributes and no children, insert children before that node
360 childNodes = parentElement.getChildNodes();
361 if (childNodes == null || childNodes.getLength() == 0) {
362 // should not happen since the base parent was chosen if it had children
366 for (int i = 0; i < childNodes.getLength(); ++i) {
367 refChild = childNodes.item(i);
368 if (refChild.hasAttributes() && !refChild.hasChildNodes()) {
374 for (int i = 0; i < moreXmlElementNodes.getLength(); ++i) {
375 xmlElement = (Element) moreXmlElementNodes.item(i);
376 childNode = xmlElement.cloneNode(true);
377 parentElement.insertBefore(childNode, refChild);
381 protected Node getXmlPropertiesNode(Element javaTypeElement) {
382 NodeList nl = javaTypeElement.getChildNodes();
384 for (int i = 0; i < nl.getLength(); ++i) {
386 if ("xml-properties".equals(child.getNodeName())) {
393 protected Node merge(NodeList nl, Node mergeNode) {
394 NamedNodeMap nnm = mergeNode.getAttributes();
396 NamedNodeMap childNnm;
398 String mergeName = nnm.getNamedItem("name").getNodeValue();
399 String mergeValue = nnm.getNamedItem("value").getNodeValue();
402 for (int j = 0; j < nl.getLength(); ++j) {
403 childNode = nl.item(j);
404 if ("xml-property".equals(childNode.getNodeName())) {
405 childNnm = childNode.getAttributes();
406 childName = childNnm.getNamedItem("name").getNodeValue();
407 childValue = childNnm.getNamedItem("value").getNodeValue();
408 if (childName.equals(mergeName)) {
410 // keep, replace or update
411 if (childValue.contains(mergeValue)) {
414 if (mergeValue.contains(childValue)) {
415 childNnm.getNamedItem("value").setTextContent(mergeValue);
418 childNnm.getNamedItem("value").setTextContent(mergeValue + "," + childValue);
423 childNode = mergeNode.cloneNode(true);
427 protected void mergeXmlProperties(Node useChildProperties, NodeList propertiesToMerge) {
428 NodeList nl = useChildProperties.getChildNodes();
431 for (int i = 0; i < propertiesToMerge.getLength(); ++i) {
432 childNode = propertiesToMerge.item(i);
433 if ("xml-property".equals(childNode.getNodeName())) {
434 newNode = merge(nl, childNode);
435 if (newNode != null) {
436 useChildProperties.appendChild(newNode);
443 protected void combineXmlProperties(int useElement, List<Element> combineElementList) {
444 // add or update xml-properties to the referenced element from the combined list
445 Element javaTypeElement = combineElementList.get(useElement);
446 NodeList nl = javaTypeElement.getChildNodes();
447 Node useChildProperties = getXmlPropertiesNode(javaTypeElement);
449 Node childProperties;
450 if (useChildProperties == null) {
451 // find xml-properties to clone
452 for (int i = 0; i < combineElementList.size(); ++i) {
453 if (i == useElement) {
456 childProperties = getXmlPropertiesNode(combineElementList.get(i));
457 if (childProperties != null) {
458 useChildProperties = childProperties.cloneNode(true);
459 javaTypeElement.appendChild(useChildProperties);
465 // find other xml-properties
466 for (int i = 0; i < combineElementList.size(); ++i) {
467 if (i == useElement || (cloneChild >= 0 && i <= cloneChild)) {
470 childProperties = getXmlPropertiesNode(combineElementList.get(i));
471 if (childProperties == null) {
474 cnl = childProperties.getChildNodes();
475 mergeXmlProperties(useChildProperties, cnl);
480 protected Element combineElements(String javaTypeName, List<Element> combineElementList) {
481 Element javaTypeElement;
482 NodeList parentNodes;
483 Element parentElement = null;
484 NodeList xmlElementNodes;
487 if (combinedJavaTypes.containsKey(javaTypeName)) {
488 return combineElementList.get((int) combinedJavaTypes.get(javaTypeName));
490 for (int i = 0; i < combineElementList.size(); ++i) {
491 javaTypeElement = combineElementList.get(i);
492 parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
493 if (parentNodes.getLength() == 0) {
496 parentElement = (Element) parentNodes.item(0);
497 xmlElementNodes = parentElement.getElementsByTagName("xml-element");
498 if (xmlElementNodes.getLength() <= 0) {
504 boolean doCombineElements = true;
505 if (useElement < 0) {
507 doCombineElements = false;
508 } else if (useElement == combineElementList.size() - 1) {
509 doCombineElements = false;
511 if (doCombineElements) {
512 // get xml-element from other javaTypeElements
513 Element otherParentElement = null;
514 for (int i = 0; i < combineElementList.size(); ++i) {
515 if (i == useElement) {
518 javaTypeElement = combineElementList.get(i);
519 parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
520 if (parentNodes.getLength() == 0) {
523 otherParentElement = (Element) parentNodes.item(0);
524 xmlElementNodes = otherParentElement.getElementsByTagName("xml-element");
525 if (xmlElementNodes.getLength() <= 0) {
528 // xml-element that are not present
529 updateParentXmlElements(parentElement, xmlElementNodes);
533 // need to combine xml-properties
534 combineXmlProperties(useElement, combineElementList);
535 combinedJavaTypes.put(javaTypeName, useElement);
536 return combineElementList.get(useElement);