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.att.eelf.configuration.EELFLogger;
26 import com.att.eelf.configuration.EELFManager;
27 import com.google.common.base.CaseFormat;
28 import org.eclipse.persistence.jaxb.JAXBContextProperties;
29 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
30 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
31 import org.onap.aai.setup.ConfigTranslator;
32 import org.onap.aai.setup.SchemaVersion;
33 import org.onap.aai.setup.SchemaVersions;
34 import org.onap.aai.setup.Translator;
35 import org.springframework.beans.factory.annotation.Autowired;
36 import org.springframework.context.annotation.PropertySource;
37 import org.springframework.stereotype.Component;
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Node;
40 import org.w3c.dom.NodeList;
41 import org.xml.sax.SAXException;
43 import javax.annotation.PostConstruct;
44 import javax.xml.XMLConstants;
45 import javax.xml.bind.JAXBException;
46 import javax.xml.parsers.DocumentBuilder;
47 import javax.xml.parsers.DocumentBuilderFactory;
48 import javax.xml.parsers.ParserConfigurationException;
50 import java.nio.charset.StandardCharsets;
52 import java.util.regex.Matcher;
53 import java.util.regex.Pattern;
57 NodeIngestor - ingests A&AI OXM files per given config, serves DynamicJAXBContext per version
59 @PropertySource(value = "classpath:schema-ingest.properties", ignoreResourceNotFound=true)
60 @PropertySource(value = "file:${schema.ingest.file}", ignoreResourceNotFound=true)
61 public class NodeIngestor {
63 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(NodeIngestor.class);
64 private static final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\.");
65 Map<SchemaVersion, List<String>> filesToIngest;
66 private Map<SchemaVersion, DynamicJAXBContext> versionContextMap = new TreeMap<>();
67 private Map<SchemaVersion, Set<String>> typesPerVersion = new TreeMap<>();
68 private Map<SchemaVersion, Document> schemaPerVersion = new TreeMap<>();
69 private String localSchema;
70 private SchemaVersions schemaVersions;
71 private Set<Translator> translators;
73 //TODO : See if you can get rid of InputStream resets
75 * Instantiates the NodeIngestor bean.
77 * @param - ConfigTranslator autowired in by Spring framework which
78 * contains the configuration information needed to ingest the desired files.
82 public NodeIngestor(Set<Translator> translatorSet) {
83 LOGGER.debug("Local Schema files will be fetched");
84 this.translators = translatorSet;
88 public void initialize() {
90 for (Translator translator : translators) {
92 LOGGER.debug("Processing the translator");
93 translateAll(translator);
95 } catch (Exception e) {
96 LOGGER.info("Error while Processing the translator" + e.getMessage());
100 if (versionContextMap.isEmpty() || schemaPerVersion.isEmpty() || typesPerVersion.isEmpty()) {
101 throw new ExceptionInInitializerError("NodeIngestor could not ingest schema");
105 private void translateAll(Translator translator) throws ExceptionInInitializerError {
106 if (translator instanceof ConfigTranslator) {
107 this.localSchema = "true";
110 Boolean retrieveLocalSchema = Boolean.parseBoolean(this.localSchema);
112 * Set this to default schemaVersion
114 this.schemaVersions = translator.getSchemaVersions();
115 List<SchemaVersion> schemaVersionList = translator.getSchemaVersions().getVersions();
118 for (SchemaVersion version : schemaVersionList) {
119 LOGGER.debug("Version being processed" + version);
120 List<InputStream> inputStreams = retrieveOXM(version, translator);
121 LOGGER.debug("Retrieved OXMs from SchemaService");
123 IOUtils.copy and copy the inputstream
125 if (inputStreams.isEmpty()) {
129 final DynamicJAXBContext ctx = ingest(inputStreams);
130 versionContextMap.put(version, ctx);
131 typesPerVersion.put(version, getAllNodeTypes(inputStreams));
132 schemaPerVersion.put(version, createCombinedSchema(inputStreams, version, retrieveLocalSchema));
134 } catch (JAXBException | ParserConfigurationException | SAXException | IOException e) {
135 throw new ExceptionInInitializerError(e);
140 * Ingests the given OXM files into DynamicJAXBContext
142 * @param inputStreams - inputStrean of oxms from SchemaService to be ingested
144 * @return DynamicJAXBContext including schema information from all given files
146 * @throws JAXBException if there's an error creating the DynamicJAXBContext
148 private DynamicJAXBContext ingest(List<InputStream> inputStreams) throws JAXBException {
149 Map<String, Object> properties = new HashMap<>();
150 properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, inputStreams);
151 LOGGER.debug("Ingested the InputStream");
152 return DynamicJAXBContextFactory.createContextFromOXM(this.getClass().getClassLoader(), properties);
155 private Set<String> getAllNodeTypes(List<InputStream> inputStreams) throws ParserConfigurationException, SAXException, IOException {
156 //Reset the InputStream to reset the offset to inital position
157 Set<String> types = new HashSet<>();
158 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
159 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
160 final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
162 for (InputStream inputStream : inputStreams) {
165 final Document doc = docBuilder.parse(inputStream);
166 final NodeList list = doc.getElementsByTagName("java-type");
168 for (int i = 0; i < list.getLength(); i++) {
169 String type = list.item(i).getAttributes().getNamedItem("name").getNodeValue();
170 types.add(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, type));
174 LOGGER.debug("Types size" + types.size());
178 private Document createCombinedSchema(List<InputStream> inputStreams, SchemaVersion version, boolean localSchema) throws ParserConfigurationException, SAXException, IOException {
180 return createCombinedSchema(inputStreams, version);
183 InputStream inputStream = inputStreams.get(0);
185 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
186 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
187 DocumentBuilder masterDocBuilder = docFactory.newDocumentBuilder();
188 return masterDocBuilder.parse(inputStream);
191 private Document createCombinedSchema(List<InputStream> inputStreams, SchemaVersion version) throws ParserConfigurationException, SAXException, IOException {
192 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
193 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
194 final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
195 DocumentBuilder masterDocBuilder = docFactory.newDocumentBuilder();
196 Document combinedDoc = masterDocBuilder.parse(getShell(version));
197 NodeList masterList = combinedDoc.getElementsByTagName("java-types");
198 Node javaTypesContainer = masterList.getLength() == 0 ? combinedDoc.getDocumentElement() : masterList.item(0);
200 for (InputStream inputStream : inputStreams) {
202 final Document doc = docBuilder.parse(inputStream);
203 final NodeList list = doc.getElementsByTagName("java-type");
204 for (int i = 0; i < list.getLength(); i++) {
205 Node copy = combinedDoc.importNode(list.item(i), true);
206 javaTypesContainer.appendChild(copy);
213 * Gets the DynamicJAXBContext for the given version
215 * @param v - schema version to retrieve the context
216 * @return DynamicJAXBContext
218 public DynamicJAXBContext getContextForVersion(SchemaVersion v) {
219 return versionContextMap.get(v);
223 * Determines if the given version contains the given node type
225 * @param nodeType - node type to check, must be in lower hyphen form (ie "type-name")
226 * @param v - schema version to check against
229 public boolean hasNodeType(String nodeType, SchemaVersion v) {
230 return typesPerVersion.get(v).contains(nodeType);
233 public Set<String> getObjectsInVersion(SchemaVersion v) {
234 return typesPerVersion.get(v);
238 * Determines if the given version contains the given node type
240 * @param v - Schemaversion to retrieve the schema
243 public Document getSchema(SchemaVersion v) {
244 return schemaPerVersion.get(v);
248 public SchemaVersion getVersionFromClassName(String classname) {
249 Matcher m = classNamePattern.matcher(classname);
251 String version = m.group(1);
252 return new SchemaVersion(version);
254 return this.schemaVersions.getDefaultVersion();
258 private List<InputStream> retrieveOXM(SchemaVersion version, Translator translator) throws IOException {
260 Call Schema MS to get versions using RestTemplate or Local
262 return translator.getVersionNodeStream(version);
266 private InputStream getShell(SchemaVersion v) {
267 String source = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
268 "<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" +
269 " <xml-schema element-form-default=\"QUALIFIED\">\n" +
270 " <xml-ns namespace-uri=\"http://org.onap.aai.inventory/" + v.toString().toLowerCase() + "\" />\n" +
275 return new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8));