Add the nodes endpoint to the schema service 48/75848/1
authorKajur, Harish (vk250x) <vk250x@att.com>
Wed, 16 Jan 2019 03:46:04 +0000 (22:46 -0500)
committerKajur, Harish (vk250x) <vk250x@att.com>
Wed, 16 Jan 2019 03:46:34 +0000 (22:46 -0500)
Issue-ID: AAI-1861
Change-Id: I33cf346f1c2a8875945631e437636f65d76a75c8
Signed-off-by: Kajur, Harish (vk250x) <vk250x@att.com>
21 files changed:
aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/AAIConfigTranslator.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/AuthorizationConfiguration.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/ConfigTranslator.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/SchemaConfiguration.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/SchemaLocationsBean.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/NodeIngestor.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/NodeSchemaResource.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/NodeSchemaService.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/SchemaVersion.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/SchemaVersions.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/AAISchemaValidationException.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/CheckEverythingStrategy.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/DefaultDuplicateNodeDefinitionValidationModule.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/DefaultVersionValidationModule.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/DuplicateNodeDefinitionValidationModule.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/FailFastStrategy.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/NodeValidator.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/SchemaErrorStrategy.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/VersionValidationModule.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/VersionValidator.java [new file with mode: 0644]
aai-schema-service/src/main/java/org/onap/aai/schemaservice/web/JerseyConfiguration.java

diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/AAIConfigTranslator.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/AAIConfigTranslator.java
new file mode 100644 (file)
index 0000000..51417b4
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.config;
+
+import org.onap.aai.schemaservice.nodeschema.SchemaVersion;
+import org.onap.aai.schemaservice.nodeschema.SchemaVersions;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * <b>AAIConfigTranslator</b> is responsible for looking at the
+ * schema files and edge files based on the available versions
+ * Also has the ability to exclude them based on the node.exclusion.pattern
+ */
+public class AAIConfigTranslator extends ConfigTranslator {
+
+    private static final String FILESEP = (System.getProperty("file.separator") == null) ? "/" : System.getProperty("file.separator");
+
+    public AAIConfigTranslator(SchemaLocationsBean bean, SchemaVersions schemaVersions) {
+               super(bean, schemaVersions);
+       }
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.setup.ConfigTranslator#getNodeFiles()
+        */
+       @Override
+       public Map<SchemaVersion, List<String>> getNodeFiles() {
+
+               Map<SchemaVersion, List<String>> files = new TreeMap<>();
+               for (SchemaVersion v : schemaVersions.getVersions()) {
+                       List<String> container = getVersionNodeFiles(v);
+                       files.put(v, container);
+               }
+
+               return files;
+       }
+
+
+       private List<String> getVersionNodeFiles(SchemaVersion v) {
+
+           return getVersionFiles(
+               bean.getNodeDirectory(),
+                       v,
+                       () -> bean.getNodesInclusionPattern().stream(),
+                       () -> bean.getNodesExclusionPattern().stream()
+               );
+       }
+
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.setup.ConfigTranslator#getEdgeFiles()
+        */
+       @Override
+       public Map<SchemaVersion, List<String>> getEdgeFiles() {
+
+               Map<SchemaVersion, List<String>> files = new TreeMap<>();
+               for (SchemaVersion v : schemaVersions.getVersions()) {
+                       List<String> container = getVersionEdgeFiles(v);
+                       files.put(v, container);
+               }
+
+               return files;
+       }
+
+       private List<String> getVersionEdgeFiles(SchemaVersion v) {
+
+               return getVersionFiles(
+                               bean.getEdgeDirectory(),
+                               v,
+                               () -> bean.getEdgesInclusionPattern().stream(),
+                               () -> bean.getEdgesExclusionPattern().stream()
+               );
+       }
+
+       private List<String> getVersionFiles(
+                       String startDirectory,
+                       SchemaVersion schemaVersion,
+                       Supplier<Stream<String>> inclusionPattern,
+                       Supplier<Stream<String>> exclusionPattern
+       ){
+
+               List<String> container;
+               final String directoryName = startDirectory + FILESEP + schemaVersion.toString() + FILESEP;
+
+               container = Arrays.stream(new File(directoryName).listFiles())
+                               .map(File::getName)
+                               .filter(name -> inclusionPattern.get().anyMatch(name::matches))
+                               .map(name -> directoryName + name)
+                               .filter(name -> exclusionPattern.get().noneMatch(name::matches))
+                               .collect(Collectors.toList());
+
+               return container;
+       }
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/AuthorizationConfiguration.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/AuthorizationConfiguration.java
new file mode 100644 (file)
index 0000000..76dd084
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.config;
+
+import org.onap.aai.auth.AAIAuthCore;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+@Profile("two-way-ssl")
+@Configuration
+public class AuthorizationConfiguration {
+
+    @Value("${schema.uri.base.path}")
+    private String basePath;
+
+    @Bean
+    public AAIAuthCore aaiAuthCore(){
+        return new AAIAuthCore(basePath);
+    }
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/ConfigTranslator.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/ConfigTranslator.java
new file mode 100644 (file)
index 0000000..a177c6d
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.config;
+
+import org.onap.aai.schemaservice.nodeschema.SchemaVersion;
+import org.onap.aai.schemaservice.nodeschema.SchemaVersions;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Converts the contents of the schema config file
+ * (which lists which schema files to be loaded) to
+ * the format the Ingestors can work with.
+ *
+ */
+public abstract class ConfigTranslator {
+       protected SchemaLocationsBean bean;
+       protected SchemaVersions schemaVersions;
+
+       @Autowired
+       public ConfigTranslator(SchemaLocationsBean schemaLocationbean, SchemaVersions schemaVersions) {
+               this.bean = schemaLocationbean;
+               this.schemaVersions = schemaVersions;
+       }
+
+       /**
+        * Translates the contents of the schema config file
+        * into the input for the NodeIngestor
+        *
+        * @return Map of Version to the list of (string) filenames to be
+        * ingested for that version
+        */
+       public abstract Map<SchemaVersion, List<String>> getNodeFiles();
+
+       /**
+        * Translates the contents of the schema config file
+        * into the input for the EdgeIngestor
+        *
+        * @return Map of Version to the List of (String) filenames to be
+        * ingested for that version
+        */
+       public abstract Map<SchemaVersion, List<String>> getEdgeFiles();
+
+       public SchemaVersions getSchemaVersions(){
+               return schemaVersions;
+       }
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/SchemaConfiguration.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/SchemaConfiguration.java
new file mode 100644 (file)
index 0000000..390525b
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.config;
+
+import org.onap.aai.schemaservice.nodeschema.NodeIngestor;
+import org.onap.aai.schemaservice.nodeschema.SchemaVersions;
+import org.onap.aai.schemaservice.nodeschema.validation.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SchemaConfiguration {
+
+    @Bean(name = "nodeIngestor")
+    public NodeIngestor nodeIngestor(ConfigTranslator configTranslator) {
+        return new NodeIngestor(configTranslator);
+    }
+
+    @Bean(name = "configTranslator")
+    public ConfigTranslator configTranslator(SchemaLocationsBean schemaLocationsBean, SchemaVersions schemaVersions) {
+        return new AAIConfigTranslator(schemaLocationsBean, schemaVersions);
+    }
+
+    @Bean
+    public SchemaErrorStrategy schemaErrorStrategy() {
+        return new CheckEverythingStrategy();
+    }
+
+    @Bean
+    public DuplicateNodeDefinitionValidationModule duplicateNodeDefinitionValidationModule() {
+        return new DefaultDuplicateNodeDefinitionValidationModule();
+    }
+
+    @Bean
+    public NodeValidator nodeValidator(
+        ConfigTranslator configTranslator,
+        SchemaErrorStrategy schemaErrorStrategy,
+        DuplicateNodeDefinitionValidationModule duplicateNodeDefinitionValidationModule
+    ) {
+        return new NodeValidator(configTranslator, schemaErrorStrategy, duplicateNodeDefinitionValidationModule);
+    }
+
+    @Bean
+    public SchemaLocationsBean schemaLocationsBean() {
+        return new SchemaLocationsBean();
+    }
+
+    @Bean
+    public SchemaVersions schemaVersions() {
+        return new SchemaVersions();
+    }
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/SchemaLocationsBean.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/config/SchemaLocationsBean.java
new file mode 100644 (file)
index 0000000..e24aa78
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
+
+import java.util.List;
+
+@Configuration
+@PropertySource(value = "classpath:schema-ingest.properties", ignoreResourceNotFound=true)
+@PropertySource(value = "file:${schema.ingest.file}", ignoreResourceNotFound=true)
+public class SchemaLocationsBean {
+       /*
+        * Per Spring documentation, the last PropertySource that works will
+        * be applied. Here, schema.ingest.file will be an environment variable
+        * set on install that tells Spring where to look for the schema
+        * ingest properties file (and the actual filename), but the former
+        * PropertySource gives the default of looking on the classpath for
+        * schema-ingest.properties in case that second one doesn't work.
+        *
+        * The schema-ingest.properties file (or its equivalent if you choose
+        * to name it otherwise) must contain the entries the below @Value
+        * annotations are looking for.
+        */
+
+       @Value("${schema.configuration.location}")
+       private String schemaConfigLoc;
+
+       @Value("${schema.nodes.location}")
+       private String nodeDirectory;
+
+       @Value("${schema.edges.location}")
+       private String edgeDirectory;
+
+       @Value("${schema.nodes.inclusion.list:}#{T(java.util.Arrays).asList(\".*oxm(.*).xml\")}")
+       private List<String> nodesInclusionPattern;
+
+       @Value("${schema.nodes.exclusion.list:}#{T(java.util.Collections).emptyList()}")
+       private List<String> nodesExclusionPattern;
+
+       @Value("${schema.edges.inclusion.list:}#{T(java.util.Arrays).asList(\"DbEdgeRules_.*.json\")}")
+       private List<String> edgesInclusionPattern;
+
+       @Value("${schema.edges.exclusion.list:}#{T(java.util.Collections).emptyList()}")
+       private List<String> edgesExclusionPattern;
+
+       /**
+        * @return the file name/location with the list of schema files to be ingested
+        */
+       public String getSchemaConfigLocation() {
+               return schemaConfigLoc;
+       }
+
+       /**
+        * Sets the name/location of the file with the list of schema files to ingest
+        *
+        * @param schemaConfigLoc - the file name/location
+        */
+       public void setSchemaConfigLocation(String schemaConfigLoc) {
+               this.schemaConfigLoc = schemaConfigLoc;
+       }
+
+       /**
+        * @return the location of the OXM files
+        */
+       public String getNodeDirectory() {
+               return nodeDirectory;
+       }
+
+       /**
+        * Sets the location of the OXM files
+        *
+        * @param nodeDirectory - the location of the OXM files
+        */
+       public void setNodeDirectory(String nodeDirectory) {
+               this.nodeDirectory = nodeDirectory;
+       }
+
+       /**
+        * @return the location of the edge rule json files
+        */
+       public String getEdgeDirectory() {
+               return edgeDirectory;
+       }
+
+       /**
+        * Sets the location of the edge rule json files
+        *
+        * @param edgeDirectory - the location of the edge rule files
+        */
+       public void setEdgeDirectory(String edgeDirectory) {
+               this.edgeDirectory = edgeDirectory;
+       }
+
+       public List<String> getNodesExclusionPattern(){
+               return this.nodesExclusionPattern;
+       }
+
+       public List<String> getNodesInclusionPattern(){
+               return this.nodesInclusionPattern;
+       }
+
+       public List<String> getEdgesExclusionPattern(){
+               return this.edgesExclusionPattern;
+       }
+
+       public List<String> getEdgesInclusionPattern(){
+               return this.edgesInclusionPattern;
+       }
+
+       //this allows the code to actually read the value from the config file
+       //without this those strings get set to literally "${edgeDir}" etc
+       @Bean
+       public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
+               return new PropertySourcesPlaceholderConfigurer();
+       }
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/NodeIngestor.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/NodeIngestor.java
new file mode 100644 (file)
index 0000000..e372c2a
--- /dev/null
@@ -0,0 +1,279 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.CaseFormat;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import org.eclipse.persistence.jaxb.JAXBContextProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
+import org.onap.aai.schemaservice.config.ConfigTranslator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * NodeIngestor - ingests A&AI OXM files per given config, serves DynamicJAXBContext per version
+ */
+@Component
+public class NodeIngestor {
+
+    private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(NodeIngestor.class);
+
+    private static final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\.");
+    private Map<SchemaVersion, DynamicJAXBContext> versionContextMap = new TreeMap<>();
+    private Map<SchemaVersion, Set<String>> typesPerVersion = new TreeMap<>();
+    private Map<SchemaVersion, Document> schemaPerVersion = new TreeMap<>();
+    private ConfigTranslator translator;
+
+
+    @Autowired
+    /**
+     * Instantiates the NodeIngestor bean.
+     *
+     * @param translator - ConfigTranslator autowired in by Spring framework which
+     * contains the configuration information needed to ingest the desired files.
+     */
+    public NodeIngestor(ConfigTranslator translator) {
+        this.translator = translator;
+        Map<SchemaVersion, List<String>> filesToIngest = translator.getNodeFiles();
+
+        try {
+            for (Entry<SchemaVersion, List<String>> verFiles : filesToIngest.entrySet()) {
+                SchemaVersion v = verFiles.getKey();
+                List<String> files = verFiles.getValue();
+                final DynamicJAXBContext ctx = ingest(files);
+                versionContextMap.put(v, ctx);
+                typesPerVersion.put(v, getAllNodeTypes(files));
+                schemaPerVersion.put(v, createCombinedSchema(files, v));
+            }
+        } catch (JAXBException | ParserConfigurationException | SAXException | IOException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    /**
+     * Ingests the given OXM files into DynamicJAXBContext
+     *
+     * @param files - List<String> of full filenames (ie including the path) to be ingested
+     * @return DynamicJAXBContext including schema information from all given files
+     * @throws FileNotFoundException if an OXM file can't be found
+     * @throws JAXBException         if there's an error creating the DynamicJAXBContext
+     */
+    private DynamicJAXBContext ingest(List<String> files) throws FileNotFoundException, JAXBException {
+        List<InputStream> streams = new ArrayList<>();
+
+        for (String name : files) {
+            streams.add(new FileInputStream(new File(name)));
+        }
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, streams);
+        return DynamicJAXBContextFactory.createContextFromOXM(this.getClass().getClassLoader(), properties);
+    }
+
+
+    private Set<String> getAllNodeTypes(List<String> files) throws ParserConfigurationException, SAXException, IOException {
+        Set<String> types = new HashSet<>();
+        final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+        docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+
+        ArrayList<Node> javaTypes = new ArrayList<>();
+        for (String file : files) {
+            InputStream inputStream = new FileInputStream(file);
+
+            final Document doc = docBuilder.parse(inputStream);
+            final NodeList list = doc.getElementsByTagName("java-type");
+
+
+            for (int i = 0; i < list.getLength(); i++) {
+                String type = list.item(i).getAttributes().getNamedItem("name").getNodeValue();
+                javaTypes.add(list.item(i));
+                types.add(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, type));
+            }
+        }
+
+        return types;
+    }
+
+    private Document createCombinedSchema(List<String> files, SchemaVersion v) throws ParserConfigurationException, SAXException, IOException {
+        final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+        docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+        DocumentBuilder masterDocBuilder = docFactory.newDocumentBuilder();
+        Document combinedDoc = masterDocBuilder.parse(getShell(v));
+        NodeList masterList = combinedDoc.getElementsByTagName("java-types");
+        Node javaTypesContainer = masterList.getLength() == 0 ? combinedDoc.getDocumentElement() : masterList.item(0);
+
+        Multimap<String, Node> nodeMultimap = ArrayListMultimap.create();
+        LOGGER.debug("Started combining the schema from list of files {} for version {}", files, v);
+
+        for (String file : files) {
+            InputStream inputStream = new FileInputStream(file);
+
+            final Document doc = docBuilder.parse(inputStream);
+            final NodeList list = doc.getElementsByTagName("java-type");
+
+            for(int i = 0; i < list.getLength(); i++){
+                Node curNode = list.item(i);
+                String name = curNode.getAttributes().getNamedItem("name").getNodeValue();
+                nodeMultimap.put(name, curNode);
+            }
+        }
+
+        Map<String, Collection<Node>> map = nodeMultimap.asMap();
+        createNode(combinedDoc, javaTypesContainer, map);
+
+        LOGGER.debug("Successfully merged all schema files for version {}", v);
+
+        return combinedDoc;
+    }
+
+    private void createNode(Document combinedDoc, Node javaTypesContainer, Map<String, Collection<Node>> map){
+
+        for (Entry<String, Collection<Node>> entry : map.entrySet()) {
+
+            List<Node> listOfNodes = (List<Node>)entry.getValue();
+            LOGGER.trace("NodeType {} Occurrences {}", entry.getKey(), listOfNodes.size());
+            Node copyOfFirstElement = null;
+            Node javaAttributeElement = null;
+
+            if(listOfNodes.size() > 1){
+                for(int index = 0; index < listOfNodes.size(); index++){
+                    if(index == 0){
+                        Node currentNode = listOfNodes.get(index);
+                        copyOfFirstElement = combinedDoc.importNode(currentNode, true);
+                        if(copyOfFirstElement.getNodeType() == Node.ELEMENT_NODE){
+                            Element element = (Element) copyOfFirstElement;
+                            NodeList javaAttributesList = element.getElementsByTagName("java-attributes");
+                            for(int javaAttributeIndex = 0; javaAttributeIndex < javaAttributesList.getLength(); javaAttributeIndex++){
+                                javaAttributeElement = javaAttributesList.item(javaAttributeIndex);
+                            }
+                        }
+                    } else {
+                        Node currentNode = listOfNodes.get(index);
+                        Node copyOfCurrentElement = combinedDoc.importNode(currentNode, true);
+                        if(copyOfCurrentElement.getNodeType() == Node.ELEMENT_NODE){
+                            Element element = (Element) copyOfCurrentElement;
+                            NodeList javaAttributesList = element.getElementsByTagName("java-attributes");
+                            for(int javaAttributeIndex = 0; javaAttributeIndex < javaAttributesList.getLength(); javaAttributeIndex++){
+                                Node jaElement = javaAttributesList.item(javaAttributeIndex);
+                                NodeList xmlElementList = jaElement.getChildNodes();
+                                for(int xmlElementIndex = 0; xmlElementIndex < xmlElementList.getLength(); xmlElementIndex++){
+                                    if(javaAttributeElement != null){
+                                        Node curElem = xmlElementList.item(xmlElementIndex);
+                                        if(curElem != null){
+                                            javaAttributeElement.appendChild(curElem.cloneNode(true));
+                                        }
+                                    }
+                                }
+                            }
+                        }
+
+                    }
+                }
+                javaTypesContainer.appendChild(copyOfFirstElement);
+            } else if(listOfNodes.size() == 1){
+                javaTypesContainer.appendChild(combinedDoc.importNode(listOfNodes.get(0), true));
+            }
+        }
+    }
+
+    /**
+     * Gets the DynamicJAXBContext for the given version
+     *
+     * @param v
+     * @return DynamicJAXBContext
+     */
+    public DynamicJAXBContext getContextForVersion(SchemaVersion v) {
+        return versionContextMap.get(v);
+    }
+
+    /**
+     * Determines if the given version contains the given node type
+     *
+     * @param nodeType - node type to check, must be in lower hyphen form (ie "type-name")
+     * @param v        - schema version to check against
+     * @return
+     */
+    public boolean hasNodeType(String nodeType, SchemaVersion v) {
+        return typesPerVersion.get(v).contains(nodeType);
+    }
+
+    public Set<String> getObjectsInVersion(SchemaVersion v) {
+        return typesPerVersion.get(v);
+    }
+
+    /**
+     * Determines if the given version contains the given node type
+     *
+     * @param nodeType - node type to check, must be in lower hyphen form (ie "type-name")
+     * @param v
+     * @return
+     */
+    public Document getSchema(SchemaVersion v) {
+        return schemaPerVersion.get(v);
+    }
+
+    private InputStream getShell(SchemaVersion v) {
+        String source = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+            "<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" +
+            "  <xml-schema element-form-default=\"QUALIFIED\">\n" +
+            "          <xml-ns namespace-uri=\"http://org.onap.aai.inventory/" + v.toString().toLowerCase() + "\" />\n" +
+            "  </xml-schema>\n" +
+            "  <java-types>\n" +
+            "  </java-types>\n" +
+            "</xml-bindings>";
+        return new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8));
+    }
+
+
+    public SchemaVersion getVersionFromClassName(String classname) {
+        Matcher m = classNamePattern.matcher(classname);
+        String version = null;
+        if (m.find()) {
+            version = m.group(1);
+            return new SchemaVersion(version);
+        } else {
+            return translator.getSchemaVersions().getDefaultVersion();
+        }
+    }
+}
+
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/NodeSchemaResource.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/NodeSchemaResource.java
new file mode 100644 (file)
index 0000000..4eccd71
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.schemaservice.nodeschema.validation.AAISchemaValidationException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.Optional;
+
+@Path("/v1")
+public class NodeSchemaResource extends RESTAPI {
+
+    private final NodeSchemaService nodeSchemaService;
+
+    private final SchemaVersions schemaVersions;
+
+    @Autowired
+    public NodeSchemaResource(NodeSchemaService nodeSchemaService, SchemaVersions schemaVersions) {
+        this.nodeSchemaService = nodeSchemaService;
+        this.schemaVersions    = schemaVersions;
+    }
+
+    @GET
+    @Path("/nodes")
+    @Produces({ "application/xml"})
+    public Response retrieveSchema(@QueryParam("version") String version,
+                                   @Context HttpHeaders headers,
+                                   @Context UriInfo info)
+    {
+        Response response;
+        Optional<String> optionalSchema = nodeSchemaService.fetch(version);
+        try {
+
+            if(StringUtils.isEmpty(version)){
+                throw new AAIException("AAI_3050");
+            }
+
+            SchemaVersion schemaVersion = new SchemaVersion(version);
+
+            if(!schemaVersions.getVersions().contains(schemaVersion)){
+                throw new AAIException("AAI_3018", version);
+            }
+
+            if (!optionalSchema.isPresent()) {
+                throw new AAIException("AAI_3001");
+            }
+
+            response = Response.ok(optionalSchema.get()).build();
+
+        } catch(AAIException ex){
+            response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
+        } catch(AAISchemaValidationException ex){
+            response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, new AAIException("AAI_3051", version));
+        } catch(Exception ex){
+            response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, new AAIException("AAI_4000"));
+        }
+
+        return response;
+    }
+
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/NodeSchemaService.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/NodeSchemaService.java
new file mode 100644 (file)
index 0000000..07f4cf4
--- /dev/null
@@ -0,0 +1,92 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.onap.aai.logging.LogFormatTools;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+@Service
+public class NodeSchemaService {
+
+    private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(NodeSchemaResource.class);
+
+    private SchemaVersions schemaVersions;
+
+    private NodeIngestor nodeIngestor;
+
+    private Map<String, String> versionMap = new HashMap<>();
+
+    public NodeSchemaService(NodeIngestor nodeIngestor, SchemaVersions schemaVersions) {
+        this.nodeIngestor = nodeIngestor;
+        this.schemaVersions = schemaVersions;
+    }
+
+    @PostConstruct
+    public void initialize() {
+
+        schemaVersions.getVersions().forEach((schemaVersion -> {
+
+            TransformerFactory tf = TransformerFactory.newInstance();
+
+            Transformer transformer = null;
+            try {
+                transformer = tf.newTransformer();
+            } catch (TransformerConfigurationException e) {
+                LOGGER.warn("Encountered an transformer configuration exception" +
+                    "during node schema service startup ", LogFormatTools.getStackTop(e));
+            }
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+            transformer.setOutputProperty(OutputKeys.INDENT, "no");
+            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+
+            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+            try {
+                DOMSource domSource = new DOMSource(nodeIngestor.getSchema(schemaVersion));
+
+                StreamResult streamResult = new StreamResult(new OutputStreamWriter(buffer, "UTF-8"));
+                transformer.transform(domSource, streamResult);
+                versionMap.put(schemaVersion.toString(), buffer.toString("UTF-8"));
+            } catch (TransformerException | UnsupportedEncodingException e) {
+                LOGGER.warn("Encountered an transformer or unsupported encoding exception " +
+                    "during node schema service startup ", LogFormatTools.getStackTop(e));
+            }
+
+        }));
+    }
+
+    public Optional<String> fetch(String version) {
+        return Optional.ofNullable(versionMap.get(version));
+    }
+
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/SchemaVersion.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/SchemaVersion.java
new file mode 100644 (file)
index 0000000..fc5b48c
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema;
+
+import org.onap.aai.schemaservice.nodeschema.validation.AAISchemaValidationException;
+
+import java.util.regex.Pattern;
+
+public class SchemaVersion implements Comparable<SchemaVersion> {
+
+    public static final Pattern VERSION_PATTERN = Pattern.compile("v[1-9][0-9]*");
+
+    private final String value;
+
+    public SchemaVersion(String value){
+
+        if(!VERSION_PATTERN.matcher(value).matches()){
+            throw new AAISchemaValidationException("Invalid Schema Version " + value + ", value doesn't match the expected regex: " + VERSION_PATTERN);
+        }
+
+        this.value = value;
+    }
+
+    @Override
+    public int hashCode(){
+        return value.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other){
+        if(this == other){
+            return true;
+        }
+
+        if(other == null){
+            return false;
+        }
+
+        if(!(other instanceof SchemaVersion)){
+            return false;
+        }
+
+        SchemaVersion obj = (SchemaVersion)other;
+        return this.value.equals(obj.value);
+    }
+
+    @Override
+    public String toString(){
+        return value;
+    }
+
+    @Override
+    public int compareTo(SchemaVersion o) {
+
+        if(o == null){
+            return -1;
+        }
+
+        // Requires to convert to integer to match the past behavior
+        // Otherwise the string comparison of versions aren't working as expected
+
+        Integer tVal = Integer.parseInt(this.value.replaceAll("v", ""));
+        Integer oVal = Integer.parseInt(o.value.replaceAll("v", ""));
+
+        return tVal.compareTo(oVal);
+    }
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/SchemaVersions.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/SchemaVersions.java
new file mode 100644 (file)
index 0000000..208d5d0
--- /dev/null
@@ -0,0 +1,158 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema;
+
+import org.onap.aai.schemaservice.nodeschema.validation.AAISchemaValidationException;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Component
+@PropertySource(value = "classpath:schema-ingest.properties", ignoreResourceNotFound = true)
+@PropertySource(value = "file:${schema.ingest.file}", ignoreResourceNotFound = true)
+public class SchemaVersions {
+
+    @Value("#{'${schema.version.list}'.split(',')}")
+    private List<String> apiVersions;
+
+    @Value("${schema.version.api.default}")
+    private String defaultApiVersion;
+
+    @Value("${schema.version.edge.label.start}")
+    private String edgeLabelStartVersion;
+
+    @Value("${schema.version.depth.start}")
+    private String depthStartVersion;
+
+    @Value("${schema.version.app.root.start}")
+    private String appRootStartVersion;
+
+    @Value("${schema.version.related.link.start}")
+    private String relatedLinkStartVersion;
+
+    @Value("${schema.version.namespace.change.start}")
+    private String namespaceChangeStartVersion;
+
+    private List<SchemaVersion> versions;
+
+    private SchemaVersion edgeLabelVersion;
+    private SchemaVersion defaultVersion;
+    private SchemaVersion depthVersion;
+    private SchemaVersion appRootVersion;
+    private SchemaVersion relatedLinkVersion;
+    private SchemaVersion namespaceChangeVersion;
+
+    @PostConstruct
+    public void initialize() {
+        versions = apiVersions.stream().map(SchemaVersion::new).collect(Collectors.toList());
+
+        edgeLabelVersion       = new SchemaVersion(edgeLabelStartVersion);
+        defaultVersion         = new SchemaVersion(defaultApiVersion);
+        depthVersion           = new SchemaVersion(depthStartVersion);
+        appRootVersion         = new SchemaVersion(appRootStartVersion);
+        relatedLinkVersion     = new SchemaVersion(relatedLinkStartVersion);
+        namespaceChangeVersion = new SchemaVersion(namespaceChangeStartVersion);
+
+        if (!versions.contains(edgeLabelVersion)) {
+            throw new AAISchemaValidationException(
+                    "Invalid, edge label version is not in the api versions list"
+                    + ", please check schema.version.list and ensure that the"
+                    + " schema.version.edge.label.start is in that list"
+            );
+        }
+
+        if (!versions.contains(defaultVersion)) {
+            throw new AAISchemaValidationException(
+                    "Invalid, default version is not in the api versions list"
+                            + ", please check schema.version.list and ensure that the"
+                            + " schema.version.api.default is in that list"
+            );
+        }
+
+        if (!versions.contains(depthVersion)) {
+            throw new AAISchemaValidationException(
+                    "Invalid, depth version is not in the api versions list"
+                            + ", please check schema.version.list and ensure that the"
+                            + " schema.version.depth.start is in that list"
+            );
+        }
+
+        if(!versions.contains(appRootVersion)){
+            throw new AAISchemaValidationException(
+                    "Invalid, app root version is not in the api versions list"
+                            + ", please check schema.version.list and ensure that the"
+                            + " schema.version.app.root.start is in that list"
+            );
+        }
+
+        if(!versions.contains(relatedLinkVersion)){
+            throw new AAISchemaValidationException(
+                    "Invalid, related link version is not in the api versions list"
+                            + ", please check schema.version.list and ensure that the"
+                            + " schema.version.related.link.start is in that list"
+            );
+        }
+
+        if(!versions.contains(namespaceChangeVersion)){
+            throw new AAISchemaValidationException(
+                    "Invalid, namespace change start version is not in the api versions list"
+                            + ", please check schema.version.list and ensure that the"
+                            + " schema.version.related.link.start is in that list"
+            );
+        }
+    }
+
+    public List<SchemaVersion> getVersions() {
+        return versions;
+    }
+
+    public SchemaVersion getEdgeLabelVersion() {
+        return edgeLabelVersion;
+    }
+
+    public SchemaVersion getDefaultVersion() {
+        return defaultVersion;
+    }
+
+    public SchemaVersion getDepthVersion() {
+        return depthVersion;
+    }
+
+    public SchemaVersion getAppRootVersion(){
+        return appRootVersion;
+    }
+
+    public SchemaVersion getRelatedLinkVersion(){
+        return relatedLinkVersion;
+    }
+
+    public SchemaVersion getNamespaceChangeVersion() {
+        return namespaceChangeVersion;
+    }
+
+    public void setNamespaceChangeVersion(SchemaVersion namespaceChangeVersion) {
+        this.namespaceChangeVersion = namespaceChangeVersion;
+    }
+
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/AAISchemaValidationException.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/AAISchemaValidationException.java
new file mode 100644 (file)
index 0000000..e096a7d
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+/**
+ * Indicates that a fatal error in the A&AI schema has been found.
+ */
+public class AAISchemaValidationException extends IllegalStateException {
+       public AAISchemaValidationException(String msg) {
+               super(msg);
+       }
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/CheckEverythingStrategy.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/CheckEverythingStrategy.java
new file mode 100644 (file)
index 0000000..de31212
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * When an error is found, mark that it is NOT ok to
+ * continue with installation/whatever other caller function,
+ * and keep track of the message but
+ * keep validating so all issues are found in one run.
+ */
+public class CheckEverythingStrategy implements SchemaErrorStrategy {
+       private boolean isOK = true;
+       private List<String> errorMsgs = new ArrayList<>();
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.edges.validation.SchemaErrorStrategy#isOK()
+        */
+       @Override
+       public boolean isOK() {
+               return isOK;
+       }
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.edges.validation.SchemaErrorStrategy#getErrorMsg()
+        */
+       @Override
+       public String getErrorMsg() {
+               if (errorMsgs.isEmpty()) {
+                       return "No errors found.";
+               } else {
+                       return StringUtils.join(errorMsgs, "\n");
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.edges.validation.SchemaErrorStrategy#notifyOnError(java.lang.String)
+        */
+       @Override
+       public void notifyOnError(String errorMsg) {
+               isOK = false;
+               errorMsgs.add(errorMsg);
+       }
+
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/DefaultDuplicateNodeDefinitionValidationModule.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/DefaultDuplicateNodeDefinitionValidationModule.java
new file mode 100644 (file)
index 0000000..915a54d
--- /dev/null
@@ -0,0 +1,101 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import org.onap.aai.schemaservice.nodeschema.SchemaVersion;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Default duplicate rules for A&AI -
+ * node types may never have a duplicate definition
+ * within the same Version's file set.
+ *
+ * Finds all duplicates and what files they're in.
+ *
+ */
+public class DefaultDuplicateNodeDefinitionValidationModule implements DuplicateNodeDefinitionValidationModule {
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.nodes.validation.DuplicateNodeDefinitionValidationModule#findDuplicates(java.util.List)
+        */
+       @Override
+       public String findDuplicates(List<String> files, SchemaVersion v) {
+               try {
+                       final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+                       docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+                       final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+
+                       Multimap<String, String> types = ArrayListMultimap.create();
+                       boolean foundDups = false;
+                       for (String file : files) {
+                               InputStream inputStream = new FileInputStream(file);
+                               final Document doc = docBuilder.parse(inputStream);
+                               final NodeList list = doc.getElementsByTagName("java-type");
+
+                               for (int i = 0; i < list.getLength(); i++) {
+                                       String type = list.item(i).getAttributes().getNamedItem("name").getNodeValue();
+                                       if (types.containsKey(type)) {
+                                               foundDups = true;
+                                       }
+                                       types.put(type, file);
+                               }
+                       }
+
+                       if (foundDups) {
+                               return buildErrorMsg(types, v);
+                       } else {
+                               return "";
+                       }
+               } catch (ParserConfigurationException | SAXException | IOException e) {
+                       // TODO something useful with this information
+                       return e.getMessage();
+               }
+       }
+
+       private String buildErrorMsg(Multimap<String, String> types, SchemaVersion v) {
+               StringBuilder errorMsg = new StringBuilder().append("Duplicates found in version ").append(v.toString()).append(". ");
+               for (String nodeType : types.keySet()) {
+                       Collection<String> files = types.get(nodeType);
+                       if (files.size() == 1) {
+                               continue; //only record the duplicated ones
+                       }
+                       errorMsg.append(nodeType).append(" has definitions in ");
+                       for (String file : files) {
+                               errorMsg.append(file).append(" ");
+                       }
+               }
+               return errorMsg.toString();
+       }
+
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/DefaultVersionValidationModule.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/DefaultVersionValidationModule.java
new file mode 100644 (file)
index 0000000..acd4095
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+import org.onap.aai.schemaservice.config.ConfigTranslator;
+import org.onap.aai.schemaservice.nodeschema.SchemaVersion;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * By default, A&AI must have schema files for all current
+ * supported Versions in the Version enum
+ *
+ */
+@Component
+public class DefaultVersionValidationModule implements VersionValidationModule {
+       private ConfigTranslator config;
+
+       @Autowired
+       public DefaultVersionValidationModule(ConfigTranslator config) {
+               this.config = config;
+       }
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.validation.VersionValidationModule#validate(org.onap.aai.setup.ConfigTranslator)
+        */
+       @Override
+       public String validate() {
+               Map<SchemaVersion, List<String>> nodeConfig = config.getNodeFiles();
+               Map<SchemaVersion, List<String>> edgeConfig = config.getEdgeFiles();
+
+               StringBuilder missingVers = new StringBuilder().append("Missing schema for the following versions: ");
+               boolean isMissing = false;
+               for (SchemaVersion v : config.getSchemaVersions().getVersions()) {
+                       if (nodeConfig.get(v) == null) {
+                               isMissing = true;
+                               missingVers.append(v.toString()).append(" has no OXM configured. ");
+                       }
+                       if (edgeConfig.get(v) == null) {
+                               isMissing = true;
+                               missingVers.append(v.toString()).append(" has no edge rules configured. ");
+                       }
+               }
+
+               if (isMissing) {
+                       return missingVers.toString();
+               } else {
+                       return "";
+               }
+       }
+
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/DuplicateNodeDefinitionValidationModule.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/DuplicateNodeDefinitionValidationModule.java
new file mode 100644 (file)
index 0000000..cb5f5e3
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+import org.onap.aai.schemaservice.nodeschema.SchemaVersion;
+
+import java.util.List;
+
+/**
+ * Defines rules for duplicate node definitions in a set of files
+ * (where the intent is the set of files is all the OXM for one version).
+ *
+ * Example Options:
+ * -Any duplicated definition found is an error
+ * -Duplicates within a namespace are OK but not across namespaces
+ * -Anything goes
+ * etc.
+ */
+public interface DuplicateNodeDefinitionValidationModule {
+       /**
+        * Finds any duplicates according to the defined rules
+        *
+        * @param files - the OXM files to use with full directory
+        * @return empty String if none found, else a String
+        *      with appropriate information about what node types
+        *  were found
+        */
+       String findDuplicates(List<String> files, SchemaVersion v);
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/FailFastStrategy.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/FailFastStrategy.java
new file mode 100644 (file)
index 0000000..7463a7d
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+/**
+ * Fails out the validation process as soon as
+ * an error is found. Tells the validation's calling
+ * process to abort.
+ */
+public class FailFastStrategy implements SchemaErrorStrategy {
+       private boolean isOK = true;
+       private String errorMsg = "No errors found.";
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.edges.validation.SchemaErrorStrategy#isOK()
+        */
+       @Override
+       public boolean isOK() {
+               return isOK;
+       }
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.edges.validation.SchemaErrorStrategy#getErrorMsg()
+        */
+       @Override
+       public String getErrorMsg() {
+               return errorMsg;
+       }
+
+       /* (non-Javadoc)
+        * @see org.onap.aai.edges.validation.SchemaErrorStrategy#notifyOnError(java.lang.String)
+        */
+       @Override
+       public void notifyOnError(String errorMsg) {
+               isOK = false;
+               this.errorMsg = errorMsg;
+               throw new AAISchemaValidationException(errorMsg);
+       }
+
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/NodeValidator.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/NodeValidator.java
new file mode 100644 (file)
index 0000000..e73331b
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+import org.onap.aai.schemaservice.config.ConfigTranslator;
+import org.onap.aai.schemaservice.nodeschema.SchemaVersion;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map.Entry;
+
+@Component
+public class NodeValidator {
+       private ConfigTranslator translator;
+       private SchemaErrorStrategy strat;
+       private DuplicateNodeDefinitionValidationModule dupChecker;
+
+       @Autowired
+       public NodeValidator(ConfigTranslator translator, SchemaErrorStrategy strategy, DuplicateNodeDefinitionValidationModule dupChecker) {
+               this.translator = translator;
+               this.strat = strategy;
+               this.dupChecker = dupChecker;
+       }
+
+       public boolean validate() {
+
+               for(Entry<SchemaVersion, List<String>> entry : translator.getNodeFiles().entrySet()) {
+                       String result = dupChecker.findDuplicates(entry.getValue(), entry.getKey());
+                       if (!"".equals(result)) {
+                               strat.notifyOnError(result);
+                       }
+               }
+               return strat.isOK();
+       }
+
+       public String getErrorMsg() {
+               return strat.getErrorMsg();
+       }
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/SchemaErrorStrategy.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/SchemaErrorStrategy.java
new file mode 100644 (file)
index 0000000..9df66cd
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+/**
+ * Controls response to finding problems in the schema files.
+ */
+public interface SchemaErrorStrategy {
+       /**
+        * Gives if it is OK to proceed with whatever process
+        * invoked the validation (probably the installation of
+        * the A&AI instance).
+        *
+        * @return boolean
+        */
+       public boolean isOK();
+
+       /**
+        * Gets the error message(s) gathered in the course
+        * of validation.
+        *
+        * @return String error message or messages concatenated together
+        */
+       public String getErrorMsg();
+
+       /**
+        * Invokes the ErrorStrategy to do whatever response to
+        * an issue in the schema having been found.
+        *
+        * Options:
+        * -Throw an exception if the whole process should be
+        *  immediately aborted
+        * -Set OK status to false, store the message and allow the
+        *  validation process to continue and find any other issues
+        * -Completely ignore that something is wrong
+        * etc.
+        *
+        * @param String errorMsg - the error message from the validator module
+        */
+       public void notifyOnError(String errorMsg);
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/VersionValidationModule.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/VersionValidationModule.java
new file mode 100644 (file)
index 0000000..607e0df
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+
+/**
+ * Defines the behavior for what versions are required/optional.
+ *
+ * Constructor must take ConfigTranslator via autowiring.
+ */
+public interface VersionValidationModule {
+
+       /**
+        * Validates that all required versions have schema
+        * configured for them.
+        *
+        * @return empty string if none missing or else an appropriate error
+        */
+       public String validate();
+}
diff --git a/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/VersionValidator.java b/aai-schema-service/src/main/java/org/onap/aai/schemaservice/nodeschema/validation/VersionValidator.java
new file mode 100644 (file)
index 0000000..8394521
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.schemaservice.nodeschema.validation;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Verifies that the schema config covers
+ * all required versions
+ */
+@Component
+public class VersionValidator {
+       private SchemaErrorStrategy strat;
+       private VersionValidationModule verMod;
+
+       @Autowired
+       public VersionValidator(SchemaErrorStrategy strategy, VersionValidationModule verMod) {
+               this.strat = strategy;
+               this.verMod = verMod;
+       }
+
+       public boolean validate() {
+               String result = verMod.validate();
+               if (!"".equals(result)) {
+                       strat.notifyOnError(result);
+               }
+
+               return strat.isOK();
+       }
+
+       public String getErrorMsg() {
+               return strat.getErrorMsg();
+       }
+}
index 579b9c6..606d24b 100644 (file)
@@ -21,6 +21,7 @@ package org.onap.aai.schemaservice.web;
 
 import org.glassfish.jersey.server.ResourceConfig;
 import org.onap.aai.schemaservice.healthcheck.EchoResource;
+import org.onap.aai.schemaservice.nodeschema.NodeSchemaResource;
 import org.onap.aai.schemaservice.versions.VersionResource;
 import org.reflections.Reflections;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -50,6 +51,7 @@ public class JerseyConfiguration extends ResourceConfig {
 
         register(VersionResource.class);
         register(EchoResource.class);
+        register(NodeSchemaResource.class);
 
         //Request Filters
         registerFiltersForRequests();