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.schemaservice.nodeschema;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24 import com.google.common.base.CaseFormat;
25 import com.google.common.collect.ArrayListMultimap;
26 import com.google.common.collect.Multimap;
27 import org.eclipse.persistence.jaxb.JAXBContextProperties;
28 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
29 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
30 import org.onap.aai.schemaservice.config.ConfigTranslator;
31 import org.springframework.beans.factory.annotation.Autowired;
32 import org.springframework.stereotype.Component;
33 import org.w3c.dom.Document;
34 import org.w3c.dom.Element;
35 import org.w3c.dom.Node;
36 import org.w3c.dom.NodeList;
37 import org.xml.sax.SAXException;
39 import javax.xml.XMLConstants;
40 import jakarta.xml.bind.JAXBException;
41 import javax.xml.parsers.DocumentBuilder;
42 import javax.xml.parsers.DocumentBuilderFactory;
43 import javax.xml.parsers.ParserConfigurationException;
45 import java.nio.charset.StandardCharsets;
47 import java.util.Map.Entry;
48 import java.util.regex.Matcher;
49 import java.util.regex.Pattern;
52 * NodeIngestor - ingests A&AI OXM files per given config, serves DynamicJAXBContext per version
55 public class NodeIngestor {
57 private static final Logger LOGGER = LoggerFactory.getLogger(NodeIngestor.class);
59 private static final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\.");
60 private Map<SchemaVersion, DynamicJAXBContext> versionContextMap = new TreeMap<>();
61 private Map<SchemaVersion, Set<String>> typesPerVersion = new TreeMap<>();
62 private Map<SchemaVersion, Document> schemaPerVersion = new TreeMap<>();
63 private ConfigTranslator translator;
68 * Instantiates the NodeIngestor bean.
70 * @param translator - ConfigTranslator autowired in by Spring framework which
71 * contains the configuration information needed to ingest the desired files.
73 public NodeIngestor(ConfigTranslator translator) {
74 this.translator = translator;
75 Map<SchemaVersion, List<String>> filesToIngest = translator.getNodeFiles();
78 for (Entry<SchemaVersion, List<String>> verFiles : filesToIngest.entrySet()) {
79 SchemaVersion v = verFiles.getKey();
80 List<String> files = verFiles.getValue();
81 final DynamicJAXBContext ctx = ingest(files);
82 versionContextMap.put(v, ctx);
83 typesPerVersion.put(v, getAllNodeTypes(files));
84 schemaPerVersion.put(v, createCombinedSchema(files, v));
86 } catch (JAXBException | ParserConfigurationException | SAXException | IOException e) {
87 throw new ExceptionInInitializerError(e);
92 * Ingests the given OXM files into DynamicJAXBContext
94 * @param files - List<String> of full filenames (ie including the path) to be ingested
95 * @return DynamicJAXBContext including schema information from all given files
96 * @throws FileNotFoundException if an OXM file can't be found
97 * @throws JAXBException if there's an error creating the DynamicJAXBContext
99 private DynamicJAXBContext ingest(List<String> files) throws FileNotFoundException, JAXBException {
100 List<InputStream> streams = new ArrayList<>();
102 for (String name : files) {
103 streams.add(new FileInputStream(new File(name)));
106 Map<String, Object> properties = new HashMap<>();
107 properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, streams);
108 return DynamicJAXBContextFactory.createContextFromOXM(this.getClass().getClassLoader(), properties);
112 private Set<String> getAllNodeTypes(List<String> files) throws ParserConfigurationException, SAXException, IOException {
113 Set<String> types = new HashSet<>();
114 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
115 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
116 final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
118 ArrayList<Node> javaTypes = new ArrayList<>();
119 for (String file : files) {
120 InputStream inputStream = new FileInputStream(file);
122 final Document doc = docBuilder.parse(inputStream);
123 final NodeList list = doc.getElementsByTagName("java-type");
126 for (int i = 0; i < list.getLength(); i++) {
127 String type = list.item(i).getAttributes().getNamedItem("name").getNodeValue();
128 javaTypes.add(list.item(i));
129 types.add(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, type));
136 private Document createCombinedSchema(List<String> files, SchemaVersion v) throws ParserConfigurationException, SAXException, IOException {
137 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
138 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
139 final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
140 DocumentBuilder masterDocBuilder = docFactory.newDocumentBuilder();
141 Document combinedDoc = masterDocBuilder.parse(getShell(v));
142 NodeList masterList = combinedDoc.getElementsByTagName("java-types");
143 Node javaTypesContainer = masterList.getLength() == 0 ? combinedDoc.getDocumentElement() : masterList.item(0);
145 Multimap<String, Node> nodeMultimap = ArrayListMultimap.create();
146 LOGGER.debug("Started combining the schema from list of files {} for version {}", files, v);
148 for (String file : files) {
149 InputStream inputStream = new FileInputStream(file);
151 final Document doc = docBuilder.parse(inputStream);
152 final NodeList list = doc.getElementsByTagName("java-type");
154 for(int i = 0; i < list.getLength(); i++){
155 Node curNode = list.item(i);
156 String name = curNode.getAttributes().getNamedItem("name").getNodeValue();
157 nodeMultimap.put(name, curNode);
161 Map<String, Collection<Node>> map = nodeMultimap.asMap();
162 createNode(combinedDoc, javaTypesContainer, map);
164 LOGGER.debug("Successfully merged all schema files for version {}", v);
169 private void createNode(Document combinedDoc, Node javaTypesContainer, Map<String, Collection<Node>> map){
171 for (Entry<String, Collection<Node>> entry : map.entrySet()) {
173 List<Node> listOfNodes = (List<Node>)entry.getValue();
174 LOGGER.trace("NodeType {} Occurrences {}", entry.getKey(), listOfNodes.size());
175 Node copyOfFirstElement = null;
176 Node javaAttributeElement = null;
178 if(listOfNodes.size() > 1){
179 for(int index = 0; index < listOfNodes.size(); index++){
181 Node currentNode = listOfNodes.get(index);
182 copyOfFirstElement = combinedDoc.importNode(currentNode, true);
183 if(copyOfFirstElement.getNodeType() == Node.ELEMENT_NODE){
184 Element element = (Element) copyOfFirstElement;
185 NodeList javaAttributesList = element.getElementsByTagName("java-attributes");
186 for(int javaAttributeIndex = 0; javaAttributeIndex < javaAttributesList.getLength(); javaAttributeIndex++){
187 javaAttributeElement = javaAttributesList.item(javaAttributeIndex);
191 Node currentNode = listOfNodes.get(index);
192 Node copyOfCurrentElement = combinedDoc.importNode(currentNode, true);
193 if(copyOfCurrentElement.getNodeType() == Node.ELEMENT_NODE){
194 Element element = (Element) copyOfCurrentElement;
195 NodeList javaAttributesList = element.getElementsByTagName("java-attributes");
196 for(int javaAttributeIndex = 0; javaAttributeIndex < javaAttributesList.getLength(); javaAttributeIndex++){
197 Node jaElement = javaAttributesList.item(javaAttributeIndex);
198 NodeList xmlElementList = jaElement.getChildNodes();
199 for(int xmlElementIndex = 0; xmlElementIndex < xmlElementList.getLength(); xmlElementIndex++){
200 if(javaAttributeElement != null){
201 Node curElem = xmlElementList.item(xmlElementIndex);
203 javaAttributeElement.appendChild(curElem.cloneNode(true));
212 javaTypesContainer.appendChild(copyOfFirstElement);
213 } else if(listOfNodes.size() == 1){
214 javaTypesContainer.appendChild(combinedDoc.importNode(listOfNodes.get(0), true));
220 * Gets the DynamicJAXBContext for the given version
223 * @return DynamicJAXBContext
225 public DynamicJAXBContext getContextForVersion(SchemaVersion v) {
226 return versionContextMap.get(v);
230 * Determines if the given version contains the given node type
232 * @param nodeType - node type to check, must be in lower hyphen form (ie "type-name")
233 * @param v - schema version to check against
236 public boolean hasNodeType(String nodeType, SchemaVersion v) {
237 return typesPerVersion.get(v).contains(nodeType);
240 public Set<String> getObjectsInVersion(SchemaVersion v) {
241 return typesPerVersion.get(v);
245 * Determines if the given version contains the given node type
247 * @param nodeType - node type to check, must be in lower hyphen form (ie "type-name")
251 public Document getSchema(SchemaVersion v) {
252 return schemaPerVersion.get(v);
255 private InputStream getShell(SchemaVersion v) {
256 String source = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
257 "<xml-bindings xmlns=\"http://www.eclipse.org/eclipselink/xsds/persistence/oxm\" package-name=\"inventory.aai.onap.org." + v.toString().toLowerCase() + "\" xml-mapping-metadata-complete=\"true\">\n" +
258 " <xml-schema element-form-default=\"QUALIFIED\">\n" +
259 " <xml-ns namespace-uri=\"http://org.onap.aai.inventory/" + v.toString().toLowerCase() + "\" />\n" +
264 return new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8));
268 public SchemaVersion getVersionFromClassName(String classname) {
269 Matcher m = classNamePattern.matcher(classname);
270 String version = null;
272 version = m.group(1);
273 return new SchemaVersion(version);
275 return translator.getSchemaVersions().getDefaultVersion();