From 0fdb2155e5c1d0e721709dd00c9dd55c175f0356 Mon Sep 17 00:00:00 2001 From: "LaMont, William (wl2432)" Date: Tue, 25 Sep 2018 15:31:25 -0400 Subject: fix xsd generation when obj crosses oxm files Issue-ID: AAI-1654 Change-Id: I118b0d94099c7f986303fc9dd9e5dae5144b4bbb Signed-off-by: LaMont, William (wl2432) --- .../aai/config/SwaggerGenerationConfiguration.java | 44 ++-- .../main/java/org/onap/aai/util/GenerateXsd.java | 3 + .../java/org/onap/aai/util/genxsd/HTMLfromOXM.java | 79 +++++-- .../org/onap/aai/util/genxsd/NodesYAMLfromOXM.java | 24 +- .../org/onap/aai/util/genxsd/OxmFileProcessor.java | 242 ++++++++++++++++++++- .../java/org/onap/aai/util/genxsd/XSDElement.java | 17 +- .../java/org/onap/aai/util/genxsd/YAMLfromOXM.java | 79 +++++-- .../org/onap/aai/util/genxsd/HTMLfromOXMTest.java | 101 ++++++--- .../onap/aai/util/genxsd/NodesYAMLfromOXMTest.java | 3 +- .../org/onap/aai/util/genxsd/XSDElementTest.java | 81 ++++++- .../org/onap/aai/util/genxsd/YAMLfromOXMTest.java | 3 +- 11 files changed, 566 insertions(+), 110 deletions(-) diff --git a/aai-core/src/main/java/org/onap/aai/config/SwaggerGenerationConfiguration.java b/aai-core/src/main/java/org/onap/aai/config/SwaggerGenerationConfiguration.java index fbbb703a..9aae5a62 100644 --- a/aai-core/src/main/java/org/onap/aai/config/SwaggerGenerationConfiguration.java +++ b/aai-core/src/main/java/org/onap/aai/config/SwaggerGenerationConfiguration.java @@ -37,25 +37,31 @@ import org.springframework.context.annotation.Scope; @Configuration public class SwaggerGenerationConfiguration { - @Value("${schema.uri.base.path}") - private String basePath; + @Value("${schema.uri.base.path}") + private String basePath; - @Bean - @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public NodesYAMLfromOXM nodesYamlFromOXM(SchemaVersions schemaVersions, NodeIngestor nodeIngestor, EdgeIngestor edgeIngestor) { - return new NodesYAMLfromOXM(basePath, schemaVersions, nodeIngestor, edgeIngestor); - } - - @Bean - @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public HTMLfromOXM htmlFromOXM(SchemaVersions schemaVersions, NodeIngestor nodeIngestor, EdgeIngestor edgeIngestor) { - return new HTMLfromOXM(schemaVersions, nodeIngestor, edgeIngestor); - } - - @Bean - @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public YAMLfromOXM yamlFromOXM(SchemaVersions schemaVersions, NodeIngestor nodeIngestor, EdgeIngestor edgeIngestor) { - return new YAMLfromOXM(basePath, schemaVersions, nodeIngestor, edgeIngestor); - } + @Value("${schema.xsd.maxoccurs:5000}") + private String maxOccurs; + + @Bean + @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public NodesYAMLfromOXM nodesYamlFromOXM(SchemaVersions schemaVersions, NodeIngestor nodeIngestor, EdgeIngestor edgeIngestor) { + NodesYAMLfromOXM nodesYamlFromOXM = new NodesYAMLfromOXM(basePath, schemaVersions, nodeIngestor, edgeIngestor); + return nodesYamlFromOXM; + } + + @Bean + @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public HTMLfromOXM htmlFromOXM(SchemaVersions schemaVersions, NodeIngestor nodeIngestor, EdgeIngestor edgeIngestor) { + HTMLfromOXM htmlFromOXM = new HTMLfromOXM(maxOccurs, schemaVersions, nodeIngestor, edgeIngestor); + return htmlFromOXM; + } + + @Bean + @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public YAMLfromOXM yamlFromOXM(SchemaVersions schemaVersions, NodeIngestor nodeIngestor, EdgeIngestor edgeIngestor) { + YAMLfromOXM yamlFromOXM = new YAMLfromOXM(basePath, schemaVersions, nodeIngestor, edgeIngestor); + return yamlFromOXM; + } } diff --git a/aai-core/src/main/java/org/onap/aai/util/GenerateXsd.java b/aai-core/src/main/java/org/onap/aai/util/GenerateXsd.java index d94457e5..84f06064 100644 --- a/aai-core/src/main/java/org/onap/aai/util/GenerateXsd.java +++ b/aai-core/src/main/java/org/onap/aai/util/GenerateXsd.java @@ -236,6 +236,7 @@ public class GenerateXsd { logger.error( "Exception creating output file " + outfileName); logger.error( e.getMessage()); e.printStackTrace(); + System.exit(-1); } } else if ( versionSupportsSwagger(apiVersion )) { outfileName = yaml_dir + "/aai_swagger_" + apiVersion + "." + generateTypeYAML; @@ -244,8 +245,10 @@ public class GenerateXsd { YAMLfromOXM swagger = (YAMLfromOXM) ctx.getBean(YAMLfromOXM.class); swagger.setVersion(v); fileContent = swagger.process(); + Map combinedJavaTypes = swagger.getCombinedJavaTypes(); NodesYAMLfromOXM nodesSwagger = ctx.getBean(NodesYAMLfromOXM.class); nodesSwagger.setVersion(v); + nodesSwagger.setCombinedJavaTypes(combinedJavaTypes); nodesContent = nodesSwagger.process(); } catch(Exception e) { logger.error( "Exception creating output file " + outfileName); diff --git a/aai-core/src/main/java/org/onap/aai/util/genxsd/HTMLfromOXM.java b/aai-core/src/main/java/org/onap/aai/util/genxsd/HTMLfromOXM.java index cba65daa..b1a4d919 100644 --- a/aai-core/src/main/java/org/onap/aai/util/genxsd/HTMLfromOXM.java +++ b/aai-core/src/main/java/org/onap/aai/util/genxsd/HTMLfromOXM.java @@ -22,10 +22,13 @@ package org.onap.aai.util.genxsd; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import javax.xml.parsers.ParserConfigurationException; - +import org.apache.commons.lang.StringUtils; import org.onap.aai.config.SpringContextAware; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; @@ -39,17 +42,22 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import com.google.common.base.CaseFormat; + public class HTMLfromOXM extends OxmFileProcessor { private static final Logger logger = LoggerFactory.getLogger("HTMLfromOXM.class"); + public static final String LINE_SEPARATOR = System.getProperty("line.separator"); + private String maxOccurs; - - public HTMLfromOXM(SchemaVersions schemaVersions, NodeIngestor ni, EdgeIngestor ei ){ + public HTMLfromOXM(String maxOccurs, SchemaVersions schemaVersions, NodeIngestor ni, EdgeIngestor ei ){ super(schemaVersions, ni,ei); + this.maxOccurs = maxOccurs; } public void setOxmVersion(File oxmFile, SchemaVersion v) { super.setOxmVersion(oxmFile, v); @@ -88,6 +96,7 @@ public class HTMLfromOXM extends OxmFileProcessor { } return sb.toString(); } + @Override public String process() throws ParserConfigurationException, SAXException, IOException, AAIException, FileNotFoundException, EdgeRuleNotFoundException { @@ -100,9 +109,21 @@ public class HTMLfromOXM extends OxmFileProcessor { } sb.append(getDocumentHeader()); StringBuilder sbInventory = new StringBuilder(); + Element elem; + String javaTypeName; + combinedJavaTypes = new HashMap(); for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { - XSDElement javaTypeElement = new XSDElement((Element)javaTypeNodes.item(i)); - String javaTypeName = javaTypeElement.name(); + elem = (Element)javaTypeNodes.item(i); + javaTypeName = elem.getAttribute("name"); + if ( !"Inventory".equals(javaTypeName ) ) { + if ( generatedJavaType.containsKey(javaTypeName) ) { + continue; + } + // will combine all matching java-types + elem = getJavaTypeElement(javaTypeName,false ); + } + XSDElement javaTypeElement = new XSDElement(elem, maxOccurs); + //javaTypeName = javaTypeElement.name(); if ( javaTypeName == null ) { String msg = "Invalid OXM file: has no name attribute in " + oxmFile; logger.error(msg); @@ -112,11 +133,8 @@ public class HTMLfromOXM extends OxmFileProcessor { logger.debug("skipping Nodes entry (temporary feature)"); continue; } - //Skip any type that has already been processed(recursion could be the reason) logger.debug(getXmlRootElementName(javaTypeName)+" vs "+ javaTypeName+":"+generatedJavaType.containsKey(getXmlRootElementName(javaTypeName))); - if ( generatedJavaType.containsKey(javaTypeName) ) { - continue; - } + if ( !"Inventory".equals(javaTypeName)) { generatedJavaType.put(javaTypeName, null); } @@ -127,11 +145,19 @@ public class HTMLfromOXM extends OxmFileProcessor { sb.append(" \n"); sb.append(" \n"); sb.append("\n"); + StringBuilder invalidSb = new StringBuilder(); return sb.toString(); } + + protected boolean isValidName( String name ) { + if ( name == null || name.length() == 0 ) { + return false; + } + String pattern = "^[a-z0-9-]*$"; + return name.matches(pattern); + } public String processJavaTypeElement( String javaTypeName, Element javaType_Element, StringBuilder sbInventory) { - String xmlRootElementName = getXMLRootElementName(javaType_Element); NodeList parentNodes = javaType_Element.getElementsByTagName("java-attributes"); @@ -160,16 +186,17 @@ public class HTMLfromOXM extends OxmFileProcessor { sb1.append(" \n"); sb1.append(" \n"); - XSDElement javaTypeElement = new XSDElement(javaType_Element); + XSDElement javaTypeElement = new XSDElement(javaType_Element, maxOccurs); logger.debug("XSDElement name: "+javaTypeElement.name()); if(versionUsesAnnotations(v.toString())) { sb1.append(javaTypeElement.getHTMLAnnotation("class", " ")); } sb1.append(" \n"); } + Element javatypeElement; for ( int i = 0; i < xmlElementNodes.getLength(); ++i ) { - XSDElement xmlElementElement = new XSDElement((Element)xmlElementNodes.item(i)); + XSDElement xmlElementElement = new XSDElement((Element)xmlElementNodes.item(i), maxOccurs); // String elementName = xmlElementElement.getAttribute("name"); String elementType = xmlElementElement.getAttribute("type"); @@ -177,7 +204,9 @@ public class HTMLfromOXM extends OxmFileProcessor { String addType = elementType.contains("." + v.toString() + ".") ? elementType.substring(elementType.lastIndexOf('.')+1) : null; if ( elementType.contains("." + v.toString() + ".") && !generatedJavaType.containsKey(addType) ) { generatedJavaType.put(addType, elementType); - sb.append(processJavaTypeElement( addType, getJavaTypeElement(addType), null )); + javatypeElement = getJavaTypeElement(addType, processingInventory); + + sb.append(processJavaTypeElement( addType, javatypeElement, null )); } if ("Nodes".equals(addType)) { logger.trace("Skipping nodes, temporary testing"); @@ -210,11 +239,13 @@ public class HTMLfromOXM extends OxmFileProcessor { return sb.toString(); } - private Element getJavaTypeElement( String javaTypeName ) + private Element getJavaTypeElement( String javaTypeName, boolean processingInventory ) { String attrName, attrValue; Attr attr; Element javaTypeElement; + + List combineElementList = new ArrayList(); for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { javaTypeElement = (Element) javaTypeNodes.item(i); NamedNodeMap attributes = javaTypeElement.getAttributes(); @@ -222,12 +253,24 @@ public class HTMLfromOXM extends OxmFileProcessor { attr = (Attr) attributes.item(j); attrName = attr.getNodeName(); attrValue = attr.getNodeValue(); - if ( attrName.equals("name") && attrValue.equals(javaTypeName)) - return javaTypeElement; + if ( attrName.equals("name") && attrValue.equals(javaTypeName)) { + if ( processingInventory ) { + return javaTypeElement; + } else { + combineElementList.add(javaTypeElement); + } + } } } - logger.error( "oxm file format error, missing java-type " + javaTypeName); - return (Element) null; + if ( combineElementList.size() == 0 ) { + logger.error( "oxm file format error, missing java-type " + javaTypeName); + return (Element) null; + } else if ( combineElementList.size() > 1 ) { + // need to combine java-attributes + return combineElements( javaTypeName, combineElementList); + } + return combineElementList.get(0); + } private boolean versionUsesAnnotations( String version) { diff --git a/aai-core/src/main/java/org/onap/aai/util/genxsd/NodesYAMLfromOXM.java b/aai-core/src/main/java/org/onap/aai/util/genxsd/NodesYAMLfromOXM.java index 5c4cd8bd..0b89ce10 100644 --- a/aai-core/src/main/java/org/onap/aai/util/genxsd/NodesYAMLfromOXM.java +++ b/aai-core/src/main/java/org/onap/aai/util/genxsd/NodesYAMLfromOXM.java @@ -117,9 +117,21 @@ public class NodesYAMLfromOXM extends OxmFileProcessor { } pathSb.append(getDocumentHeader()); StringBuffer definitionsSb = new StringBuffer(); + Element elem; + String javaTypeName; for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { - XSDElement javaTypeElement = new XSDElement((Element)javaTypeNodes.item(i)); - String javaTypeName = javaTypeElement.name(); + elem = (Element)javaTypeNodes.item(i); + javaTypeName = elem.getAttribute("name"); + if ( !"Inventory".equals(javaTypeName ) ) { + if ( generatedJavaType.containsKey(javaTypeName) ) { + continue; + } + // will combine all matching java-types + elem = getJavaTypeElementSwagger(javaTypeName ); + } + + XSDElement javaTypeElement = new XSDElement(elem); + logger.debug("External: "+javaTypeElement.getAttribute("name")+"/"+getXmlRootElementName(javaTypeName)); if ( javaTypeName == null ) { @@ -128,10 +140,7 @@ public class NodesYAMLfromOXM extends OxmFileProcessor { throw new AAIException(msg); } namespaceFilter.add(getXmlRootElementName(javaTypeName)); - //Skip any type that has already been processed(recursion could be the reason) - if ( generatedJavaType.containsKey(getXmlRootElementName(javaTypeName)) ) { - continue; - } + processJavaTypeElementSwagger( javaTypeName, javaTypeElement, pathSb, definitionsSb, null, null, null, null, null, null); } @@ -491,7 +500,8 @@ public class NodesYAMLfromOXM extends OxmFileProcessor { } Path path = Paths.get(outfileName); Charset charset = Charset.forName("UTF-8"); - try(BufferedWriter bw = Files.newBufferedWriter(path, charset);) { + try { + BufferedWriter bw = Files.newBufferedWriter(path, charset); bw.write(fileContent); if ( bw != null ) { bw.close(); diff --git a/aai-core/src/main/java/org/onap/aai/util/genxsd/OxmFileProcessor.java b/aai-core/src/main/java/org/onap/aai/util/genxsd/OxmFileProcessor.java index 391142cc..44e5a9f8 100644 --- a/aai-core/src/main/java/org/onap/aai/util/genxsd/OxmFileProcessor.java +++ b/aai-core/src/main/java/org/onap/aai/util/genxsd/OxmFileProcessor.java @@ -23,6 +23,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -34,6 +36,13 @@ import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; @@ -46,6 +55,7 @@ import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; @@ -62,6 +72,8 @@ public abstract class OxmFileProcessor { protected String apiVersion = null; protected SchemaVersions schemaVersions; + protected Map combinedJavaTypes; + protected static int annotationsStartVersion = 9; // minimum version to support annotations in xsd protected static int annotationsMinVersion = 6; // lower versions support annotations in xsd @@ -248,12 +260,22 @@ public abstract class OxmFileProcessor { return null; } + public Map getCombinedJavaTypes() { + return combinedJavaTypes; + } + + public void setCombinedJavaTypes(Map combinedJavaTypes) { + this.combinedJavaTypes = combinedJavaTypes; + } + public Element getJavaTypeElementSwagger( String javaTypeName ) { String attrName, attrValue; Attr attr; Element javaTypeElement; + + List combineElementList = new ArrayList(); for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { javaTypeElement = (Element) javaTypeNodes.item(i); NamedNodeMap attributes = javaTypeElement.getAttributes(); @@ -261,11 +283,18 @@ public abstract class OxmFileProcessor { attr = (Attr) attributes.item(j); attrName = attr.getNodeName(); attrValue = attr.getNodeValue(); - if ( attrName.equals("name") && attrValue.equals(javaTypeName)) - return javaTypeElement; + if ( attrName.equals("name") && attrValue.equals(javaTypeName)) { + combineElementList.add(javaTypeElement); + } } } - return (Element) null; + if ( combineElementList.size() == 0 ) { + return (Element) null; + } else if ( combineElementList.size() > 1 ) { + // need to combine java-attributes + return combineElements( javaTypeName, combineElementList); + } + return combineElementList.get(0); } public boolean versionSupportsSwaggerDiff( String version) { @@ -284,4 +313,211 @@ public abstract class OxmFileProcessor { return false; } + protected void updateParentXmlElements(Element parentElement, NodeList moreXmlElementNodes) { + Element xmlElement; + NodeList childNodes; + Node childNode; + + Node refChild = null; + // find childNode with attributes and no children, insert children before that node + childNodes = parentElement.getChildNodes(); + if ( childNodes == null || childNodes.getLength() == 0 ) { + // should not happen since the base parent was chosen if it had children + return; + } + + for ( int i = 0; i < childNodes.getLength(); ++i ) { + refChild = childNodes.item(i); + if ( refChild.hasAttributes() && !refChild.hasChildNodes()) { + break; + } + + } + + for ( int i = 0; i < moreXmlElementNodes.getLength(); ++i ) { + xmlElement = (Element)moreXmlElementNodes.item(i); + childNode = xmlElement.cloneNode(true); + parentElement.insertBefore(childNode, refChild); + } + } + + protected Node getXmlPropertiesNode(Element javaTypeElement ) { + NodeList nl = javaTypeElement.getChildNodes(); + Node child; + for ( int i = 0; i < nl.getLength(); ++i ) { + child = nl.item(i); + if ( "xml-properties".equals(child.getNodeName())) { + return child; + } + } + return null; + } + + protected Node merge( NodeList nl, Node mergeNode ) { + NamedNodeMap nnm = mergeNode.getAttributes(); + Node childNode; + NamedNodeMap childNnm; + + String mergeName = nnm.getNamedItem("name").getNodeValue(); + String mergeValue = nnm.getNamedItem("value").getNodeValue(); + String childName; + String childValue; + for ( int j = 0; j < nl.getLength(); ++j ) { + childNode = nl.item(j); + if ( "xml-property".equals(childNode.getNodeName())) { + childNnm = childNode.getAttributes(); + childName = childNnm.getNamedItem("name").getNodeValue(); + childValue = childNnm.getNamedItem("value").getNodeValue(); + if ( childName.equals(mergeName)) { + // attribute exists + // keep, replace or update + if ( childValue.contains(mergeValue) ) { + return null; + } + if ( mergeValue.contains(childValue) ) { + childNnm.getNamedItem("value").setTextContent(mergeValue); + return null; + } + childNnm.getNamedItem("value").setTextContent(mergeValue + "," + childValue); + return null; + } + } + } + childNode = mergeNode.cloneNode(true); + return childNode; + } + + protected void mergeXmlProperties(Node useChildProperties, NodeList propertiesToMerge ) { + NodeList nl = useChildProperties.getChildNodes(); + Node childNode; + Node newNode; + for ( int i = 0; i < propertiesToMerge.getLength(); ++i ) { + childNode = propertiesToMerge.item(i); + if ( "xml-property".equals(childNode.getNodeName()) ) { + newNode = merge(nl, childNode); + if ( newNode != null ) { + useChildProperties.appendChild(newNode); + } + } + + } + } + + protected void combineXmlProperties(int useElement, List combineElementList) { + // add or update xml-properties to the referenced element from the combined list + Element javaTypeElement = combineElementList.get(useElement); + NodeList nl = javaTypeElement.getChildNodes(); + Node useChildProperties = getXmlPropertiesNode( javaTypeElement); + int cloneChild = -1; + Node childProperties; + if ( useChildProperties == null ) { + // find xml-properties to clone + for ( int i = 0; i < combineElementList.size(); ++i ) { + if ( i == useElement ) { + continue; + } + childProperties = getXmlPropertiesNode(combineElementList.get(i)); + if ( childProperties != null ) { + useChildProperties = childProperties.cloneNode(true); + javaTypeElement.appendChild(useChildProperties); + cloneChild = i; + } + } + } + NodeList cnl; + // find other xml-properties + for ( int i = 0; i < combineElementList.size(); ++i ) { + if ( i == useElement|| ( cloneChild >= 0 && i <= cloneChild )) { + continue; + } + childProperties = getXmlPropertiesNode(combineElementList.get(i)); + if ( childProperties == null ) { + continue; + } + cnl = childProperties.getChildNodes(); + mergeXmlProperties( useChildProperties, cnl); + } + + } + + protected Element combineElements( String javaTypeName, List combineElementList ) { + Element javaTypeElement; + NodeList parentNodes; + Element parentElement = null; + NodeList xmlElementNodes; + + int useElement = -1; + if ( combinedJavaTypes.containsKey( javaTypeName) ) { + return combineElementList.get((int)combinedJavaTypes.get(javaTypeName)); + } + for ( int i = 0; i < combineElementList.size(); ++i ) { + javaTypeElement = combineElementList.get(i); + parentNodes = javaTypeElement.getElementsByTagName("java-attributes"); + if ( parentNodes.getLength() == 0 ) { + continue; + } + parentElement = (Element)parentNodes.item(0); + xmlElementNodes = parentElement.getElementsByTagName("xml-element"); + if ( xmlElementNodes.getLength() <= 0 ) { + continue; + } + useElement = i; + break; + } + boolean doCombineElements = true; + if ( useElement < 0 ) { + useElement = 0; + doCombineElements = false; + } else if ( useElement == combineElementList.size() - 1) { + doCombineElements = false; + } + if ( doCombineElements ) { + // get xml-element from other javaTypeElements + Element otherParentElement = null; + for ( int i = 0; i < combineElementList.size(); ++i ) { + if ( i == useElement ) { + continue; + } + javaTypeElement = combineElementList.get(i); + parentNodes = javaTypeElement.getElementsByTagName("java-attributes"); + if ( parentNodes.getLength() == 0 ) { + continue; + } + otherParentElement = (Element)parentNodes.item(0); + xmlElementNodes = otherParentElement.getElementsByTagName("xml-element"); + if ( xmlElementNodes.getLength() <= 0 ) { + continue; + } + // xml-element that are not present + updateParentXmlElements( parentElement, xmlElementNodes); + + } + } + // need to combine xml-properties + combineXmlProperties(useElement, combineElementList ); + combinedJavaTypes.put( javaTypeName, useElement); + return combineElementList.get(useElement); + } + + + private static void prettyPrint(Node node, String tab) + { + // for debugging + try { + // Set up the output transformer + TransformerFactory transfac = TransformerFactory.newInstance(); + Transformer trans = transfac.newTransformer(); + trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + trans.setOutputProperty(OutputKeys.INDENT, "yes"); + StringWriter sw = new StringWriter(); + StreamResult result = new StreamResult(sw); + DOMSource source = new DOMSource(node); + trans.transform(source, result); + String xmlString = sw.toString(); + System.out.println(xmlString); + } + catch (TransformerException e) { + e.printStackTrace(); + } + } } diff --git a/aai-core/src/main/java/org/onap/aai/util/genxsd/XSDElement.java b/aai-core/src/main/java/org/onap/aai/util/genxsd/XSDElement.java index f9ce7c11..1494b8f6 100644 --- a/aai-core/src/main/java/org/onap/aai/util/genxsd/XSDElement.java +++ b/aai-core/src/main/java/org/onap/aai/util/genxsd/XSDElement.java @@ -40,16 +40,25 @@ import com.google.common.base.Joiner; public class XSDElement implements Element { Element xmlElementElement; + String maxOccurs; private static final int VALUE_NONE = 0; private static final int VALUE_DESCRIPTION = 1; private static final int VALUE_INDEXED_PROPS = 2; private static final int VALUE_CONTAINER = 3; private static final int VALUE_REQUIRES = 4; + public XSDElement(Element xmlElementElement, String maxOccurs) { + super(); + this.xmlElementElement = xmlElementElement; + this.maxOccurs = maxOccurs; + } + public XSDElement(Element xmlElementElement) { super(); this.xmlElementElement = xmlElementElement; + this.maxOccurs = null; } + public String name() { return this.getAttribute("name"); } @@ -297,14 +306,14 @@ public class XSDElement implements Element { sbElement.append(" type=\"xs:int\""); if ( elementType.equals("java.lang.Boolean")) sbElement.append(" type=\"xs:boolean\""); - if ( ("java.lang.Boolean".equals(elementType)) || (elementIsRequired == null || !elementIsRequired.equals("true")||addType != null)) { + if ( addType != null || elementType.startsWith("java.lang.") ) { sbElement.append(" minOccurs=\"0\""); } if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) { - sbElement.append(" maxOccurs=\"5000\""); + sbElement.append(" maxOccurs=\"" + maxOccurs + "\""); } if(useAnnotation) { - String annotation = new XSDElement(xmlElementElement).getHTMLAnnotation("field", " "); + String annotation = new XSDElement(xmlElementElement, maxOccurs).getHTMLAnnotation("field", " "); sbElement.append(StringUtils.isNotEmpty(annotation) ? ">\n" : ""); sbElement.append(annotation); sbElement.append(StringUtils.isNotEmpty(annotation) ? " \n" : "/>\n" ); @@ -340,7 +349,7 @@ public class XSDElement implements Element { sbElement.append(">\n"); sbElement.append(" \n"); if(useAnnotation) { - XSDElement javaTypeElement = new XSDElement((Element)this.getParentNode()); + XSDElement javaTypeElement = new XSDElement((Element)this.getParentNode(), maxOccurs); sbElement.append(javaTypeElement.getHTMLAnnotation("class", " ")); } sbElement.append(" \n"); diff --git a/aai-core/src/main/java/org/onap/aai/util/genxsd/YAMLfromOXM.java b/aai-core/src/main/java/org/onap/aai/util/genxsd/YAMLfromOXM.java index f90d54e6..a14a6977 100644 --- a/aai-core/src/main/java/org/onap/aai/util/genxsd/YAMLfromOXM.java +++ b/aai-core/src/main/java/org/onap/aai/util/genxsd/YAMLfromOXM.java @@ -27,6 +27,7 @@ import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -111,25 +112,33 @@ public class YAMLfromOXM extends OxmFileProcessor { try { init(); } catch(Exception e) { - logger.error( "Error initializing " + this.getClass(),e); + logger.error( "Error initializing " + this.getClass()); throw e; } pathSb.append(getDocumentHeader()); StringBuffer definitionsSb = new StringBuffer(); + Element elem; + String javaTypeName; + combinedJavaTypes = new HashMap(); for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) { - XSDElement javaTypeElement = new XSDElement((Element)javaTypeNodes.item(i)); - logger.debug("External: "+javaTypeElement.getAttribute("name")); - String javaTypeName = javaTypeElement.name(); + elem = (Element)javaTypeNodes.item(i); + javaTypeName = elem.getAttribute("name"); + if ( !"Inventory".equals(javaTypeName ) ) { + if ( generatedJavaType.containsKey(getXmlRootElementName(javaTypeName) ) ) { + continue; + } + // will combine all matching java-types + elem = getJavaTypeElementSwagger(javaTypeName ); + } + + XSDElement javaTypeElement = new XSDElement(elem); if ( javaTypeName == null ) { String msg = "Invalid OXM file: has no name attribute in " + oxmFile; logger.error(msg); throw new AAIException(msg); } namespaceFilter.add(getXmlRootElementName(javaTypeName)); - //Skip any type that has already been processed(recursion could be the reason) - if ( generatedJavaType.containsKey(getXmlRootElementName(javaTypeName)) ) { - continue; - } + processJavaTypeElementSwagger( javaTypeName, javaTypeElement, pathSb, definitionsSb, null, null, null, null, null, null); } @@ -160,8 +169,8 @@ public class YAMLfromOXM extends OxmFileProcessor { if(namespaceFilter != null && (! namespaceFilter.contains(entry.getKey()))) { continue; } - logger.debug("Key: "+entry.getKey()+"Test: "+ (entry.getKey() == "relationship")); - if(entry.getKey().matches("relationship")) { + logger.debug("Key: "+entry.getKey()+"Test: "+ (entry.getKey() == "relationship-dict")); + if(entry.getKey().matches("relationship-dict")) { String jb=entry.getValue(); logger.debug("Value: "+jb); int ndx=jb.indexOf("related-to-property:"); @@ -209,10 +218,24 @@ public class YAMLfromOXM extends OxmFileProcessor { return sb.toString(); } + private String getDictionary(String resource ) { + StringBuffer dictSb = new StringBuffer(); + dictSb.append(" " + resource + ":\n"); + dictSb.append(" description: |\n"); + dictSb.append(" dictionary of " + resource + "\n" ); + dictSb.append(" type: object\n"); + dictSb.append(" properties:\n"); + dictSb.append(" " + resource + ":\n"); + dictSb.append(" type: array\n"); + dictSb.append(" items:\n"); + dictSb.append(" $ref: \"#/definitions/" + resource + "-dict\"\n"); + return dictSb.toString(); + } + private String processJavaTypeElementSwagger( String javaTypeName, Element javaTypeElement, StringBuffer pathSb, StringBuffer definitionsSb, String path, String tag, String opId, String getItemName, StringBuffer pathParams, String validEdges) { - + String xmlRootElementName = getXMLRootElementName(javaTypeElement); StringBuilder definitionsLocalSb = new StringBuilder(256); @@ -409,6 +432,7 @@ public class YAMLfromOXM extends OxmFileProcessor { } boolean processingInventoryDef = false; + String dict = null; if ( xmlRootElementName.equals("inventory")) { // inventory properties for each oxm to be concatenated processingInventoryDef = true; @@ -418,7 +442,10 @@ public class YAMLfromOXM extends OxmFileProcessor { definitionsLocalSb.append(" " + xmlRootElementName + ":\n"); definitionsLocalSb.append(" properties:\n"); } - + } else if ( xmlRootElementName.equals("relationship")) { + definitionsSb.append(" " + "relationship-dict" + ":\n"); + definitionsLocalSb.append(" " + "relationship-dict" + ":\n"); + dict = getDictionary(xmlRootElementName); } else { definitionsSb.append(" " + xmlRootElementName + ":\n"); definitionsLocalSb.append(" " + xmlRootElementName + ":\n"); @@ -441,7 +468,7 @@ public class YAMLfromOXM extends OxmFileProcessor { results.get(key).stream().filter((i) -> (i.getFrom().equals(xmlRootElementName) && (! i.isPrivateEdge() && i.getPreventDelete().equals("OUT")))).forEach((i) ->{ preventDelete.add(i.getTo().toUpperCase());} ); } } catch(Exception e) { - logger.debug("xmlRootElementName: "+xmlRootElementName+"\n",e); + logger.debug("xmlRootElementName: "+xmlRootElementName+"\n"+e); } try { EdgeRuleQuery q1 = new EdgeRuleQuery.Builder(xmlRootElementName).version(v).toOnly().build(); @@ -454,7 +481,7 @@ public class YAMLfromOXM extends OxmFileProcessor { results.get(key).stream().filter((i) -> (i.getTo().equals(xmlRootElementName) && (! i.isPrivateEdge() && i.getPreventDelete().equals("IN")))).forEach((i) ->{ preventDelete.add(i.getFrom().toUpperCase());} ); } } catch(Exception e) { - logger.debug("xmlRootElementName: "+xmlRootElementName+"\n",e); + logger.debug("xmlRootElementName: "+xmlRootElementName+"\n"+e); } if(preventDelete.size() > 0) { prevent = xmlRootElementName.toUpperCase()+" cannot be deleted if related to "+String.join(",",preventDelete); @@ -501,11 +528,14 @@ public class YAMLfromOXM extends OxmFileProcessor { if ( xmlRootElementName.equals("inventory") ) { //will add to javaTypeDefinitions at end inventoryDefSb.append(definitionsLocalSb.toString()); + } else if ( xmlRootElementName.equals("relationship") ){ + javaTypeDefinitions.put(xmlRootElementName, dict); + javaTypeDefinitions.put(xmlRootElementName+ "-dict", definitionsLocalSb.toString()); } else { javaTypeDefinitions.put(xmlRootElementName, definitionsLocalSb.toString()); } } catch (Exception e) { - logger.error("Exception adding in javaTypeDefinitions",e); + e.printStackTrace(); } if ( xmlRootElementName.equals("inventory") ) { logger.trace("skip xmlRootElementName(2)="+xmlRootElementName); @@ -535,16 +565,21 @@ public class YAMLfromOXM extends OxmFileProcessor { try { outfile.createNewFile(); } catch (IOException e) { - logger.error( "Exception creating output file " + outfileName,e); + logger.error( "Exception creating output file " + outfileName); + e.printStackTrace(); } + BufferedWriter bw = null; + Charset charset = Charset.forName("UTF-8"); + Path path = Paths.get(outfileName); try { - Charset charset = Charset.forName("UTF-8"); - Path path = Paths.get(outfileName); - try(BufferedWriter bw = Files.newBufferedWriter(path, charset)){ - bw.write(fileContent); + bw = Files.newBufferedWriter(path, charset); + bw.write(fileContent); + if ( bw != null ) { + bw.close(); } } catch ( IOException e) { - logger.error( "Exception writing output file " + outfileName,e); + logger.error( "Exception writing output file " + outfileName); + e.printStackTrace(); } } @@ -565,4 +600,4 @@ public class YAMLfromOXM extends OxmFileProcessor { return false; } -} +} \ No newline at end of file diff --git a/aai-core/src/test/java/org/onap/aai/util/genxsd/HTMLfromOXMTest.java b/aai-core/src/test/java/org/onap/aai/util/genxsd/HTMLfromOXMTest.java index d35cc4f0..5e019196 100644 --- a/aai-core/src/test/java/org/onap/aai/util/genxsd/HTMLfromOXMTest.java +++ b/aai-core/src/test/java/org/onap/aai/util/genxsd/HTMLfromOXMTest.java @@ -65,7 +65,8 @@ import org.w3c.dom.Element; }) @TestPropertySource(properties = { - "schema.uri.base.path = /aai" + "schema.uri.base.path = /aai", + "schema.xsd.maxoccurs = 5000" }) public class HTMLfromOXMTest { private static final Logger logger = LoggerFactory.getLogger("HTMLfromOXMTest.class"); @@ -95,14 +96,18 @@ public class HTMLfromOXMTest { @Before public void setUp() throws Exception { + setUp(0); + } + + public void setUp(int sbopt) throws Exception + { XSDElementTest x = new XSDElementTest(); - x.setUp(); + x.setUp(sbopt); testXML = x.testXML; logger.debug(testXML); BufferedWriter bw = new BufferedWriter(new FileWriter(OXMFILENAME)); bw.write(testXML); bw.close(); - } @Test @@ -133,7 +138,23 @@ public class HTMLfromOXMTest { } logger.debug("FileContent-I:"); logger.debug(fileContent); - assertThat(fileContent, is(HTMLresult())); + assertThat(fileContent, is(HTMLresult(0))); + } + + @Test + public void testProcessWithCombiningJavaTypes() { + SchemaVersion v = schemaVersions.getAppRootVersion(); + String fileContent = null; + try { + setUp(1); + htmlFromOxm.setXmlVersion(testXML, v); + fileContent = htmlFromOxm.process(); + } catch(Exception e) { + e.printStackTrace(); + } + logger.debug("FileContent-I:"); + logger.debug(fileContent); + assertThat(fileContent, is(HTMLresult(1))); } @Test @@ -158,7 +179,7 @@ public class HTMLfromOXMTest { XMLfile.delete(); logger.debug("FileContent-I:"); logger.debug(fileContent); - assertThat(fileContent, is(HTMLresult())); + assertThat(fileContent, is(HTMLresult(0))); } @Test @@ -173,7 +194,7 @@ public class HTMLfromOXMTest { } logger.debug("FileContent-II:"); logger.debug(fileContent); - assertThat(fileContent, is(HTMLresult())); + assertThat(fileContent, is(HTMLresult(0))); } @Test @@ -193,9 +214,13 @@ public class HTMLfromOXMTest { assertThat("Element="+customer.getNodeName()+"/"+customer.getAttribute("name"), is(target)); } public String HTMLresult() { + return HTMLresult(0); + } + + public String HTMLresult(int sbopt) { StringBuilder sb = new StringBuilder(32368); sb.append(HTMLheader()); - sb.append(HTMLdefs()); + sb.append(HTMLdefs(sbopt)); return sb.toString(); } @@ -208,7 +233,11 @@ public class HTMLfromOXMTest { sb.append(" jaxb:extensionBindingPrefixes=\"annox\">\n\n"); return sb.toString(); } + public String HTMLdefs() { + return HTMLdefs(0); + } + public String HTMLdefs(int sbopt) { StringBuilder sb = new StringBuilder(1500); sb.append(" \n"); sb.append(" \n"); @@ -218,7 +247,7 @@ public class HTMLfromOXMTest { sb.append(" \r\n"); sb.append(" \r\n"); sb.append(" \n"); - sb.append(" \n"); + sb.append(" \n"); sb.append(" \r\n"); sb.append(" \r\n"); sb.append(" @org.onap.aai.annotations.Metadata(isKey=true,description=\"Value defined by orchestration to identify this service.\")\r\n"); @@ -258,38 +287,60 @@ public class HTMLfromOXMTest { sb.append(" \n"); sb.append(" \r\n"); sb.append(" \r\n"); - sb.append(" @org.onap.aai.annotations.Metadata(description=\"customer identifiers to provide linkage back to BSS information.\",nameProps=\"subscriber-name\",indexedProps=\"subscriber-name,global-customer-id,subscriber-type\",searchable=\"global-customer-id,subscriber-name\",uniqueProps=\"global-customer-id\",container=\"customers\",namespace=\"business\")\r\n"); + if ( sbopt == 0 ) { + sb.append(" @org.onap.aai.annotations.Metadata(description=\"customer identifiers to provide linkage back to BSS information.\",nameProps=\"subscriber-name\",indexedProps=\"subscriber-name,global-customer-id,subscriber-type\",searchable=\"global-customer-id,subscriber-name\",uniqueProps=\"global-customer-id\",container=\"customers\",namespace=\"business\")\r\n"); + } else { + sb.append(" @org.onap.aai.annotations.Metadata(description=\"customer identifiers to provide linkage back to BSS information.\",nameProps=\"subscriber-name\",indexedProps=\"subscriber-type,subscriber-name,global-customer-id\",searchable=\"global-customer-id,subscriber-name\",uniqueProps=\"global-customer-id\",container=\"customers\",namespace=\"business\")\r\n"); + } sb.append(" \r\n"); sb.append(" \r\n"); sb.append(" \n"); - sb.append(" \n"); + sb.append(" \n"); sb.append(" \r\n"); sb.append(" \r\n"); sb.append(" @org.onap.aai.annotations.Metadata(isKey=true,description=\"Global customer id used across to uniquely identify customer.\")\r\n"); sb.append(" \r\n"); sb.append(" \r\n"); sb.append(" \n"); - sb.append(" \n"); + sb.append(" \n"); sb.append(" \r\n"); sb.append(" \r\n"); sb.append(" @org.onap.aai.annotations.Metadata(description=\"Subscriber name, an alternate way to retrieve a customer.\")\r\n"); sb.append(" \r\n"); sb.append(" \r\n"); sb.append(" \n"); - sb.append(" \n"); - sb.append(" \r\n"); - sb.append(" \r\n"); - sb.append(" @org.onap.aai.annotations.Metadata(description=\"Subscriber type, a way to provide VID with only the INFRA customers.\",defaultValue=\"CUST\")\r\n"); - sb.append(" \r\n"); - sb.append(" \r\n"); - sb.append(" \n"); - sb.append(" \n"); - sb.append(" \r\n"); - sb.append(" \r\n"); - sb.append(" @org.onap.aai.annotations.Metadata(description=\"Used for optimistic concurrency. Must be empty on create, valid on update and delete.\")\r\n"); - sb.append(" \r\n"); - sb.append(" \r\n"); - sb.append(" \n"); + if ( sbopt == 0 ) { + sb.append(" \n"); + sb.append(" \r\n"); + sb.append(" \r\n"); + sb.append(" @org.onap.aai.annotations.Metadata(description=\"Subscriber type, a way to provide VID with only the INFRA customers.\",defaultValue=\"CUST\")\r\n"); + sb.append(" \r\n"); + sb.append(" \r\n"); + sb.append(" \n"); + sb.append(" \n"); + sb.append(" \r\n"); + sb.append(" \r\n"); + sb.append(" @org.onap.aai.annotations.Metadata(description=\"Used for optimistic concurrency. Must be empty on create, valid on update and delete.\")\r\n"); + sb.append(" \r\n"); + sb.append(" \r\n"); + sb.append(" \n"); + } else { + sb.append(" \n"); + sb.append(" \r\n"); + sb.append(" \r\n"); + sb.append(" @org.onap.aai.annotations.Metadata(description=\"Used for optimistic concurrency. Must be empty on create, valid on update and delete.\")\r\n"); + sb.append(" \r\n"); + sb.append(" \r\n"); + sb.append(" \n"); + sb.append(" \n"); + sb.append(" \r\n"); + sb.append(" \r\n"); + sb.append(" @org.onap.aai.annotations.Metadata(description=\"Subscriber type, a way to provide VID with only the INFRA customers.\",defaultValue=\"CUST\")\r\n"); + sb.append(" \r\n"); + sb.append(" \r\n"); + sb.append(" \n"); + + } sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); diff --git a/aai-core/src/test/java/org/onap/aai/util/genxsd/NodesYAMLfromOXMTest.java b/aai-core/src/test/java/org/onap/aai/util/genxsd/NodesYAMLfromOXMTest.java index 2dfcd4ed..b19a524b 100644 --- a/aai-core/src/test/java/org/onap/aai/util/genxsd/NodesYAMLfromOXMTest.java +++ b/aai-core/src/test/java/org/onap/aai/util/genxsd/NodesYAMLfromOXMTest.java @@ -64,7 +64,8 @@ import org.w3c.dom.Element; }) @TestPropertySource(properties = { - "schema.uri.base.path = /aai" + "schema.uri.base.path = /aai", + "schema.xsd.maxoccurs = 5000" }) public class NodesYAMLfromOXMTest { //public class NodesYAMLfromOXMTest extends AAISetup { diff --git a/aai-core/src/test/java/org/onap/aai/util/genxsd/XSDElementTest.java b/aai-core/src/test/java/org/onap/aai/util/genxsd/XSDElementTest.java index 94047c37..7f0d1ed7 100644 --- a/aai-core/src/test/java/org/onap/aai/util/genxsd/XSDElementTest.java +++ b/aai-core/src/test/java/org/onap/aai/util/genxsd/XSDElementTest.java @@ -70,16 +70,25 @@ public class XSDElementTest { @Before public void setUp() throws Exception { - StringBuilder sb = new StringBuilder(maxSizeForXml); - addNamespace(sb); - addBusiness(sb); - addCustomers(sb); - addCustomer(sb); - addServiceSubscriptions(sb); - addServiceSubscription(sb); - addEndOfXML(sb); - testXML = sb.toString(); - init(); + setUp(0); + } + + public void setUp(int sbopt) throws Exception { + StringBuilder sb = new StringBuilder(maxSizeForXml); + addNamespace(sb); + addBusiness(sb); + addCustomers(sb); + if ( sbopt == 0 ) { + addCustomer(sb); + } else { + addCustomerNoSubscriberType(sb); + addCustomerSubscriberType(sb); + } + addServiceSubscriptions(sb); + addServiceSubscription(sb); + addEndOfXML(sb); + testXML = sb.toString(); + init(); } private void addNamespace(StringBuilder sb){ @@ -163,6 +172,58 @@ public class XSDElementTest { sb.append("\n"); } + private void addCustomerNoSubscriberType(StringBuilder sb){ + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); +// sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + } + + private void addCustomerSubscriberType(StringBuilder sb){ + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + } + private void addServiceSubscriptions(StringBuilder sb){ sb.append("\n"); sb.append("\n"); diff --git a/aai-core/src/test/java/org/onap/aai/util/genxsd/YAMLfromOXMTest.java b/aai-core/src/test/java/org/onap/aai/util/genxsd/YAMLfromOXMTest.java index e1288978..813ad837 100644 --- a/aai-core/src/test/java/org/onap/aai/util/genxsd/YAMLfromOXMTest.java +++ b/aai-core/src/test/java/org/onap/aai/util/genxsd/YAMLfromOXMTest.java @@ -76,7 +76,8 @@ import com.google.common.collect.Multimap; }) @TestPropertySource(properties = { - "schema.uri.base.path = /aai" + "schema.uri.base.path = /aai", + "schema.xsd.maxoccurs = 5000" }) public class YAMLfromOXMTest { @Autowired -- cgit 1.2.3-korg