2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright © 2018 IBM.
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
23 package org.onap.aai.nodes;
25 import com.google.common.base.CaseFormat;
26 import java.io.ByteArrayInputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.nio.charset.StandardCharsets;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.List;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
37 import javax.annotation.PostConstruct;
38 import javax.xml.XMLConstants;
39 import javax.xml.bind.JAXBException;
40 import javax.xml.parsers.DocumentBuilder;
41 import javax.xml.parsers.DocumentBuilderFactory;
42 import javax.xml.parsers.ParserConfigurationException;
43 import org.eclipse.persistence.jaxb.JAXBContextProperties;
44 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
45 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
46 import org.onap.aai.setup.ConfigTranslator;
47 import org.onap.aai.setup.SchemaVersion;
48 import org.onap.aai.setup.SchemaVersions;
49 import org.onap.aai.setup.Translator;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52 import org.springframework.beans.factory.annotation.Autowired;
53 import org.springframework.context.annotation.PropertySource;
54 import org.springframework.stereotype.Component;
55 import org.w3c.dom.Document;
56 import org.w3c.dom.Node;
57 import org.w3c.dom.NodeList;
58 import org.xml.sax.SAXException;
62 * NodeIngestor - ingests A&AI OXM files per given config, serves DynamicJAXBContext per version
64 @PropertySource(value = "classpath:schema-ingest.properties", ignoreResourceNotFound = true)
65 @PropertySource(value = "file:${schema.ingest.file}", ignoreResourceNotFound = true)
66 public class NodeIngestor {
68 private static final Logger LOGGER = LoggerFactory.getLogger(NodeIngestor.class);
69 private static final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\.");
70 private Map<SchemaVersion, DynamicJAXBContext> versionContextMap = new HashMap<>();
71 private Map<SchemaVersion, Set<String>> typesPerVersion = new HashMap<>();
72 private Map<SchemaVersion, Document> schemaPerVersion = new HashMap<>();
73 private String localSchema;
74 private SchemaVersions schemaVersions;
75 private Set<Translator> translators;
77 private CaseFormatStore caseFormatStore;
78 // TODO : See if you can get rid of InputStream resets
81 * Instantiates the NodeIngestor bean.
83 * @param translatorSet
87 public NodeIngestor(Set<Translator> translatorSet) {
88 this.translators = translatorSet;
89 this.caseFormatStore = new CaseFormatStore();
93 public void initialize() {
95 for (Translator translator : translators) {
97 LOGGER.debug("Processing the translator");
98 translateAll(translator);
100 } catch (Exception e) {
101 LOGGER.error("Error while Processing the translator" + e.getMessage());
102 throw new ExceptionInInitializerError("NodeIngestor could not ingest schema");
105 if (versionContextMap.isEmpty() || schemaPerVersion.isEmpty() || typesPerVersion.isEmpty()) {
106 throw new ExceptionInInitializerError("NodeIngestor could not ingest schema");
110 private void translateAll(Translator translator) throws ExceptionInInitializerError {
111 if (translator instanceof ConfigTranslator) {
112 this.localSchema = "true";
115 Boolean retrieveLocalSchema = Boolean.parseBoolean(this.localSchema);
117 * Set this to default schemaVersion
119 this.schemaVersions = translator.getSchemaVersions();
120 List<SchemaVersion> schemaVersionList = translator.getSchemaVersions().getVersions();
123 for (SchemaVersion version : schemaVersionList) {
124 LOGGER.debug("Version being processed" + version);
125 List<InputStream> inputStreams = retrieveOXM(version, translator);
126 LOGGER.debug("Retrieved OXMs from SchemaService");
128 * IOUtils.copy and copy the inputstream
130 if (inputStreams.isEmpty()) {
134 final DynamicJAXBContext ctx = ingest(inputStreams);
135 versionContextMap.put(version, ctx);
136 setAllTypesAndProperties(version, inputStreams);
137 schemaPerVersion.put(version, createCombinedSchema(inputStreams, version, retrieveLocalSchema));
139 } catch (JAXBException | ParserConfigurationException | SAXException | IOException e) {
140 throw new ExceptionInInitializerError(e);
145 * Ingests the given OXM files into DynamicJAXBContext
147 * @param inputStreams - inputStrean of oxms from SchemaService to be ingested
149 * @return DynamicJAXBContext including schema information from all given files
151 * @throws JAXBException if there's an error creating the DynamicJAXBContext
153 private DynamicJAXBContext ingest(List<InputStream> inputStreams) throws JAXBException {
154 Map<String, Object> properties = new HashMap<>();
155 properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, inputStreams);
156 LOGGER.debug("Ingested the InputStream");
157 return DynamicJAXBContextFactory.createContextFromOXM(this.getClass().getClassLoader(), properties);
160 private void setAllTypesAndProperties(SchemaVersion version, List<InputStream> inputStreams)
161 throws ParserConfigurationException, IOException, SAXException {
162 Set<String> types = new HashSet<>();
163 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
164 docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
165 docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
166 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
167 final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
169 for (InputStream inputStream : inputStreams) {
172 final Document doc = docBuilder.parse(inputStream);
173 final NodeList list = doc.getElementsByTagName("java-type");
174 getAllNodeTypes(list, types);
175 caseFormatStore.parse(doc);
178 LOGGER.debug("Types size {}", types.size());
179 typesPerVersion.put(version, types);
182 private void getAllNodeTypes(NodeList list, Set<String> types) {
184 for (int i = 0; i < list.getLength(); i++) {
185 String type = list.item(i).getAttributes().getNamedItem("name").getNodeValue();
186 types.add(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, type));
190 private Document createCombinedSchema(List<InputStream> inputStreams, SchemaVersion version, boolean localSchema)
191 throws ParserConfigurationException, SAXException, IOException {
193 return createCombinedSchema(inputStreams, version);
196 InputStream inputStream = inputStreams.get(0);
198 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
199 docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
200 docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
201 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
202 DocumentBuilder masterDocBuilder = docFactory.newDocumentBuilder();
203 return masterDocBuilder.parse(inputStream);
206 private Document createCombinedSchema(List<InputStream> inputStreams, SchemaVersion version)
207 throws ParserConfigurationException, SAXException, IOException {
208 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
209 docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
210 docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
211 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
212 final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
213 DocumentBuilder masterDocBuilder = docFactory.newDocumentBuilder();
214 Document combinedDoc = masterDocBuilder.parse(getShell(version));
215 NodeList masterList = combinedDoc.getElementsByTagName("java-types");
216 Node javaTypesContainer = masterList.getLength() == 0 ? combinedDoc.getDocumentElement() : masterList.item(0);
218 for (InputStream inputStream : inputStreams) {
220 final Document doc = docBuilder.parse(inputStream);
221 final NodeList list = doc.getElementsByTagName("java-type");
222 for (int i = 0; i < list.getLength(); i++) {
223 Node copy = combinedDoc.importNode(list.item(i), true);
224 javaTypesContainer.appendChild(copy);
231 * Gets the DynamicJAXBContext for the given version
233 * @param v - schema version to retrieve the context
234 * @return DynamicJAXBContext
236 public DynamicJAXBContext getContextForVersion(SchemaVersion v) {
237 return versionContextMap.get(v);
241 * Determines if the given version contains the given node type
243 * @param nodeType - node type to check, must be in lower hyphen form (ie "type-name")
244 * @param v - schema version to check against
247 public boolean hasNodeType(String nodeType, SchemaVersion v) {
248 return typesPerVersion.get(v).contains(nodeType);
251 public Set<String> getObjectsInVersion(SchemaVersion v) {
252 return typesPerVersion.get(v);
256 * Determines if the given version contains the given node type
258 * @param v - Schemaversion to retrieve the schema
261 public Document getSchema(SchemaVersion v) {
262 return schemaPerVersion.get(v);
265 public SchemaVersion getVersionFromClassName(String classname) {
266 Matcher m = classNamePattern.matcher(classname);
268 String version = m.group(1);
269 return new SchemaVersion(version);
271 return this.schemaVersions.getDefaultVersion();
275 private List<InputStream> retrieveOXM(SchemaVersion version, Translator translator) throws IOException {
277 * Call Schema MS to get versions using RestTemplate or Local
279 return translator.getVersionNodeStream(version);
283 private InputStream getShell(SchemaVersion v) {
284 String source = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
285 + "<xml-bindings xmlns=\"http://www.eclipse.org/eclipselink/xsds/persistence/oxm\" package-name=\"inventory.aai.onap.org."
286 + v.toString().toLowerCase() + "\" xml-mapping-metadata-complete=\"true\">\n"
287 + " <xml-schema element-form-default=\"QUALIFIED\">\n"
288 + " <xml-ns namespace-uri=\"http://org.onap.aai.inventory/" + v.toString().toLowerCase() + "\" />\n"
289 + " </xml-schema>\n" + " <java-types>\n" + " </java-types>\n" + "</xml-bindings>";
290 return new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8));
293 public CaseFormatStore getCaseFormatStore() {
294 return caseFormatStore;