Fix all blocker sonar issues and some checkstyle
[aai/aai-common.git] / aai-schema-ingest / src / main / java / org / onap / aai / nodes / NodeIngestor.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
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
12  *
13  *    http://www.apache.org/licenses/LICENSE-2.0
14  *
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=========================================================
21  */
22
23 package org.onap.aai.nodes;
24
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;
33 import java.util.Map;
34 import java.util.Set;
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;
59
60 @Component
61 /*
62  * NodeIngestor - ingests A&AI OXM files per given config, serves DynamicJAXBContext per version
63  */
64 @PropertySource(value = "classpath:schema-ingest.properties", ignoreResourceNotFound = true)
65 @PropertySource(value = "file:${schema.ingest.file}", ignoreResourceNotFound = true)
66 public class NodeIngestor {
67
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;
76
77     private CaseFormatStore caseFormatStore;
78     // TODO : See if you can get rid of InputStream resets
79
80     /**
81      * Instantiates the NodeIngestor bean.
82      *
83      * @param translatorSet
84      */
85
86     @Autowired
87     public NodeIngestor(Set<Translator> translatorSet) {
88         this.translators = translatorSet;
89         this.caseFormatStore = new CaseFormatStore();
90     }
91
92     @PostConstruct
93     public void initialize() {
94
95         for (Translator translator : translators) {
96             try {
97                 LOGGER.debug("Processing the translator");
98                 translateAll(translator);
99
100             } catch (Exception e) {
101                 LOGGER.error("Error while Processing the translator" + e.getMessage());
102                 throw new ExceptionInInitializerError("NodeIngestor could not ingest schema");
103             }
104         }
105         if (versionContextMap.isEmpty() || schemaPerVersion.isEmpty() || typesPerVersion.isEmpty()) {
106             throw new ExceptionInInitializerError("NodeIngestor could not ingest schema");
107         }
108     }
109
110     private void translateAll(Translator translator) throws ExceptionInInitializerError {
111         if (translator instanceof ConfigTranslator) {
112             this.localSchema = "true";
113         }
114
115         Boolean retrieveLocalSchema = Boolean.parseBoolean(this.localSchema);
116         /*
117          * Set this to default schemaVersion
118          */
119         this.schemaVersions = translator.getSchemaVersions();
120         List<SchemaVersion> schemaVersionList = translator.getSchemaVersions().getVersions();
121
122         try {
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");
127                 /*
128                  * IOUtils.copy and copy the inputstream
129                  */
130                 if (inputStreams.isEmpty()) {
131                     continue;
132                 }
133
134                 final DynamicJAXBContext ctx = ingest(inputStreams);
135                 versionContextMap.put(version, ctx);
136                 setAllTypesAndProperties(version, inputStreams);
137                 schemaPerVersion.put(version, createCombinedSchema(inputStreams, version, retrieveLocalSchema));
138             }
139         } catch (JAXBException | ParserConfigurationException | SAXException | IOException e) {
140             throw new ExceptionInInitializerError(e);
141         }
142     }
143
144     /**
145      * Ingests the given OXM files into DynamicJAXBContext
146      *
147      * @param inputStreams - inputStrean of oxms from SchemaService to be ingested
148      *
149      * @return DynamicJAXBContext including schema information from all given files
150      *
151      * @throws JAXBException if there's an error creating the DynamicJAXBContext
152      */
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);
158     }
159
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();
168
169         for (InputStream inputStream : inputStreams) {
170             // TODO Change this
171             inputStream.reset();
172             final Document doc = docBuilder.parse(inputStream);
173             final NodeList list = doc.getElementsByTagName("java-type");
174             getAllNodeTypes(list, types);
175             caseFormatStore.parse(doc);
176         }
177
178         LOGGER.debug("Types size {}", types.size());
179         typesPerVersion.put(version, types);
180     }
181
182     private void getAllNodeTypes(NodeList list, Set<String> types) {
183
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));
187         }
188     }
189
190     private Document createCombinedSchema(List<InputStream> inputStreams, SchemaVersion version, boolean localSchema)
191             throws ParserConfigurationException, SAXException, IOException {
192         if (localSchema) {
193             return createCombinedSchema(inputStreams, version);
194         }
195
196         InputStream inputStream = inputStreams.get(0);
197         inputStream.reset();
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);
204     }
205
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);
217
218         for (InputStream inputStream : inputStreams) {
219             inputStream.reset();
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);
225             }
226         }
227         return combinedDoc;
228     }
229
230     /**
231      * Gets the DynamicJAXBContext for the given version
232      *
233      * @param v - schema version to retrieve the context
234      * @return DynamicJAXBContext
235      */
236     public DynamicJAXBContext getContextForVersion(SchemaVersion v) {
237         return versionContextMap.get(v);
238     }
239
240     /**
241      * Determines if the given version contains the given node type
242      *
243      * @param nodeType - node type to check, must be in lower hyphen form (ie "type-name")
244      * @param v - schema version to check against
245      * @return boolean
246      */
247     public boolean hasNodeType(String nodeType, SchemaVersion v) {
248         return typesPerVersion.get(v).contains(nodeType);
249     }
250
251     public Set<String> getObjectsInVersion(SchemaVersion v) {
252         return typesPerVersion.get(v);
253     }
254
255     /**
256      * Determines if the given version contains the given node type
257      *
258      * @param v - Schemaversion to retrieve the schema
259      * @return Document
260      */
261     public Document getSchema(SchemaVersion v) {
262         return schemaPerVersion.get(v);
263     }
264
265     public SchemaVersion getVersionFromClassName(String classname) {
266         Matcher m = classNamePattern.matcher(classname);
267         if (m.find()) {
268             String version = m.group(1);
269             return new SchemaVersion(version);
270         } else {
271             return this.schemaVersions.getDefaultVersion();
272         }
273     }
274
275     private List<InputStream> retrieveOXM(SchemaVersion version, Translator translator) throws IOException {
276         /*
277          * Call Schema MS to get versions using RestTemplate or Local
278          */
279         return translator.getVersionNodeStream(version);
280
281     }
282
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));
291     }
292
293     public CaseFormatStore getCaseFormatStore() {
294         return caseFormatStore;
295     }
296 }