Integrate aai-schema-ingest library into aai-core
[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-18 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
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.aai.nodes;
22
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileNotFoundException;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.util.*;
29 import java.io.ByteArrayInputStream;
30 import java.nio.charset.StandardCharsets;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Map.Entry;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
39
40 import javax.xml.XMLConstants;
41 import javax.xml.bind.JAXBException;
42 import javax.xml.parsers.DocumentBuilder;
43 import javax.xml.parsers.DocumentBuilderFactory;
44 import javax.xml.parsers.ParserConfigurationException;
45
46 import org.eclipse.persistence.jaxb.JAXBContextProperties;
47 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
48 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
49
50 import org.onap.aai.setup.ConfigTranslator;
51 import org.onap.aai.setup.SchemaVersion;
52 import org.springframework.beans.factory.annotation.Autowired;
53 import org.springframework.stereotype.Component;
54 import org.w3c.dom.Document;
55 import org.w3c.dom.Node;
56 import org.w3c.dom.NodeList;
57 import org.xml.sax.SAXException;
58
59 import com.google.common.base.CaseFormat;
60
61 @Component
62 /**
63  * NodeIngestor - ingests A&AI OXM files per given config, serves DynamicJAXBContext per version
64  */
65 public class NodeIngestor {
66
67
68         private Map<SchemaVersion, DynamicJAXBContext> versionContextMap = new TreeMap<>();
69         private Map<SchemaVersion, Set<String>> typesPerVersion = new TreeMap<>();
70         private Map<SchemaVersion, Document> schemaPerVersion = new TreeMap<>();
71         private static final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\.");
72
73         private ConfigTranslator translator;
74
75
76         @Autowired
77         /**
78          * Instantiates the NodeIngestor bean.
79          *
80          * @param translator - ConfigTranslator autowired in by Spring framework which
81          * contains the configuration information needed to ingest the desired files.
82          */
83         public NodeIngestor(ConfigTranslator translator) {
84                 this.translator = translator;
85                 Map<SchemaVersion, List<String>> filesToIngest = translator.getNodeFiles();
86
87                 try {
88                         for (Entry<SchemaVersion, List<String>> verFiles : filesToIngest.entrySet()) {
89                                 SchemaVersion v = verFiles.getKey();
90                                 List<String> files = verFiles.getValue();
91                                 final DynamicJAXBContext ctx = ingest(files);
92                                 versionContextMap.put(v, ctx);
93                                 typesPerVersion.put(v, getAllNodeTypes(files));
94                                 schemaPerVersion.put(v, createCombinedSchema(files, v));
95                         }
96                 } catch (JAXBException | ParserConfigurationException | SAXException | IOException e) {
97                         throw new ExceptionInInitializerError(e);
98                 }
99         }
100
101         /**
102          * Ingests the given OXM files into DynamicJAXBContext
103          *
104          * @param files - List<String> of full filenames (ie including the path) to be ingested
105          *
106          * @return DynamicJAXBContext including schema information from all given files
107          *
108          * @throws FileNotFoundException if an OXM file can't be found
109          * @throws JAXBException if there's an error creating the DynamicJAXBContext
110          */
111         private DynamicJAXBContext ingest(List<String> files) throws FileNotFoundException, JAXBException {
112                 List<InputStream> streams = new ArrayList<>();
113
114                 for (String name : files) {
115                         streams.add(new FileInputStream(new File(name)));
116                 }
117
118                 Map<String, Object> properties = new HashMap<>();
119                 properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, streams);
120                 return DynamicJAXBContextFactory.createContextFromOXM(this.getClass().getClassLoader(), properties);
121         }
122
123
124
125         private Set<String> getAllNodeTypes(List<String> files) throws ParserConfigurationException, SAXException, IOException {
126                 Set<String> types = new HashSet<>();
127                 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
128                 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
129                 final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
130
131                 ArrayList<Node> javaTypes = new ArrayList<Node>();
132                 for (String file : files) {
133                         InputStream inputStream = new FileInputStream(file);
134
135                         final Document doc = docBuilder.parse(inputStream);
136                         final NodeList list = doc.getElementsByTagName("java-type");
137
138                         for (int i = 0; i < list.getLength(); i++) {
139                                 String type = list.item(i).getAttributes().getNamedItem("name").getNodeValue();
140                                 javaTypes.add(list.item(i));
141                                 types.add(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, type));
142                         }
143                 }
144
145                 return types;
146         }
147         
148         private Document createCombinedSchema(List<String> files,SchemaVersion v) throws ParserConfigurationException, SAXException, IOException {
149                 final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
150                 docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
151                 final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
152                 DocumentBuilder masterDocBuilder = docFactory.newDocumentBuilder();
153                 Document combinedDoc = masterDocBuilder.parse(getShell(v));
154                 NodeList masterList = combinedDoc.getElementsByTagName("java-types");
155                 Node javaTypesContainer = masterList.getLength() == 0 ? combinedDoc.getDocumentElement() : masterList.item(0);
156                 for (String file : files) {
157                         InputStream inputStream = new FileInputStream(file);
158                         
159                         final Document doc = docBuilder.parse(inputStream);
160                         final NodeList list = doc.getElementsByTagName("java-type");
161                         for (int i = 0; i < list.getLength(); i++) {
162                                 Node copy = combinedDoc.importNode(list.item(i),true);
163                                 javaTypesContainer.appendChild(copy);
164                         }
165                 }               
166                 return combinedDoc;
167         }
168
169         /**
170          * Gets the DynamicJAXBContext for the given version
171          *
172          * @param v
173          * @return DynamicJAXBContext
174          */
175         public DynamicJAXBContext getContextForVersion(SchemaVersion v) {
176                 return versionContextMap.get(v);
177         }
178
179         /**
180          * Determines if the given version contains the given node type
181          *
182          * @param nodeType - node type to check, must be in lower hyphen form (ie "type-name")
183          * @param v - schema version to check against
184          * @return
185          */
186         public boolean hasNodeType(String nodeType, SchemaVersion v) {
187                 return typesPerVersion.get(v).contains(nodeType);
188         }
189
190         public Set<String> getObjectsInVersion(SchemaVersion v){
191                 return typesPerVersion.get(v);
192         }
193         /**
194          * Determines if the given version contains the given node type
195          * 
196          * @param String nodeType - node type to check, must be in lower hyphen form (ie "type-name")
197          * @param v
198          * @return
199          */
200         public Document getSchema(SchemaVersion v) {
201                 return schemaPerVersion.get(v);
202         }
203         
204         private InputStream getShell(SchemaVersion v) {
205                 String source = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 
206                                 "<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" + 
207                                 "       <xml-schema element-form-default=\"QUALIFIED\">\n" + 
208                                 "               <xml-ns namespace-uri=\"http://org.onap.aai.inventory/"+v.toString().toLowerCase()+"\" />\n" + 
209                                 "       </xml-schema>\n" + 
210                                 "       <java-types>\n" + 
211                                 "       </java-types>\\n" + 
212                                 "</xml-bindings>";
213 //              source.rep.replace("v11", v.toString());
214                 return new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8));
215         }
216                 
217
218         public SchemaVersion getVersionFromClassName (String classname) {
219                 Matcher m = classNamePattern.matcher(classname);
220                 String version = null;
221                 if (m.find()) {
222                         version = m.group(1);
223                         return new SchemaVersion(version);
224                 } else {
225                     return translator.getSchemaVersions().getDefaultVersion();
226                 }
227         }
228 }
229