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 dBuilder = dbFactory.newDocumentBuilder();
225 } catch (ParserConfigurationException e) {
230 doc = dBuilder.parse(oxmFile);
232 InputSource isInput = new InputSource(new StringReader(xml));
233 doc = dBuilder.parse(isInput);
235 } catch (SAXException e) {
237 } catch (IOException e) {
243 public abstract String getDocumentHeader();
245 public abstract String process() throws ParserConfigurationException, SAXException, IOException,
246 FileNotFoundException, EdgeRuleNotFoundException;
248 public String getXMLRootElementName(Element javaTypeElement) {
249 String xmlRootElementName = null;
250 NamedNodeMap attributes;
252 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
253 Element valElement = (Element) valNodes.item(0);
254 attributes = valElement.getAttributes();
255 for (int i = 0; i < attributes.getLength(); ++i) {
256 Attr attr = (Attr) attributes.item(i);
257 String attrName = attr.getNodeName();
259 String attrValue = attr.getNodeValue();
260 if (attrName.equals("name")) {
261 xmlRootElementName = attrValue;
264 return xmlRootElementName;
267 public String getXmlRootElementName(String javaTypeName) {
268 String attrName, attrValue;
270 Element javaTypeElement;
271 for (int i = 0; i < javaTypeNodes.getLength(); ++i) {
272 javaTypeElement = (Element) javaTypeNodes.item(i);
273 NamedNodeMap attributes = javaTypeElement.getAttributes();
274 for (int j = 0; j < attributes.getLength(); ++j) {
275 attr = (Attr) attributes.item(j);
276 attrName = attr.getNodeName();
277 attrValue = attr.getNodeValue();
278 if (attrName.equals("name") && attrValue.equals(javaTypeName)) {
279 NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
280 Element valElement = (Element) valNodes.item(0);
281 attributes = valElement.getAttributes();
282 for (int k = 0; k < attributes.getLength(); ++k) {
283 attr = (Attr) attributes.item(k);
284 attrName = attr.getNodeName();
286 attrValue = attr.getNodeValue();
287 if (attrName.equals("name")) {
297 public Map getCombinedJavaTypes() {
298 return combinedJavaTypes;
301 public void setCombinedJavaTypes(Map combinedJavaTypes) {
302 this.combinedJavaTypes = combinedJavaTypes;
305 public Element getJavaTypeElementSwagger(String javaTypeName) {
307 String attrName, attrValue;
309 Element javaTypeElement;
311 List<Element> combineElementList = new ArrayList<Element>();
312 for (int i = 0; i < javaTypeNodes.getLength(); ++i) {
313 javaTypeElement = (Element) javaTypeNodes.item(i);
314 NamedNodeMap attributes = javaTypeElement.getAttributes();
315 for (int j = 0; j < attributes.getLength(); ++j) {
316 attr = (Attr) attributes.item(j);
317 attrName = attr.getNodeName();
318 attrValue = attr.getNodeValue();
319 if (attrName.equals("name") && attrValue.equals(javaTypeName)) {
320 combineElementList.add(javaTypeElement);
324 if (combineElementList.size() == 0) {
325 return (Element) null;
326 } else if (combineElementList.size() > 1) {
327 return combineElements(javaTypeName, combineElementList);
329 return combineElementList.get(0);
332 public boolean versionSupportsSwaggerDiff(String version) {
333 int ver = new Integer(version.substring(1)).intValue();
334 if (ver >= HTMLfromOXM.swaggerDiffStartVersion) {
340 public boolean versionSupportsBasePathProperty(String version) {
341 int ver = new Integer(version.substring(1)).intValue();
342 if (ver <= HTMLfromOXM.swaggerMinBasepath) {
348 protected void updateParentXmlElements(Element parentElement, NodeList moreXmlElementNodes) {
353 Node refChild = null;
354 // find childNode with attributes and no children, insert children before that node
355 childNodes = parentElement.getChildNodes();
356 if (childNodes == null || childNodes.getLength() == 0) {
357 // should not happen since the base parent was chosen if it had children
361 for (int i = 0; i < childNodes.getLength(); ++i) {
362 refChild = childNodes.item(i);
363 if (refChild.hasAttributes() && !refChild.hasChildNodes()) {
369 for (int i = 0; i < moreXmlElementNodes.getLength(); ++i) {
370 xmlElement = (Element) moreXmlElementNodes.item(i);
371 childNode = xmlElement.cloneNode(true);
372 parentElement.insertBefore(childNode, refChild);
376 protected Node getXmlPropertiesNode(Element javaTypeElement) {
377 NodeList nl = javaTypeElement.getChildNodes();
379 for (int i = 0; i < nl.getLength(); ++i) {
381 if ("xml-properties".equals(child.getNodeName())) {
388 protected Node merge(NodeList nl, Node mergeNode) {
389 NamedNodeMap nnm = mergeNode.getAttributes();
391 NamedNodeMap childNnm;
393 String mergeName = nnm.getNamedItem("name").getNodeValue();
394 String mergeValue = nnm.getNamedItem("value").getNodeValue();
397 for (int j = 0; j < nl.getLength(); ++j) {
398 childNode = nl.item(j);
399 if ("xml-property".equals(childNode.getNodeName())) {
400 childNnm = childNode.getAttributes();
401 childName = childNnm.getNamedItem("name").getNodeValue();
402 childValue = childNnm.getNamedItem("value").getNodeValue();
403 if (childName.equals(mergeName)) {
405 // keep, replace or update
406 if (childValue.contains(mergeValue)) {
409 if (mergeValue.contains(childValue)) {
410 childNnm.getNamedItem("value").setTextContent(mergeValue);
413 childNnm.getNamedItem("value").setTextContent(mergeValue + "," + childValue);
418 childNode = mergeNode.cloneNode(true);
422 protected void mergeXmlProperties(Node useChildProperties, NodeList propertiesToMerge) {
423 NodeList nl = useChildProperties.getChildNodes();
426 for (int i = 0; i < propertiesToMerge.getLength(); ++i) {
427 childNode = propertiesToMerge.item(i);
428 if ("xml-property".equals(childNode.getNodeName())) {
429 newNode = merge(nl, childNode);
430 if (newNode != null) {
431 useChildProperties.appendChild(newNode);
438 protected void combineXmlProperties(int useElement, List<Element> combineElementList) {
439 // add or update xml-properties to the referenced element from the combined list
440 Element javaTypeElement = combineElementList.get(useElement);
441 NodeList nl = javaTypeElement.getChildNodes();
442 Node useChildProperties = getXmlPropertiesNode(javaTypeElement);
444 Node childProperties;
445 if (useChildProperties == null) {
446 // find xml-properties to clone
447 for (int i = 0; i < combineElementList.size(); ++i) {
448 if (i == useElement) {
451 childProperties = getXmlPropertiesNode(combineElementList.get(i));
452 if (childProperties != null) {
453 useChildProperties = childProperties.cloneNode(true);
454 javaTypeElement.appendChild(useChildProperties);
460 // find other xml-properties
461 for (int i = 0; i < combineElementList.size(); ++i) {
462 if (i == useElement || (cloneChild >= 0 && i <= cloneChild)) {
465 childProperties = getXmlPropertiesNode(combineElementList.get(i));
466 if (childProperties == null) {
469 cnl = childProperties.getChildNodes();
470 mergeXmlProperties(useChildProperties, cnl);
475 protected Element combineElements(String javaTypeName, List<Element> combineElementList) {
476 Element javaTypeElement;
477 NodeList parentNodes;
478 Element parentElement = null;
479 NodeList xmlElementNodes;
482 if (combinedJavaTypes.containsKey(javaTypeName)) {
483 return combineElementList.get((int) combinedJavaTypes.get(javaTypeName));
485 for (int i = 0; i < combineElementList.size(); ++i) {
486 javaTypeElement = combineElementList.get(i);
487 parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
488 if (parentNodes.getLength() == 0) {
491 parentElement = (Element) parentNodes.item(0);
492 xmlElementNodes = parentElement.getElementsByTagName("xml-element");
493 if (xmlElementNodes.getLength() <= 0) {
499 boolean doCombineElements = true;
500 if (useElement < 0) {
502 doCombineElements = false;
503 } else if (useElement == combineElementList.size() - 1) {
504 doCombineElements = false;
506 if (doCombineElements) {
507 // get xml-element from other javaTypeElements
508 Element otherParentElement = null;
509 for (int i = 0; i < combineElementList.size(); ++i) {
510 if (i == useElement) {
513 javaTypeElement = combineElementList.get(i);
514 parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
515 if (parentNodes.getLength() == 0) {
518 otherParentElement = (Element) parentNodes.item(0);
519 xmlElementNodes = otherParentElement.getElementsByTagName("xml-element");
520 if (xmlElementNodes.getLength() <= 0) {
523 // xml-element that are not present
524 updateParentXmlElements(parentElement, xmlElementNodes);
528 // need to combine xml-properties
529 combineXmlProperties(useElement, combineElementList);
530 combinedJavaTypes.put(javaTypeName, useElement);
531 return combineElementList.get(useElement);