Adding apex utiliites and basic-model module 77/48677/6
authoreikrwaq <waqas.ikram@ericsson.com>
Wed, 23 May 2018 13:08:29 +0000 (14:08 +0100)
committerwaqas.ikram <waqas.ikram@ericsson.com>
Thu, 24 May 2018 11:30:24 +0000 (12:30 +0100)
Change-Id: Ib72677912eb5ac4b872e555f24570c86a627802f
Issue-ID: POLICY-855
Signed-off-by: waqas.ikram <waqas.ikram@ericsson.com>
112 files changed:
model/basic-model/pom.xml [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexConceptException.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexException.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexRuntimeException.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxArtifactKey.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConcept.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetter.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetterImpl.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKey.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInfo.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInformation.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyUse.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxModel.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxReferenceKey.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationMessage.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationResult.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/package-info.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDao.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDaoFactory.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/DAOParameters.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/CDATAConditioner.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/UUID2String.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/package-info.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/DefaultApexDao.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/package-info.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/package-info.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelCreator.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelException.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelFileWriter.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelReader.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelSaver.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelStringWriter.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelWriter.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexSchemaGenerator.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/package-info.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/package-info.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/AbstractParameters.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ModelService.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ParameterService.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/package-info.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModel.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModelCreator.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/package-info.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/AxReferenceKeyAdapter.java [new file with mode: 0644]
model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/package-info.java [new file with mode: 0644]
model/basic-model/src/main/resources/doc/JDBCPropertiesExamples.txt [new file with mode: 0644]
model/basic-model/src/main/resources/xml/example.xsd [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/AxKeyTest.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestAxKeyInfo.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestAxReferenceKey.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestEntity.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestExceptions.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestValidation.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/testKeyUse.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/dao/EntityTest.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/dao/TestDaoMisc.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/AxModelWithReferences.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexBasicModel.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexBasicModelConcepts.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexBasicModelCreator.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexTestModelCreator0.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexTestModelCreator1.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexTestModelCreator2.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestBasicModelTest.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestConceptGetter.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestExceptions.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelFileWriter.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelReader.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelSaver.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelStringWriter.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelWriter.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestSchemaGenerator.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/IllegalParameters.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/LegalParameters.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/TestAbstractParameters.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/TestModelService.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/TestParameterService.java [new file with mode: 0644]
model/basic-model/src/test/java/org/onap/apex/model/basicmodel/xml/TestAxReferenceKeyAdapter.java [new file with mode: 0644]
model/basic-model/src/test/resources/META-INF/persistence.xml [new file with mode: 0644]
model/basic-model/src/test/resources/logback-test.xml [new file with mode: 0644]
model/pom.xml [new file with mode: 0644]
model/utiliites/pom.xml [new file with mode: 0644]
model/utiliites/src/main/antlr4/org/onap/policy/apex/model/utilities/typeutils/ParametrizedType.g4 [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/Assertions.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/CollectionUtils.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/DirectoryUtils.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/PropertyUtils.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/ResourceUtils.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/TextFileUtils.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/TreeMapUtils.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyComparer.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyDifference.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyedMapComparer.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyedMapDifference.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/package-info.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/package-info.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/typeutils/ClassBuilder.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/typeutils/TypeBuilder.java [new file with mode: 0644]
model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/typeutils/package-info.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/AssertionsTest.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/CollectionUtilitiesTest.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/DirectoryUtilsTest.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/PropertyUtilsTest.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/ResourceUtilsTest.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/TextFileUtilsTest.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/TreeMapUtilsTest.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/typeutils/ParserTest.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/typeutils/TestKeyComparer.java [new file with mode: 0644]
model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/typeutils/TestKeyedMapComparer.java [new file with mode: 0644]
model/utiliites/src/test/resources/testdir/testfile.xml [new file with mode: 0644]
pom.xml [new file with mode: 0644]
version.properties [new file with mode: 0644]

diff --git a/model/basic-model/pom.xml b/model/basic-model/pom.xml
new file mode 100644 (file)
index 0000000..df25dcb
--- /dev/null
@@ -0,0 +1,121 @@
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2018 Ericsson. 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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onap.policy.apex.apex-pdp.model</groupId>
+        <artifactId>model</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>basic-model</artifactId>
+    <name>${project.artifactId}</name>
+    <description>Basic Models used and model handling in Apex</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onap.policy.apex.apex-pdp.model</groupId>
+            <artifactId>utiliites</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>eclipselink</artifactId>
+            <version>2.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.derby</groupId>
+            <artifactId>derby</artifactId>
+            <version>10.13.1.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-xml-schema</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>java</goal>
+                        </goals>
+                        <configuration>
+                            <mainClass>org.onap.apex.model.basicmodel.handling.ApexSchemaGenerator</mainClass>
+                            <classpathScope>compile</classpathScope>
+                            <arguments>
+                                <argument>org.onap.apex.model.basicmodel.concepts.AxModel</argument>
+                                <argument>${project.build.directory}/model/xml/apex-basic-model.xsd</argument>
+                            </arguments>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+    <profiles>
+        <profile>
+            <!--This profile is used to store Eclipse m2e settings only. It has no 
+                influence on the Maven build itself. -->
+            <id>only-eclipse</id>
+            <activation>
+                <property>
+                    <name>m2e.version</name>
+                </property>
+            </activation>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.eclipse.m2e</groupId>
+                            <artifactId>lifecycle-mapping</artifactId>
+                            <version>1.0.0</version>
+                            <configuration>
+                                <lifecycleMappingMetadata>
+                                    <pluginExecutions>
+                                        <pluginExecution>
+                                            <pluginExecutionFilter>
+                                                <groupId>org.codehaus.mojo</groupId>
+                                                <artifactId>exec-maven-plugin</artifactId>
+                                                <versionRange>1.2.1</versionRange>
+                                                <goals>
+                                                    <goal>java</goal>
+                                                </goals>
+                                            </pluginExecutionFilter>
+                                            <action>
+                                                <execute />
+                                            </action>
+                                        </pluginExecution>
+                                    </pluginExecutions>
+                                </lifecycleMappingMetadata>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+    </profiles>
+</project>
\ No newline at end of file
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexConceptException.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexConceptException.java
new file mode 100644 (file)
index 0000000..bfe296d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+/**
+ * This class is an exception thrown on Apex Concept errors.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexConceptException extends ApexException {
+    private static final long serialVersionUID = -8507246953751956974L;
+
+    /**
+     * Instantiates a new apex concept exception.
+     *
+     * @param message the message on the exception
+     */
+    public ApexConceptException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Instantiates a new apex concept exception.
+     *
+     * @param message the message on the exception
+     * @param e the exception that caused this Apex exception
+     */
+    public ApexConceptException(final String message, final Exception e) {
+        super(message, e);
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexException.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexException.java
new file mode 100644 (file)
index 0000000..74a60e2
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+/**
+ * This class is a base exception from which all Apex exceptions are sub classes.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexException extends Exception {
+    private static final long serialVersionUID = -8507246953751956974L;
+
+    // The object on which the exception was thrown
+    private transient Object object = null;
+
+    /**
+     * Instantiates a new apex exception.
+     *
+     * @param message the message on the exception
+     */
+    public ApexException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Instantiates a new apex exception.
+     *
+     * @param message the message on the exception
+     * @param object the object that the exception was thrown on
+     */
+    public ApexException(final String message, final Object object) {
+        super(message);
+        this.object = object;
+    }
+
+    /**
+     * Instantiates a new apex exception.
+     *
+     * @param message the message on the exception
+     * @param e the exception that caused this Apex exception
+     */
+    public ApexException(final String message, final Exception e) {
+        super(message, e);
+    }
+
+    /**
+     * Instantiates a new apex exception.
+     *
+     * @param message the message on the exception
+     * @param e the exception that caused this Apex exception
+     * @param object the object that the exception was thrown on
+     */
+    public ApexException(final String message, final Exception e, final Object object) {
+        super(message, e);
+        this.object = object;
+    }
+
+    /**
+     * Get the message from this exception and its causes.
+     *
+     * @return the cascaded messages from this exception and the exceptions that caused it
+     */
+    public String getCascadedMessage() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(this.getMessage());
+
+        for (Throwable t = this; t != null; t = t.getCause()) {
+            builder.append("\ncaused by: ");
+            builder.append(t.getMessage());
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     *
+     * Get the object on which the exception was thrown.
+     *
+     * @return The object on which the exception was thrown
+     */
+    public Object getObject() {
+        return object;
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexRuntimeException.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/ApexRuntimeException.java
new file mode 100644 (file)
index 0000000..4cdfbe4
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+/**
+ * This class is a base run time exception from which all Apex run time exceptions are sub classes.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexRuntimeException extends RuntimeException {
+    private static final long serialVersionUID = -8507246953751956974L;
+
+    // The object on which the exception was thrown
+    private transient Object object = null;
+
+    /**
+     * Instantiates a new apex runtime exception.
+     *
+     * @param message the message on the exception
+     */
+    public ApexRuntimeException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Instantiates a new apex runtime exception.
+     *
+     * @param message the message on the exception
+     * @param object the object that the exception was thrown on
+     */
+    public ApexRuntimeException(final String message, final Object object) {
+        super(message);
+        this.object = object;
+    }
+
+    /**
+     * Instantiates a new apex runtime exception.
+     *
+     * @param message the message on the exception
+     * @param e the exception that caused this Apex exception
+     */
+    public ApexRuntimeException(final String message, final Exception e) {
+        super(message, e);
+    }
+
+    /**
+     * Instantiates a new apex runtime exception.
+     *
+     * @param message the message on the exception
+     * @param e the exception that caused this Apex exception
+     * @param object the object that the exception was thrown on
+     */
+    public ApexRuntimeException(final String message, final Exception e, final Object object) {
+        super(message, e);
+        this.object = object;
+    }
+
+    /**
+     * Get the message from this exception and its causes.
+     *
+     * @return the message of this exception and all the exceptions that caused this exception
+     */
+    public String getCascadedMessage() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(this.getMessage());
+
+        for (Throwable t = this; t != null; t = t.getCause()) {
+            builder.append("\ncaused by: ");
+            builder.append(t.getMessage());
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * Get the object on which the exception was thrown.
+     *
+     * @return The object
+     */
+    public Object getObject() {
+        return object;
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxArtifactKey.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxArtifactKey.java
new file mode 100644 (file)
index 0000000..1de7ae7
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * An artifact key uniquely identifies every first order entity in the system. Every first order concept in the system must have
+ * an {@link AxArtifactKey} to identify it. Concepts that are wholly contained in another concept are identified using
+ * a {@link AxReferenceKey} key.
+ * <p>
+ * Key validation checks that the name and version fields match the {@link NAME_REGEXP} and {@link VERSION_REGEXP} regular expressions respectively.
+ */
+@Embeddable
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexArtifactKey", namespace = "http://www.ericsson.com/apex")
+
+@XmlType(name = "AxArtifactKey", namespace = "http://www.ericsson.com/apex", propOrder = { "name", "version" })
+
+public class AxArtifactKey extends AxKey {
+       private static final long serialVersionUID = 8932717618579392561L;
+
+       private static final String NAME_TOKEN = "name";
+       private static final String VERSION_TOKEN = "version";
+
+       @Column(name = NAME_TOKEN)
+       @XmlElement(required = true)
+       private String name;
+
+       @Column(name = VERSION_TOKEN)
+       @XmlElement(required = true)
+       private String version;
+
+       /**
+        * The default constructor creates a null artifact key.
+        */
+       public AxArtifactKey() {
+               this(NULL_KEY_NAME, NULL_KEY_VERSION);
+       }
+
+    /**
+     * Copy constructor
+     * @param copyConcept the concept to copy from
+     */
+    public AxArtifactKey(final AxArtifactKey copyConcept) {
+               super(copyConcept);
+    }
+    
+       /**
+        * Constructor to create a key with the specified name and version.
+        *
+        * @param name the key name
+        * @param version the key version
+        */
+       public AxArtifactKey(final String name, final String version) {
+               super();
+               this.name = Assertions.validateStringParameter(NAME_TOKEN, name, NAME_REGEXP);
+               this.version = Assertions.validateStringParameter(VERSION_TOKEN, version, VERSION_REGEXP);
+       }
+
+       /**
+        * Constructor to create a key using the key and version from the specified key ID.
+        *
+        * @param id the key ID in a format that respects the {@link KEY_ID_REGEXP}
+        */
+       public AxArtifactKey(final String id) {
+               Assertions.argumentNotNull(id, "id may not be null");
+
+               // Check the incoming ID is valid
+               Assertions.validateStringParameter("id", id, KEY_ID_REGEXP);
+
+               // Split on colon, if the id passes the regular expression test above
+               // it'll have just one colon separating the name and version
+               // No need for range checks or size checks on the array
+               final String[] nameVersionArray = id.split(":");
+
+               // Return the new key
+               name = Assertions.validateStringParameter(NAME_TOKEN, nameVersionArray[0], NAME_REGEXP);
+               version = Assertions.validateStringParameter(VERSION_TOKEN, nameVersionArray[1], VERSION_REGEXP);
+       }
+
+       /**
+        * Get a null artifact key.
+        *
+        * @return a null artifact key
+        */
+       public static final AxArtifactKey getNullKey() {
+               return new AxArtifactKey(AxKey.NULL_KEY_NAME, AxKey.NULL_KEY_VERSION);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey()
+        */
+       @Override
+       public AxArtifactKey getKey() {
+               return this;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys()
+        */
+       @Override
+       public List<AxKey> getKeys() {
+               final List<AxKey> keyList = new ArrayList<>();
+               keyList.add(getKey());
+               return keyList;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getID()
+        */
+       @Override
+       public String getID() {
+               return name + ':' + version;
+       }
+
+       /**
+        * Gets the key name.
+        *
+        * @return the key name
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Sets the key name.
+        *
+        * @param name the key name
+        */
+       public void setName(final String name) {
+               this.name = Assertions.validateStringParameter(NAME_TOKEN, name, NAME_REGEXP);
+       }
+
+       /**
+        * Gets the key version.
+        *
+        * @return the key version
+        */
+       public String getVersion() {
+               return version;
+       }
+
+       /**
+        * Sets the key version.
+        *
+        * @param version the key version
+        */
+       public void setVersion(final String version) {
+               this.version = Assertions.validateStringParameter(VERSION_TOKEN, version, VERSION_REGEXP);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getCompatibility(com. ericsson.apex.model.basicmodel.concepts.AxKey)
+        */
+       @Override
+       public AxKey.Compatibility getCompatibility(final AxKey otherKey) {
+               if (!(otherKey instanceof AxArtifactKey)) {
+                       return Compatibility.DIFFERENT;
+               }
+               final AxArtifactKey otherArtifactKey = (AxArtifactKey) otherKey;
+
+               if (this.equals(otherArtifactKey)) {
+                       return Compatibility.IDENTICAL;
+               }
+               if (!this.getName().equals(otherArtifactKey.getName())) {
+                       return Compatibility.DIFFERENT;
+               }
+
+               final String[] thisVersionArray = getVersion().split("\\.");
+               final String[] otherVersionArray = otherArtifactKey.getVersion().split("\\.");
+
+               // There must always be at least one element in each version
+               if (!thisVersionArray[0].equals(otherVersionArray[0])) {
+                       return Compatibility.MAJOR;
+               }
+
+               if (thisVersionArray.length >= 2 && otherVersionArray.length >= 2 && !thisVersionArray[1].equals(otherVersionArray[1])) {
+                       return Compatibility.MINOR;
+               }
+
+               return Compatibility.PATCH;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#isCompatible(com. ericsson.apex.model.basicmodel.concepts.AxKey)
+        */
+       @Override
+       public boolean isCompatible(final AxKey otherKey) {
+               if (!(otherKey instanceof AxArtifactKey)) {
+                       return false;
+               }
+               final AxArtifactKey otherArtifactKey = (AxArtifactKey) otherKey;
+
+               final Compatibility compatibility = this.getCompatibility(otherArtifactKey);
+
+               return !(compatibility == Compatibility.DIFFERENT || compatibility == Compatibility.MAJOR);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.apex.model.basicmodel.concepts.AxValidationResult)
+        */
+       @Override
+       public AxValidationResult validate(final AxValidationResult result) {
+               try {
+                       Assertions.validateStringParameter(NAME_TOKEN, name, NAME_REGEXP);
+               }
+               catch (final IllegalArgumentException e) {
+                       result.addValidationMessage(
+                                       new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "name invalid-" + e.getMessage()));
+               }
+
+               try {
+                       Assertions.validateStringParameter(VERSION_TOKEN, version, VERSION_REGEXP);
+               }
+               catch (final IllegalArgumentException e) {
+                       result.addValidationMessage(
+                                       new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "version invalid-" + e.getMessage()));
+               }
+
+               return result;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean()
+        */
+       @Override
+       public void clean() {
+               name = Assertions.validateStringParameter(NAME_TOKEN, name, NAME_REGEXP);
+               version = Assertions.validateStringParameter(VERSION_TOKEN, version, VERSION_REGEXP);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString()
+        */
+       @Override
+       public String toString() {
+               final StringBuilder builder = new StringBuilder();
+               builder.append(this.getClass().getSimpleName());
+               builder.append(":(");
+               builder.append("name=");
+               builder.append(name);
+               builder.append(",version=");
+               builder.append(version);
+               builder.append(")");
+               return builder.toString();
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept)
+        */
+       @Override
+       public AxConcept copyTo(final AxConcept target) {
+               Assertions.argumentNotNull(target, "target may not be null");
+
+               final AxConcept copyObject = target;
+               Assertions.instanceOf(copyObject, AxArtifactKey.class);
+
+               final AxArtifactKey copy = ((AxArtifactKey) copyObject);
+               copy.setName(name);
+               copy.setVersion(version);
+
+               return copyObject;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#hashCode()
+        */
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + name.hashCode();
+               result = prime * result + version.hashCode();
+               return result;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#equals(java.lang. Object)
+        */
+       @Override
+       public boolean equals(final Object obj) {
+               if (obj == null) {
+                       return false;
+               }
+               if (this == obj) {
+                       return true;
+               }
+               if (getClass() != obj.getClass()) {
+                       return false;
+               }
+
+               final AxArtifactKey other = (AxArtifactKey) obj;
+
+               if (!name.equals(other.name)) {
+                       return false;
+               }
+               return version.equals(other.version);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see java.lang.Comparable#compareTo(java.lang.Object)
+        */
+       @Override
+       public int compareTo(final AxConcept otherObj) {
+               Assertions.argumentNotNull(otherObj, "comparison object may not be null");
+
+               if (this == otherObj) {
+                       return 0;
+               }
+               if (getClass() != otherObj.getClass()) {
+                       return this.hashCode() - otherObj.hashCode();
+               }
+
+               final AxArtifactKey other = (AxArtifactKey) otherObj;
+
+               if (!name.equals(other.name)) {
+                       return name.compareTo(other.name);
+               }
+               return version.compareTo(other.version);
+       }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConcept.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConcept.java
new file mode 100644 (file)
index 0000000..005d17d
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class is the base class for all Apex concept classes. It enforces implementation of abstract methods and interfaces on all concepts
+ * that are sub-classes of this class.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+
+@XmlType(name = "AxConcept", namespace = "http://www.ericsson.com/apex")
+
+public abstract class AxConcept implements Serializable, Comparable<AxConcept> {
+    private static final long serialVersionUID = -7434939557282697490L;
+
+    /**
+     * Default constructor
+     */
+    public AxConcept() {
+    }
+    
+    /**
+     * Copy constructor
+     * @param copyConcept the concept to copy from
+     */
+    public AxConcept(final AxConcept copyConcept) {
+        Assertions.argumentNotNull(copyConcept, "copy concept may not be null");
+               copyConcept.copyTo(this);
+    }
+    
+    /**
+     * Gets the key of this concept.
+     *
+     * @return the concept key
+     */
+    public abstract AxKey getKey();
+
+    /**
+     * Gets a list of all keys for this concept and all concepts that are defined or referenced by this concept and its sub-concepts.
+     *
+     * @return the keys used by this concept and it's contained concepts
+     */
+    public abstract List<AxKey> getKeys();
+
+    /**
+     * Validate that this concept is structurally correct.
+     *
+     * @param result the parameter in which the result of the validation will be returned
+     * @return the validation result that was passed in in the @{link result} field with the result of this validation added
+     */
+    public abstract AxValidationResult validate(AxValidationResult result);
+
+    /**
+     * Clean this concept, tidy up any superfluous information such as leading and trailing white space.
+     */
+    public abstract void clean();
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public abstract boolean equals(Object otherObject);
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public abstract String toString();
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public abstract int hashCode();
+
+    /**
+     * Copy this concept to another object. The target object must have the same class as the source object.
+     *
+     * @param target the target object to which this object is copied
+     * @return the copied object
+     */
+    public abstract AxConcept copyTo(AxConcept target);
+
+    /**
+     * Gets the ID string of this concept.
+     *
+     * @return the ID string of this concept
+     */
+    public String getID() {
+        return getKey().getID();
+    }
+
+    /**
+     * Checks if this key matches the given key ID.
+     *
+     * @param id the key ID to match against
+     * @return true, if this key matches the ID
+     */
+    public final boolean matchesID(final String id) {
+        Assertions.argumentNotNull(id, "id may not be null");
+
+        // Check the ID
+        return getID().equals(id);
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetter.java
new file mode 100644 (file)
index 0000000..d5d1752
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.Set;
+
+/**
+ * This interface is used to allow get methods to be placed on concepts that have embedded maps.
+ * <p>
+ * It forces those concepts with maps to implement the get methods specified on this interface as convenience methods to avoid concept users having to use a
+ * second level of referencing to access concepts in the the maps.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <C> the type of concept on which the interface is applied.
+ */
+public interface AxConceptGetter<C> {
+
+    /**
+     * Get the latest version for a concept with the given key.
+     *
+     * @param conceptKey The key of the concept
+     * @return The concept
+     */
+    C get(AxArtifactKey conceptKey);
+
+    /**
+     * Get the latest version for a concept with the given key name.
+     *
+     * @param conceptKeyName The name of the concept
+     * @return The concept
+     */
+    C get(String conceptKeyName);
+
+    /**
+     * Get the latest version for a concept with the given key name and version.
+     *
+     * @param conceptKeyName The name of the concept
+     * @param conceptKeyVersion The version of the concept
+     * @return The concept
+     */
+    C get(String conceptKeyName, String conceptKeyVersion);
+
+    /**
+     * Get the all versions for a concept with the given key name.
+     *
+     * @param conceptKeyName The name of the concept
+     * @return The concepts
+     */
+    Set<C> getAll(String conceptKeyName);
+
+    /**
+     * Get the all versions for a concept with the given key name and starting version.
+     *
+     * @param conceptKeyName The name of the concept
+     * @param conceptKeyVersion The first version version of the concept to get
+     * @return The concepts
+     */
+    Set<C> getAll(String conceptKeyName, String conceptKeyVersion);
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetterImpl.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxConceptGetterImpl.java
new file mode 100644 (file)
index 0000000..af97641
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * Implements concept getting from navigable maps.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <C> the type of concept on which the interface implementation is applied.
+ */
+public class AxConceptGetterImpl<C> implements AxConceptGetter<C> {
+
+    // The map from which to get concepts
+    private final NavigableMap<AxArtifactKey, C> conceptMap;
+
+    /**
+     * Constructor that sets the concept map on which the getter methods in the interface will operate..
+     *
+     * @param conceptMap the concept map on which the method will operate
+     */
+    public AxConceptGetterImpl(final NavigableMap<AxArtifactKey, C> conceptMap) {
+        this.conceptMap = conceptMap;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(com. ericsson.apex.core.basicmodel.concepts.AxArtifactKey)
+     */
+    @Override
+    public C get(final AxArtifactKey conceptKey) {
+        return conceptMap.get(conceptKey);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang. String)
+     */
+    @Override
+    public C get(final String conceptKeyName) {
+        Assertions.argumentNotNull(conceptKeyName, "conceptKeyName may not be null");
+
+        // The very fist key that could have this name
+        final AxArtifactKey lowestArtifactKey = new AxArtifactKey(conceptKeyName, "0.0.1");
+
+        // Check if we found a key for our name
+        AxArtifactKey foundKey = conceptMap.ceilingKey(lowestArtifactKey);
+        if (foundKey == null || !foundKey.getName().equals(conceptKeyName)) {
+            return null;
+        }
+
+        // Look for higher versions of the key
+        do {
+            final AxArtifactKey nextkey = conceptMap.higherKey(foundKey);
+            if (nextkey == null || !nextkey.getName().equals(conceptKeyName)) {
+                break;
+            }
+            foundKey = nextkey;
+        }
+        while (true);
+
+        return conceptMap.get(foundKey);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang. String, java.lang.String)
+     */
+    @Override
+    public C get(final String conceptKeyName, final String conceptKeyVersion) {
+        Assertions.argumentNotNull(conceptKeyName, "conceptKeyName may not be null");
+
+        if (conceptKeyVersion != null) {
+            return conceptMap.get(new AxArtifactKey(conceptKeyName, conceptKeyVersion));
+        }
+        else {
+            return this.get(conceptKeyName);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java. lang.String)
+     */
+    @Override
+    public Set<C> getAll(final String conceptKeyName) {
+        return getAll(conceptKeyName, null);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java. lang.String, java.lang.String)
+     */
+    @Override
+    public Set<C> getAll(final String conceptKeyName, final String conceptKeyVersion) {
+        final Set<C> returnSet = new TreeSet<>();
+
+        if (conceptKeyName == null) {
+            returnSet.addAll(conceptMap.values());
+            return returnSet;
+        }
+
+        // The very fist key that could have this name
+        final AxArtifactKey lowestArtifactKey = new AxArtifactKey(conceptKeyName, "0.0.1");
+        if (conceptKeyVersion != null) {
+            lowestArtifactKey.setVersion(conceptKeyVersion);
+        }
+
+        // Check if we found a key for our name
+        AxArtifactKey foundKey = conceptMap.ceilingKey(lowestArtifactKey);
+        if (foundKey == null || !foundKey.getName().equals(conceptKeyName)) {
+            return returnSet;
+        }
+        returnSet.add(conceptMap.get(foundKey));
+
+        // Look for higher versions of the key
+        do {
+            foundKey = conceptMap.higherKey(foundKey);
+            if (foundKey == null || !foundKey.getName().equals(conceptKeyName)) {
+                break;
+            }
+            returnSet.add(conceptMap.get(foundKey));
+        }
+        while (true);
+
+        return returnSet;
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKey.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKey.java
new file mode 100644 (file)
index 0000000..0d63dbf
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+/**
+ * The key uniquely identifies every entity in the system. This class is an abstract class to give a common parent for all key types in the
+ * system.
+ */
+public abstract class AxKey extends AxConcept {
+    private static final long serialVersionUID = 6281159885962014041L;
+
+    /** Regular expression to specify the structure of key names. */
+    public static final String NAME_REGEXP = "[A-Za-z0-9\\-_\\.]+";
+
+    /** Regular expression to specify the structure of key versions. */
+    public static final String VERSION_REGEXP = "[A-Za-z0-9.]+";
+
+    /** Regular expression to specify the structure of key IDs. */
+    public static final String KEY_ID_REGEXP = "[A-Za-z0-9\\-_\\.]+:[0-9].[0-9].[0-9]";
+
+    /** Specifies the value for names in NULL keys. */
+    public static final String NULL_KEY_NAME = "NULL";
+
+    /** Specifies the value for versions in NULL keys. */
+    public static final String NULL_KEY_VERSION = "0.0.0";
+
+    /**
+     * This enumeration is returned on key compatibility checks.
+     */
+    public enum Compatibility {
+        /** The keys have different names. */
+        DIFFERENT,
+        /** The name of the key matches but the Major version number of the keys is different (x in x.y.z do not match). */
+        MAJOR,
+        /** The name of the key matches but the Minor version number of the keys is different (y in x.y.z do not match). */
+        MINOR,
+        /** The name of the key matches but the Patch version number of the keys is different (z in x.y.z do not match). */
+        PATCH,
+        /** The keys match completely. */
+        IDENTICAL
+    }
+
+    /**
+     * Default constructor
+     */
+    public AxKey() {
+               super();
+    }
+    
+    /**
+     * Copy constructor
+     * @param copyConcept the concept to copy from
+     */
+    public AxKey(final AxKey copyConcept) {
+               super(copyConcept);
+    }
+    
+   /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getID()
+     */
+    @Override
+    public abstract String getID();
+
+    /**
+     * Return the result of a compatibility check of two keys.
+     *
+     * @param otherKey the key to check compatibility against
+     * @return the compatibility result of the check
+     */
+    public abstract Compatibility getCompatibility(AxKey otherKey);
+
+    /**
+     * Check if two keys are compatible, that is the keys are IDENTICAL or have only MINOR, PATCH differences.
+     *
+     * @param otherKey the key to check compatibility against
+     * @return true, if the keys are compatible
+     */
+    public abstract boolean isCompatible(AxKey otherKey);
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInfo.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInfo.java
new file mode 100644 (file)
index 0000000..1ffb40b
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.List;
+import java.util.Random;
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.apex.model.basicmodel.dao.converters.CDATAConditioner;
+import org.onap.apex.model.basicmodel.dao.converters.UUID2String;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * The key information on an {@link AxArtifactKey} key in an Apex policy model. Each {@link AxArtifactKey} must have an {@link AxKeyInfo} object. THe
+ * information held is the key's UUID and it's description.
+ * <p>
+ * Validation checks that all fields are defined and that the key is valid. It also observes that descriptions are blank and warns if the UUID is a zero UUID.
+ */
+
+@Entity
+@Table(name = "AxKeyInfo")
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexKeyInfo", namespace = "http://www.ericsson.com/apex")
+@XmlType(name = "AxKeyInfo", namespace = "http://www.ericsson.com/apex", propOrder = { "key", "uuid", "description" })
+
+public class AxKeyInfo extends AxConcept {
+    private static final long serialVersionUID = -4023935924068914308L;
+
+    private static final int MAX_DESCRIPTION_LENGTH_8192 = 8192;
+    private static final int UUID_BYTE_LENGTH_16 = 16;
+
+    @EmbeddedId
+    @XmlElement(name = "key", required = true)
+    private AxArtifactKey key;
+
+    @Column(name = "uuid")
+    @Convert(converter = UUID2String.class)
+    @XmlJavaTypeAdapter(value = UUID2String.class)
+    @XmlElement(name = "UUID", required = true)
+    private UUID uuid;
+
+    @Column(name = "description", length = MAX_DESCRIPTION_LENGTH_8192)
+    @Convert(converter = CDATAConditioner.class)
+    @XmlJavaTypeAdapter(value = CDATAConditioner.class)
+    @XmlElement(required = true)
+    private String description;
+
+    /**
+     * The Default Constructor creates this concept with a NULL artifact key.
+     */
+    public AxKeyInfo() {
+        this(new AxArtifactKey());
+    }
+
+    /**
+     * Copy constructor
+     * @param copyConcept the concept to copy from
+     */
+    public AxKeyInfo(final AxKeyInfo copyConcept) {
+               super(copyConcept);
+    }
+    
+    /**
+     * Constructor to create this concept with the specified key.
+     *
+     * @param key the key of the concept
+     */
+    public AxKeyInfo(final AxArtifactKey key) {
+        this(key, UUID.randomUUID(), "Generated description for concept referred to by key \"" + key.getID() + "\"");
+    }
+
+    /**
+     * Constructor to create this concept and set all its fields.
+     *
+     * @param key the key of the concept
+     * @param uuid the UUID of the concept
+     * @param description the description of the concept
+     */
+    public AxKeyInfo(final AxArtifactKey key, final UUID uuid, final String description) {
+        super();
+        Assertions.argumentNotNull(key, "key may not be null");
+        Assertions.argumentNotNull(uuid, "uuid may not be null");
+        Assertions.argumentNotNull(description, "description may not be null");
+
+        this.key = key;
+        this.uuid = uuid;
+        this.description = description.trim();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey()
+     */
+    @Override
+    public AxArtifactKey getKey() {
+        return key;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys()
+     */
+    @Override
+    public List<AxKey> getKeys() {
+        return key.getKeys();
+    }
+
+    /**
+     * Sets the key of the concept.
+     *
+     * @param key the concept key
+     */
+    public void setKey(final AxArtifactKey key) {
+        Assertions.argumentNotNull(key, "key may not be null");
+        this.key = key;
+    }
+
+    /**
+     * Gets the UUID of the concept.
+     *
+     * @return the uuid of the concept
+     */
+    public UUID getUUID() {
+        return uuid;
+    }
+
+    /**
+     * Sets the UUID of the concept.
+     *
+     * @param uuid the uuid of the concept
+     */
+    public void setUuid(final UUID uuid) {
+        Assertions.argumentNotNull(uuid, "uuid may not be null");
+        this.uuid = uuid;
+    }
+
+    /**
+     * Gets the description of the concept.
+     *
+     * @return the description of the concept
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Sets the description of the concept.
+     *
+     * @param description the description of the concept
+     */
+    public void setDescription(final String description) {
+        Assertions.argumentNotNull(description, "description may not be null");
+        this.description = description.trim();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.apex.model.basicmodel.concepts.AxValidationResult)
+     */
+    @Override
+    public AxValidationResult validate(final AxValidationResult resultIn) {
+        AxValidationResult result = resultIn;
+
+        if (key.equals(AxArtifactKey.getNullKey())) {
+            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+        }
+
+        result = key.validate(result);
+
+        if (description.trim().length() == 0) {
+            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.OBSERVATION, "description is blank"));
+        }
+
+        if (uuid.equals(new UUID(0, 0))) {
+            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.WARNING, "UUID is a zero UUID: " + new UUID(0, 0)));
+        }
+
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean()
+     */
+    @Override
+    public void clean() {
+        key.clean();
+        description = description.trim();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString()
+     */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(this.getClass().getSimpleName());
+        builder.append(":(");
+        builder.append("artifactId=");
+        builder.append(key);
+        builder.append(",uuid=");
+        builder.append(uuid);
+        builder.append(",description=");
+        builder.append(description);
+        builder.append(")");
+        return builder.toString();
+    }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept)
+        */
+       @Override
+       public AxConcept copyTo(final AxConcept target) {
+        Assertions.argumentNotNull(target, "target may not be null");
+
+        final Object copyObject = target;
+        Assertions.instanceOf(copyObject, AxKeyInfo.class);
+
+        final AxKeyInfo copy = ((AxKeyInfo) copyObject);
+        copy.setKey(new AxArtifactKey(key));
+        copy.setUuid(UUID.fromString(uuid.toString()));
+        copy.setDescription(description);
+
+        return copy;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + key.hashCode();
+        result = prime * result + uuid.hashCode();
+        result = prime * result + description.hashCode();
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#equals(java.lang. Object)
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        final AxKeyInfo other = (AxKeyInfo) obj;
+        if (!key.equals(other.key)) {
+            return false;
+        }
+        if (!uuid.equals(other.uuid)) {
+            return false;
+        }
+        final String thisdesc = CDATAConditioner.clean(description);
+        final String otherdesc = CDATAConditioner.clean(other.description);
+        return thisdesc.equals(otherdesc);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    @Override
+    public int compareTo(final AxConcept otherObj) {
+        if (otherObj == null) {
+            return -1;
+        }
+        if (this == otherObj) {
+            return 0;
+        }
+        if (getClass() != otherObj.getClass()) {
+            return this.hashCode() - otherObj.hashCode();
+        }
+
+        final AxKeyInfo other = (AxKeyInfo) otherObj;
+        if (!key.equals(other.key)) {
+            return key.compareTo(other.key);
+        }
+        if (!uuid.equals(other.uuid)) {
+            return uuid.compareTo(other.uuid);
+        }
+        return description.compareTo(other.description);
+    }
+
+    /**
+     * Generate a reproducible UUID for a given string seed.
+     *
+     * @param seed the seed
+     * @return the uuid
+     */
+    public static UUID generateReproducibleUUID(final String seed) {
+        final Random random;
+        if (seed != null && seed.length() > 0) {
+            random = new Random(seed.hashCode());
+        }
+        else {
+            random = new Random();
+        }
+        byte[] array = new byte[UUID_BYTE_LENGTH_16];
+        random.nextBytes(array);
+        return UUID.nameUUIDFromBytes(array);
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInformation.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyInformation.java
new file mode 100644 (file)
index 0000000..3082c4f
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import javax.persistence.CascadeType;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * The Class AxKeyInformation holds a map of the key information for the entire Apex model. All Apex models {@link AxModel} must have an
+ * {@link AxKeyInformation} field. The {@link AxKeyInformation} class implements the helper methods of the {@link AxConceptGetter} interface to allow
+ * {@link AxKeyInfo} instances to be retrieved by calling methods directly on this class without referencing the contained map.
+ * <p>
+ * Validation checks that the key is not null, that the key information map is not empty, that each key and value in the map is defined, that the key in each
+ * map entry matches the key if each entry value, and that no duplicate UUIDs exist. Each key information entry is then validated individually.
+ */
+@Entity
+@Table(name = "AxKeyInformation")
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "AxKeyInformation", namespace = "http://www.ericsson.com/apex", propOrder = { "key", "keyInfoMap" })
+
+public class AxKeyInformation extends AxConcept implements AxConceptGetter<AxKeyInfo> {
+       private static final long serialVersionUID = -2746380769017043888L;
+
+       @EmbeddedId
+       @XmlElement(name = "key", required = true)
+       private AxArtifactKey key;
+
+       // @formatter:off
+       @ManyToMany(cascade = CascadeType.ALL)
+       @JoinTable(
+                       joinColumns = {
+                                       @JoinColumn(name = "keyInfoMapName", referencedColumnName = "name"),
+                                       @JoinColumn(name = "keyInfoMapVersion", referencedColumnName = "version"),
+                       },
+                       inverseJoinColumns = {
+                                       @JoinColumn(name = "keyInfoName", referencedColumnName = "name"),
+                                       @JoinColumn(name = "keyInfoVersion", referencedColumnName = "version")
+                       })
+       private Map<AxArtifactKey, AxKeyInfo> keyInfoMap;
+       // @formatter:on
+
+       /**
+        * The Default Constructor creates this concept with a null key.
+        */
+       public AxKeyInformation() {
+               this(new AxArtifactKey());
+       }
+
+    /**
+     * Copy constructor
+     * @param copyConcept the concept to copy from
+     */
+    public AxKeyInformation(final AxKeyInformation copyConcept) {
+               super(copyConcept);
+    }
+    
+       /**
+        * Constructor to create this concept with the specified key.
+        *
+        * @param key the key of the concept
+        */
+       public AxKeyInformation(final AxArtifactKey key) {
+               this(key, new TreeMap<AxArtifactKey, AxKeyInfo>());
+       }
+
+       /**
+        * Constructor to create this concept and set all its fields.
+        *
+        * @param key the key of the concept
+        * @param keyInfoMap the key info map of the concept
+        */
+       public AxKeyInformation(final AxArtifactKey key, final Map<AxArtifactKey, AxKeyInfo> keyInfoMap) {
+               super();
+               Assertions.argumentNotNull(key, "key may not be null");
+               Assertions.argumentNotNull(keyInfoMap, "keyInfoMap may not be null");
+
+               this.key = key;
+               this.keyInfoMap = new TreeMap<>();
+               this.keyInfoMap.putAll(keyInfoMap);
+       }
+
+       /**
+        * When a model is unmarshalled from disk or from the database, the key information map is returned as a raw Hash Map. This method is called by JAXB
+        * after unmarshaling and is used to convert the hash map to a {@link NavigableMap} so that it will work with the {@link AxConceptGetter} interface.
+        *
+        * @param u the unmarshaler that is unmarshaling the model
+        * @param parent the parent object of this object in the unmarshaler
+        */
+       public void afterUnmarshal(final Unmarshaller u, final Object parent) {
+               // The map must be navigable to allow name and version searching,
+               // unmarshaling returns a hash map
+               final NavigableMap<AxArtifactKey, AxKeyInfo> navigablekeyInfoMap = new TreeMap<>();
+               navigablekeyInfoMap.putAll(keyInfoMap);
+               keyInfoMap = navigablekeyInfoMap;
+       }
+
+       /**
+        * This method generates default key information for all keys found in the concept passed in as a parameter that do not already have key information.
+        *
+        * @param concept the concept for which to generate key information
+        */
+       public void generateKeyInfo(final AxConcept concept) {
+               for (final AxKey axKey : concept.getKeys()) {
+                       if (!(axKey instanceof AxArtifactKey)) {
+                               continue;
+                       }
+
+                       final AxArtifactKey artifactKey = (AxArtifactKey) axKey;
+                       if (!keyInfoMap.containsKey(artifactKey)) {
+                               final AxKeyInfo keyInfo = new AxKeyInfo(artifactKey);
+                               //generate a reproducible UUID
+                               keyInfo.setUuid(AxKeyInfo.generateReproducibleUUID(keyInfo.getID() + keyInfo.getDescription()));
+                               keyInfoMap.put(artifactKey, keyInfo);
+                       }
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey()
+        */
+       @Override
+       public AxArtifactKey getKey() {
+               return key;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys()
+        */
+       @Override
+       public List<AxKey> getKeys() {
+               final List<AxKey> keyList = key.getKeys();
+               keyList.addAll(keyInfoMap.keySet());
+
+               return keyList;
+       }
+
+       /**
+        * Sets the key of this concept.
+        *
+        * @param key the key of this concept
+        */
+       public void setKey(final AxArtifactKey key) {
+               Assertions.argumentNotNull(key, "key may not be null");
+               this.key = key;
+       }
+
+       /**
+        * Gets the key info map of this concept.
+        *
+        * @return the key info map of this concept
+        */
+       public Map<AxArtifactKey, AxKeyInfo> getKeyInfoMap() {
+               return keyInfoMap;
+       }
+
+       /**
+        * Sets the key info map of this concept.
+        *
+        * @param keyInfoMap the key info map of this concept
+        */
+       public void setKeyInfoMap(final Map<AxArtifactKey, AxKeyInfo> keyInfoMap) {
+               Assertions.argumentNotNull(keyInfoMap, "keyInfoMap may not be null");
+               this.keyInfoMap = new TreeMap<>();
+               this.keyInfoMap.putAll(keyInfoMap);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.apex.model.basicmodel.concepts.AxValidationResult)
+        */
+       @Override
+       public AxValidationResult validate(final AxValidationResult resultIn) {
+               AxValidationResult result = resultIn;
+
+               if (key.equals(AxArtifactKey.getNullKey())) {
+                       result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+               }
+
+               result = key.validate(result);
+
+               if (keyInfoMap.size() == 0) {
+                       result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "keyInfoMap may not be empty"));
+               }
+               else {
+                       final Set<UUID> uuidSet = new TreeSet<>();
+
+                       for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry : keyInfoMap.entrySet()) {
+                               result = validateKeyInfoEntry(keyInfoEntry, uuidSet, result);
+                       }
+               }
+
+               return result;
+       }
+
+       /**
+        * Validate an key information entry
+        * @param keyInfoEntry the key information entry
+        * @param uuidSet the set of UUIDs encountered in validation so far, the UUID of this entry is added to the set
+        * @param result the validation result to append to
+        * @return The validation result
+        */
+       private AxValidationResult validateKeyInfoEntry(final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry, Set<UUID> uuidSet, AxValidationResult result) {
+               if (keyInfoEntry.getKey().equals(AxArtifactKey.getNullKey())) {
+                       result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+                                       "key on keyInfoMap entry " + keyInfoEntry.getKey() + " may not be the null key"));
+               }
+               else if (keyInfoEntry.getValue() == null) {
+                       result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+                                       "value on keyInfoMap entry " + keyInfoEntry.getKey() + " may not be null"));
+               }
+               else {
+                       if (!keyInfoEntry.getKey().equals(keyInfoEntry.getValue().getKey())) {
+                               result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+                                               "key on keyInfoMap entry " + keyInfoEntry.getKey() + " does not equal entry key " + keyInfoEntry.getValue().getKey()));
+                       }
+
+                       result = keyInfoEntry.getValue().validate(result);
+
+                       if (uuidSet.contains(keyInfoEntry.getValue().getUUID())) {
+                               result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+                                               "duplicate UUID found on keyInfoMap entry " + keyInfoEntry.getKey() + ":" + keyInfoEntry.getValue().getUUID()));
+                       }
+                       else {
+                               uuidSet.add(keyInfoEntry.getValue().getUUID());
+                       }
+               }
+               
+               return result;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean()
+        */
+       @Override
+       public void clean() {
+               key.clean();
+               for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry : keyInfoMap.entrySet()) {
+                       keyInfoEntry.getKey().clean();
+                       keyInfoEntry.getValue().clean();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString()
+        */
+       @Override
+       public String toString() {
+               final StringBuilder builder = new StringBuilder();
+               builder.append(this.getClass().getSimpleName());
+               builder.append(":(");
+               builder.append("key=");
+               builder.append(key);
+               builder.append(",keyInfoMap=");
+               builder.append(keyInfoMap);
+               builder.append(")");
+               return builder.toString();
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept)
+        */
+       @Override
+       public AxConcept copyTo(final AxConcept target) {
+               Assertions.argumentNotNull(target, "target may not be null");
+
+               final Object copyObject = target;
+               Assertions.instanceOf(copyObject, AxKeyInformation.class);
+
+               final AxKeyInformation copy = ((AxKeyInformation) copyObject);
+               copy.setKey(new AxArtifactKey(key));
+               final Map<AxArtifactKey, AxKeyInfo> newKeyInfoMap = new TreeMap<>();
+               for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoMapEntry : keyInfoMap.entrySet()) {
+                       newKeyInfoMap.put(new AxArtifactKey(keyInfoMapEntry.getKey()), new AxKeyInfo(keyInfoMapEntry.getValue()));
+               }
+               copy.setKeyInfoMap(newKeyInfoMap);
+
+               return copy;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#hashCode()
+        */
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + key.hashCode();
+               result = prime * result + keyInfoMap.hashCode();
+               return result;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#equals(java.lang. Object)
+        */
+       @Override
+       public boolean equals(final Object obj) {
+               if (obj == null) {
+                       return false;
+               }
+               if (this == obj) {
+                       return true;
+               }
+
+               if (getClass() != obj.getClass()) {
+                       return false;
+               }
+
+               final AxKeyInformation other = (AxKeyInformation) obj;
+               if (!key.equals(other.key)) {
+                       return false;
+               }
+               return keyInfoMap.equals(other.keyInfoMap);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see java.lang.Comparable#compareTo(java.lang.Object)
+        */
+       @Override
+       public int compareTo(final AxConcept otherObj) {
+               if (otherObj == null) {
+                       return -1;
+               }
+               if (this == otherObj) {
+                       return 0;
+               }
+               if (getClass() != otherObj.getClass()) {
+                       return this.hashCode() - otherObj.hashCode();
+               }
+
+               final AxKeyInformation other = (AxKeyInformation) otherObj;
+               if (!key.equals(other.key)) {
+                       return key.compareTo(other.key);
+               }
+               if (!keyInfoMap.equals(other.keyInfoMap)) {
+                       return (keyInfoMap.hashCode() - other.keyInfoMap.hashCode());
+               }
+
+               return 0;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(com. ericsson.apex.core.basicmodel.concepts.AxArtifactKey)
+        */
+       @Override
+       public AxKeyInfo get(final AxArtifactKey conceptKey) {
+               return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKey);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang. String)
+        */
+       @Override
+       public AxKeyInfo get(final String conceptKeyName) {
+               return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKeyName);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang. String, java.lang.String)
+        */
+       @Override
+       public AxKeyInfo get(final String conceptKeyName, final String conceptKeyVersion) {
+               return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKeyName, conceptKeyVersion);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java. lang.String)
+        */
+       @Override
+       public Set<AxKeyInfo> getAll(final String conceptKeyName) {
+               return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).getAll(conceptKeyName);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java. lang.String, java.lang.String)
+        */
+       @Override
+       public Set<AxKeyInfo> getAll(final String conceptKeyName, final String conceptKeyVersion) {
+               return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).getAll(conceptKeyName, conceptKeyVersion);
+       }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyUse.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxKeyUse.java
new file mode 100644 (file)
index 0000000..990c8f7
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.List;
+
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class records a usage of a key in the system. When the list of keys being used by a concept is built using the getKeys() method of
+ * the {@link AxConcept} class, an instance of this class is created for every key occurrence. The list of keys returned by the getKeys()
+ * method is a list of {@link AxKeyUse} objects.
+ * <p>
+ * Validation checks that each key is valid.
+ */
+
+public class AxKeyUse extends AxKey {
+    private static final long serialVersionUID = 2007147220109881705L;
+
+    private AxKey usedKey;
+
+    /**
+     * The Default Constructor creates this concept with a null key.
+     */
+    public AxKeyUse() {
+        this(new AxArtifactKey());
+    }
+
+    /**
+     * Copy constructor
+     * @param copyConcept the concept to copy from
+     */
+    public AxKeyUse(final AxKeyUse copyConcept) {
+               super(copyConcept);
+    }
+    
+    /**
+     * This constructor creates an instance of this class, and holds a reference to a used key.
+     *
+     * @param usedKey a used key
+     */
+    public AxKeyUse(final AxKey usedKey) {
+        Assertions.argumentNotNull(usedKey, "usedKey may not be null");
+        this.usedKey = usedKey;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey()
+     */
+    @Override
+    public AxKey getKey() {
+        return usedKey;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys()
+     */
+    @Override
+    public List<AxKey> getKeys() {
+        return usedKey.getKeys();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getID()
+     */
+    @Override
+    public String getID() {
+        return usedKey.getID();
+    }
+
+    /**
+     * Sets the key.
+     *
+     * @param key the key
+     */
+    public void setKey(final AxKey key) {
+        Assertions.argumentNotNull(key, "usedKey may not be null");
+        this.usedKey = key;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getCompatibility(com. ericsson.apex.model.basicmodel.concepts.AxKey)
+     */
+    @Override
+    public AxKey.Compatibility getCompatibility(final AxKey otherKey) {
+        return usedKey.getCompatibility(otherKey);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#isCompatible(com. ericsson.apex.model.basicmodel.concepts.AxKey)
+     */
+    @Override
+    public boolean isCompatible(final AxKey otherKey) {
+        return usedKey.isCompatible(otherKey);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.apex.model.basicmodel.concepts.AxValidationResult)
+     */
+    @Override
+    public AxValidationResult validate(final AxValidationResult result) {
+        if (usedKey.equals(AxArtifactKey.getNullKey())) {
+            result.addValidationMessage(
+                    new AxValidationMessage(usedKey, this.getClass(), ValidationResult.INVALID, "usedKey is a null key"));
+        }
+        return usedKey.validate(result);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean()
+     */
+    @Override
+    public void clean() {
+        usedKey.clean();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString()
+     */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(this.getClass().getSimpleName());
+        builder.append(":(");
+        builder.append("usedKey=");
+        builder.append(usedKey);
+        builder.append(")");
+        return builder.toString();
+    }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept)
+        */
+       @Override
+       public AxConcept copyTo(final AxConcept target) {
+        Assertions.argumentNotNull(target, "target may not be null");
+
+        final Object copyObject = target;
+        Assertions.instanceOf(copyObject, AxKeyUse.class);
+
+        final AxKeyUse copy = ((AxKeyUse) copyObject);
+        try {
+                       copy.usedKey = usedKey.getClass().newInstance();
+               }
+        catch (Exception e) {
+               throw new ApexRuntimeException("error copying concept key: " + e.getMessage(), e);
+               }
+        usedKey.copyTo(copy.usedKey);
+        
+        return copy;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + usedKey.hashCode();
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#equals(java.lang. Object)
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            throw new IllegalArgumentException("comparison object may not be null");
+        }
+
+        if (this == obj) {
+            return true;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        final AxKeyUse other = (AxKeyUse) obj;
+        return usedKey.equals(other.usedKey);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    @Override
+    public int compareTo(final AxConcept otherObj) {
+        Assertions.argumentNotNull(otherObj, "comparison object may not be null");
+
+        if (this == otherObj) {
+            return 0;
+        }
+        if (getClass() != otherObj.getClass()) {
+            return this.hashCode() - otherObj.hashCode();
+        }
+
+        final AxKeyUse other = (AxKeyUse) otherObj;
+
+        return usedKey.compareTo(other.usedKey);
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxModel.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxModel.java
new file mode 100644 (file)
index 0000000..f0489c7
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.persistence.CascadeType;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinColumns;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.apex.model.basicmodel.service.ModelService;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class is the base class for all models in Apex. All model classes inherit from this model so all models must have a key and have key information.
+ * <p>
+ * Validation checks that the model key is valid. It goes on to check for null keys and checks each key for uniqueness in the model. A check is carried out to
+ * ensure that an {@link AxKeyInfo} instance exists for every {@link AxArtifactKey} key. For each {@link AxReferenceKey} instance, a check is made that its
+ * parent and local name are nut null and that a {@link AxKeyInfo} entry exists for its parent. Then a check is made that each used {@link AxArtifactKey} and
+ * {@link AxReferenceKey} usage references a key that exists. Finally, a check is made to ensure that an {@link AxArtifactKey} instance exists for every
+ * {@link AxKeyInfo} instance.
+ */
+
+@Entity
+@Table(name = "AxModel")
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+
+@XmlRootElement(name = "apexModel", namespace = "http://www.ericsson.com/apex")
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "AxModel", namespace = "http://www.ericsson.com/apex", propOrder = { "key", "keyInformation" })
+
+public class AxModel extends AxConcept {
+    private static final String IS_A_NULL_KEY = " is a null key";
+
+       private static final long serialVersionUID = -771659065637205430L;
+
+    @EmbeddedId
+    @XmlElement(name = "key", required = true)
+    private AxArtifactKey key;
+
+    // @formatter:off
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumns({
+        @JoinColumn(name = "keyInformationName", referencedColumnName = "name"),
+        @JoinColumn(name = "keyInformationVersion", referencedColumnName = "version")
+    })
+    @XmlElement(name = "keyInformation", required = true)
+    private AxKeyInformation keyInformation;
+    // @formatter:on
+
+    /**
+     * The Default Constructor creates this concept with a NULL artifact key.
+     */
+    public AxModel() {
+        this(new AxArtifactKey());
+    }
+
+    /**
+     * Copy constructor
+     * @param copyConcept the concept to copy from
+     */
+    public AxModel(final AxModel copyConcept) {
+               super(copyConcept);
+    }
+    
+    /**
+     * Constructor to create this concept with the specified key.
+     *
+     * @param key the key of this concept
+     */
+    public AxModel(final AxArtifactKey key) {
+        this(key, new AxKeyInformation(new AxArtifactKey(key.getName() + "_KeyInfo", key.getVersion())));
+    }
+
+    /**
+     * Constructor to create this concept and set all its fields.
+     *
+     * @param key the key of this concept
+     * @param keyInformation the key information of this concept
+     */
+    public AxModel(final AxArtifactKey key, final AxKeyInformation keyInformation) {
+        super();
+        Assertions.argumentNotNull(key, "key may not be null");
+        Assertions.argumentNotNull(keyInformation, "keyInformation may not be null");
+
+        this.key = key;
+        this.keyInformation = keyInformation;
+    }
+
+    /**
+     * Registers this model with the {@link ModelService}. All models are registered with the model service so that models can be references from anywhere in
+     * the Apex system without being passed as references through deep call chains.
+     */
+    public void register() {
+        ModelService.registerModel(AxKeyInformation.class, getKeyInformation());
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey()
+     */
+    @Override
+    public AxArtifactKey getKey() {
+        return key;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys()
+     */
+    @Override
+    public List<AxKey> getKeys() {
+        final List<AxKey> keyList = key.getKeys();
+
+        // We just add the key for the KeyInformation itself. We don't add the
+        // keys from key information because
+        // that is a list of key information for existing keys
+        keyList.add(keyInformation.getKey());
+
+        return keyList;
+    }
+
+    /**
+     * Sets the key of this concept.
+     *
+     * @param key the key of this concept
+     */
+    public void setKey(final AxArtifactKey key) {
+        Assertions.argumentNotNull(key, "key may not be null");
+        this.key = key;
+    }
+
+    /**
+     * Gets the key information of this concept.
+     *
+     * @return the key information of this concept
+     */
+    public AxKeyInformation getKeyInformation() {
+        return keyInformation;
+    }
+
+    /**
+     * Sets the key information of this concept.
+     *
+     * @param keyInformation the key information of this concept
+     */
+    public void setKeyInformation(final AxKeyInformation keyInformation) {
+        Assertions.argumentNotNull(keyInformation, "keyInformation may not be null");
+        this.keyInformation = keyInformation;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.apex.model.basicmodel.concepts.AxValidationResult)
+     */
+    @Override
+    public AxValidationResult validate(final AxValidationResult resultIn) {
+        AxValidationResult result = resultIn;
+
+        if (key.equals(AxArtifactKey.getNullKey())) {
+            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
+        }
+
+        result = key.validate(result);
+        result = keyInformation.validate(result);
+
+        // Key consistency check
+        final Set<AxArtifactKey> artifactKeySet = new TreeSet<>();
+        final Set<AxReferenceKey> referenceKeySet = new TreeSet<>();
+        final Set<AxKeyUse> usedKeySet = new TreeSet<>();
+
+        for (final AxKey axKey : this.getKeys()) {
+            // Check for the two type of keys we have
+            if (axKey instanceof AxArtifactKey) {
+                       result = validateArtifactKeyInModel((AxArtifactKey) axKey, artifactKeySet, result);
+            }
+            else if (axKey instanceof AxReferenceKey) {
+                               result = validateReferenceKeyInModel((AxReferenceKey) axKey, referenceKeySet, result);
+            }
+            // It must be an AxKeyUse, nothing else is legal
+            else {
+                usedKeySet.add((AxKeyUse) axKey);
+            }
+        }
+
+        // Check all reference keys have correct parent keys
+        for (final AxReferenceKey referenceKey : referenceKeySet) {
+            if (!artifactKeySet.contains(referenceKey.getParentArtifactKey())) {
+                result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+                        "parent artifact key not found for reference key " + referenceKey));
+            }
+        }
+
+        result = validateKeyUses(usedKeySet, artifactKeySet, referenceKeySet, result);
+
+        // Check key information for unused key information
+        for (final AxArtifactKey keyInfoKey : keyInformation.getKeyInfoMap().keySet()) {
+            if (!artifactKeySet.contains(keyInfoKey)) {
+                result.addValidationMessage(
+                        new AxValidationMessage(keyInfoKey, this.getClass(), ValidationResult.WARNING, "key not found for key information entry"));
+            }
+        }
+
+        return result;
+    }
+
+       /**
+     * Check for consistent usage of an artifact key in the model
+     * @param artifactKey The artifact key to check
+     * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to the set 
+     * @param result The validation result to append to
+     * @return the result of the validation
+     */
+    private AxValidationResult validateArtifactKeyInModel(final AxArtifactKey artifactKey, Set<AxArtifactKey> artifactKeySet, AxValidationResult result) {
+        // Null key check
+        if (artifactKey.equals(AxArtifactKey.getNullKey())) {
+            result.addValidationMessage(
+                    new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key " + artifactKey + IS_A_NULL_KEY));
+        }
+
+        // Null key name start check
+        if (artifactKey.getName().toUpperCase().startsWith(AxKey.NULL_KEY_NAME)) {
+            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+                    "key " + artifactKey + " name starts with keyword " + AxKey.NULL_KEY_NAME));
+        }
+
+        // Unique key check
+        if (artifactKeySet.contains(artifactKey)) {
+            result.addValidationMessage(
+                    new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "duplicate key " + artifactKey + " found"));
+        }
+        else {
+            artifactKeySet.add(artifactKey);
+        }
+
+        // Key information check
+        if (!keyInformation.getKeyInfoMap().containsKey(artifactKey)) {
+            result.addValidationMessage(
+                    new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key information not found for key " + artifactKey));
+        }
+        
+        return result;
+       }
+
+       /**
+     * Check for consistent usage of a reference key in the model
+     * @param artifactKey The reference key to check
+     * @param referenceKeySet The set of reference keys encountered so far, this key is appended to the set 
+     * @param result The validation result to append to
+     * @return the result of the validation
+     */
+    private AxValidationResult validateReferenceKeyInModel(final AxReferenceKey referenceKey, Set<AxReferenceKey> referenceKeySet, AxValidationResult result) {
+        // Null key check
+        if (referenceKey.equals(AxReferenceKey.getNullKey())) {
+            result.addValidationMessage(
+                    new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key " + referenceKey + IS_A_NULL_KEY));
+        }
+
+        // Null parent key check
+        if (referenceKey.getParentArtifactKey().equals(AxArtifactKey.getNullKey())) {
+            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+                    "parent artifact key of key " + referenceKey + IS_A_NULL_KEY));
+        }
+
+        // Null local name check
+        if (referenceKey.getLocalName().equals(AxKey.NULL_KEY_NAME)) {
+            result.addValidationMessage(
+                    new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key " + referenceKey + " has a null local name"));
+        }
+
+        // Null key name start check
+        if (referenceKey.getParentArtifactKey().getName().toUpperCase().startsWith(AxKey.NULL_KEY_NAME)) {
+            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+                    "key " + referenceKey + " parent name starts with keyword " + AxKey.NULL_KEY_NAME));
+        }
+
+        // Unique key check
+        if (referenceKeySet.contains(referenceKey)) {
+            result.addValidationMessage(
+                    new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "duplicate key " + referenceKey + " found"));
+        }
+        else {
+            referenceKeySet.add(referenceKey);
+        }
+
+        // Key information check
+        if (!keyInformation.getKeyInfoMap().containsKey(referenceKey.getParentArtifactKey())) {
+            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
+                    "key information not found for parent key of key " + referenceKey));
+        }
+
+        return result;
+       }
+    
+       /**
+     * Check for consistent usage of cross-key references in the model
+     * @param usedKeySet The set of all keys used in the model
+     * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to the set 
+     * @param referenceKeySet The set of reference keys encountered so far, this key is appended to the set 
+     * @param result The validation result to append to
+     * @return the result of the validation
+     */
+       private AxValidationResult validateKeyUses(final Set<AxKeyUse> usedKeySet, final Set<AxArtifactKey> artifactKeySet,
+                       final Set<AxReferenceKey> referenceKeySet, AxValidationResult result) {
+        // Check all key uses
+        for (final AxKeyUse usedKey : usedKeySet) {
+            if (usedKey.getKey() instanceof AxArtifactKey) {
+                // AxArtifact key usage, check the key exists
+                if (!artifactKeySet.contains(usedKey.getKey())) {
+                    result.addValidationMessage(new AxValidationMessage(usedKey.getKey(), this.getClass(), ValidationResult.INVALID,
+                            "an artifact key used in the model is not defined"));
+                }
+            }
+            else {
+                // AxReference key usage, check the key exists
+                if (!referenceKeySet.contains(usedKey.getKey())) {
+                    result.addValidationMessage(new AxValidationMessage(usedKey.getKey(), this.getClass(), ValidationResult.INVALID,
+                            "a reference key used in the model is not defined"));
+                }
+            }
+        }
+        
+        return result;
+       }
+
+
+       /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean()
+     */
+    @Override
+    public void clean() {
+        key.clean();
+        keyInformation.clean();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString()
+     */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(this.getClass().getSimpleName());
+        builder.append(":(");
+        builder.append("key=");
+        builder.append(key);
+        builder.append(",keyInformation=");
+        builder.append(keyInformation);
+        builder.append(")");
+        return builder.toString();
+    }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept)
+        */
+       @Override
+       public AxConcept copyTo(final AxConcept target) {
+        Assertions.argumentNotNull(target, "target may not be null");
+
+        final Object copyObject = target;
+        Assertions.instanceOf(copyObject, AxModel.class);
+
+        final AxModel copy = ((AxModel) copyObject);
+        copy.setKey(new AxArtifactKey(key));
+        copy.setKeyInformation(new AxKeyInformation(keyInformation));
+
+        return copy;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + key.hashCode();
+        result = prime * result + keyInformation.hashCode();
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#equals(java.lang. Object)
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        final AxModel other = (AxModel) obj;
+        if (!key.equals(other.key)) {
+            return false;
+        }
+        return keyInformation.equals(other.keyInformation);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    @Override
+    public int compareTo(final AxConcept otherObj) {
+        if (otherObj == null) {
+            return -1;
+        }
+        if (this == otherObj) {
+            return 0;
+        }
+        if (getClass() != otherObj.getClass()) {
+            return this.hashCode() - otherObj.hashCode();
+        }
+
+        final AxModel other = (AxModel) otherObj;
+        if (!key.equals(other.key)) {
+            return key.compareTo(other.key);
+        }
+        return keyInformation.compareTo(other.keyInformation);
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxReferenceKey.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxReferenceKey.java
new file mode 100644 (file)
index 0000000..9401152
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * A reference key identifies entities in the system that are contained in other entities. Every contained concept in the system must have an
+ * {@link AxReferenceKey} to identify it. Non-contained first order concepts are identified using an {@link AxArtifactKey} key.
+ * <p>
+ * An {@link AxReferenceKey} contains an {@link AxArtifactKey} key reference to the first order entity that contains it. The local name of the reference key
+ * must uniquely identify the referenced concept among those concepts contained in the reference key's parent. In other words, if a parent concept has more than
+ * one child, the local name in the key of all its children must be unique.
+ * <p>
+ * If a reference key's parent is itself a reference key, then the parent's local name must be set in the reference key. If the parent is a first order concept,
+ * then the parent's local name in the key will be set to NULL.
+ * <p>
+ * Key validation checks that the parent name and parent version fields match the {@link NAME_REGEXP} and {@link VERSION_REGEXP} regular expressions
+ * respectively and that the local name fields match the {@link LOCAL_NAME_REGEXP} regular expression.
+ */
+@Embeddable
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "apexReferenceKey", namespace = "http://www.ericsson.com/apex")
+@XmlType(name = "AxReferenceKey", namespace = "http://www.ericsson.com/apex", propOrder = { "parentKeyName", "parentKeyVersion", "parentLocalName",
+        "localName" })
+
+public class AxReferenceKey extends AxKey {
+       private static final String PARENT_KEY_NAME = "parentKeyName";
+       private static final String PARENT_KEY_VERSION = "parentKeyVersion";
+       private static final String PARENT_LOCAL_NAME = "parentLocalName";
+    private static final String LOCAL_NAME = "localName";
+
+       private static final long serialVersionUID = 8932717618579392561L;
+
+    /** Regular expression to specify the structure of local names in reference keys.*/
+    public static final String LOCAL_NAME_REGEXP = "[A-Za-z0-9\\-_\\.]+|^$";
+
+    /** Regular expression to specify the structure of IDs in reference keys.*/
+    public static final String REFERENCE_KEY_ID_REGEXP = "[A-Za-z0-9\\-_]+:[0-9].[0-9].[0-9]:[A-Za-z0-9\\-_]+:[A-Za-z0-9\\-_]+";
+
+    private static final int PARENT_NAME_FIELD = 0;
+    private static final int PARENT_VERSION_FIELD = 1;
+    private static final int PARENT_LOCAL_NAME_FIELD = 2;
+    private static final int LOCAL_NAME_FIELD = 3;
+
+    @Column(name = PARENT_KEY_NAME)
+    @XmlElement(required = true)
+    private String parentKeyName;
+
+    @Column(name = PARENT_KEY_VERSION)
+    @XmlElement(required = true)
+    private String parentKeyVersion;
+
+    @Column(name = PARENT_LOCAL_NAME)
+    @XmlElement(required = true)
+    private String parentLocalName;
+
+    @Column(name = LOCAL_NAME)
+    @XmlElement(required = true)
+    private String localName;
+
+    /**
+     * The default constructor creates a null reference key.
+     */
+    public AxReferenceKey() {
+        this(NULL_KEY_NAME, NULL_KEY_VERSION, NULL_KEY_NAME, NULL_KEY_NAME);
+    }
+
+    /**
+     * The Copy Constructor creates a key by copying another key.
+     *
+     * @param referenceKey the reference key to copy from
+     */
+    public AxReferenceKey(final AxReferenceKey referenceKey) {
+        this(referenceKey.getParentKeyName(), referenceKey.getParentKeyVersion(), referenceKey.getParentLocalName(), referenceKey.getLocalName());
+    }
+
+    /**
+     * Constructor to create a null reference key for the specified parent artifact key.
+     *
+     * @param axArtifactKey the parent artifact key of this reference key
+     */
+    public AxReferenceKey(final AxArtifactKey axArtifactKey) {
+        this(axArtifactKey.getName(), axArtifactKey.getVersion(), NULL_KEY_NAME, NULL_KEY_NAME);
+    }
+
+    /**
+     * Constructor to create a reference key for the given parent artifact key with the given local name.
+     *
+     * @param axArtifactKey the parent artifact key of this reference key
+     * @param localName the local name of this reference key
+     */
+    public AxReferenceKey(final AxArtifactKey axArtifactKey, final String localName) {
+        this(axArtifactKey, NULL_KEY_NAME, localName);
+    }
+
+    /**
+     * Constructor to create a reference key for the given parent reference key with the given local name.
+     *
+     * @param parentReferenceKey the parent reference key of this reference key
+     * @param localName the local name of this reference key
+     */
+    public AxReferenceKey(final AxReferenceKey parentReferenceKey, final String localName) {
+        this(parentReferenceKey.getParentArtifactKey(), parentReferenceKey.getLocalName(), localName);
+    }
+
+    /**
+     * Constructor to create a reference key for the given parent reference key (specified by the parent reference key's artifact key and local name) with the
+     * given local name.
+     *
+     * @param axArtifactKey the artifact key of the parent reference key of this reference key
+     * @param parentLocalName the local name of the parent reference key of this reference key
+     * @param localName the local name of this reference key
+     */
+    public AxReferenceKey(final AxArtifactKey axArtifactKey, final String parentLocalName, final String localName) {
+        this(axArtifactKey.getName(), axArtifactKey.getVersion(), parentLocalName, localName);
+    }
+
+    /**
+     * Constructor to create a reference key for the given parent artifact key (specified by the parent artifact key's name and version) with the given local
+     * name.
+     *
+     * @param parentKeyName the name of the parent artifact key of this reference key
+     * @param parentKeyVersion the version of the parent artifact key of this reference key
+     * @param localName the local name of this reference key
+     */
+    public AxReferenceKey(final String parentKeyName, final String parentKeyVersion, final String localName) {
+        this(parentKeyName, parentKeyVersion, NULL_KEY_NAME, localName);
+    }
+
+    /**
+     * Constructor to create a reference key for the given parent key (specified by the parent key's name, version nad local name) with the given local name.
+     *
+     * @param parentKeyName the parent key name of this reference key
+     * @param parentKeyVersion the parent key version of this reference key
+     * @param parentLocalName the parent local name of this reference key
+     * @param localName the local name of this reference key
+     */
+    public AxReferenceKey(final String parentKeyName, final String parentKeyVersion, final String parentLocalName, final String localName) {
+        super();
+        this.parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP);
+        this.parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP);
+        this.parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP);
+        this.localName = Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP);
+    }
+
+    /**
+     * Constructor to create a key from the specified key ID.
+     *
+     * @param id the key ID in a format that respects the {@link KEY_ID_REGEXP}
+     */
+    public AxReferenceKey(final String id) {
+        final String conditionedId = Assertions.validateStringParameter("id", id, REFERENCE_KEY_ID_REGEXP);
+
+        // Split on colon, if the id passes the regular expression test above
+        // it'll have just three colons separating the parent name,
+        // parent version, parent local name, and and local name
+        // No need for range checks or size checks on the array
+        final String[] nameVersionNameArray = conditionedId.split(":");
+
+        // Initiate the new key
+        parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, nameVersionNameArray[PARENT_NAME_FIELD], NAME_REGEXP);
+        parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, nameVersionNameArray[PARENT_VERSION_FIELD], VERSION_REGEXP);
+        parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, nameVersionNameArray[PARENT_LOCAL_NAME_FIELD], LOCAL_NAME_REGEXP);
+        localName = Assertions.validateStringParameter(LOCAL_NAME, nameVersionNameArray[LOCAL_NAME_FIELD], LOCAL_NAME_REGEXP);
+    }
+
+    /**
+     * Get a null reference key.
+     *
+     * @return a null reference key
+     */
+    public static AxReferenceKey getNullKey() {
+        return new AxReferenceKey(AxKey.NULL_KEY_NAME, AxKey.NULL_KEY_VERSION, AxKey.NULL_KEY_NAME, AxKey.NULL_KEY_NAME);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKey()
+     */
+    @Override
+    public AxReferenceKey getKey() {
+        return this;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#getKeys()
+     */
+    @Override
+    public List<AxKey> getKeys() {
+        final List<AxKey> keyList = new ArrayList<>();
+        keyList.add(getKey());
+        return keyList;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getID()
+     */
+    @Override
+    public String getID() {
+        return parentKeyName + ':' + parentKeyVersion + ':' + parentLocalName + ':' + localName;
+    }
+
+    /**
+     * Gets the parent artifact key of this reference key.
+     *
+     * @return the parent artifact key of this reference key
+     */
+    public AxArtifactKey getParentArtifactKey() {
+        return new AxArtifactKey(parentKeyName, parentKeyVersion);
+    }
+
+    /**
+     * Gets the parent reference key of this reference key.
+     *
+     * @return the parent reference key of this reference key
+     */
+    public AxReferenceKey getParentReferenceKey() {
+        return new AxReferenceKey(parentKeyName, parentKeyVersion, parentLocalName);
+    }
+
+    /**
+     * Sets the parent artifact key of this reference key.
+     *
+     * @param parentKey the parent artifact key of this reference key
+     */
+    public void setParentArtifactKey(final AxArtifactKey parentKey) {
+        Assertions.argumentNotNull(parentKey, "parentKey may not be null");
+
+        parentKeyName = parentKey.getName();
+        parentKeyVersion = parentKey.getVersion();
+        parentLocalName = NULL_KEY_NAME;
+    }
+
+    /**
+     * Sets the parent reference key of this reference key.
+     *
+     * @param parentKey the parent reference key of this reference key
+     */
+    public void setParentReferenceKey(final AxReferenceKey parentKey) {
+        Assertions.argumentNotNull(parentKey, "parentKey may not be null");
+
+        parentKeyName = parentKey.getParentKeyName();
+        parentKeyVersion = parentKey.getParentKeyVersion();
+        parentLocalName = parentKey.getLocalName();
+    }
+
+    /**
+     * Gets the parent key name of this reference key.
+     *
+     * @return the parent key name of this reference key
+     */
+    public String getParentKeyName() {
+        return parentKeyName;
+    }
+
+    /**
+     * Sets the parent key name of this reference key.
+     *
+     * @param parentKeyName the parent key name of this reference key
+     */
+    public void setParentKeyName(final String parentKeyName) {
+        this.parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP);
+    }
+
+    /**
+     * Gets the parent key version of this reference key.
+     *
+     * @return the parent key version of this reference key
+     */
+    public String getParentKeyVersion() {
+        return parentKeyVersion;
+    }
+
+    /**
+     * Sets the parent key version of this reference key.
+     *
+     * @param parentKeyVersion the parent key version of this reference key
+     */
+    public void setParentKeyVersion(final String parentKeyVersion) {
+        this.parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP);
+    }
+
+    /**
+     * Gets the parent local name of this reference key.
+     *
+     * @return the parent local name of this reference key
+     */
+    public String getParentLocalName() {
+        return parentLocalName;
+    }
+
+    /**
+     * Sets the parent local name of this reference key.
+     *
+     * @param parentLocalName the parent local name of this reference key
+     */
+    public void setParentLocalName(final String parentLocalName) {
+        this.parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP);
+    }
+
+    /**
+     * Gets the local name of this reference key.
+     *
+     * @return the local name of this reference key
+     */
+    public String getLocalName() {
+        return localName;
+    }
+
+    /**
+     * Sets the local name of this reference key.
+     *
+     * @param localName the local name of this reference key
+     */
+    public void setLocalName(final String localName) {
+        this.localName = Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#getCompatibility(com. ericsson.apex.model.basicmodel.concepts.AxKey)
+     */
+    @Override
+    public AxKey.Compatibility getCompatibility(final AxKey otherKey) {
+        if (!(otherKey instanceof AxReferenceKey)) {
+            return Compatibility.DIFFERENT;
+        }
+        final AxReferenceKey otherReferenceKey = (AxReferenceKey) otherKey;
+
+        return this.getParentArtifactKey().getCompatibility(otherReferenceKey.getParentArtifactKey());
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxKey#isCompatible(com. ericsson.apex.model.basicmodel.concepts.AxKey)
+     */
+    @Override
+    public boolean isCompatible(final AxKey otherKey) {
+        if (!(otherKey instanceof AxReferenceKey)) {
+            return false;
+        }
+        final AxReferenceKey otherReferenceKey = (AxReferenceKey) otherKey;
+
+        return this.getParentArtifactKey().isCompatible(otherReferenceKey.getParentArtifactKey());
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#validate(com. ericsson.apex.model.basicmodel.concepts.AxValidationResult)
+     */
+    @Override
+    public AxValidationResult validate(final AxValidationResult result) {
+        try {
+            Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP);
+        }
+        catch (final IllegalArgumentException e) {
+            result.addValidationMessage(new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "parentKeyName invalid-" + e.getMessage()));
+        }
+
+        try {
+            Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP);
+        }
+        catch (final IllegalArgumentException e) {
+            result.addValidationMessage(new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "parentKeyVersion invalid-" + e.getMessage()));
+        }
+
+        try {
+            Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP);
+        }
+        catch (final IllegalArgumentException e) {
+            result.addValidationMessage(new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "parentLocalName invalid-" + e.getMessage()));
+        }
+
+        try {
+            Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP);
+        }
+        catch (final IllegalArgumentException e) {
+            result.addValidationMessage(new AxValidationMessage(this, this.getClass(), ValidationResult.INVALID, "localName invalid-" + e.getMessage()));
+        }
+
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#clean()
+     */
+    @Override
+    public void clean() {
+        parentKeyName = Assertions.validateStringParameter(PARENT_KEY_NAME, parentKeyName, NAME_REGEXP);
+        parentKeyVersion = Assertions.validateStringParameter(PARENT_KEY_VERSION, parentKeyVersion, VERSION_REGEXP);
+        parentLocalName = Assertions.validateStringParameter(PARENT_LOCAL_NAME, parentLocalName, LOCAL_NAME_REGEXP);
+        localName = Assertions.validateStringParameter(LOCAL_NAME, localName, LOCAL_NAME_REGEXP);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#toString()
+     */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(this.getClass().getSimpleName());
+        builder.append(":(");
+        builder.append("parentKeyName=");
+        builder.append(parentKeyName);
+        builder.append(",parentKeyVersion=");
+        builder.append(parentKeyVersion);
+        builder.append(",parentLocalName=");
+        builder.append(parentLocalName);
+        builder.append(",localName=");
+        builder.append(localName);
+        builder.append(")");
+        return builder.toString();
+    }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#copyTo(com.ericsson.apex.model.basicmodel.concepts.AxConcept)
+        */
+       @Override
+       public AxConcept copyTo(final AxConcept target) {
+        Assertions.argumentNotNull(target, "target may not be null");
+
+        final Object copyObject = target;
+        Assertions.instanceOf(copyObject, AxReferenceKey.class);
+
+        final AxReferenceKey copy = ((AxReferenceKey) copyObject);
+        copy.setParentKeyName(parentKeyName);
+        copy.setParentKeyVersion(parentKeyVersion);
+        copy.setLocalName(localName);
+        copy.setParentLocalName(parentLocalName);
+
+        return copy;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + parentKeyName.hashCode();
+        result = prime * result + parentKeyVersion.hashCode();
+        result = prime * result + parentLocalName.hashCode();
+        result = prime * result + localName.hashCode();
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see com.ericsson.apex.model.basicmodel.concepts.AxConcept#equals(java.lang. Object)
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            throw new IllegalArgumentException("comparison object may not be null");
+        }
+
+        if (this == obj) {
+            return true;
+        }
+
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        final AxReferenceKey other = (AxReferenceKey) obj;
+
+        if (!parentKeyName.equals(other.parentKeyName)) {
+            return false;
+        }
+        if (!parentKeyVersion.equals(other.parentKeyVersion)) {
+            return false;
+        }
+        if (!parentLocalName.equals(other.parentLocalName)) {
+            return false;
+        }
+        return localName.equals(other.localName);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    @Override
+    public int compareTo(final AxConcept otherObj) {
+        Assertions.argumentNotNull(otherObj, "comparison object may not be null");
+
+        if (this == otherObj) {
+            return 0;
+        }
+        if (getClass() != otherObj.getClass()) {
+            return this.hashCode() - otherObj.hashCode();
+        }
+
+        final AxReferenceKey other = (AxReferenceKey) otherObj;
+        if (!parentKeyName.equals(other.parentKeyName)) {
+            return parentKeyName.compareTo(other.parentKeyName);
+        }
+        if (!parentKeyVersion.equals(other.parentKeyVersion)) {
+            return parentKeyVersion.compareTo(other.parentKeyVersion);
+        }
+        if (!parentLocalName.equals(other.parentLocalName)) {
+            return parentLocalName.compareTo(other.parentLocalName);
+        }
+        return localName.compareTo(other.localName);
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationMessage.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationMessage.java
new file mode 100644 (file)
index 0000000..ef8eb31
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * A validation message is created for each validation observation observed during validation of a concept. The message holds the key and
+ * the class of the concept on which the observation was made as well as the type of observation and a message describing the observation.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class AxValidationMessage {
+    private final AxKey observedKey;
+    private ValidationResult validationResult = ValidationResult.VALID;
+    private final String observedClass;
+    private final String message;
+
+    /**
+     * Create an validation observation with the given fields.
+     *
+     * @param observedKey the key of the class on which the validation observation was made
+     * @param observedClass the class on which the validation observation was made
+     * @param validationResult the type of observation made
+     * @param message a message describing the observation
+     */
+    public AxValidationMessage(final AxKey observedKey, final Class<?> observedClass, final ValidationResult validationResult, final String message) {
+        Assertions.argumentNotNull(observedKey, "observedKey may not be null");
+        Assertions.argumentNotNull(observedClass, "observedClass may not be null");
+        Assertions.argumentNotNull(validationResult, "validationResult may not be null");
+        Assertions.argumentNotNull(message, "message may not be null");
+
+        this.observedKey = observedKey;
+        this.observedClass = observedClass.getCanonicalName();
+        this.validationResult = validationResult;
+        this.message = message;
+    }
+
+    /**
+     * Gets the key of the observation.
+     *
+     * @return the key of the observation
+     */
+    public AxKey getObservedKey() {
+        return observedKey;
+    }
+
+    /**
+     * Gets the observed class.
+     *
+     * @return the observed class
+     */
+    public String getObservedClass() {
+        return observedClass;
+    }
+
+    /**
+     * Gets the type of observation made.
+     *
+     * @return the type of observation made
+     */
+    public ValidationResult getValidationResult() {
+        return validationResult;
+    }
+
+    /**
+     * Get a description of the observation.
+     *
+     * @return the observation description
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return observedKey.toString() + ':' + observedClass + ':' + validationResult.name() + ':' + message;
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationResult.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/AxValidationResult.java
new file mode 100644 (file)
index 0000000..363fd15
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class records the result of a validation and holds all validatino observation messages.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class AxValidationResult {
+    /**
+     * The ValidationResult enumeration describes the severity of a validation result.
+     */
+    public enum ValidationResult {
+        /** No problems or observations were detected during validation. */
+        VALID,
+        /** Observations were made on a concept (such as blank descriptions) of a nature that will not affect the use of the concept. */
+        OBSERVATION,
+        /** Warnings were made on a concept (such as defined but unused concepts) of a nature that may affect the use of the concept. */
+        WARNING,
+        /**
+         * Errors were detected on a concept (such as referenced but undefined concepts) of a nature that will affect the use of the concept.
+         */
+        INVALID
+    }
+
+    // The actual verification result
+    private ValidationResult validationResult = ValidationResult.VALID;
+
+    // Messages collected during the verification process
+    private final List<AxValidationMessage> messageList = new LinkedList<>();
+
+    /**
+     * Check if a validation reported a valid concept, returns true if the model is usable (that is, even if the model has warnings or
+     * observations).
+     *
+     * @return true, if the concept is reported as valid and can be used
+     */
+    public boolean isValid() {
+        return validationResult != ValidationResult.INVALID;
+    }
+
+    /**
+     * Check if a validation reported a concept with no errors or warnings, returns true if the model is OK to use.
+     *
+     * @return true, if the concept has no warnings or errors
+     */
+    public boolean isOK() {
+        return validationResult == ValidationResult.VALID || validationResult == ValidationResult.OBSERVATION;
+    }
+
+    /**
+     * Gets the validation result.
+     *
+     * @return the validation result on a concept
+     */
+    public ValidationResult getValidationResult() {
+        return validationResult;
+    }
+
+    /**
+     * Gets the list of validation results on the concept.
+     *
+     * @return the list of validaiton results
+     */
+    public List<AxValidationMessage> getMessageList() {
+        return messageList;
+    }
+
+    /**
+     * Adds a validation message to the validation result, used by validate() implementations on {@link AxConcept} subclasses to report
+     * validaiton observations.
+     *
+     * @param validationMessage the validation message
+     */
+    public void addValidationMessage(final AxValidationMessage validationMessage) {
+        messageList.add(validationMessage);
+
+        // Check if the incoming message has a more sever status than the
+        // current one on the overall validation result,
+        // if so, the overall result goes to that level
+        if (validationMessage.getValidationResult().ordinal() > validationResult.ordinal()) {
+            validationResult = validationMessage.getValidationResult();
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+
+        switch (validationResult) {
+        case VALID:
+
+        builder.append("***validation of model successful***");
+            return builder.toString();
+        case OBSERVATION:
+
+        builder.append("\n***observations noted during validation of model***\n");
+            break;
+        case WARNING:
+
+        builder.append("\n***warnings issued during validation of model***\n");
+            break;
+        case INVALID:
+        builder.append("\n***validation of model failed***\n");
+            break;
+        default:
+            break;
+        }
+
+        for (final AxValidationMessage message : messageList) {
+            builder.append(message);
+            builder.append("\n");
+        }
+
+        builder.append("********************************");
+        return builder.toString();
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/concepts/package-info.java
new file mode 100644 (file)
index 0000000..4d5c91c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * This package contains the fundamental concepts for all APEX models.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+
+@XmlSchema(namespace = "http://www.ericsson.com/apex", elementFormDefault = XmlNsForm.QUALIFIED, xmlns = {
+        @XmlNs(namespaceURI = "http://www.ericsson.com/apex", prefix = "") })
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlNsForm;
+import javax.xml.bind.annotation.XmlSchema;
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDao.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDao.java
new file mode 100644 (file)
index 0000000..5aab39c
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.dao;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+
+/**
+ * The Interface ApexDao describes the DAO interface for reading and writing Apex {@link AxConcept} concepts to and from databases using
+ * JDBC.
+ *
+ * @author Sergey Sachkov
+ * @author liam.fallon@ericsson.com
+ */
+public interface ApexDao {
+
+    /**
+     * Initialize the Apex DAO with the given parameters.
+     *
+     * @param daoParameters parameters to use to access the database
+     * @throws ApexException on initialization errors
+     */
+    void init(DAOParameters daoParameters) throws ApexException;
+
+    /**
+     * Close the Apex DAO.
+     */
+    void close();
+
+    /**
+     * Creates an Apex concept on the database.
+     *
+     * @param <T> the type of the object to create, a subclass of {@link AxConcept}
+     * @param obj the object to create
+     */
+    <T extends AxConcept> void create(T obj);
+
+    /**
+     * Delete an Apex concept on the database.
+     *
+     * @param <T> the type of the object to delete, a subclass of {@link AxConcept}
+     * @param obj the object to delete
+     */
+    <T extends AxConcept> void delete(T obj);
+
+    /**
+     * Delete an Apex concept on the database.
+     *
+     * @param <T> the type of the object to delete, a subclass of {@link AxConcept}
+     * @param aClass the class of the object to delete, a subclass of {@link AxConcept}
+     * @param key the key of the object to delete
+     */
+    <T extends AxConcept> void delete(Class<T> aClass, AxArtifactKey key);
+
+    /**
+     * Delete an Apex concept on the database.
+     *
+     * @param <T> the type of the object to delete, a subclass of {@link AxConcept}
+     * @param aClass the class of the object to delete, a subclass of {@link AxConcept}
+     * @param key the key of the object to delete
+     */
+    <T extends AxConcept> void delete(Class<T> aClass, AxReferenceKey key);
+
+    /**
+     * Create a collection of objects in the database.
+     *
+     * @param <T> the type of the object to create, a subclass of {@link AxConcept}
+     * @param objs the objects to create
+     */
+    <T extends AxConcept> void create(Collection<T> objs);
+
+    /**
+     * Delete a collection of objects in the database.
+     *
+     * @param <T> the type of the objects to delete, a subclass of {@link AxConcept}
+     * @param objs the objects to delete
+     */
+    <T extends AxConcept> void delete(Collection<T> objs);
+
+    /**
+     * Delete a collection of objects in the database referred to by artifact key.
+     *
+     * @param <T> the type of the objects to delete, a subclass of {@link AxConcept}
+     * @param aClass the class of the objects to delete, a subclass of {@link AxConcept}
+     * @param keys the keys of the objects to delete
+     * @return the number of objects deleted
+     */
+    <T extends AxConcept> int deleteByArtifactKey(Class<T> aClass, Collection<AxArtifactKey> keys);
+
+    /**
+     * Delete a collection of objects in the database referred to by reference key.
+     *
+     * @param <T> the type of the objects to delete, a subclass of {@link AxConcept}
+     * @param aClass the class of the objects to delete, a subclass of {@link AxConcept}
+     * @param keys the keys of the objects to delete
+     * @return the number of objects deleted
+     */
+    <T extends AxConcept> int deleteByReferenceKey(Class<T> aClass, Collection<AxReferenceKey> keys);
+
+    /**
+     * Delete all objects of a given class in the database.
+     *
+     * @param <T> the type of the objects to delete, a subclass of {@link AxConcept}
+     * @param aClass the class of the objects to delete, a subclass of {@link AxConcept}
+     */
+    <T extends AxConcept> void deleteAll(Class<T> aClass);
+
+    /**
+     * Get an object from the database, referred to by artifact key.
+     *
+     * @param <T> the type of the object to get, a subclass of {@link AxConcept}
+     * @param aClass the class of the object to get, a subclass of {@link AxConcept}
+     * @param key the key of the object to get
+     * @return the object that was retrieved from the database
+     */
+    <T extends AxConcept> T get(Class<T> aClass, AxArtifactKey key);
+
+    /**
+     * Get an object from the database, referred to by reference key.
+     *
+     * @param <T> the type of the object to get, a subclass of {@link AxConcept}
+     * @param aClass the class of the object to get, a subclass of {@link AxConcept}
+     * @param key the key of the object to get
+     * @return the object that was retrieved from the database or null if the object was not retrieved
+     */
+    <T extends AxConcept> T get(Class<T> aClass, AxReferenceKey key);
+
+    /**
+     * Get all the objects in the database of a given type.
+     *
+     * @param <T> the type of the objects to get, a subclass of {@link AxConcept}
+     * @param aClass the class of the objects to get, a subclass of {@link AxConcept}
+     * @return the objects or null if no objects were retrieved
+     */
+    <T extends AxConcept> List<T> getAll(Class<T> aClass);
+
+    /**
+     * Get all the objects in the database of the given type with the given parent artifact key.
+     *
+     * @param <T> the type of the objects to get, a subclass of {@link AxConcept}
+     * @param aClass the class of the objects to get, a subclass of {@link AxConcept}
+     * @param parentKey the parent key of the concepts to get
+     * @return the all
+     */
+    <T extends AxConcept> List<T> getAll(Class<T> aClass, AxArtifactKey parentKey);
+
+    /**
+     * Get a concept from the database with the given artifact key.
+     *
+     * @param <T> the type of the object to get, a subclass of {@link AxConcept}
+     * @param aClass the class of the object to get, a subclass of {@link AxConcept}
+     * @param artifactID the artifact key of the concept to get
+     * @return the concept that matches the key or null if the concept is not retrieved
+     */
+    <T extends AxConcept> T getArtifact(Class<T> aClass, AxArtifactKey artifactID);
+
+    /**
+     * Get a concept from the database with the given reference key.
+     *
+     * @param <T> the type of the object to get, a subclass of {@link AxConcept}
+     * @param aClass the class of the object to get, a subclass of {@link AxConcept}
+     * @param artifactID the artifact key of the concept to get
+     * @return the concept that matches the key or null if the concept is not retrieved
+     */
+    <T extends AxConcept> T getArtifact(Class<T> aClass, AxReferenceKey artifactID);
+
+    /**
+     * Get the number of instances of a concept that exist in the database.
+     *
+     * @param <T> the type of the object to get, a subclass of {@link AxConcept}
+     * @param aClass the class of the object to get, a subclass of {@link AxConcept}
+     * @return the number of instances of the concept in the database
+     */
+    <T extends AxConcept> long size(Class<T> aClass);
+
+    /**
+     * Update a concept in the database.
+     *
+     * @param <T> the type of the object to get, a subclass of {@link AxConcept}
+     * @param obj the object to update
+     * @return the updated object
+     */
+    <T extends AxConcept> T update(T obj);
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDaoFactory.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/ApexDaoFactory.java
new file mode 100644 (file)
index 0000000..ecb8a46
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.dao;
+
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.model.utilities.Assertions;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This factory class returns an Apex DAO for the configured persistence mechanism. The factory uses the plugin class specified in {@link DAOParameters} to
+ * instantiate a DAO instance.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexDaoFactory {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexDaoFactory.class);
+
+    /**
+     * Return an Apex DAO for the required APEX DAO plugin class.
+     *
+     * @param daoParameters parameters to use to read the database configuration information
+     * @return the Apex DAO
+     * @throws ApexException on invalid JPA plugins
+     */
+    public ApexDao createApexDao(final DAOParameters daoParameters) throws ApexException {
+        Assertions.argumentNotNull(daoParameters, ApexException.class, "Parameter \"daoParameters\" may not be null");
+
+        // Get the class for the DAO using reflection
+        Object apexDaoObject = null;
+        try {
+            apexDaoObject = Class.forName(daoParameters.getPluginClass()).newInstance();
+        }
+        catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+            LOGGER.error("Apex DAO class not found for DAO plugin \"" + daoParameters.getPluginClass() + "\"", e);
+            throw new ApexException("Apex DAO class not found for DAO plugin \"" + daoParameters.getPluginClass() + "\"", e);
+        }
+
+        // Check the class is an Apex DAO
+        if (!(apexDaoObject instanceof ApexDao)) {
+            LOGGER.error("Specified Apex DAO plugin class \"" + daoParameters.getPluginClass() + "\" does not implement the ApexDao interface");
+            throw new ApexException("Specified Apex DAO plugin class \"" + daoParameters.getPluginClass() + "\" does not implement the ApexDao interface");
+        }
+
+        return (ApexDao) apexDaoObject;
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/DAOParameters.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/DAOParameters.java
new file mode 100644 (file)
index 0000000..ccf15fe
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.dao;
+
+import java.util.Properties;
+
+/**
+ * This class is a POJO that holds properties for Apex DAOs.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class DAOParameters {
+    /** The default Apex DAO plugin class. */
+    public static final String DEFAULT_PLUGIN_CLASS = "org.onap.apex.model.basicmodel.dao.impl.DefaultApexDao";
+
+    private String pluginClass = DEFAULT_PLUGIN_CLASS;
+    private String persistenceUnit;
+
+    private Properties jdbcProperties = new Properties();
+
+    /**
+     * Gets the DAO plugin class, this is the DAO class to use and it must implement the {@link ApexDao} interface.
+     *
+     * @return the DAO plugin class
+     */
+    public String getPluginClass() {
+        return pluginClass;
+    }
+
+    /**
+     * Sets the DAO plugin class, a class that implements the {@link ApexDao} interface.
+     *
+     * @param daoPluginClass the DAO plugin class
+     */
+    public void setPluginClass(final String daoPluginClass) {
+        pluginClass = daoPluginClass;
+    }
+
+    /**
+     * Gets the persistence unit for the DAO. The persistence unit defines the JDBC properties the DAO will use. The persistence unit must defined in the
+     * {@code META-INF/persistence.xml} resource file
+     *
+     * @return the persistence unit to use for JDBC access
+     */
+    public String getPersistenceUnit() {
+        return persistenceUnit;
+    }
+
+    /**
+     * Sets the persistence unit for the DAO. The persistence unit defines the JDBC properties the DAO will use. The persistence unit must defined in the
+     * {@code META-INF/persistence.xml} resource file
+     *
+     * @param daoPersistenceUnit the persistence unit to use for JDBC access
+     */
+    public void setPersistenceUnit(final String daoPersistenceUnit) {
+        persistenceUnit = daoPersistenceUnit;
+    }
+
+    /**
+     * Gets the JDBC properties.
+     *
+     * @return the JDBC properties
+     */
+    public Properties getJdbcProperties() {
+        return jdbcProperties;
+    }
+
+    /**
+     * Sets the JDBC properties.
+     *
+     * @param jdbcProperties the JDBC properties
+     */
+    public void setJdbcProperties(final Properties jdbcProperties) {
+        this.jdbcProperties = jdbcProperties;
+    }
+
+    /**
+     * Gets a single JDBC property.
+     *
+     * @param key the key of the property
+     * @return the JDBC property
+     */
+    public String getJdbcProperty(final String key) {
+        return jdbcProperties.getProperty(key);
+    }
+
+    /**
+     * Sets a single JDBC property.
+     *
+     * @param key the key of the property
+     * @param value the value of the JDBC property
+     */
+    public void setJdbcProperty(final String key, final String value) {
+        jdbcProperties.setProperty(key, value);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "DAOParameters [pluginClass=" + pluginClass + ", persistenceUnit=" + persistenceUnit + ", jdbcProperties=" + jdbcProperties + "]";
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/CDATAConditioner.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/CDATAConditioner.java
new file mode 100644 (file)
index 0000000..d949ab2
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.dao.converters;
+
+import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * The Class CDATAConditioner converts a CDATA String to and from database format by removing spaces at the ends of lines and
+ * platform-specific new line endings.
+ *
+ * @author John Keeney (John.Keeney@ericsson.com)
+ */
+@Converter
+public class CDATAConditioner extends XmlAdapter<String, String> implements AttributeConverter<String, String> {
+
+    private static final String NL = "\n";
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.persistence.AttributeConverter#convertToDatabaseColumn(java.lang.Object)
+     */
+    @Override
+    public String convertToDatabaseColumn(final String raw) {
+        return clean(raw);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.persistence.AttributeConverter#convertToEntityAttribute(java.lang.Object)
+     */
+    @Override
+    public String convertToEntityAttribute(final String db) {
+        return clean(db);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.bind.annotation.adapters.XmlAdapter
+     */
+    @Override
+    public String unmarshal(final String v) throws Exception {
+        return this.convertToEntityAttribute(v);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.bind.annotation.adapters.XmlAdapter
+     */
+    @Override
+    public String marshal(final String v) throws Exception {
+        return this.convertToDatabaseColumn(v);
+    }
+
+    /**
+     * Clean.
+     *
+     * @param in the in
+     * @return the string
+     */
+    public static final String clean(final String in) {
+        if (in == null) {
+            return null;
+        }
+        else {
+            return in.replaceAll("\\s+$", "").replaceAll("\\r?\\n", NL);
+        }
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/UUID2String.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/UUID2String.java
new file mode 100644 (file)
index 0000000..4e6b660
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.dao.converters;
+
+import java.util.UUID;
+
+import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * The Class UUIDConverter converts a UUID to and from database format.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+@Converter
+public class UUID2String extends XmlAdapter<String, UUID> implements AttributeConverter<UUID, String> {
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.persistence.AttributeConverter#convertToDatabaseColumn(java.lang.Object)
+     */
+    @Override
+    public String convertToDatabaseColumn(final UUID uuid) {
+        String returnString;
+        if (uuid == null) {
+            returnString = "";
+        }
+        else {
+            returnString = uuid.toString();
+        }
+        return returnString;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.persistence.AttributeConverter#convertToEntityAttribute(java.lang.Object)
+     */
+    @Override
+    public UUID convertToEntityAttribute(final String uuidString) {
+        return UUID.fromString(uuidString);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.bind.annotation.adapters.XmlAdapter
+     */
+    @Override
+    public UUID unmarshal(final String v) throws Exception {
+        return this.convertToEntityAttribute(v);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.bind.annotation.adapters.XmlAdapter
+     */
+    @Override
+    public String marshal(final UUID v) throws Exception {
+        return this.convertToDatabaseColumn(v);
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/converters/package-info.java
new file mode 100644 (file)
index 0000000..c7bad67
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains converters used by APEX EclipseLink marshaling and unmarshaling of {@link org.onap.apex.model.basicmodel.concepts.AxConcept}
+ * instances to and from files and databases.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.apex.model.basicmodel.dao.converters;
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/DefaultApexDao.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/DefaultApexDao.java
new file mode 100644 (file)
index 0000000..a73a15e
--- /dev/null
@@ -0,0 +1,526 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.dao.impl;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.ApexRuntimeException;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.apex.model.basicmodel.dao.ApexDao;
+import org.onap.apex.model.basicmodel.dao.DAOParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The Class DefaultApexDao is an JPA implementation of the {@link ApexDao} class for Apex concepts ({@link AxConcept}). It uses the default
+ * JPA implementation in the javax {@link Persistence} class.
+ *
+ *
+ * @author Sergey Sachkov (sergey.sachkov@ericsson.com)
+ */
+public class DefaultApexDao implements ApexDao {
+       private static final XLogger LOGGER = XLoggerFactory.getXLogger(DefaultApexDao.class);
+
+       private static final String SELECT_C_FROM = "SELECT c FROM ";
+       private static final String AND_C_KEY_LOCAL_NAME = "' AND c.key.localName='";
+       private static final String AND_C_KEY_PARENT_KEY_VERSION = "' AND c.key.parentKeyVersion='";
+       private static final String C_WHERE_C_KEY_PARENT_KEY_NAME = " c WHERE c.key.parentKeyName='";
+       private static final String AND_C_KEY_VERSION = "' AND c.key.version='";
+       private static final String C_WHERE_C_KEY_NAME = " c WHERE c.key.name='";
+       private static final String DELETE_FROM = "DELETE FROM ";
+
+       // Entity manager for JPA
+       private EntityManagerFactory emf = null;
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#init(com.ericsson.apex.model.basicmodel.dao.DAOParameters)
+        */
+       @Override
+       public void init(final DAOParameters daoParameters) throws ApexException {
+               if (daoParameters == null || daoParameters.getPersistenceUnit() == null) {
+                       LOGGER.error("Apex persistence unit parameter not set");
+                       throw new ApexException("Apex persistence unit parameter not set");
+               }
+
+               LOGGER.debug("Creating Apex persistence unit \"" + daoParameters.getPersistenceUnit() + "\" . . .");
+               try {
+                       emf = Persistence.createEntityManagerFactory(daoParameters.getPersistenceUnit(), daoParameters.getJdbcProperties());
+               }
+               catch (final Exception e) {
+                       LOGGER.warn("Creation of Apex persistence unit \"" + daoParameters.getPersistenceUnit() + "\" failed", e);
+                       throw new ApexException("Creation of Apex persistence unit \"" + daoParameters.getPersistenceUnit() + "\" failed", e);
+               }
+               LOGGER.debug("Created Apex persistence unit \"" + daoParameters.getPersistenceUnit() + "\"");
+       }
+
+       /**
+        * Gets the entity manager for this DAO.
+        *
+        * @return the entity manager
+        */
+       protected final synchronized EntityManager getEntityManager() {
+               if (emf == null) {
+                       LOGGER.warn("Apex DAO has not been initialized");
+                       throw new ApexRuntimeException("Apex DAO has not been initialized");
+               }
+
+               return emf.createEntityManager();
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#close()
+        */
+       @Override
+       public final void close() {
+               if (emf != null) {
+                       emf.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#create(com.ericsson.apex.model.basicmodel.concepts.AxConcept)
+        */
+       @Override
+       public <T extends AxConcept> void create(final T obj) {
+               if (obj == null) {
+                       return;
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       mg.getTransaction().begin();
+                       mg.merge(obj);
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#delete(com.ericsson.apex.model.basicmodel.concepts.AxConcept)
+        */
+       @Override
+       public <T extends AxConcept> void delete(final T obj) {
+               if (obj == null) {
+                       return;
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       mg.getTransaction().begin();
+                       mg.remove(mg.contains(obj) ? obj : mg.merge(obj));
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#delete(java.lang.Class,
+        * com.ericsson.apex.model.basicmodel.concepts.AxArtifactKey)
+        */
+       @Override
+       public <T extends AxConcept> void delete(final Class<T> aClass, final AxArtifactKey key) {
+               if (key == null) {
+                       return;
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       mg.getTransaction().begin();
+                       mg.createQuery(DELETE_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_NAME + key.getName() + AND_C_KEY_VERSION
+                                       + key.getVersion() + "'", aClass).executeUpdate();
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#delete(java.lang.Class,
+        * com.ericsson.apex.model.basicmodel.concepts.AxReferenceKey)
+        */
+       @Override
+       public <T extends AxConcept> void delete(final Class<T> aClass, final AxReferenceKey key) {
+               if (key == null) {
+                       return;
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       mg.getTransaction().begin();
+                       mg.createQuery(DELETE_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_PARENT_KEY_NAME + key.getParentKeyName()
+                       + AND_C_KEY_PARENT_KEY_VERSION + key.getParentKeyVersion() + AND_C_KEY_LOCAL_NAME + key.getLocalName() + "'",
+                       aClass).executeUpdate();
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#create(java.util.Collection)
+        */
+       @Override
+       public <T extends AxConcept> void create(final Collection<T> objs) {
+               if (objs == null || objs.isEmpty()) {
+                       return;
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       mg.getTransaction().begin();
+                       for (final T t : objs) {
+                               mg.merge(t);
+                       }
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#delete(java.util.Collection)
+        */
+       @Override
+       public <T extends AxConcept> void delete(final Collection<T> objs) {
+               if (objs == null || objs.isEmpty()) {
+                       return;
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       mg.getTransaction().begin();
+                       for (final T t : objs) {
+                               mg.remove(mg.contains(t) ? t : mg.merge(t));
+                       }
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#deleteByArtifactKey(java.lang.Class, java.util.Collection)
+        */
+       @Override
+       public <T extends AxConcept> int deleteByArtifactKey(final Class<T> aClass, final Collection<AxArtifactKey> keys) {
+               if (keys == null || keys.isEmpty()) {
+                       return 0;
+               }
+               int deletedCount = 0;
+               final EntityManager mg = getEntityManager();
+               try {
+                       mg.getTransaction().begin();
+                       for (final AxArtifactKey key : keys) {
+                               deletedCount += mg.createQuery(DELETE_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_NAME + key.getName()
+                               + AND_C_KEY_VERSION + key.getVersion() + "'", aClass).executeUpdate();
+                       }
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+               return deletedCount;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#deleteByReferenceKey(java.lang.Class, java.util.Collection)
+        */
+       @Override
+       public <T extends AxConcept> int deleteByReferenceKey(final Class<T> aClass, final Collection<AxReferenceKey> keys) {
+               if (keys == null || keys.isEmpty()) {
+                       return 0;
+               }
+               int deletedCount = 0;
+               final EntityManager mg = getEntityManager();
+               try {
+                       mg.getTransaction().begin();
+                       for (final AxReferenceKey key : keys) {
+                               deletedCount += mg.createQuery(DELETE_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_PARENT_KEY_NAME
+                                               + key.getParentKeyName() + AND_C_KEY_PARENT_KEY_VERSION + key.getParentKeyVersion() + AND_C_KEY_LOCAL_NAME
+                                               + key.getLocalName() + "'", aClass).executeUpdate();
+                       }
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+               return deletedCount;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#deleteAll(java.lang.Class)
+        */
+       @Override
+       public <T extends AxConcept> void deleteAll(final Class<T> aClass) {
+               final EntityManager mg = getEntityManager();
+               try {
+                       mg.getTransaction().begin();
+                       mg.createQuery(DELETE_FROM + aClass.getSimpleName() + " c ", aClass).executeUpdate();
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#get(java.lang.Class, com.ericsson.apex.model.basicmodel.concepts.AxArtifactKey)
+        */
+       @Override
+       public <T extends AxConcept> T get(final Class<T> aClass, final AxArtifactKey key) {
+               if (aClass == null) {
+                       return null;
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       final T t = mg.find(aClass, key);
+                       if (t != null) {
+                               // This clone is created to force the JPA DAO to recurse down through the object
+                               try { 
+                                       T clonedT = aClass.newInstance();
+                                       t.copyTo(clonedT);
+                                       return clonedT;
+                               }
+                               catch (Exception e) {
+                                       LOGGER.warn("Could not clone object of class \"" + aClass.getCanonicalName() + "\"", e);
+                                       return null;
+                               }
+                       }
+                       else {
+                               return null;
+                       }
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#get(java.lang.Class, com.ericsson.apex.model.basicmodel.concepts.AxReferenceKey)
+        */
+       @Override
+       public <T extends AxConcept> T get(final Class<T> aClass, final AxReferenceKey key) {
+               if (aClass == null) {
+                       return null;
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       final T t = mg.find(aClass, key);
+                       if (t != null) {
+                               try { 
+                                       T clonedT = aClass.newInstance();
+                                       t.copyTo(clonedT);
+                                       return clonedT;
+                               }
+                               catch (Exception e) {
+                                       LOGGER.warn("Could not clone object of class \"" + aClass.getCanonicalName() + "\"", e);
+                                       return null;
+                               }
+                       }
+                       else {
+                               return null;
+                       }
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#getAll(java.lang.Class)
+        */
+       @Override
+       public <T extends AxConcept> List<T> getAll(final Class<T> aClass) {
+               if (aClass == null) {
+                       return Collections.emptyList();
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       return mg.createQuery(SELECT_C_FROM + aClass.getSimpleName() + " c", aClass).getResultList();
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#getAll(java.lang.Class,
+        * com.ericsson.apex.model.basicmodel.concepts.AxArtifactKey)
+        */
+       @Override
+       public <T extends AxConcept> List<T> getAll(final Class<T> aClass, final AxArtifactKey parentKey) {
+               if (aClass == null) {
+                       return Collections.emptyList();
+               }
+               final EntityManager mg = getEntityManager();
+               try {
+                       return mg.createQuery(SELECT_C_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_PARENT_KEY_NAME + parentKey.getName()
+                       + AND_C_KEY_PARENT_KEY_VERSION + parentKey.getVersion() + "'", aClass).getResultList();
+               }
+               finally {
+                       mg.close();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#getArtifact(java.lang.Class,
+        * com.ericsson.apex.model.basicmodel.concepts.AxArtifactKey)
+        */
+       @Override
+       public <T extends AxConcept> T getArtifact(final Class<T> aClass, final AxArtifactKey key) {
+               if (aClass == null || key == null) {
+                       return null;
+               }
+               final EntityManager mg = getEntityManager();
+               List<T> ret;
+               try {
+                       ret = mg.createQuery(SELECT_C_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_NAME + key.getName()
+                       + AND_C_KEY_VERSION + key.getVersion() + "'", aClass).getResultList();
+               }
+               finally {
+                       mg.close();
+               }
+               if (ret == null || ret.isEmpty()) {
+                       return null;
+               }
+               if (ret.size() > 1) {
+                       throw new IllegalArgumentException(
+                                       "More than one result was returned for search for " + aClass + " with key " + key.getID() + ": " + ret);
+               }
+               return ret.get(0);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#getArtifact(java.lang.Class,
+        * com.ericsson.apex.model.basicmodel.concepts.AxReferenceKey)
+        */
+       @Override
+       public <T extends AxConcept> T getArtifact(final Class<T> aClass, final AxReferenceKey key) {
+               if (aClass == null || key == null) {
+                       return null;
+               }
+               final EntityManager mg = getEntityManager();
+               List<T> ret;
+               try {
+                       ret = mg.createQuery(SELECT_C_FROM + aClass.getSimpleName() + C_WHERE_C_KEY_PARENT_KEY_NAME + key.getParentKeyName()
+                       + AND_C_KEY_PARENT_KEY_VERSION + key.getParentKeyVersion() + AND_C_KEY_LOCAL_NAME + key.getLocalName() + "'",
+                       aClass).getResultList();
+               }
+               finally {
+                       mg.close();
+               }
+               if (ret == null || ret.isEmpty()) {
+                       return null;
+               }
+               if (ret.size() > 1) {
+                       throw new IllegalArgumentException(
+                                       "More than one result was returned for search for " + aClass + " with key " + key.getID() + ": " + ret);
+               }
+               return ret.get(0);
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#update(com.ericsson.apex.model.basicmodel.concepts.AxConcept)
+        */
+       @Override
+       public <T extends AxConcept> T update(final T obj) {
+               final EntityManager mg = getEntityManager();
+               T ret;
+               try {
+                       mg.getTransaction().begin();
+                       ret = mg.merge(obj);
+                       mg.flush();
+                       mg.getTransaction().commit();
+               }
+               finally {
+                       mg.close();
+               }
+               return ret;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see com.ericsson.apex.model.basicmodel.dao.ApexDao#size(java.lang.Class)
+        */
+       @Override
+       public <T extends AxConcept> long size(final Class<T> aClass) {
+               if (aClass == null) {
+                       return 0;
+               }
+               final EntityManager mg = getEntityManager();
+               long size = 0;
+               try {
+                       size = mg.createQuery("SELECT COUNT(c) FROM " + aClass.getSimpleName() + " c", Long.class).getSingleResult();
+               }
+               finally {
+                       mg.close();
+               }
+               return size;
+       }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/impl/package-info.java
new file mode 100644 (file)
index 0000000..16da226
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains a default DAO implementation for APEX {@link org.onap.apex.model.basicmodel.concepts.AxConcept} classes that uses javax persistence.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.apex.model.basicmodel.dao.impl;
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/dao/package-info.java
new file mode 100644 (file)
index 0000000..0ad255a
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Defines and implements the Data Access Object (DAO) that allows Apex {@link org.onap.apex.model.basicmodel.concepts.AxConcept} concepts to
+ * be read from and written to databases over JDBC.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.apex.model.basicmodel.dao;
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelCreator.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelCreator.java
new file mode 100644 (file)
index 0000000..5a9de96
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+
+/**
+ * This interface is implemented by factories that create Apex models. It is mainly used by unit test classes that generate Apex models for test purposes.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <M> the type of Apex model to create, must be a sub class of {@link AxModel}
+ */
+public interface ApexModelCreator<M extends AxModel> {
+
+    /**
+     * Gets the model created by the model creator.
+     *
+     * @return the model created by the model creator
+     */
+    M getModel();
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelException.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelException.java
new file mode 100644 (file)
index 0000000..252bee4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+
+/**
+ * This exception is invoked if an exception occurs in model handling.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexModelException extends ApexException {
+    private static final long serialVersionUID = -4245694568321686450L;
+
+    /**
+     * Instantiates a new apex model handling exception.
+     *
+     * @param message the message
+     */
+    public ApexModelException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Instantiates a new apex model handling exception.
+     *
+     * @param message the message
+     * @param e the e
+     */
+    public ApexModelException(final String message, final Exception e) {
+        super(message, e);
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelFileWriter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelFileWriter.java
new file mode 100644 (file)
index 0000000..8d9cf2a
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.io.File;
+import java.io.FileOutputStream;
+
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class writes an Apex model to a file.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <M> the type of Apex model to write to file, must be a sub class of {@link AxModel}
+ */
+public class ApexModelFileWriter<M extends AxModel> {
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelFileWriter.class);
+
+    // Should models being written to files be valid
+    private boolean validateFlag;
+
+    /**
+     * Constructor, set the validation flag.
+     *
+     * @param validateFlag indicates if validation be performed prior to output
+     */
+    public ApexModelFileWriter(final boolean validateFlag) {
+        this.validateFlag = validateFlag;
+    }
+
+    /**
+     * Write a model to an XML file.
+     *
+     * @param model The model to write
+     * @param rootModelClass The concept class
+     * @param modelFileName The name of the file to write to
+     * @throws ApexException thrown on errors
+     */
+    public void apexModelWriteXMLFile(final M model, final Class<M> rootModelClass, final String modelFileName)
+            throws ApexException {
+        LOGGER.debug("running apexModelWriteXMLFile . . .");
+
+        final ApexModelWriter<M> modelWriter = new ApexModelWriter<>(rootModelClass);
+        modelWriter.setValidateFlag(validateFlag);
+        modelWriter.getCDataFieldSet().add("description");
+        modelWriter.getCDataFieldSet().add("logic");
+        modelWriter.getCDataFieldSet().add("uiLogic");
+
+        writeModelFile(model, modelWriter, modelFileName);
+
+        LOGGER.debug("ran apexModelWriteXMLFile");
+    }
+
+    /**
+     * Write a model to an JSON file.
+     *
+     * @param model The model to write
+     * @param rootModelClass The concept class
+     * @param modelFileName The name of the file to write to
+     * @throws ApexException thrown on errors
+     */
+    public void apexModelWriteJSONFile(final M model, final Class<M> rootModelClass, final String modelFileName)
+            throws ApexException {
+        LOGGER.debug("running apexModelWriteJSONFile . . .");
+
+        final ApexModelWriter<M> modelWriter = new ApexModelWriter<>(rootModelClass);
+        modelWriter.setJsonOutput(true);
+        modelWriter.setValidateFlag(validateFlag);
+
+        writeModelFile(model, modelWriter, modelFileName);
+
+        LOGGER.debug("ran apexModelWriteJSONFile");
+    }
+
+    /**
+     * Checks if the validation flag is set.
+     *
+     * @return true, the validation flag is set
+     */
+    public boolean isValidateFlag() {
+        return validateFlag;
+    }
+
+    /**
+     * Sets the validate flag.
+     *
+     * @param validateFlag the validate flag value
+     */
+    public void setValidateFlag(final boolean validateFlag) {
+        this.validateFlag = validateFlag;
+    }
+
+    /**
+     * Write a model to a file using a model writer.
+     *
+     * @param model The model to write
+     * @param modelWriter the model writer to use to write the model to the file
+     * @param modelFileName the file name of the file to write to
+     * @throws ApexException on exceptions writing the model
+     */
+    private void writeModelFile(final M model, final ApexModelWriter<M> modelWriter, final String modelFileName) throws ApexException {
+        final File modelFile = new File(modelFileName);
+        if (!modelFile.getParentFile().exists() && !modelFile.getParentFile().mkdirs()) {
+            LOGGER.warn("could not create directory  " + modelFile.getParentFile());
+            throw new ApexException("could not create directory  " + modelFile.getParentFile());
+        }
+
+        try {
+            final FileOutputStream fileOutputStream = new FileOutputStream(modelFile);
+            modelWriter.write(model, fileOutputStream);
+            fileOutputStream.close();
+        }
+        catch (final Exception e) {
+            LOGGER.warn("error processing file " + modelFile.getAbsolutePath(), e);
+            throw new ApexException("error processing file " + modelFile.getAbsolutePath(), e);
+        }
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelReader.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelReader.java
new file mode 100644 (file)
index 0000000..84760f5
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.regex.Pattern;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.eclipse.persistence.jaxb.JAXBContextFactory;
+import org.eclipse.persistence.jaxb.MarshallerProperties;
+import org.eclipse.persistence.oxm.MediaType;
+import org.onap.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+import org.onap.policy.apex.model.utilities.ResourceUtils;
+import org.onap.policy.apex.model.utilities.TextFileUtils;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class reads an Apex concept from an XML file into a Java Apex Concept {@link AxConcept}.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <C> the type of Apex concept to read, must be a sub class of {@link AxConcept}
+ */
+public class ApexModelReader<C extends AxConcept> {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelReader.class);
+
+    // Regular expressions for checking input types
+    private static final String XML_INPUT_TYPE_REGEXP = "^\\s*<\\?xml.*>\\s*"; // (starts with <?xml...>
+    private static final String JSON_INPUT_TYPE_REGEXP = "^\\s*[\\(\\{\\[][\\s+\\S]*[\\)\\}\\]]"; // starts with some kind of bracket [ or (
+    // or {, then has something, then has
+    // and has a close bracket
+
+    // Â The root class of the concept we are reading
+    private final Class<C> rootConceptClass;
+
+    // The unmarshaller for the Apex concepts
+    private Unmarshaller unmarshaller = null;
+
+    // All read concepts are validated after reading if this flag is set
+    private boolean validateFlag = true;
+
+    /**
+     * Constructor, initiates the reader with validation on.
+     *
+     * @param rootConceptClass the root concept class for concept reading
+     * @throws ApexModelException the apex concept reader exception
+     */
+    public ApexModelReader(final Class<C> rootConceptClass) throws ApexModelException {
+        // Save the root concept class
+        this.rootConceptClass = rootConceptClass;
+
+        try {
+            final JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] {rootConceptClass}, null);
+
+            // Set up the unmarshaller to carry out validation
+            unmarshaller = jaxbContext.createUnmarshaller();
+            unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
+        }
+        catch (final JAXBException e) {
+            LOGGER.error("Unable to set JAXB context", e);
+            throw new ApexModelException("Unable to set JAXB context", e);
+        }
+    }
+
+    /**
+     * Constructor, initiates the reader.
+     *
+     * @param rootConceptClass the root concept class for concept reading
+     * @param validate whether to perform validation by default
+     * @throws ApexModelException the apex concept reader exception
+     */
+    public ApexModelReader(final Class<C> rootConceptClass, final boolean validate) throws ApexModelException {
+        this(rootConceptClass);
+        this.validateFlag = validate;
+    }
+
+    /**
+     * Set the schema to use for reading XML files.
+     *
+     * @param schemaFileName the schema file to use
+     * @throws ApexModelException if the schema cannot be set
+     */
+    public void setSchema(final String schemaFileName) throws ApexModelException {
+        // Has a schema been set
+        if (schemaFileName != null) {
+            try {
+                // Set the concept schema
+                final URL schemaURL = ResourceUtils.getURLResource(schemaFileName);
+                final Schema apexConceptSchema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaURL);
+                unmarshaller.setSchema(apexConceptSchema);
+            }
+            catch (final Exception e) {
+                LOGGER.error("Unable to load schema ", e);
+                throw new ApexModelException("Unable to load schema", e);
+            }
+        }
+        else {
+            // Clear the schema
+            unmarshaller.setSchema(null);
+        }
+    }
+
+    /**
+     * This method checks the specified Apex concept XML file and reads it into an Apex concept.
+     *
+     * @param apexConceptStream the apex concept stream
+     * @return the Apex concept
+     * @throws ApexModelException on reading exceptions
+     */
+    public C read(final InputStream apexConceptStream) throws ApexModelException {
+        Assertions.argumentNotNull(apexConceptStream, "concept stream may not be null");
+
+        return read(new BufferedReader(new InputStreamReader(apexConceptStream)));
+    }
+
+    /**
+     * This method reads the specified Apex reader into an Apex concept.
+     *
+     * @param apexConceptReader the apex concept reader
+     * @return the Apex concept
+     * @throws ApexModelException on reading exceptions
+     */
+    public C read(final BufferedReader apexConceptReader) throws ApexModelException {
+        Assertions.argumentNotNull(apexConceptReader, "concept reader may not be null");
+
+        LOGGER.entry("reading Apex concept into a String . . .");
+
+        // Get the Apex concept as a string
+        String apexConceptString = null;
+        try {
+            apexConceptString = TextFileUtils.getReaderAsString(apexConceptReader).trim();
+        }
+        catch (final IOException e) {
+            throw new ApexModelException("Unable to read Apex concept ", e);
+        }
+
+        return read(apexConceptString);
+    }
+
+    /**
+     * This method reads the specified Apex string into an Apex concept.
+     *
+     * @param apexConceptString the apex concept as a string
+     * @return the Apex concept
+     * @throws ApexModelException on reading exceptions
+     */
+    public C read(final String apexConceptString) throws ApexModelException {
+        Assertions.argumentNotNull(apexConceptString, "concept string may not be null");
+
+        LOGGER.entry("reading Apex concept from string . . .");
+
+        final String apexString = apexConceptString.trim();
+
+        // Set the type of input for this stream
+        setInputType(apexString);
+
+        // The Apex Concept
+        C apexConcept = null;
+
+        // Use JAXB to read and verify the Apex concept XML file
+        try {
+            // Load the configuration file
+            final StreamSource source = new StreamSource(new StringReader(apexString));
+            final JAXBElement<C> rootElement = unmarshaller.unmarshal(source, rootConceptClass);
+            apexConcept = rootElement.getValue();
+        }
+        catch (final JAXBException e) {
+            throw new ApexModelException("Unable to unmarshal Apex concept ", e);
+        }
+
+        LOGGER.debug("reading of Apex concept {} completed");
+
+        // Check if the concept should be validated
+        if (validateFlag) {
+            // Validate the configuration file
+            final AxValidationResult validationResult = apexConcept.validate(new AxValidationResult());
+            LOGGER.debug(validationResult.toString());
+            if (validationResult.isValid()) {
+                return apexConcept;
+            }
+            else {
+                LOGGER.error("Apex concept validation failed" + validationResult.toString());
+                throw new ApexModelException("Apex concept validation failed" + validationResult.toString());
+            }
+        }
+        else {
+            // No validation check
+            return apexConcept;
+        }
+    }
+
+    /**
+     * Gets the value of the validation flag.
+     *
+     * @return the validation flag value
+     */
+    public boolean getValidateFlag() {
+        return validateFlag;
+    }
+
+    /**
+     * Sets the validation flag.
+     *
+     * @param validateFlag the validation flag value
+     */
+    public void setValidateFlag(final boolean validateFlag) {
+        this.validateFlag = validateFlag;
+    }
+
+    /**
+     * Set the type of input for the concept reader.
+     *
+     * @param apexConceptString The stream with
+     * @throws ApexModelException on errors setting input type
+     */
+    private void setInputType(final String apexConceptString) throws ApexModelException {
+        // Check the input type
+        if (Pattern.compile(JSON_INPUT_TYPE_REGEXP).matcher(apexConceptString).find()) {
+            //is json
+            try {
+                unmarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
+                unmarshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true);
+            }
+            catch (final Exception e) {
+                LOGGER.warn("JAXB error setting marshaller for JSON Input", e);
+                throw new ApexModelException("JAXB error setting marshaller for JSON Input", e);
+            }
+        }
+        else if (Pattern.compile(XML_INPUT_TYPE_REGEXP).matcher(apexConceptString).find()) {
+            //is xml
+            try {
+                unmarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_XML);
+            }
+            catch (final Exception e) {
+                LOGGER.warn("JAXB error setting marshaller for XML Input", e);
+                throw new ApexModelException("JAXB error setting marshaller for XML Input", e);
+            }
+        }
+        else {
+            LOGGER.warn("format of input for Apex concept is neither JSON nor XML");
+            throw new ApexModelException("format of input for Apex concept is neither JSON nor XML");
+        }
+    }
+
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelSaver.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelSaver.java
new file mode 100644 (file)
index 0000000..7f4efee
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.io.File;
+
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.policy.apex.model.utilities.Assertions;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class is used to save Apex models to file in XML or JSON format.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <M> the type of Apex model to save to file, must be a sub class of {@link AxModel}
+ */
+public class ApexModelSaver<M extends AxModel> {
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelSaver.class);
+
+    // The class of the model and the model to write to disk
+    private final Class<M> rootModelClass;
+    private final M model;
+
+    // The path into which to write the models
+    private final String writePath;
+
+    /**
+     * Constructor, specifies the type of the Apex model (a sub class of {@link AxModel}), the model to write, and the path of a directory to which to write the
+     * model.
+     *
+     * @param rootModelClass the class of the model, a sub class of {@link AxModel}
+     * @param model the model to write, an instance of a sub class of {@link AxModel}
+     * @param writePath the directory to which models will be written. The name of the written model will be the Model Name for its key with the suffix
+     *            {@code .xml} or {@code .json}.
+     */
+    public ApexModelSaver(final Class<M> rootModelClass, final M model, final String writePath) {
+        Assertions.argumentNotNull(rootModelClass, "argument rootModelClass may not be null");
+        Assertions.argumentNotNull(model, "argument model may not be null");
+        Assertions.argumentNotNull(writePath, "writePath rootModelClass may not be null");
+
+        this.rootModelClass = rootModelClass;
+        this.model = model;
+        this.writePath = writePath;
+    }
+
+    /**
+     * Write an Apex model to a file in XML format. The model will be written to {@code <writePath/modelKeyName.xml>}
+     *
+     * @throws ApexException on errors writing the Apex model
+     */
+    public void apexModelWriteXML() throws ApexException {
+        LOGGER.debug("running apexModelWriteXML . . .");
+
+        // Write the file to disk
+        final File xmlFile = new File(writePath + File.separatorChar + model.getKey().getName() + ".xml");
+        new ApexModelFileWriter<M>(true).apexModelWriteXMLFile(model, rootModelClass, xmlFile.getPath());
+
+        LOGGER.debug("ran apexModelWriteXML");
+    }
+
+    /**
+     * Write an Apex model to a file in JSON format. The model will be written to {@code <writePath/modelKeyName.json>}
+     *
+     * @throws ApexException on errors writing the Apex model
+     */
+    public void apexModelWriteJSON() throws ApexException {
+        LOGGER.debug("running apexModelWriteJSON . . .");
+
+        // Write the file to disk
+        final File jsonFile = new File(writePath + File.separatorChar + model.getKey().getName() + ".json");
+        new ApexModelFileWriter<M>(true).apexModelWriteJSONFile(model, rootModelClass, jsonFile.getPath());
+
+        LOGGER.debug("ran apexModelWriteJSON");
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelStringWriter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelStringWriter.java
new file mode 100644 (file)
index 0000000..882092c
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.io.ByteArrayOutputStream;
+
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.policy.apex.model.utilities.Assertions;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class writes an Apex concept to a string.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <C> the type of Apex concept to write to a string, must be a sub class of {@link AxConcept}
+ */
+public class ApexModelStringWriter<C extends AxConcept> {
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelStringWriter.class);
+
+    // Should concepts being written to files be valid
+    private boolean validateFlag;
+
+    /**
+     * Constructor, set the validation flag.
+     *
+     * @param validateFlag Should validation be performed prior to output
+     */
+    public ApexModelStringWriter(final boolean validateFlag) {
+        this.validateFlag = validateFlag;
+    }
+
+    /**
+     * Write a concept to a string.
+     *
+     * @param concept The concept to write
+     * @param rootConceptClass The concept class
+     * @param jsonFlag writes JSON if true, and a generic string if false
+     * @return The string with the concept
+     * @throws ApexException thrown on errors
+     */
+    public String writeString(final C concept, final Class<C> rootConceptClass, final boolean jsonFlag) throws ApexException {
+        Assertions.argumentNotNull(concept, "concept may not be null");
+        
+        if (jsonFlag) {
+            return writeJSONString(concept, rootConceptClass);
+        }
+        else {
+            return concept.toString();
+        }
+    }
+
+    /**
+     * Write a concept to an XML string.
+     *
+     * @param concept The concept to write
+     * @param rootConceptClass The concept class
+     * @return The string with the concept
+     * @throws ApexException thrown on errors
+     */
+    public String writeXMLString(final C concept, final Class<C> rootConceptClass) throws ApexException {
+        LOGGER.debug("running writeXMLString . . .");
+
+        final ApexModelWriter<C> conceptWriter = new ApexModelWriter<>(rootConceptClass);
+        conceptWriter.setValidateFlag(validateFlag);
+        conceptWriter.getCDataFieldSet().add("description");
+        conceptWriter.getCDataFieldSet().add("logic");
+        conceptWriter.getCDataFieldSet().add("uiLogic");
+
+        final ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
+        try {
+            conceptWriter.write(concept, baOutputStream);
+            baOutputStream.close();
+        }
+        catch (final Exception e) {
+            LOGGER.warn("error writing XML string", e);
+            throw new ApexException("error writing XML string", e);
+        }
+
+        LOGGER.debug("ran writeXMLString");
+        return baOutputStream.toString();
+    }
+
+    /**
+     * Write a concept to a JSON string.
+     *
+     * @param concept The concept to write
+     * @param rootConceptClass The concept class
+     * @return The string with the concept
+     * @throws ApexException thrown on errors
+     */
+    public String writeJSONString(final C concept, final Class<C> rootConceptClass) throws ApexException {
+        LOGGER.debug("running writeJSONString . . .");
+
+        final ApexModelWriter<C> conceptWriter = new ApexModelWriter<>(rootConceptClass);
+        conceptWriter.setJsonOutput(true);
+        conceptWriter.setValidateFlag(validateFlag);
+
+        final ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
+        try {
+            conceptWriter.write(concept, baOutputStream);
+            baOutputStream.close();
+        }
+        catch (final Exception e) {
+            LOGGER.warn("error writing JSON string", e);
+            throw new ApexException("error writing JSON string", e);
+        }
+
+        LOGGER.debug("ran writeJSONString");
+        return baOutputStream.toString();
+    }
+
+    /**
+     * Checks if is validate flag.
+     *
+     * @return true, if checks if is validate flag
+     */
+    public boolean isValidateFlag() {
+        return validateFlag;
+    }
+
+    /**
+     * Sets the validate flag.
+     *
+     * @param validateFlag the validate flag
+     */
+    public void setValidateFlag(final boolean validateFlag) {
+        this.validateFlag = validateFlag;
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelWriter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexModelWriter.java
new file mode 100644 (file)
index 0000000..5b7a956
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.eclipse.persistence.jaxb.JAXBContextFactory;
+import org.eclipse.persistence.jaxb.MarshallerProperties;
+import org.eclipse.persistence.oxm.MediaType;
+import org.onap.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.policy.apex.model.utilities.Assertions;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+import org.w3c.dom.Document;
+
+/**
+ * This class writes an Apex concept to an XML file or JSON file from a Java Apex Concept.
+ *
+ * @author John Keeney (john.keeney@ericsson.com)
+ * @param <C> the type of Apex concept to write, must be a sub class of {@link AxConcept}
+ */
+public class ApexModelWriter<C extends AxConcept> {
+       private static final String CONCEPT_MAY_NOT_BE_NULL = "concept may not be null";
+    private static final String CONCEPT_WRITER_MAY_NOT_BE_NULL = "concept writer may not be null";
+       private static final String CONCEPT_STREAM_MAY_NOT_BE_NULL = "concept stream may not be null";
+
+       // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexModelWriter.class);
+
+    // Writing as JSON or XML
+    private boolean jsonOutput = false;
+
+    // The list of fields to output as CDATA
+    private final Set<String> cDataFieldSet = new TreeSet<>();
+
+    // The Marshaller for the Apex concepts
+    private Marshaller marshaller = null;
+
+    // All written concepts are validated before writing if this flag is set
+    private boolean validateFlag = true;
+
+    /**
+     * Constructor, initiates the writer.
+     *
+     * @param rootConceptClass the root concept class for concept reading
+     * @throws ApexModelException the apex concept writer exception
+     */
+    public ApexModelWriter(final Class<C> rootConceptClass) throws ApexModelException {
+        // Set up Eclipselink for XML and JSON output
+        System.setProperty("javax.xml.bind.context.factory", "org.eclipse.persistence.jaxb.JAXBContextFactory");
+
+        try {
+            final JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] {rootConceptClass}, null);
+
+            // Set up the unmarshaller to carry out validation
+            marshaller = jaxbContext.createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            marshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
+        }
+        catch (final JAXBException e) {
+            LOGGER.error("JAXB marshaller creation exception", e);
+            throw new ApexModelException("JAXB marshaller creation exception", e);
+        }
+    }
+
+    /**
+     * The set of fields to be output as CDATA.
+     *
+     * @return the set of fields
+     */
+    public Set<String> getCDataFieldSet() {
+        return cDataFieldSet;
+    }
+
+    /**
+     * Return true if JSON output enabled, XML output if false.
+     *
+     * @return true for JSON output
+     */
+    public boolean isJsonOutput() {
+        return jsonOutput;
+    }
+
+    /**
+     * Set the value of JSON output, true for JSON output, false for XML output.
+     *
+     * @param jsonOutput true for JSON output
+     * @throws ApexModelException on errors setting output type
+     */
+    public void setJsonOutput(final boolean jsonOutput) throws ApexModelException {
+        this.jsonOutput = jsonOutput;
+
+        // Set up output specific parameters
+        if (this.jsonOutput) {
+            try {
+                marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
+                marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true);
+            }
+            catch (final Exception e) {
+                LOGGER.warn("JAXB error setting marshaller for JSON output", e);
+                throw new ApexModelException("JAXB error setting marshaller for JSON output", e);
+            }
+        }
+        else {
+            try {
+                marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_XML);
+            }
+            catch (final Exception e) {
+                LOGGER.warn("JAXB error setting marshaller for XML output", e);
+                throw new ApexModelException("JAXB error setting marshaller for XML output", e);
+            }
+        }
+    }
+
+    /**
+     * This method validates the Apex concept then writes it into a stream.
+     *
+     * @param concept the concept to write
+     * @param apexConceptStream the stream to write to
+     * @throws ApexModelException on validation or writing exceptions
+     */
+    public void write(final C concept, final OutputStream apexConceptStream) throws ApexModelException {
+        Assertions.argumentNotNull(concept, CONCEPT_MAY_NOT_BE_NULL);
+        Assertions.argumentNotNull(apexConceptStream, CONCEPT_STREAM_MAY_NOT_BE_NULL);
+        
+        this.write(concept, new OutputStreamWriter(apexConceptStream));
+    }
+
+    /**
+     * This method validates the Apex concept then writes it into a writer.
+     *
+     * @param concept the concept to write
+     * @param apexConceptWriter the writer to write to
+     * @throws ApexModelException on validation or writing exceptions
+     */
+    public void write(final C concept, final Writer apexConceptWriter) throws ApexModelException {
+        Assertions.argumentNotNull(concept, CONCEPT_MAY_NOT_BE_NULL);
+        Assertions.argumentNotNull(apexConceptWriter, CONCEPT_WRITER_MAY_NOT_BE_NULL);
+
+        // Check if we should validate the concept
+        if (validateFlag) {
+            // Validate the concept first
+            final AxValidationResult validationResult = concept.validate(new AxValidationResult());
+            LOGGER.debug(validationResult.toString());
+            if (!validationResult.isValid()) {
+                LOGGER.warn(validationResult.toString());
+                throw new ApexModelException("Apex concept xml (" + concept.getKey().getID() + ") validation failed");
+            }
+        }
+
+        if (jsonOutput) {
+            writeJSON(concept, apexConceptWriter);
+        }
+        else {
+            writeXML(concept, apexConceptWriter);
+        }
+    }
+
+    /**
+     * This method writes the Apex concept into a writer in XML format.
+     *
+     * @param concept the concept to write
+     * @param apexConceptWriter the writer to write to
+     * @throws ApexModelException on validation or writing exceptions
+     */
+    private void writeXML(final C concept, final Writer apexConceptWriter) throws ApexModelException {
+        Assertions.argumentNotNull(concept, CONCEPT_MAY_NOT_BE_NULL);
+
+        LOGGER.debug("writing Apex concept XML . . .");
+
+        try {
+            // Write the concept into a DOM document, then transform to add CDATA fields and pretty print, then write out the result
+            final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
+            final Document document = docBuilderFactory.newDocumentBuilder().newDocument();
+
+            // Marshal the concept into the empty document.
+            marshaller.marshal(concept, document);
+
+            // Transform the DOM to the output stream
+            final TransformerFactory transformerFactory = TransformerFactory.newInstance();
+            final Transformer domTransformer = transformerFactory.newTransformer();
+
+            // Pretty print
+            try {
+                domTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
+                // May fail if not using XALAN XSLT engine. But not in any way vital
+                domTransformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+            }
+            catch (final Exception ignore) {
+                       // We ignore exceptions here and catch errors below
+            }
+
+            // Convert the cDataFieldSet into a space delimited string
+            domTransformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, cDataFieldSet.toString().replaceAll("[\\[\\]\\,]", " "));
+            domTransformer.transform(new DOMSource(document), new StreamResult(apexConceptWriter));
+        }
+        catch (JAXBException | TransformerException | ParserConfigurationException e) {
+            LOGGER.warn("Unable to marshal Apex concept XML", e);
+            throw new ApexModelException("Unable to marshal Apex concept XML", e);
+        }
+        LOGGER.debug("wrote Apex concept XML");
+    }
+
+    /**
+     * This method writes the Apex concept into a writer in JSON format.
+     *
+     * @param concept the concept to write
+     * @param apexConceptWriter the writer to write to
+     * @throws ApexModelException on validation or writing exceptions
+     */
+    private void writeJSON(final C concept, final Writer apexConceptWriter) throws ApexModelException {
+        Assertions.argumentNotNull(concept, CONCEPT_MAY_NOT_BE_NULL);
+
+        LOGGER.debug("writing Apex concept JSON . . .");
+
+        try {
+            marshaller.marshal(concept, apexConceptWriter);
+        }
+        catch (final JAXBException e) {
+            LOGGER.warn("Unable to marshal Apex concept JSON", e);
+            throw new ApexModelException("Unable to marshal Apex concept JSON", e);
+        }
+        LOGGER.debug("wrote Apex concept JSON");
+    }
+
+    /**
+     * Gets the validation flag value.
+     *
+     * @return the validation flag value
+     */
+    public boolean getValidateFlag() {
+        return validateFlag;
+    }
+
+    /**
+     * Sets the validation flag.
+     *
+     * @param validateFlag the validation flag value
+     */
+    public void setValidateFlag(final boolean validateFlag) {
+        this.validateFlag = validateFlag;
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexSchemaGenerator.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/ApexSchemaGenerator.java
new file mode 100644 (file)
index 0000000..5055df6
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class generates the XML model schema from the given Apex concept classes.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexSchemaGenerator {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexSchemaGenerator.class);
+
+    /**
+     * A Main method to allow schema generation from the command line or from maven or scripts.
+     *
+     * @param args the command line arguments, usage is {@code ApexSchemaGenerator apex-root-class [schema-file-name]}
+     */
+    public static void main(final String[] args) {
+        PrintStream printStream = null;
+
+        if (args.length == 1) {
+            printStream = System.out;
+        }
+        else if (args.length == 2) {
+            final File schemaFile = new File(args[1]);
+
+            try {
+                schemaFile.getParentFile().mkdirs();
+                printStream = new PrintStream(schemaFile);
+            }
+            catch (final Exception e) {
+                LOGGER.error("error on Apex schema output", e);
+                return;
+            }
+        }
+        else {
+            LOGGER.error("usage: ApexSchemaGenerator apex-root-class [schema-file-name]");
+            return;
+        }
+
+        // Get the schema
+        final String schema = new ApexSchemaGenerator().generate(args[0]);
+
+        // Output the schema
+        printStream.println(schema);
+
+        printStream.close();
+    }
+
+    /**
+     * Generates the XML schema (XSD) for the Apex model described using JAXB annotations.
+     *
+     * @param rootClassName the name of the root class for schema generation
+     * @return The schema
+     */
+    public String generate(final String rootClassName) {
+        JAXBContext jaxbContext;
+        try {
+            jaxbContext = JAXBContext.newInstance(Class.forName(rootClassName));
+        }
+        catch (final ClassNotFoundException e) {
+            LOGGER.error("could not create JAXB context, root class " + rootClassName + " not found", e);
+            return null;
+        }
+        catch (final JAXBException e) {
+            LOGGER.error("could not create JAXB context", e);
+            return null;
+        }
+
+        final ApexSchemaOutputResolver sor = new ApexSchemaOutputResolver();
+        try {
+            jaxbContext.generateSchema(sor);
+        }
+        catch (final IOException e) {
+            LOGGER.error("error generating the Apex schema (XSD) file", e);
+            return null;
+        }
+
+        String schemaString = sor.getSchema();
+        schemaString = fixForUnqualifiedBug(schemaString);
+
+        return schemaString;
+    }
+
+    /**
+     * There is a bug in schema generation that does not specify the elements from Java Maps as being unqualified. This method "hacks" those
+     * elements in the schema to fix this, the elements being {@code entry}, {@code key}, and {@code value}
+     *
+     * @param schemaString The schema in which elements should be fixed
+     * @return the string
+     */
+    private String fixForUnqualifiedBug(final String schemaString) {
+        // Fix the "entry" element
+        String newSchemaString = schemaString.replaceAll("<xs:element name=\"entry\" minOccurs=\"0\" maxOccurs=\"unbounded\">",
+                "<xs:element name=\"entry\" minOccurs=\"0\" maxOccurs=\"unbounded\" form=\"unqualified\">");
+
+        // Fix the "key" element
+        newSchemaString = newSchemaString.replaceAll("<xs:element name=\"key\"", "<xs:element name=\"key\" form=\"unqualified\"");
+
+        // Fix the "value" element
+        newSchemaString = newSchemaString.replaceAll("<xs:element name=\"value\"", "<xs:element name=\"value\" form=\"unqualified\"");
+
+        return newSchemaString;
+    }
+
+    /**
+     * This inner class is used to receive the output of schema generation from the JAXB schema generator.
+     */
+    private class ApexSchemaOutputResolver extends SchemaOutputResolver {
+        private final StringWriter stringWriter = new StringWriter();
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see javax.xml.bind.SchemaOutputResolver#createOutput(java.lang.String, java.lang.String)
+         */
+        @Override
+        public Result createOutput(final String namespaceURI, final String suggestedFileName) throws IOException {
+            final StreamResult result = new StreamResult(stringWriter);
+            result.setSystemId(suggestedFileName);
+            return result;
+        }
+
+        /**
+         * Get the schema from the string writer created in the {@link createOutput()} method.
+         *
+         * @return the schema generated by JAXB
+         */
+        public String getSchema() {
+            return stringWriter.toString();
+        }
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/handling/package-info.java
new file mode 100644 (file)
index 0000000..871a0ea
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains a number of utility classes for handling APEX {@link org.onap.apex.model.basicmodel.concepts.AxModel} models and
+ * {@link org.onap.apex.model.basicmodel.concepts.AxConcept} concepts.
+ * Classes to read and write models to files, strings, and databases are included, as
+ * well as classes to generate XML schemas for models.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+
+@XmlSchema(namespace = "http://www.ericsson.com/apex", elementFormDefault = XmlNsForm.QUALIFIED, xmlns = {
+        @XmlNs(namespaceURI = "http://www.ericsson.com/apex", prefix = "") })
+
+package org.onap.apex.model.basicmodel.handling;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlNsForm;
+import javax.xml.bind.annotation.XmlSchema;
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/package-info.java
new file mode 100644 (file)
index 0000000..dbee9cc
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides the base definition of an APEX model. It also defines the Model Service, the mechanism that allows access to the
+ * model for APEX concepts anywhere in the system.
+ *
+ * It also provides handling support to models, allowing them to be read and written to file and databases in JSON and XML format.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.apex.model.basicmodel;
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/AbstractParameters.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/AbstractParameters.java
new file mode 100644 (file)
index 0000000..2cde325
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.service;
+
+import org.onap.apex.model.basicmodel.concepts.ApexRuntimeException;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * This class defines an abstract parameter class that acts as a base class for all parameters in Apex. The abstract parameter class holds the name of a
+ * subclass of this abstract parameter class {@link AbstractParameters}. The class of the parameter class is checked at construction and on calls to the
+ * {@link #getParameterClass()} method.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class AbstractParameters {
+    // The name of the parameter subclass
+    private String parameterClassName = this.getClass().getCanonicalName();
+
+    /**
+     * Constructor, creates a parameter class that must be a subclass of {@link AbstractParameters}.
+     *
+     * @param parameterClassName the full canonical class name of the parameter class
+     */
+    public AbstractParameters(final String parameterClassName) {
+        try {
+            Assertions.assignableFrom(Class.forName(parameterClassName), AbstractParameters.class);
+        }
+        catch (IllegalArgumentException | ClassNotFoundException e) {
+            throw new ApexRuntimeException(
+                    "class \"" + parameterClassName + "\" not found or not an instance of \"" + this.getClass().getCanonicalName() + "\"", e);
+        }
+    }
+
+    /**
+     * Gets the parameter class.
+     *
+     * @return the parameter class
+     */
+    @SuppressWarnings("unchecked")
+    public final Class<? extends AbstractParameters> getParameterClass() {
+        try {
+            return (Class<? extends AbstractParameters>) Class.forName(parameterClassName);
+        }
+        catch (final ClassNotFoundException e) {
+            throw new ApexRuntimeException("class not found for parameter class name \"" + parameterClassName + "\"");
+        }
+    }
+
+    /**
+     * Gets the parameter class name.
+     *
+     * @return the parameter class name
+     */
+    public final String getParameterClassName() {
+        return parameterClassName;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "AbstractParameters [parameterClassName=" + parameterClassName + "]";
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ModelService.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ModelService.java
new file mode 100644 (file)
index 0000000..688beaa
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.service;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.onap.apex.model.basicmodel.concepts.ApexRuntimeException;
+import org.onap.apex.model.basicmodel.concepts.AxConcept;
+
+/**
+ * The model service makes Apex models available to all classes in a JVM.
+ *
+ * The reason for having a model service is to avoid having to pass concept and model definitions down long call chains in modules such as the Apex engine and
+ * editor. The model service makes the model and concept definitions available statically.
+ *
+ * Note that the use of the model service means that only a single Apex model of a particular type may exist in Apex (particularly the engine) at any time. Of
+ * course the model in a JVM can be changed at any time provided all users of the model are stopped and restrted in an orderly manner.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class ModelService {
+    // The map holding the models
+    private static Map<Class<?>, AxConcept> modelMap = new ConcurrentHashMap<>();
+
+    /**
+     * This class is an abstract static class that cannot be extended.
+     */
+    private ModelService() {
+    }
+
+    /**
+     * Register a model with the model service.
+     *
+     * @param <M> the generic type
+     * @param modelClass the class of the model, used to index the model
+     * @param model The model
+     */
+    public static <M extends AxConcept> void registerModel(final Class<M> modelClass, final M model) {
+        modelMap.put(modelClass, model);
+    }
+
+    /**
+     * Remove a model from the model service.
+     *
+     * @param <M> the generic type
+     * @param modelClass the class of the model, used to index the model
+     */
+    public static <M extends AxConcept> void deregisterModel(final Class<M> modelClass) {
+        modelMap.remove(modelClass);
+    }
+
+    /**
+     * Get a model from the model service.
+     *
+     * @param <M> the generic type
+     * @param modelClass the class of the model, used to index the model
+     * @return The model
+     */
+    @SuppressWarnings("unchecked")
+    public static <M extends AxConcept> M getModel(final Class<M> modelClass) {
+        final M model = (M) modelMap.get(modelClass);
+
+        if (model == null) {
+            throw new ApexRuntimeException("Model for " + modelClass.getCanonicalName() + " not found in model service");
+        }
+
+        return model;
+    }
+
+    /**
+     * Check if a model is defined on the model service.
+     *
+     * @param <M> the generic type
+     * @param modelClass the class of the model, used to index the model
+     * @return true if the model is defined
+     */
+    public static <M extends AxConcept> boolean existsModel(final Class<M> modelClass) {
+        return modelMap.get(modelClass) != null;
+    }
+
+    /**
+     * Clear all models in the model service.
+     */
+    public static void clear() {
+        modelMap.clear();
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ParameterService.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/ParameterService.java
new file mode 100644 (file)
index 0000000..9a254b0
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.service;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.onap.apex.model.basicmodel.concepts.ApexRuntimeException;
+
+/**
+ * The parameter service makes Apex parameters available to all classes in a JVM.
+ *
+ * The reason for having a parameter service is to avoid having to pass parameters down long call chains in modules such as the Apex engine and editor. The
+ * parameter service makes parameters available statically.
+ *
+ * The parameter service must be used with care because changing a parameter set anywhere in a JVM will affect all users of those parameters anywhere in the
+ * JVM.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class ParameterService {
+    // The map holding the parameters
+    private static Map<Class<?>, AbstractParameters> parameterMap = new ConcurrentHashMap<>();
+
+    /**
+     * This class is an abstract static class that cannot be extended.
+     */
+    private ParameterService() {
+    }
+
+    /**
+     * Register parameters with the parameter service.
+     *
+     * @param <P> the generic type
+     * @param parametersClass the class of the parameter, used to index the parameter
+     * @param parameters the parameters
+     */
+    public static <P extends AbstractParameters> void registerParameters(final Class<P> parametersClass, final P parameters) {
+        parameterMap.put(parametersClass, parameters);
+    }
+
+    /**
+     * Remove parameters from the parameter service.
+     *
+     * @param <P> the generic type
+     * @param parametersClass the class of the parameter, used to index the parameter
+     */
+    public static <P extends AbstractParameters> void deregisterParameters(final Class<P> parametersClass) {
+        parameterMap.remove(parametersClass);
+    }
+
+    /**
+     * Get parameters from the parameter service.
+     *
+     * @param <P> the generic type
+     * @param parametersClass the class of the parameter, used to index the parameter
+     * @return The parameter
+     */
+    @SuppressWarnings("unchecked")
+    public static <P extends AbstractParameters> P getParameters(final Class<P> parametersClass) {
+        final P parameter = (P) parameterMap.get(parametersClass);
+
+        if (parameter == null) {
+            throw new ApexRuntimeException("Parameters for " + parametersClass.getCanonicalName() + " not found in parameter service");
+        }
+
+        return parameter;
+    }
+
+    /**
+     * Check if parameters is defined on the parameter service.
+     *
+     * @param <P> the generic type
+     * @param parametersClass the class of the parameter, used to index the parameter
+     * @return true if the parameter is defined
+     */
+    public static <P extends AbstractParameters> boolean existsParameters(final Class<P> parametersClass) {
+        return parameterMap.get(parametersClass) != null;
+    }
+
+    /**
+     * Get all the entries in the parameters map.
+     *
+     * @return The entries
+     */
+    public static Set<Entry<Class<?>, AbstractParameters>> getAll() {
+        return parameterMap.entrySet();
+    }
+
+    /**
+     * Clear all parameters in the parameter service.
+     */
+    public static void clear() {
+        parameterMap.clear();
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/service/package-info.java
new file mode 100644 (file)
index 0000000..da6c698
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains the static services in Apex that make models and parameters available to all objects in the JVM.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.apex.model.basicmodel.service;
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModel.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModel.java
new file mode 100644 (file)
index 0000000..e7e5067
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.net.URL;
+
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.apex.model.basicmodel.dao.ApexDao;
+import org.onap.apex.model.basicmodel.dao.ApexDaoFactory;
+import org.onap.apex.model.basicmodel.dao.DAOParameters;
+import org.onap.apex.model.basicmodel.handling.ApexModelFileWriter;
+import org.onap.apex.model.basicmodel.handling.ApexModelReader;
+import org.onap.apex.model.basicmodel.handling.ApexModelWriter;
+import org.onap.policy.apex.model.utilities.ResourceUtils;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class tests reading and writing of Apex models to file and to a database using JPA. It also tests validation of Apex models. This class is designed for
+ * use in unit tests in modules that define Apex models.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <M> the generic type
+ */
+public class TestApexModel<M extends AxModel> {
+    private static final String MODEL_IS_INVALID = "model is invalid ";
+       private static final String ERROR_PROCESSING_FILE = "error processing file ";
+       private static final String TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE = "test model does not equal model read from XML file ";
+       private static final String ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL = "error creating temporary file for Apex model";
+
+       private static final XLogger LOGGER = XLoggerFactory.getXLogger(TestApexModel.class);
+
+    // The root model class that specifies the root to import and export from
+    private final Class<M> rootModelClass;
+
+    // The class that provides the model
+    private TestApexModelCreator<M> modelCreator = null;
+
+    /**
+     * Constructor, defines the subclass of {@link AxModel} that is being tested and the {@link TestApexModelCreator} object that is used to generate Apex
+     * models.
+     *
+     * @param rootModelClass the Apex model class, a sub class of {@link AxModel}
+     * @param modelCreator the @link TestApexModelCreator} that will generate Apex models of various types for testing
+     */
+    public TestApexModel(final Class<M> rootModelClass, final TestApexModelCreator<M> modelCreator) {
+        this.rootModelClass = rootModelClass;
+        this.modelCreator = modelCreator;
+    }
+
+    /**
+     * Get a test Apex model using the model creator.
+     *
+     * @return the test Apex model
+     */
+    public final M getModel() {
+        return modelCreator.getModel();
+    }
+
+    /**
+     * Test write and read in XML format.
+     *
+     * @throws ApexException on write/read errors
+     */
+    public final void testApexModelWriteReadXML() throws ApexException {
+        LOGGER.debug("running testApexModelWriteReadXML . . .");
+
+        final M model = modelCreator.getModel();
+
+        // Write the file to disk
+        File xmlFile;
+        
+        try {
+            xmlFile = File.createTempFile("ApexModel", ".xml");
+            xmlFile.deleteOnExit();
+        }
+        catch (final Exception e) {
+            LOGGER.warn(ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL, e);
+            throw new ApexException(ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL, e);
+        }
+        new ApexModelFileWriter<M>(true).apexModelWriteXMLFile(model, rootModelClass, xmlFile.getPath());
+
+        // Read the file from disk
+        final ApexModelReader<M> modelReader = new ApexModelReader<>(rootModelClass);
+
+        try {
+            final URL apexModelURL = ResourceUtils.getLocalFile(xmlFile.getAbsolutePath());
+            final M fileModel = modelReader.read(apexModelURL.openStream());
+            if (!model.equals(fileModel)) {
+                LOGGER.warn(TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE + xmlFile.getAbsolutePath());
+                throw new ApexException(TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE + xmlFile.getAbsolutePath());
+            }
+        }
+        catch (final Exception e) {
+            LOGGER.warn(ERROR_PROCESSING_FILE + xmlFile.getAbsolutePath(), e);
+            throw new ApexException(ERROR_PROCESSING_FILE + xmlFile.getAbsolutePath(), e);
+        }
+
+        final ApexModelWriter<M> modelWriter = new ApexModelWriter<>(rootModelClass);
+        modelWriter.getCDataFieldSet().add("description");
+        modelWriter.getCDataFieldSet().add("logic");
+        modelWriter.getCDataFieldSet().add("uiLogic");
+
+        final ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
+        modelWriter.write(model, baOutputStream);
+        final ByteArrayInputStream baInputStream = new ByteArrayInputStream(baOutputStream.toByteArray());
+        final M byteArrayModel = modelReader.read(baInputStream);
+        if (!model.equals(byteArrayModel)) {
+            LOGGER.warn("test model does not equal XML marshalled and unmarshalled model");
+            throw new ApexException("test model does not equal XML marshalled and unmarshalled model");
+        }
+
+        LOGGER.debug("ran testApexModelWriteReadXML");
+    }
+
+    /**
+     * Test write and read in JSON format.
+     *
+     * @throws ApexException on write/read errors
+     */
+    public final void testApexModelWriteReadJSON() throws ApexException {
+        LOGGER.debug("running testApexModelWriteReadJSON . . .");
+
+        final M model = modelCreator.getModel();
+
+        // Write the file to disk
+        File jsonFile;
+        try {
+            jsonFile = File.createTempFile("ApexModel", ".xml");
+            jsonFile.deleteOnExit();
+        }
+        catch (final Exception e) {
+            LOGGER.warn(ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL, e);
+            throw new ApexException(ERROR_CREATING_TEMPORARY_FILE_FOR_APEX_MODEL, e);
+        }
+        new ApexModelFileWriter<M>(true).apexModelWriteJSONFile(model, rootModelClass, jsonFile.getPath());
+
+        // Read the file from disk
+        final ApexModelReader<M> modelReader = new ApexModelReader<>(rootModelClass);
+
+        try {
+            final URL apexModelURL = ResourceUtils.getLocalFile(jsonFile.getAbsolutePath());
+            final M fileModel = modelReader.read(apexModelURL.openStream());
+            if (!model.equals(fileModel)) {
+                LOGGER.warn(TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE + jsonFile.getAbsolutePath());
+                throw new ApexException(TEST_MODEL_DOES_NOT_EQUAL_MODEL_READ_FROM_XML_FILE + jsonFile.getAbsolutePath());
+            }
+        }
+        catch (final Exception e) {
+            LOGGER.warn(ERROR_PROCESSING_FILE + jsonFile.getAbsolutePath(), e);
+            throw new ApexException(ERROR_PROCESSING_FILE + jsonFile.getAbsolutePath(), e);
+        }
+
+        final ApexModelWriter<M> modelWriter = new ApexModelWriter<>(rootModelClass);
+        modelWriter.setJsonOutput(true);
+
+        final ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
+        modelWriter.write(model, baOutputStream);
+        final ByteArrayInputStream baInputStream = new ByteArrayInputStream(baOutputStream.toByteArray());
+        final M byteArrayModel = modelReader.read(baInputStream);
+        if (!model.equals(byteArrayModel)) {
+            LOGGER.warn("test model does not equal JSON marshalled and unmarshalled model");
+            throw new ApexException("test model does not equal JSON marshalled and unmarshalled model");
+        }
+
+        LOGGER.debug("ran testApexModelWriteReadJSON");
+    }
+
+    /**
+     * Test write and read of an Apex model to database using JPA.
+     *
+     * @param daoParameters the DAO parameters to use for JPA/JDBC
+     * @throws ApexException thrown on errors writing or reading the model to database
+     */
+    public final void testApexModelWriteReadJPA(final DAOParameters daoParameters) throws ApexException {
+        LOGGER.debug("running testApexModelWriteReadJPA . . .");
+
+        final M model = modelCreator.getModel();
+
+        final ApexDao apexDao = new ApexDaoFactory().createApexDao(daoParameters);
+        apexDao.init(daoParameters);
+
+        apexDao.create(model);
+        final M dbJPAModel = apexDao.get(rootModelClass, model.getKey());
+        apexDao.close();
+
+        if (!model.equals(dbJPAModel)) {
+            LOGGER.warn("test model does not equal model written and read using generic JPA");
+            throw new ApexException("test model does not equal model written and read using generic JPA");
+        }
+
+        LOGGER.debug("ran testApexModelWriteReadJPA");
+    }
+
+    /**
+     * Test that an Apex model is valid.
+     *
+     * @return the result of the validation
+     * @throws ApexException thrown on errors validating the Apex model
+     */
+    public final AxValidationResult testApexModelValid() throws ApexException {
+        LOGGER.debug("running testApexModelVaid . . .");
+
+        final M model = modelCreator.getModel();
+        final AxValidationResult result = model.validate(new AxValidationResult());
+
+        if (!result.isValid()) {
+            LOGGER.warn(MODEL_IS_INVALID + result.toString());
+            throw new ApexException(MODEL_IS_INVALID + result.toString());
+        }
+
+        LOGGER.debug("ran testApexModelVaid");
+        return result;
+    }
+
+    /**
+     * Test that an Apex model is structured incorrectly.
+     *
+     * @return the result of the validation
+     * @throws ApexException thrown on errors validating the Apex model
+     */
+    public final AxValidationResult testApexModelVaidateMalstructured() throws ApexException {
+        LOGGER.debug("running testApexModelVaidateMalstructured . . .");
+
+        final M model = modelCreator.getMalstructuredModel();
+        final AxValidationResult result = model.validate(new AxValidationResult());
+
+        if (result.isValid()) {
+            LOGGER.warn("model should not be valid " + result.toString());
+            throw new ApexException("should not be valid " + result.toString());
+        }
+
+        LOGGER.debug("ran testApexModelVaidateMalstructured");
+        return result;
+    }
+
+    /**
+     * Test that an Apex model has observations.
+     *
+     * @return the result of the validation
+     * @throws ApexException thrown on errors validating the Apex model
+     */
+    public final AxValidationResult testApexModelVaidateObservation() throws ApexException {
+        LOGGER.debug("running testApexModelVaidateObservation . . .");
+
+        final M model = modelCreator.getObservationModel();
+        final AxValidationResult result = model.validate(new AxValidationResult());
+
+        if (!result.isValid()) {
+            LOGGER.warn(MODEL_IS_INVALID + result.toString());
+            throw new ApexException(MODEL_IS_INVALID + result.toString());
+        }
+
+        if (!result.getValidationResult().equals(AxValidationResult.ValidationResult.OBSERVATION)) {
+            LOGGER.warn("model should have observations");
+            throw new ApexException("model should have observations");
+        }
+
+        LOGGER.debug("ran testApexModelVaidateObservation");
+        return result;
+    }
+
+    /**
+     * Test that an Apex model has warnings.
+     *
+     * @return the result of the validation
+     * @throws ApexException thrown on errors validating the Apex model
+     */
+    public final AxValidationResult testApexModelVaidateWarning() throws ApexException {
+        LOGGER.debug("running testApexModelVaidateWarning . . .");
+
+        final M model = modelCreator.getWarningModel();
+        final AxValidationResult result = model.validate(new AxValidationResult());
+
+        if (!result.isValid()) {
+            LOGGER.warn(MODEL_IS_INVALID + result.toString());
+            throw new ApexException(MODEL_IS_INVALID + result.toString());
+        }
+
+        if (!result.getValidationResult().equals(AxValidationResult.ValidationResult.WARNING)) {
+            LOGGER.warn("model should have warnings");
+            throw new ApexException("model should have warnings");
+        }
+
+        LOGGER.debug("ran testApexModelVaidateWarning");
+        return result;
+    }
+
+    /**
+     * Test that an Apex model is invalid.
+     *
+     * @return the result of the validation
+     * @throws ApexException thrown on errors validating the Apex model
+     */
+    public final AxValidationResult testApexModelVaidateInvalidModel() throws ApexException {
+        LOGGER.debug("running testApexModelVaidateInvalidModel . . .");
+
+        final M model = modelCreator.getInvalidModel();
+        final AxValidationResult result = model.validate(new AxValidationResult());
+
+        if (result.isValid()) {
+            LOGGER.warn("model should not be valid " + result.toString());
+            throw new ApexException("should not be valid " + result.toString());
+        }
+
+        LOGGER.debug("ran testApexModelVaidateInvalidModel");
+        return result;
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModelCreator.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/TestApexModelCreator.java
new file mode 100644 (file)
index 0000000..7213c66
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.test;
+
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.handling.ApexModelCreator;
+
+/**
+ * The Interface TestApexModelCreator is used to create models for Apex model tests. It is mainly used by unit tests for Apex domain models so that
+ * developers can write test Java programs to create models.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <M> the generic type
+ */
+public interface TestApexModelCreator<M extends AxModel> extends ApexModelCreator<M> {
+
+    /**
+     * Gets the malstructured model.
+     *
+     * @return the malstructured model
+     */
+    M getMalstructuredModel();
+
+    /**
+     * Gets the observation model.
+     *
+     * @return the observation model
+     */
+    M getObservationModel();
+
+    /**
+     * Gets the warning model.
+     *
+     * @return the warning model
+     */
+    M getWarningModel();
+
+    /**
+     * Gets the invalid model.
+     *
+     * @return the invalid model
+     */
+    M getInvalidModel();
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/test/package-info.java
new file mode 100644 (file)
index 0000000..6bd6b73
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains utility classes that allow testing of validation and reads and writes on APEX models to files and databases.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.apex.model.basicmodel.test;
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/AxReferenceKeyAdapter.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/AxReferenceKeyAdapter.java
new file mode 100644 (file)
index 0000000..a2bfbb8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.xml;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+
+/**
+ * This class manages marshaling and unmarshaling of Apex {@link AxReferenceKey} concepts using JAXB. The local name in reference keys must have specific
+ * handling.
+ */
+@XmlAccessorType(XmlAccessType.PROPERTY)
+@XmlType(namespace = "http://www.ericsson.com/apex")
+public class AxReferenceKeyAdapter extends XmlAdapter<String, AxReferenceKey> implements Serializable {
+
+    private static final long serialVersionUID = -3480405083900107029L;
+
+    /*
+     * (non-Javadoc)
+     * @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
+     */
+    @Override
+    public final String marshal(final AxReferenceKey key) throws Exception {
+        return key.getLocalName();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
+     */
+    @Override
+    public final AxReferenceKey unmarshal(final String key) throws Exception {
+        final AxReferenceKey axReferenceKey = new AxReferenceKey();
+        axReferenceKey.setLocalName(key);
+        return axReferenceKey;
+    }
+}
diff --git a/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/package-info.java b/model/basic-model/src/main/java/org/onap/apex/model/basicmodel/xml/package-info.java
new file mode 100644 (file)
index 0000000..77bc0c1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains utility classes for managing marshaling and unmarshaling of APEX models using JAXB.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+
+@XmlSchema(namespace = "http://www.ericsson.com/apex", elementFormDefault = XmlNsForm.QUALIFIED, xmlns = {
+        @XmlNs(namespaceURI = "http://www.ericsson.com/apex", prefix = "") })
+
+package org.onap.apex.model.basicmodel.xml;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlNsForm;
+import javax.xml.bind.annotation.XmlSchema;
diff --git a/model/basic-model/src/main/resources/doc/JDBCPropertiesExamples.txt b/model/basic-model/src/main/resources/doc/JDBCPropertiesExamples.txt
new file mode 100644 (file)
index 0000000..6e105a6
--- /dev/null
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------------------------
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2016-2018 Ericsson. 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.
+# 
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#-------------------------------------------------------------------------------
+
+Properties jdbcProperties = new Properties();
+jdbcProperties.put("javax.persistence.jdbc.url", "jdbc:postgresql://localhost:5432/apex_test");
+jdbcProperties.put("eclipselink.ddl-generation", "drop-and-create-tables");
+
+Properties jdbcProperties = new Properties();
+jdbcProperties.put("javax.persistence.jdbc.url", "jdbc:postgresql://localhost:5432/apex_test");
+jdbcProperties.put("hibernate.hbm2ddl.auto",     "create-drop");
+
+Properties jdbcProperties = new Properties();
+jdbcProperties.put("javax.persistence.jdbc.url", "jdbc:postgresql://localhost:5432/apex");
+jdbcProperties.put("eclipselink.ddl-generation", "create-or-extend-tables");
+
+Properties jdbcProperties = new Properties();
+jdbcProperties.put("javax.persistence.jdbc.url", "jdbc:postgresql://localhost:5432/apex");
+jdbcProperties.put("hibernate.hbm2ddl.auto",     "update");
diff --git a/model/basic-model/src/main/resources/xml/example.xsd b/model/basic-model/src/main/resources/xml/example.xsd
new file mode 100644 (file)
index 0000000..9f253f2
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" standalone="yes"?>
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2016-2018 Ericsson. 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.
+  
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+<xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="http://www.ericsson.com/apex" xmlns="http://www.ericsson.com/apex" xmlns:tns="http://www.ericsson.com/apex" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+  <xs:element name="apexArtifactKey" type="AxArtifactKey"/>
+
+  <xs:element name="apexKeyInfo" type="AxKeyInfo"/>
+
+  <xs:element name="apexModel" type="AxModel"/>
+
+  <xs:complexType name="AxModel">
+    <xs:complexContent>
+      <xs:extension base="AxConcept">
+        <xs:sequence>
+          <xs:element name="key" form="unqualified" type="AxArtifactKey"/>
+          <xs:element name="keyInformation" type="AxKeyInformation"/>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+
+  <xs:complexType name="AxConcept" abstract="true">
+    <xs:sequence/>
+  </xs:complexType>
+
+  <xs:complexType name="AxArtifactKey">
+    <xs:complexContent>
+      <xs:extension base="axKey">
+        <xs:sequence>
+          <xs:element name="name" type="xs:string"/>
+          <xs:element name="version" type="xs:string"/>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+
+  <xs:complexType name="axKey" abstract="true">
+    <xs:complexContent>
+      <xs:extension base="AxConcept">
+        <xs:sequence/>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+
+  <xs:complexType name="AxKeyInformation">
+    <xs:complexContent>
+      <xs:extension base="AxConcept">
+        <xs:sequence>
+          <xs:element name="key" form="unqualified" type="AxArtifactKey"/>
+          <xs:element name="keyInfoMap">
+            <xs:complexType>
+              <xs:sequence>
+                <xs:element name="entry" minOccurs="0" maxOccurs="unbounded" form="unqualified">
+                  <xs:complexType>
+                    <xs:sequence>
+                      <xs:element name="key" form="unqualified" minOccurs="0" type="AxArtifactKey"/>
+                      <xs:element name="value" form="unqualified" minOccurs="0" type="AxKeyInfo"/>
+                    </xs:sequence>
+                  </xs:complexType>
+                </xs:element>
+              </xs:sequence>
+            </xs:complexType>
+          </xs:element>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+
+  <xs:complexType name="AxKeyInfo">
+    <xs:complexContent>
+      <xs:extension base="AxConcept">
+        <xs:sequence>
+          <xs:element name="key" form="unqualified" type="AxArtifactKey"/>
+          <xs:element name="UUID" type="xs:string"/>
+          <xs:element name="description" type="xs:string"/>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+</xs:schema>
+
+
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/AxKeyTest.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/AxKeyTest.java
new file mode 100644 (file)
index 0000000..a454aaf
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKey;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.apex.model.basicmodel.concepts.AxKey.Compatibility;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class AxKeyTest {
+
+    @Test
+    public void testArtifactKey() {
+        AxArtifactKey aKey0 = new AxArtifactKey();
+        AxArtifactKey aKey1 = new AxArtifactKey("name", "0.0.1");
+        AxArtifactKey aKey2 = new AxArtifactKey(aKey1);
+        AxArtifactKey aKey3 = new AxArtifactKey(aKey1.getID());
+        AxArtifactKey aKey4 = new AxArtifactKey(aKey1);
+        AxArtifactKey aKey5 = new AxArtifactKey(aKey1);
+        AxArtifactKey aKey6 = new AxArtifactKey(aKey1);
+
+        try {
+            new AxArtifactKey("some bad key id");
+            fail("This test should throw an exception");
+        }
+        catch (IllegalArgumentException e) {
+            assertEquals("parameter \"id\": value \"some bad key id\", does not match regular expression \"[A-Za-z0-9\\-_\\.]+:[0-9].[0-9].[0-9]\"", e.getMessage());
+        }
+        
+        assertEquals(AxArtifactKey.getNullKey(), aKey0);
+        assertEquals(aKey1, aKey2);
+        assertEquals(aKey1, aKey3);
+        
+        assertEquals(aKey2, aKey1.getKey());
+        assertEquals(1, aKey1.getKeys().size());
+        
+        aKey0.setName("zero");
+        aKey0.setVersion("0.0.2");
+        aKey3.setVersion("0.0.2");
+        aKey4.setVersion("0.1.2");
+        aKey5.setVersion("1.2.2");
+        aKey6.setVersion("3");
+        
+        assertEquals(Compatibility.DIFFERENT, aKey0.getCompatibility(new AxReferenceKey()));
+        assertEquals(Compatibility.DIFFERENT, aKey0.getCompatibility(aKey1));
+        assertEquals(Compatibility.IDENTICAL, aKey2.getCompatibility(aKey1));
+        assertEquals(Compatibility.PATCH,     aKey3.getCompatibility(aKey1));
+        assertEquals(Compatibility.MINOR,     aKey4.getCompatibility(aKey1));
+        assertEquals(Compatibility.MAJOR,     aKey5.getCompatibility(aKey1));
+        assertEquals(Compatibility.MAJOR,     aKey6.getCompatibility(aKey1));
+        
+        assertTrue(aKey1.isCompatible(aKey2));
+        assertTrue(aKey1.isCompatible(aKey3));
+        assertTrue(aKey1.isCompatible(aKey4));
+        assertFalse(aKey1.isCompatible(aKey0));
+        assertFalse(aKey1.isCompatible(aKey5));
+        assertFalse(aKey1.isCompatible(new AxReferenceKey()));
+        
+        assertEquals(AxValidationResult.ValidationResult.VALID, aKey0.validate(new AxValidationResult()).getValidationResult());
+        assertEquals(AxValidationResult.ValidationResult.VALID, aKey1.validate(new AxValidationResult()).getValidationResult());
+        assertEquals(AxValidationResult.ValidationResult.VALID, aKey2.validate(new AxValidationResult()).getValidationResult());
+        assertEquals(AxValidationResult.ValidationResult.VALID, aKey3.validate(new AxValidationResult()).getValidationResult());
+        assertEquals(AxValidationResult.ValidationResult.VALID, aKey4.validate(new AxValidationResult()).getValidationResult());
+        assertEquals(AxValidationResult.ValidationResult.VALID, aKey5.validate(new AxValidationResult()).getValidationResult());
+        assertEquals(AxValidationResult.ValidationResult.VALID, aKey6.validate(new AxValidationResult()).getValidationResult());
+        
+        aKey0.clean();
+        assertNotNull(aKey0.toString());
+        
+        AxArtifactKey aKey7 = new AxArtifactKey(aKey1);
+        assertEquals(150332875, aKey7.hashCode());
+        assertEquals(0, aKey7.compareTo(aKey1));
+        assertEquals(-12, aKey7.compareTo(aKey0));
+        
+        try {
+            aKey0.compareTo(null);
+        }
+        catch (IllegalArgumentException e) {
+            assertEquals("comparison object may not be null", e.getMessage());
+        }
+        
+        assertEquals(0, aKey0.compareTo(aKey0));
+        assertEquals(353602977, aKey0.compareTo(new AxReferenceKey()));
+        
+        assertFalse(aKey0.equals(null));
+        assertTrue(aKey0.equals(aKey0));
+        assertFalse(((AxKey)aKey0).equals(new AxReferenceKey()));
+    }
+
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestAxKeyInfo.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestAxKeyInfo.java
new file mode 100644 (file)
index 0000000..6af662b
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.UUID;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestAxKeyInfo {
+
+    @Test
+    public void testAxKeyInfo() {
+        assertNotNull(new AxKeyInfo());
+        assertNotNull(new AxKeyInfo(new AxArtifactKey()));
+        assertNotNull(new AxKeyInfo(new AxArtifactKey(), UUID.randomUUID(), "Key description"));
+
+        AxKeyInfo testKeyInfo = new AxKeyInfo();
+        testKeyInfo.setKey((new AxArtifactKey("PN", "0.0.1")));
+        assertEquals("PN:0.0.1", testKeyInfo.getKey().getID());
+
+        AxArtifactKey key = new AxArtifactKey("key", "0.0.1");
+        testKeyInfo.setKey(key);
+        assertEquals(key, testKeyInfo.getKey());
+        
+        UUID uuid = UUID.randomUUID();
+        testKeyInfo.setUuid(uuid);
+        assertEquals(uuid, testKeyInfo.getUUID());
+        testKeyInfo.setDescription("Key Description");
+        assertEquals("Key Description", testKeyInfo.getDescription());
+        
+        AxKeyInfo clonedReferenceKey = new AxKeyInfo(testKeyInfo);
+        assertTrue(clonedReferenceKey.toString().startsWith("AxKeyInfo:(artifactId=AxArtifactKey:(name=key,version=0.0.1),uuid="));
+        
+        assertFalse(testKeyInfo.hashCode() == 0);
+        
+        assertTrue(testKeyInfo.equals(testKeyInfo));
+        assertTrue(testKeyInfo.equals(clonedReferenceKey));
+        assertFalse(testKeyInfo.equals(null));
+        assertFalse(testKeyInfo.equals(new AxArtifactKey()));
+        assertFalse(testKeyInfo.equals(new AxKeyInfo(new AxArtifactKey())));
+        assertFalse(testKeyInfo.equals(new AxKeyInfo(key, UUID.randomUUID(), "Some Description")));
+        assertFalse(testKeyInfo.equals(new AxKeyInfo(key, uuid, "Some Description")));
+        assertTrue(testKeyInfo.equals(new AxKeyInfo(key, uuid, "Key Description")));
+        
+        assertEquals(0, testKeyInfo.compareTo(testKeyInfo));
+        assertEquals(0, testKeyInfo.compareTo(clonedReferenceKey));
+        assertNotEquals(0, testKeyInfo.compareTo(null));
+        assertNotEquals(0, testKeyInfo.compareTo(new AxArtifactKey()));
+        assertNotEquals(0, testKeyInfo.compareTo(new AxKeyInfo(new AxArtifactKey())));
+        assertNotEquals(0, testKeyInfo.compareTo(new AxKeyInfo(key, UUID.randomUUID(), "Some Description")));
+        assertNotEquals(0, testKeyInfo.compareTo(new AxKeyInfo(key, uuid, "Some Description")));
+        assertEquals(0, testKeyInfo.compareTo(new AxKeyInfo(key, uuid, "Key Description")));
+        
+        assertNotNull(testKeyInfo.getKeys());
+        
+        AxValidationResult result = new AxValidationResult();
+        result = testKeyInfo.validate(result);
+        assertEquals(AxValidationResult.ValidationResult.VALID, result.getValidationResult());
+        
+        testKeyInfo.setDescription("");
+        result = testKeyInfo.validate(result);
+        assertEquals(AxValidationResult.ValidationResult.OBSERVATION, result.getValidationResult());
+        
+        testKeyInfo.setUuid(new UUID(0, 0));
+        result = testKeyInfo.validate(result);
+        assertEquals(AxValidationResult.ValidationResult.WARNING, result.getValidationResult());
+        
+        testKeyInfo.setKey(AxArtifactKey.getNullKey());
+        result = testKeyInfo.validate(result);
+        assertEquals(AxValidationResult.ValidationResult.INVALID, result.getValidationResult());
+        
+        assertNotNull(AxKeyInfo.generateReproducibleUUID(null));
+        assertNotNull(AxKeyInfo.generateReproducibleUUID("SeedString"));
+        
+        testKeyInfo.clean();
+        assertNotNull(testKeyInfo);
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestAxReferenceKey.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestAxReferenceKey.java
new file mode 100644 (file)
index 0000000..7ec3cbb
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKey;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestAxReferenceKey {
+
+    @Test
+    public void testAxReferenceKey() {
+        assertNotNull(new AxReferenceKey());
+        assertNotNull(new AxReferenceKey(new AxArtifactKey()));
+        assertNotNull(new AxReferenceKey(new AxArtifactKey(), "LocalName"));
+        assertNotNull(new AxReferenceKey(new AxReferenceKey()));
+        assertNotNull(new AxReferenceKey(new AxReferenceKey(), "LocalName"));
+        assertNotNull(new AxReferenceKey(new AxArtifactKey(), "ParentLocalName", "LocalName"));
+        assertNotNull(new AxReferenceKey("ParentKeyName", "0.0.1", "LocalName"));
+        assertNotNull(new AxReferenceKey("ParentKeyName", "0.0.1", "ParentLocalName", "LocalName"));
+        assertNotNull(new AxReferenceKey("ParentKeyName:0.0.1:ParentLocalName:LocalName"));
+        assertEquals(AxReferenceKey.getNullKey().getKey(), AxReferenceKey.getNullKey());
+        assertEquals("NULL:0.0.0:NULL:NULL", AxReferenceKey.getNullKey().getID());
+
+        AxReferenceKey testReferenceKey = new AxReferenceKey();
+        testReferenceKey.setParentArtifactKey(new AxArtifactKey("PN", "0.0.1"));
+        assertEquals("PN:0.0.1", testReferenceKey.getParentArtifactKey().getID());
+        
+        testReferenceKey.setParentReferenceKey(new AxReferenceKey("PN", "0.0.1", "LN"));
+        assertEquals("PN:0.0.1:NULL:LN", testReferenceKey.getParentReferenceKey().getID());
+        
+        testReferenceKey.setParentKeyName("NPKN");
+        assertEquals("NPKN", testReferenceKey.getParentKeyName());
+        
+        testReferenceKey.setParentKeyVersion("0.0.1");
+        assertEquals("0.0.1", testReferenceKey.getParentKeyVersion());
+        
+        testReferenceKey.setParentLocalName("NPKLN");
+        assertEquals("NPKLN", testReferenceKey.getParentLocalName());
+        
+        testReferenceKey.setLocalName("NLN");
+        assertEquals("NLN", testReferenceKey.getLocalName());
+        
+        assertFalse(testReferenceKey.isCompatible(AxArtifactKey.getNullKey()));
+        assertFalse(testReferenceKey.isCompatible(AxReferenceKey.getNullKey()));
+        assertTrue(testReferenceKey.isCompatible(testReferenceKey));
+        
+        assertEquals(AxKey.Compatibility.DIFFERENT, testReferenceKey.getCompatibility(AxArtifactKey.getNullKey()));
+        assertEquals(AxKey.Compatibility.DIFFERENT, testReferenceKey.getCompatibility(AxReferenceKey.getNullKey()));
+        assertEquals(AxKey.Compatibility.IDENTICAL, testReferenceKey.getCompatibility(testReferenceKey));
+        
+        AxValidationResult result = new AxValidationResult();
+        result = testReferenceKey.validate(result);
+        assertEquals(AxValidationResult.ValidationResult.VALID, result.getValidationResult());
+        
+        testReferenceKey.clean();
+        
+        AxReferenceKey clonedReferenceKey = new AxReferenceKey(testReferenceKey);
+        assertEquals("AxReferenceKey:(parentKeyName=NPKN,parentKeyVersion=0.0.1,parentLocalName=NPKLN,localName=NLN)", clonedReferenceKey.toString());
+        
+        assertFalse(testReferenceKey.hashCode() == 0);
+        
+        assertTrue(testReferenceKey.equals(testReferenceKey));
+        assertTrue(testReferenceKey.equals(clonedReferenceKey));
+        assertFalse(testReferenceKey.equals("Hello"));
+        assertFalse(testReferenceKey.equals(new AxReferenceKey("PKN", "0.0.2", "PLN", "LN")));
+        assertFalse(testReferenceKey.equals(new AxReferenceKey("NPKN", "0.0.2", "PLN", "LN")));
+        assertFalse(testReferenceKey.equals(new AxReferenceKey("NPKN", "0.0.1", "PLN", "LN")));
+        assertFalse(testReferenceKey.equals(new AxReferenceKey("NPKN", "0.0.1", "NPLN", "LN")));
+        assertTrue(testReferenceKey.equals(new AxReferenceKey("NPKN", "0.0.1", "NPKLN", "NLN")));
+        
+        assertEquals(0, testReferenceKey.compareTo(testReferenceKey));
+        assertEquals(0, testReferenceKey.compareTo(clonedReferenceKey));
+        assertNotEquals(0, testReferenceKey.compareTo(new AxArtifactKey()));
+        assertNotEquals(0, testReferenceKey.compareTo(new AxReferenceKey("PKN", "0.0.2", "PLN", "LN")));
+        assertNotEquals(0, testReferenceKey.compareTo(new AxReferenceKey("NPKN", "0.0.2", "PLN", "LN")));
+        assertNotEquals(0, testReferenceKey.compareTo(new AxReferenceKey("NPKN", "0.0.1", "PLN", "LN")));
+        assertNotEquals(0, testReferenceKey.compareTo(new AxReferenceKey("NPKN", "0.0.1", "NPLN", "LN")));
+        assertEquals(0, testReferenceKey.compareTo(new AxReferenceKey("NPKN", "0.0.1", "NPKLN", "NLN")));
+        
+        assertNotNull(testReferenceKey.getKeys());
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestEntity.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestEntity.java
new file mode 100644 (file)
index 0000000..3e821f7
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.onap.apex.model.basicmodel.concepts.AxConcept;
+import org.onap.apex.model.basicmodel.concepts.AxKey;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.apex.model.basicmodel.xml.AxReferenceKeyAdapter;
+
+@Entity
+@Table(name = "TestEntity")
+
+public class TestEntity extends AxConcept {
+    private static final long serialVersionUID = -2962570563281067894L;
+
+    @EmbeddedId()
+    @XmlElement(name = "key", required = true)
+    @XmlJavaTypeAdapter(AxReferenceKeyAdapter.class)
+    protected AxReferenceKey key;
+
+    private double doubleValue;
+   
+    public TestEntity() {
+        this.key = new AxReferenceKey();
+        this.doubleValue = 0;
+    }
+   
+    public TestEntity(Double doubleValue) {
+        this.key = new AxReferenceKey();
+        this.doubleValue = doubleValue;
+    }
+   
+    public TestEntity(AxReferenceKey key, Double doubleValue) {
+        this.key = key;
+        this.doubleValue = doubleValue;
+    }
+   
+    public AxReferenceKey getKey() {
+        return key;
+    }
+
+    public List<AxKey> getKeys() {
+        return Arrays.asList((AxKey) getKey());
+    }
+
+    public void setKey(AxReferenceKey key) {
+        this.key = key;
+    }
+
+    public boolean checkSetKey() {
+        return (this.key != null);
+    }
+
+    public double getDoubleValue() {
+        return doubleValue;
+    }
+
+    public void setDoubleValue(double doubleValue) {
+        this.doubleValue = doubleValue;
+    }
+
+    @Override
+    public AxValidationResult validate(AxValidationResult result) {
+        return key.validate(result);
+    }
+
+    @Override
+    public void clean() {
+        key.clean();
+    }
+   
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("doubleValue=");
+        builder.append(doubleValue);
+        return builder.toString();
+    }
+
+    @Override
+    public AxConcept copyTo(AxConcept target) {
+        final Object copyObject = ((target == null) ? new TestEntity(): target);
+        if (copyObject instanceof TestEntity) {
+            final TestEntity copy = ((TestEntity) copyObject);
+            if (this.checkSetKey()) {
+                copy.setKey(new AxReferenceKey(key));
+            }
+            else {
+                copy.key = null;
+            }
+            copy.doubleValue = doubleValue;
+            return copy;
+        }
+        else {
+                       return null;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((key == null) ? 0 : key.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null)
+            return false;
+        if (this == obj)
+            return true;
+        if (getClass() != obj.getClass())
+            return false;
+        TestEntity other = (TestEntity) obj;
+        if (key == null) {
+            if (other.key != null)
+                return false;
+        }
+        else
+            if (!key.equals(other.key))
+                return false;
+        if (doubleValue != other.doubleValue)
+                return false;
+        return true;
+    }
+   
+    @Override
+    public int compareTo(AxConcept otherObj) {
+        if (otherObj == null)
+            return -1;
+        if (this == otherObj)
+            return 0;
+        TestEntity other = (TestEntity) otherObj;
+        if (key == null) {
+            if (other.key != null)
+                return 1;
+        }
+        else
+            if (!key.equals(other.key))
+                return key.compareTo(other.key);
+        if (doubleValue != other.doubleValue)
+            return new Double(doubleValue).compareTo(other.doubleValue);
+       
+        return 0;
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestExceptions.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestExceptions.java
new file mode 100644 (file)
index 0000000..1d37cd8
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexConceptException;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.ApexRuntimeException;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestExceptions {
+
+    @Test
+    public void test() {
+        assertNotNull(new ApexException("Message"));
+        assertNotNull(new ApexException("Message", new AxArtifactKey()));
+        assertNotNull(new ApexException("Message", new IOException()));
+        assertNotNull(new ApexException("Message", new IOException(), new AxArtifactKey()));
+        
+        AxArtifactKey key = new AxArtifactKey();
+        ApexException ae = new ApexException("Message", new IOException("IO exception message"), key);
+        assertEquals("Message\ncaused by: Message\ncaused by: IO exception message", ae.getCascadedMessage());
+        assertEquals(key, ae.getObject());
+        
+        assertNotNull(new ApexRuntimeException("Message"));
+        assertNotNull(new ApexRuntimeException("Message", new AxArtifactKey()));
+        assertNotNull(new ApexRuntimeException("Message", new IOException()));
+        assertNotNull(new ApexRuntimeException("Message", new IOException(), new AxArtifactKey()));
+        
+        AxArtifactKey rKey = new AxArtifactKey();
+        ApexRuntimeException re = new ApexRuntimeException("Runtime Message", new IOException("IO runtime exception message"), rKey);
+        assertEquals("Runtime Message\ncaused by: Runtime Message\ncaused by: IO runtime exception message", re.getCascadedMessage());
+        assertEquals(key, re.getObject());
+        
+        assertNotNull(new ApexConceptException("Message"));
+        assertNotNull(new ApexConceptException("Message", new IOException()));
+        
+        AxArtifactKey cKey = new AxArtifactKey();
+        ApexException ace = new ApexException("Concept Message", new IOException("IO concept exception message"), cKey);
+        assertEquals("Concept Message\ncaused by: Concept Message\ncaused by: IO concept exception message", ace.getCascadedMessage());
+        assertEquals(cKey, ace.getObject());
+    }
+
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestValidation.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/TestValidation.java
new file mode 100644 (file)
index 0000000..e8eff52
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.apex.model.basicmodel.concepts.AxValidationMessage;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestValidation {
+
+    @Test
+    public void test() {
+        AxValidationResult result = new AxValidationResult();
+        AxReferenceKey refKey = new AxReferenceKey("PK", "0.0.1", "PLN", "LN");
+        result = refKey.validate(result);
+        
+        assertNotNull(result);
+        assertTrue(result.isOK());
+        assertTrue(result.isValid());
+        assertEquals(AxValidationResult.ValidationResult.VALID, result.getValidationResult());
+        assertNotNull(result.getMessageList());
+        
+        AxValidationMessage vMess0 = new AxValidationMessage(AxArtifactKey.getNullKey(), AxArtifactKey.class, ValidationResult.VALID, "Some message");
+        result.addValidationMessage(vMess0);
+        
+        assertTrue(result.isOK());
+        assertTrue(result.isValid());
+        assertEquals(AxValidationResult.ValidationResult.VALID, result.getValidationResult());
+        assertNotNull(result.getMessageList());
+        assertNotNull("hello", result.toString());
+        
+        AxValidationMessage vMess1 = new AxValidationMessage(AxArtifactKey.getNullKey(), AxArtifactKey.class, ValidationResult.OBSERVATION, "Some message");
+        result.addValidationMessage(vMess1);
+        
+        assertTrue(result.isOK());
+        assertTrue(result.isValid());
+        assertEquals(AxValidationResult.ValidationResult.OBSERVATION, result.getValidationResult());
+        assertNotNull(result.getMessageList());
+        assertNotNull("hello", result.toString());
+        
+        AxValidationMessage vMess2 = new AxValidationMessage(AxArtifactKey.getNullKey(), AxArtifactKey.class, ValidationResult.WARNING, "Some message");
+        result.addValidationMessage(vMess2);
+        
+        assertFalse(result.isOK());
+        assertTrue(result.isValid());
+        assertEquals(AxValidationResult.ValidationResult.WARNING, result.getValidationResult());
+        assertNotNull(result.getMessageList());
+        assertNotNull("hello", result.toString());
+        
+        AxValidationMessage vMess3 = new AxValidationMessage(AxArtifactKey.getNullKey(), AxArtifactKey.class, ValidationResult.INVALID, "Some message");
+        result.addValidationMessage(vMess3);
+        
+        assertFalse(result.isOK());
+        assertFalse(result.isValid());
+        assertEquals(AxValidationResult.ValidationResult.INVALID, result.getValidationResult());
+        assertNotNull(result.getMessageList());
+        assertNotNull("hello", result.toString());
+        
+        assertEquals(AxValidationResult.ValidationResult.INVALID, result.getMessageList().get(3).getValidationResult());
+        assertEquals("Some message", result.getMessageList().get(3).getMessage());
+        assertEquals(AxArtifactKey.class.getCanonicalName(), result.getMessageList().get(3).getObservedClass());
+        assertEquals(AxArtifactKey.getNullKey(), result.getMessageList().get(3).getObservedKey());
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/testKeyUse.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/concepts/testKeyUse.java
new file mode 100644 (file)
index 0000000..ca1e5c1
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.concepts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKeyUse;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.apex.model.basicmodel.concepts.AxKey.Compatibility;
+
+public class testKeyUse {
+
+    @Test
+    public void test() {
+        assertNotNull(new AxKeyUse());
+        assertNotNull(new AxKeyUse(new AxArtifactKey()));
+        assertNotNull(new AxKeyUse(new AxReferenceKey()));
+        
+        AxArtifactKey key = new AxArtifactKey("Key", "0.0.1");
+        AxKeyUse keyUse = new AxKeyUse();
+        keyUse.setKey(key);
+        assertEquals(key, keyUse.getKey());
+        assertEquals("Key:0.0.1", keyUse.getID());
+        assertEquals(key, keyUse.getKeys().get(0));
+        
+        assertEquals(Compatibility.IDENTICAL, keyUse.getCompatibility(key));
+        assertTrue(keyUse.isCompatible(key));
+        
+        keyUse.clean();
+        assertNotNull(keyUse);
+        
+        AxValidationResult result = new AxValidationResult();
+        result = keyUse.validate(result);
+        assertNotNull(result);
+        
+        assertNotEquals(0, keyUse.hashCode());
+        
+        AxKeyUse clonedKeyUse = new AxKeyUse(keyUse);
+        assertEquals("AxKeyUse:(usedKey=AxArtifactKey:(name=Key,version=0.0.1))", clonedKeyUse.toString());
+        
+        assertFalse(keyUse.hashCode() == 0);
+        
+        assertTrue(keyUse.equals(keyUse));
+        assertTrue(keyUse.equals(clonedKeyUse));
+        assertFalse(keyUse.equals("Hello"));
+        assertTrue(keyUse.equals(new AxKeyUse(key)));
+        
+        assertEquals(0, keyUse.compareTo(keyUse));
+        assertEquals(0, keyUse.compareTo(clonedKeyUse));
+        assertNotEquals(0, keyUse.compareTo(new AxArtifactKey()));
+        assertEquals(0, keyUse.compareTo(new AxKeyUse(key)));
+        
+        AxKeyUse keyUseNull = new AxKeyUse(AxArtifactKey.getNullKey());
+        AxValidationResult resultNull = new AxValidationResult();
+        assertEquals(false, keyUseNull.validate(resultNull).isValid());
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/dao/EntityTest.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/dao/EntityTest.java
new file mode 100644 (file)
index 0000000..8777984
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.apex.model.basicmodel.concepts.TestEntity;
+import org.onap.apex.model.basicmodel.dao.ApexDao;
+import org.onap.apex.model.basicmodel.dao.ApexDaoFactory;
+import org.onap.apex.model.basicmodel.dao.DAOParameters;
+
+/**
+ * JUnit test class
+ */
+public class EntityTest {
+    private Connection connection;
+    private ApexDao apexDao;
+
+    @Before
+    public void setup() throws Exception {
+        Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
+        connection = DriverManager.getConnection("jdbc:derby:memory:apex_test;create=true");
+    }
+
+    @After
+    public void teardown() throws Exception {
+        connection.close();
+        new File("derby.log").delete();
+    }
+
+    @Test
+    public void testEntityTestSanity() throws ApexException {
+        final DAOParameters daoParameters = new DAOParameters();
+
+        apexDao = new ApexDaoFactory().createApexDao(daoParameters);
+
+        try {
+            apexDao.init(null);
+            fail("Test should throw an exception here");
+        }
+        catch (final Exception e) {
+            assertEquals("Apex persistence unit parameter not set", e.getMessage());
+        }
+
+        try {
+            apexDao.init(daoParameters);
+            fail("Test should throw an exception here");
+        }
+        catch (final Exception e) {
+            assertEquals("Apex persistence unit parameter not set", e.getMessage());
+        }
+
+        daoParameters.setPluginClass("somewhere.over.the.rainbow");
+        daoParameters.setPersistenceUnit("Dorothy");
+        try {
+            apexDao.init(daoParameters);
+            fail("Test should throw an exception here");
+        }
+        catch (final Exception e) {
+            assertEquals("Creation of Apex persistence unit \"Dorothy\" failed", e.getMessage());
+        }
+        try {
+            apexDao.create(new AxArtifactKey());
+            fail("Test should throw an exception here");
+        }
+        catch (final Exception e) {
+            assertEquals("Apex DAO has not been initialized", e.getMessage());
+        }
+        apexDao.close();
+    }
+
+    @Test
+    public void testEntityTestAllOpsJPA() throws ApexException {
+        final DAOParameters daoParameters = new DAOParameters();
+        daoParameters.setPluginClass("org.onap.apex.model.basicmodel.dao.impl.DefaultApexDao");
+        daoParameters.setPersistenceUnit("DAOTest");
+
+        apexDao = new ApexDaoFactory().createApexDao(daoParameters);
+        apexDao.init(daoParameters);
+
+        testAllOps();
+        apexDao.close();
+    }
+
+    @Test
+    public void testEntityTestBadVals() throws ApexException {
+        final DAOParameters daoParameters = new DAOParameters();
+        daoParameters.setPluginClass("org.onap.apex.model.basicmodel.dao.impl.DefaultApexDao");
+        daoParameters.setPersistenceUnit("DAOTest");
+
+        apexDao = new ApexDaoFactory().createApexDao(daoParameters);
+        apexDao.init(daoParameters);
+
+        final AxArtifactKey nullKey = null;
+        final AxReferenceKey nullRefKey = null;
+        final List<AxArtifactKey> nullKeyList = null;
+        final List<AxArtifactKey> emptyKeyList = new ArrayList<>();
+        final List<AxReferenceKey> nullRKeyList = null;
+        final List<AxReferenceKey> emptyRKeyList = new ArrayList<>();
+
+        apexDao.create(nullKey);
+        apexDao.create(nullKeyList);
+        apexDao.create(emptyKeyList);
+
+        apexDao.delete(nullKey);
+        apexDao.delete(nullKeyList);
+        apexDao.delete(emptyKeyList);
+        apexDao.delete(AxArtifactKey.class, nullKey);
+        apexDao.delete(AxReferenceKey.class, nullRefKey);
+        apexDao.deleteByArtifactKey(AxArtifactKey.class, nullKeyList);
+        apexDao.deleteByArtifactKey(AxArtifactKey.class, emptyKeyList);
+        apexDao.deleteByReferenceKey(AxReferenceKey.class, nullRKeyList);
+        apexDao.deleteByReferenceKey(AxReferenceKey.class, emptyRKeyList);
+
+        apexDao.get(null, nullKey);
+        apexDao.get(null, nullRefKey);
+        apexDao.getAll(null);
+        apexDao.getAll(null, nullKey);
+        apexDao.getArtifact(null, nullKey);
+        apexDao.getArtifact(AxArtifactKey.class, nullKey);
+        apexDao.getArtifact(null, nullRefKey);
+        apexDao.getArtifact(AxReferenceKey.class, nullRefKey);
+        apexDao.size(null);
+
+        apexDao.close();
+    }
+
+    private void testAllOps(){
+        final AxArtifactKey  aKey0    = new AxArtifactKey("A-KEY0", "0.0.1");
+        final AxArtifactKey  aKey1    = new AxArtifactKey("A-KEY1", "0.0.1");
+        final AxArtifactKey  aKey2    = new AxArtifactKey("A-KEY2", "0.0.1");
+        final AxKeyInfo      keyInfo0 = new AxKeyInfo(aKey0, UUID.fromString("00000000-0000-0000-0000-000000000000"), "key description 0");
+        final AxKeyInfo      keyInfo1 = new AxKeyInfo(aKey1, UUID.fromString("00000000-0000-0000-0000-000000000001"), "key description 1");
+        final AxKeyInfo      keyInfo2 = new AxKeyInfo(aKey2, UUID.fromString("00000000-0000-0000-0000-000000000002"), "key description 2");
+
+        apexDao.create(keyInfo0);
+
+        final AxKeyInfo keyInfoBack0 = apexDao.get(AxKeyInfo.class, aKey0);
+        assertTrue(keyInfo0.equals(keyInfoBack0));
+
+        final AxKeyInfo keyInfoBackNull = apexDao.get(AxKeyInfo.class, AxArtifactKey.getNullKey());
+        assertNull(keyInfoBackNull);
+
+        final AxKeyInfo keyInfoBack1 = apexDao.getArtifact(AxKeyInfo.class, aKey0);
+        assertTrue(keyInfoBack0.equals(keyInfoBack1));
+
+        final AxKeyInfo keyInfoBack2 = apexDao.getArtifact(AxKeyInfo.class,  new AxArtifactKey("A-KEY3", "0.0.1"));
+        assertNull(keyInfoBack2);
+
+        final Set<AxKeyInfo> keyInfoSetIn = new TreeSet<AxKeyInfo>();
+        keyInfoSetIn.add(keyInfo1);
+        keyInfoSetIn.add(keyInfo2);
+
+        apexDao.create(keyInfoSetIn);
+
+        Set<AxKeyInfo> keyInfoSetOut = new TreeSet<AxKeyInfo>(apexDao.getAll(AxKeyInfo.class));
+
+        keyInfoSetIn.add(keyInfo0);
+        assertTrue(keyInfoSetIn.equals(keyInfoSetOut));
+
+        apexDao.delete(keyInfo1);
+        keyInfoSetIn.remove(keyInfo1);
+        keyInfoSetOut = new TreeSet<AxKeyInfo>(apexDao.getAll(AxKeyInfo.class));
+        assertTrue(keyInfoSetIn.equals(keyInfoSetOut));
+
+        apexDao.delete(keyInfoSetIn);
+        keyInfoSetOut = new TreeSet<AxKeyInfo>(apexDao.getAll(AxKeyInfo.class));
+        assertEquals(0, keyInfoSetOut.size());
+
+        keyInfoSetIn.add(keyInfo0);
+        keyInfoSetIn.add(keyInfo1);
+        keyInfoSetIn.add(keyInfo0);
+        apexDao.create(keyInfoSetIn);
+        keyInfoSetOut = new TreeSet<AxKeyInfo>(apexDao.getAll(AxKeyInfo.class));
+        assertTrue(keyInfoSetIn.equals(keyInfoSetOut));
+
+        apexDao.delete(AxKeyInfo.class, aKey0);
+        keyInfoSetOut = new TreeSet<AxKeyInfo>(apexDao.getAll(AxKeyInfo.class));
+        assertEquals(2, keyInfoSetOut.size());
+        assertEquals(2, apexDao.size(AxKeyInfo.class));
+
+        final Set<AxArtifactKey> keySetIn = new TreeSet<AxArtifactKey>();
+        keySetIn.add(aKey1);
+        keySetIn.add(aKey2);
+
+        final int deletedCount = apexDao.deleteByArtifactKey(AxKeyInfo.class, keySetIn);
+        assertEquals(2, deletedCount);
+
+        keyInfoSetOut = new TreeSet<AxKeyInfo>(apexDao.getAll(AxKeyInfo.class));
+        assertEquals(0, keyInfoSetOut.size());
+
+        keyInfoSetIn.add(keyInfo0);
+        keyInfoSetIn.add(keyInfo1);
+        keyInfoSetIn.add(keyInfo0);
+        apexDao.create(keyInfoSetIn);
+        keyInfoSetOut = new TreeSet<AxKeyInfo>(apexDao.getAll(AxKeyInfo.class));
+        assertTrue(keyInfoSetIn.equals(keyInfoSetOut));
+
+        apexDao.deleteAll(AxKeyInfo.class);
+        assertEquals(0, apexDao.size(AxKeyInfo.class));
+
+        final AxArtifactKey owner0Key = new AxArtifactKey("Owner0", "0.0.1");
+        final AxArtifactKey owner1Key = new AxArtifactKey("Owner1", "0.0.1");
+        final AxArtifactKey owner2Key = new AxArtifactKey("Owner2", "0.0.1");
+        final AxArtifactKey owner3Key = new AxArtifactKey("Owner3", "0.0.1");
+        final AxArtifactKey owner4Key = new AxArtifactKey("Owner4", "0.0.1");
+        final AxArtifactKey owner5Key = new AxArtifactKey("Owner5", "0.0.1");
+
+        apexDao.create(new TestEntity(new AxReferenceKey(owner0Key, "Entity0"), 100.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner0Key, "Entity1"), 101.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner0Key, "Entity2"), 102.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner0Key, "Entity3"), 103.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner0Key, "Entity4"), 104.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner1Key, "Entity5"), 105.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner1Key, "Entity6"), 106.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner1Key, "Entity7"), 107.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner2Key, "Entity8"), 108.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner2Key, "Entity9"), 109.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner3Key, "EntityA"), 110.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner4Key, "EntityB"), 111.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner5Key, "EntityC"), 112.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner5Key, "EntityD"), 113.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner5Key, "EntityE"), 114.0));
+        apexDao.create(new TestEntity(new AxReferenceKey(owner5Key, "EntityF"), 115.0));
+
+        TreeSet<TestEntity> testEntitySetOut = new TreeSet<TestEntity>(apexDao.getAll(TestEntity.class));
+        assertEquals(16, testEntitySetOut.size());
+
+        testEntitySetOut = new TreeSet<TestEntity>(apexDao.getAll(TestEntity.class, owner0Key));
+        assertEquals(5, testEntitySetOut.size());
+
+        testEntitySetOut = new TreeSet<TestEntity>(apexDao.getAll(TestEntity.class, owner1Key));
+        assertEquals(3, testEntitySetOut.size());
+
+        testEntitySetOut = new TreeSet<TestEntity>(apexDao.getAll(TestEntity.class, owner2Key));
+        assertEquals(2, testEntitySetOut.size());
+
+        testEntitySetOut = new TreeSet<TestEntity>(apexDao.getAll(TestEntity.class, owner3Key));
+        assertEquals(1, testEntitySetOut.size());
+
+        testEntitySetOut = new TreeSet<TestEntity>(apexDao.getAll(TestEntity.class, owner4Key));
+        assertEquals(1, testEntitySetOut.size());
+
+        testEntitySetOut = new TreeSet<TestEntity>(apexDao.getAll(TestEntity.class, owner5Key));
+        assertEquals(4, testEntitySetOut.size());
+
+        assertNotNull(apexDao.get(TestEntity.class, new AxReferenceKey(owner0Key, "Entity0")));
+        assertNotNull(apexDao.getArtifact(TestEntity.class, new AxReferenceKey(owner0Key, "Entity0")));
+        assertNull(apexDao.get(TestEntity.class, new AxReferenceKey(owner0Key, "Entity1000")));
+        assertNull(apexDao.getArtifact(TestEntity.class, new AxReferenceKey(owner0Key, "Entity1000")));
+        apexDao.delete(TestEntity.class, new AxReferenceKey(owner0Key, "Entity0"));
+
+        final Set<AxReferenceKey> rKeySetIn = new TreeSet<AxReferenceKey>();
+        rKeySetIn.add(new AxReferenceKey(owner4Key, "EntityB"));
+        rKeySetIn.add(new AxReferenceKey(owner5Key, "EntityD"));
+
+        final int deletedRCount = apexDao.deleteByReferenceKey(TestEntity.class, rKeySetIn);
+        assertEquals(2, deletedRCount);
+
+        apexDao.update(new TestEntity(new AxReferenceKey(owner5Key, "EntityF"), 120.0));
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/dao/TestDaoMisc.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/dao/TestDaoMisc.java
new file mode 100644 (file)
index 0000000..9109bc2
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.util.Properties;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.dao.ApexDaoFactory;
+import org.onap.apex.model.basicmodel.dao.DAOParameters;
+import org.onap.apex.model.basicmodel.dao.converters.CDATAConditioner;
+import org.onap.apex.model.basicmodel.dao.converters.UUID2String;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestDaoMisc {
+
+    @Test
+    public void testUUID2StringMopUp() {
+        UUID2String uuid2String = new UUID2String();
+        assertEquals("", uuid2String.convertToDatabaseColumn(null));
+    }
+
+    @Test
+    public void testCDataConditionerMopUp() {
+        assertNull(CDATAConditioner.clean(null));
+    }
+    
+    @Test
+    public void testDaoFactory() {
+        DAOParameters daoParameters = new DAOParameters();
+
+        daoParameters.setPluginClass("somewhere.over.the.rainbow");
+        try {
+            new ApexDaoFactory().createApexDao(daoParameters);
+            fail("test shold throw an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("Apex DAO class not found for DAO plugin \"somewhere.over.the.rainbow\"", e.getMessage());
+        }
+        
+        daoParameters.setPluginClass("java.lang.String");
+        try {
+            new ApexDaoFactory().createApexDao(daoParameters);
+            fail("test shold throw an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("Specified Apex DAO plugin class \"java.lang.String\" does not implement the ApexDao interface", e.getMessage());
+        }
+    }
+    
+    @Test
+    public void testDaoParameters() {
+        DAOParameters pars = new DAOParameters();
+        pars.setJdbcProperties(new Properties());
+        assertEquals(0, pars.getJdbcProperties().size());
+        
+        pars.setJdbcProperty("name", "Dorothy");
+        assertEquals("Dorothy", pars.getJdbcProperty("name"));
+        
+        pars.setPersistenceUnit("Kansas");
+        assertEquals("Kansas", pars.getPersistenceUnit());
+        
+        pars.setPluginClass("somewhere.over.the.rainbow");
+        assertEquals("somewhere.over.the.rainbow", pars.getPluginClass());
+        
+        assertEquals("DAOParameters [pluginClass=somewhere.over.the.rainbow, persistenceUnit=Kansas, jdbcProperties={name=Dorothy}]", pars.toString());
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/AxModelWithReferences.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/AxModelWithReferences.java
new file mode 100644 (file)
index 0000000..e08b448
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKey;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+
+public class AxModelWithReferences extends AxModel {
+    private static final long serialVersionUID = -8194956638511120008L;
+
+    private List<AxKey> extraKeyList = new ArrayList<>();
+    
+    public AxModelWithReferences(final AxArtifactKey key) {
+        super(key);
+    }
+    
+    @Override
+    public List<AxKey> getKeys() {
+        List<AxKey> keys = super.getKeys();
+        keys.addAll(extraKeyList);
+
+        return keys;
+    }
+
+    public List<AxKey> getExtraKeyList() {
+        return extraKeyList;
+    }
+
+    public void setReferenceKeyList() {
+        List<AxKey> keys = super.getKeys();
+        
+        for (AxKey key: keys) {
+            AxArtifactKey aKey = (AxArtifactKey)key;
+            AxReferenceKey keyRef = new AxReferenceKey(aKey, aKey.getName());
+            extraKeyList.add(keyRef);
+        }
+    }
+    
+    public void addKey(final AxKey aKey) {
+        extraKeyList.add(aKey);
+    }
+    
+    public void removeKey(final AxKey aKey) {
+        extraKeyList.remove(aKey);
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexBasicModel.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexBasicModel.java
new file mode 100644 (file)
index 0000000..e4d91b7
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.apex.model.basicmodel.dao.DAOParameters;
+import org.onap.apex.model.basicmodel.test.TestApexModel;
+
+public class TestApexBasicModel {
+    private Connection connection;
+    TestApexModel<AxModel> testApexModel;
+
+    @Before
+    public void setup() throws Exception {
+        Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
+        connection = DriverManager.getConnection("jdbc:derby:memory:apex_test;create=true");
+
+        testApexModel = new TestApexModel<AxModel>(AxModel.class, new TestApexBasicModelCreator());
+    }
+
+    @After
+    public void teardown() throws Exception {
+        connection.close();
+        new File("derby.log").delete();
+    }
+
+    @Test
+    public void testModelValid() throws Exception {
+        AxValidationResult result = testApexModel.testApexModelValid();
+        assertTrue(result.toString().equals(VALID_MODEL_STRING));
+    }
+
+    @Test
+    public void testApexModelVaidateObservation() throws Exception {
+        try {
+            testApexModel.testApexModelVaidateObservation();
+        }
+        catch (ApexException e) {
+            assertEquals("model should have observations", e.getMessage());
+        }
+    }
+
+    @Test
+    public void testApexModelVaidateWarning() throws Exception {
+        AxValidationResult result = testApexModel.testApexModelVaidateWarning();
+        assertTrue(result.toString().equals(WARNING_MODEL_STRING));
+    }
+
+    @Test
+    public void testModelVaidateInvalidModel() throws Exception {
+        AxValidationResult result = testApexModel.testApexModelVaidateInvalidModel();
+        assertTrue(result.toString().equals(INVALID_MODEL_STRING));
+    }
+
+    @Test
+    public void testModelVaidateMalstructured() throws Exception {
+        AxValidationResult result = testApexModel.testApexModelVaidateMalstructured();
+        assertTrue(result.toString().equals(INVALID_MODEL_MALSTRUCTURED_STRING));
+    }
+
+    @Test
+    public void testModelWriteReadXML() throws Exception {
+        testApexModel.testApexModelWriteReadXML();
+    }
+
+    @Test
+    public void testModelWriteReadJSON() throws Exception {
+        testApexModel.testApexModelWriteReadJSON();
+    }
+
+    @Test
+    public void testModelWriteReadJPA() throws Exception {
+        DAOParameters daoParameters = new DAOParameters();
+        daoParameters.setPluginClass("org.onap.apex.model.basicmodel.dao.impl.DefaultApexDao");
+        daoParameters.setPersistenceUnit("DAOTest");
+
+        testApexModel.testApexModelWriteReadJPA(daoParameters);
+    }
+
+    // As there are no real concepts in a basic model, this is as near to a valid model as we can get
+    private static final String VALID_MODEL_STRING = "\n" +
+            "***warnings issued during validation of model***\n" +
+            "AxArtifactKey:(name=FloatKIKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxModel:WARNING:key not found for key information entry\n" +
+            "AxArtifactKey:(name=IntegerKIKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxModel:WARNING:key not found for key information entry\n" +
+            "********************************";
+
+    private static final String WARNING_MODEL_STRING = "\n" +
+            "***warnings issued during validation of model***\n" +
+            "AxArtifactKey:(name=FloatKIKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxModel:WARNING:key not found for key information entry\n" +
+            "AxArtifactKey:(name=IntegerKIKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxModel:WARNING:key not found for key information entry\n" +
+            "AxArtifactKey:(name=Unref0,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxModel:WARNING:key not found for key information entry\n" +
+            "AxArtifactKey:(name=Unref1,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxModel:WARNING:key not found for key information entry\n" +
+            "********************************";
+
+    private static final String INVALID_MODEL_STRING = "\n" +
+            "***validation of model failed***\n" +
+            "AxArtifactKey:(name=BasicModelKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxKeyInfo:WARNING:UUID is a zero UUID: 00000000-0000-0000-0000-000000000000\n" +
+            "AxArtifactKey:(name=KeyInfoMapKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxKeyInfo:OBSERVATION:description is blank\n" +
+            "AxArtifactKey:(name=KeyInfoMapKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxKeyInfo:WARNING:UUID is a zero UUID: 00000000-0000-0000-0000-000000000000\n" +
+            "AxArtifactKey:(name=KeyInfoMapKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxKeyInformation:INVALID:duplicate UUID found on keyInfoMap entry AxArtifactKey:(name=KeyInfoMapKey,version=0.0.1):00000000-0000-0000-0000-000000000000\n" +
+            "********************************";
+
+    private static final String INVALID_MODEL_MALSTRUCTURED_STRING = "\n" +
+            "***validation of model failed***\n" +
+            "AxArtifactKey:(name=BasicModelKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxKeyInfo:WARNING:UUID is a zero UUID: 00000000-0000-0000-0000-000000000000\n" +
+            "AxArtifactKey:(name=BasicModelKey,version=0.0.1):org.onap.apex.model.basicmodel.concepts.AxModel:INVALID:key information not found for key AxArtifactKey:(name=KeyInfoMapKey,version=0.0.1)\n" +
+            "********************************";
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexBasicModelConcepts.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexBasicModelConcepts.java
new file mode 100644 (file)
index 0000000..9d29c08
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKey;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInformation;
+import org.onap.apex.model.basicmodel.concepts.AxKeyUse;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult;
+import org.onap.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.apex.model.basicmodel.service.ModelService;
+import org.onap.apex.model.basicmodel.test.TestApexModel;
+
+public class TestApexBasicModelConcepts {
+    TestApexModel<AxModel> testApexModel;
+
+    @Before
+    public void setup() throws Exception {
+        testApexModel = new TestApexModel<AxModel>(AxModel.class, new TestApexBasicModelCreator());
+    }
+
+    @Test
+    public void testModelConcepts() {
+        AxModel model = testApexModel.getModel();
+        assertNotNull(model);
+        model.clean();
+        assertNotNull(model);
+
+        AxValidationResult result = new AxValidationResult();
+        result = model.validate(result);
+        assertEquals(ValidationResult.WARNING, result.getValidationResult());
+
+        model.register();
+        assertEquals(model.getKeyInformation(), ModelService.getModel(AxKeyInformation.class));
+
+        AxModel clonedModel = new AxModel(model);
+        assertTrue(clonedModel.toString().startsWith("AxModel:(key=AxArtifactKey:(name=BasicModel"));
+
+        assertFalse(model.hashCode() == 0);
+
+        assertTrue(model.equals(model));
+        assertTrue(model.equals(clonedModel));
+        assertFalse(model.equals(null));
+        assertFalse(model.equals("Hello"));
+        clonedModel.getKey().setVersion("0.0.2");
+        assertFalse(model.equals(clonedModel));
+        clonedModel.getKey().setVersion("0.0.1");
+
+        assertEquals(0, model.compareTo(model));
+        assertNotEquals(0, model.compareTo(null));
+        assertNotEquals(0, model.compareTo(new AxReferenceKey()));
+        assertEquals(0, model.compareTo(clonedModel));
+        clonedModel.getKey().setVersion("0.0.2");
+        assertNotEquals(0, model.compareTo(clonedModel));
+        clonedModel.getKey().setVersion("0.0.1");
+
+        assertNotNull(model.getKeys());
+
+        model.getKeyInformation().generateKeyInfo(model);
+        assertNotNull(model.getKeyInformation());
+
+        AxKeyInformation keyI = model.getKeyInformation();
+        AxKeyInformation clonedKeyI = new AxKeyInformation(keyI);
+
+        assertFalse(keyI.equals(null));
+        assertFalse(keyI.equals(new AxArtifactKey()));
+        assertTrue(keyI.equals(clonedKeyI));
+
+        clonedKeyI.setKey(new AxArtifactKey());
+        assertFalse(keyI.equals(clonedKeyI));
+        clonedKeyI.setKey(keyI.getKey());
+
+        assertEquals(0, keyI.compareTo(keyI));
+        assertEquals(0, keyI.compareTo(clonedKeyI));
+        assertNotEquals(0, keyI.compareTo(null));
+        assertNotEquals(0, keyI.compareTo(new AxArtifactKey()));
+
+        clonedKeyI.setKey(new AxArtifactKey());
+        assertNotEquals(0, keyI.compareTo(clonedKeyI));
+        clonedKeyI.setKey(keyI.getKey());
+        assertEquals(0, keyI.compareTo(clonedKeyI));
+
+        clonedKeyI.getKeyInfoMap().clear();
+        assertNotEquals(0, keyI.compareTo(clonedKeyI));
+
+        AxKeyInfo keyInfo = keyI.get("BasicModel");
+        assertNotNull(keyInfo);
+
+        keyInfo = keyI.get(new AxArtifactKey("BasicModel", "0.0.1"));
+        assertNotNull(keyInfo);
+
+        Set<AxKeyInfo> keyInfoSet = keyI.getAll("BasicModel");
+        assertNotNull(keyInfoSet);
+
+        keyInfoSet = keyI.getAll("BasicModel", "0..0.1");
+        assertNotNull(keyInfoSet);
+
+        List<AxKey> keys = model.getKeys();
+        assertNotEquals(0, keys.size());
+
+        keys = keyI.getKeys();
+        assertNotEquals(0, keys.size());
+
+        model.getKeyInformation().generateKeyInfo(model);
+        assertNotNull(model.getKeyInformation());
+        model.getKeyInformation().getKeyInfoMap().clear();
+        model.getKeyInformation().generateKeyInfo(model);
+        assertNotNull(model.getKeyInformation());
+
+        clonedKeyI.setKey(AxArtifactKey.getNullKey());
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        clonedKeyI.setKey(keyI.getKey());
+
+        clonedKeyI.getKeyInfoMap().clear();
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        clonedKeyI.generateKeyInfo(model);
+
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+
+        clonedKeyI.getKeyInfoMap().put(AxArtifactKey.getNullKey(), null);
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        clonedKeyI.getKeyInfoMap().clear();
+        clonedKeyI.generateKeyInfo(model);
+
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+
+        clonedKeyI.getKeyInfoMap().put(new AxArtifactKey("SomeKey", "0.0.1"), null);
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        clonedKeyI.getKeyInfoMap().clear();
+        clonedKeyI.generateKeyInfo(model);
+
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+
+        AxKeyInfo mk = clonedKeyI.get(new AxArtifactKey("BasicModel", "0.0.1"));
+        assertNotNull(mk);
+        mk.setKey(AxArtifactKey.getNullKey());
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        clonedKeyI.getKeyInfoMap().clear();
+        clonedKeyI.generateKeyInfo(model);
+
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+        
+        clonedModel.setKey(AxArtifactKey.getNullKey());
+        result = new AxValidationResult();
+        result = clonedModel.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+
+        clonedModel.setKey(model.getKey());
+        result = new AxValidationResult();
+        result = clonedKeyI.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+    }
+    
+    @Test
+    public void testModelConceptsWithReferences() {
+        AxModelWithReferences mwr = new TestApexBasicModelCreator().getModelWithReferences();
+        assertNotNull(mwr);
+        mwr.getKeyInformation().getKeyInfoMap().clear();
+        mwr.getKeyInformation().generateKeyInfo(mwr);
+        
+        AxValidationResult result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+
+        // Duplicate key error
+        mwr.addKey(mwr.getKey());
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        mwr.removeKey(mwr.getKey());
+
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+
+        // Null Reference Key
+        mwr.addKey(AxReferenceKey.getNullKey());
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        mwr.removeKey(AxReferenceKey.getNullKey());
+
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+
+        // Duplicate Reference Key
+        AxReferenceKey rKey = new AxReferenceKey(mwr.getKey(), "LocalName");
+        mwr.addKey(rKey);
+        mwr.addKey(rKey);
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        mwr.removeKey(rKey);
+        mwr.removeKey(rKey);
+
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+        
+        // Key Use is legal
+        AxKeyUse keyU = new AxKeyUse(mwr.getKey());
+        mwr.addKey(keyU);
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+        mwr.removeKey(keyU);
+
+        // Key Use on bad artifact key
+        AxKeyUse keyBU = new AxKeyUse(new AxArtifactKey("SomeKey", "0.0.1"));
+        mwr.addKey(keyBU);
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        mwr.removeKey(keyBU);
+
+        // Key Use on bad reference key
+        AxKeyUse keyBRU = new AxKeyUse(new AxReferenceKey("SomeKey", "0.0.1", "Local"));
+        mwr.addKey(keyBRU);
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.INVALID, result.getValidationResult());
+        mwr.removeKey(keyBRU);
+
+        result = new AxValidationResult();
+        result = mwr.validate(result);
+        assertEquals(ValidationResult.VALID, result.getValidationResult());
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexBasicModelCreator.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexBasicModelCreator.java
new file mode 100644 (file)
index 0000000..fca6c44
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.util.UUID;
+
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInformation;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.test.TestApexModelCreator;
+
+public class TestApexBasicModelCreator implements TestApexModelCreator<AxModel> {
+
+    @Override
+    public AxModel getModel() {
+        AxModel basicModel = new AxModel();
+
+        basicModel.setKey(new AxArtifactKey("BasicModel", "0.0.1"));
+        basicModel.setKeyInformation(new AxKeyInformation(new AxArtifactKey("KeyInfoMapKey", "0.0.1")));
+
+        basicModel.getKeyInformation().getKeyInfoMap().put(basicModel.getKey(), new AxKeyInfo(basicModel.getKey()));
+        basicModel.getKeyInformation().getKeyInfoMap().put(basicModel.getKeyInformation().getKey(), new AxKeyInfo(basicModel.getKeyInformation().getKey()));
+
+        AxKeyInfo intKI = new AxKeyInfo(new AxArtifactKey("IntegerKIKey", "0.0.1"), UUID.randomUUID(), "IntegerKIKey description");
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI.getKey(), new AxKeyInfo(intKI.getKey()));
+
+        AxKeyInfo floatKI = new AxKeyInfo(new AxArtifactKey("FloatKIKey", "0.0.1"), UUID.randomUUID(), "FloatKIKey description");
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI.getKey(), new AxKeyInfo(floatKI.getKey()));
+
+        return basicModel;
+    }
+
+    @Override
+    public final AxModel getMalstructuredModel() {
+        AxModel basicModel = new AxModel();
+
+        // Note: No Data types
+        basicModel.setKey(new AxArtifactKey("BasicModelKey", "0.0.1"));
+        basicModel.setKeyInformation(new AxKeyInformation(new AxArtifactKey("KeyInfoMapKey", "0.0.1")));
+
+        basicModel.getKeyInformation().getKeyInfoMap().put(
+                basicModel.getKey(),
+                new AxKeyInfo(
+                        basicModel.getKey(),
+                        UUID.fromString("00000000-0000-0000-0000-000000000000"),
+                        "\nbasic model description\nThis is a multi line description\nwith another line of text."));
+
+        return basicModel;
+    }
+
+    @Override
+    public final AxModel getObservationModel() {
+        AxModel basicModel = getModel();
+
+        // Set key information as blank
+        basicModel.getKeyInformation().getKeyInfoMap().get(basicModel.getKey()).setDescription("");
+
+        return basicModel;
+    }
+
+    @Override
+    public final AxModel getWarningModel() {
+        AxModel basicModel = getModel();
+
+        // Add unreferenced key information
+        AxKeyInfo unreferencedKeyInfo0 = new AxKeyInfo(new AxArtifactKey("Unref0", "0.0.1"));
+        AxKeyInfo unreferencedKeyInfo1 = new AxKeyInfo(new AxArtifactKey("Unref1", "0.0.1"));
+
+        basicModel.getKeyInformation().getKeyInfoMap().put(unreferencedKeyInfo0.getKey(), unreferencedKeyInfo0);
+        basicModel.getKeyInformation().getKeyInfoMap().put(unreferencedKeyInfo1.getKey(), unreferencedKeyInfo1);
+
+        return basicModel;
+    }
+
+    @Override
+    public final AxModel getInvalidModel() {
+        AxModel basicModel = new AxModel();
+
+        basicModel.setKey(new AxArtifactKey("BasicModelKey", "0.0.1"));
+        basicModel.setKeyInformation(new AxKeyInformation(new AxArtifactKey("KeyInfoMapKey", "0.0.1")));
+
+        basicModel.getKeyInformation().getKeyInfoMap().put(
+                basicModel.getKey(),
+                new AxKeyInfo(
+                        basicModel.getKey(),
+                        UUID.fromString("00000000-0000-0000-0000-000000000000"),
+                        "nbasic model description\nThis is a multi line description\nwith another line of text."));
+        basicModel.getKeyInformation().getKeyInfoMap().put(
+                basicModel.getKeyInformation().getKey(),
+                new AxKeyInfo(
+                        basicModel.getKeyInformation().getKey(),
+                        UUID.fromString("00000000-0000-0000-0000-000000000000"),
+                        ""));
+
+        return basicModel;
+    }
+    
+    public final AxModelWithReferences getModelWithReferences() {
+        AxModel model = getModel();
+        
+        AxModelWithReferences modelWithReferences = new AxModelWithReferences(model.getKey());
+        modelWithReferences.setKeyInformation(model.getKeyInformation());
+        modelWithReferences.setReferenceKeyList();
+        
+        return modelWithReferences;
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexTestModelCreator0.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexTestModelCreator0.java
new file mode 100644 (file)
index 0000000..4b3c002
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInformation;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.test.TestApexModelCreator;
+
+public class TestApexTestModelCreator0 implements TestApexModelCreator<AxModel> {
+
+    @Override
+    public AxModel getModel() {
+        AxModel basicModel = new AxModel();
+
+        basicModel.setKey(new AxArtifactKey("BasicModel", "0.0.1"));
+        basicModel.setKeyInformation(new AxKeyInformation(new AxArtifactKey("KeyInfoMapKey", "0.0.1")));
+
+        basicModel.getKeyInformation().getKeyInfoMap().put(basicModel.getKey(), new AxKeyInfo(basicModel.getKey()));
+        basicModel.getKeyInformation().getKeyInfoMap().put(basicModel.getKeyInformation().getKey(), new AxKeyInfo(basicModel.getKeyInformation().getKey()));
+
+        return basicModel;
+    }
+
+    @Override
+    public final AxModel getMalstructuredModel() {
+        return getModel();
+    }
+
+    @Override
+    public final AxModel getObservationModel() {
+        return getModel();
+    }
+
+    @Override
+    public final AxModel getWarningModel() {
+        return getModel();
+    }
+
+    @Override
+    public final AxModel getInvalidModel() {
+        return getModel();
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexTestModelCreator1.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexTestModelCreator1.java
new file mode 100644 (file)
index 0000000..e208bd8
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.util.UUID;
+
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInformation;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.test.TestApexModelCreator;
+
+public class TestApexTestModelCreator1 implements TestApexModelCreator<AxModel> {
+
+    @Override
+    public AxModel getModel() {
+        return getInvalidModel();
+    }
+
+    @Override
+    public final AxModel getMalstructuredModel() {
+        return getInvalidModel();
+    }
+
+    @Override
+    public final AxModel getObservationModel() {
+        return getInvalidModel();
+    }
+
+    @Override
+    public final AxModel getWarningModel() {
+        return getInvalidModel();
+    }
+
+    @Override
+    public final AxModel getInvalidModel() {
+        AxModel basicModel = new AxModel();
+
+        basicModel.setKey(new AxArtifactKey("BasicModelKey", "0.0.1"));
+        basicModel.setKeyInformation(new AxKeyInformation(new AxArtifactKey("KeyInfoMapKey", "0.0.1")));
+
+        basicModel.getKeyInformation().getKeyInfoMap().put(
+                basicModel.getKey(),
+                new AxKeyInfo(
+                        basicModel.getKey(),
+                        UUID.fromString("00000000-0000-0000-0000-000000000000"),
+                        "nbasic model description\nThis is a multi line description\nwith another line of text."));
+        basicModel.getKeyInformation().getKeyInfoMap().put(
+                basicModel.getKeyInformation().getKey(),
+                new AxKeyInfo(
+                        basicModel.getKeyInformation().getKey(),
+                        UUID.fromString("00000000-0000-0000-0000-000000000000"),
+                        ""));
+
+        return basicModel;
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexTestModelCreator2.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestApexTestModelCreator2.java
new file mode 100644 (file)
index 0000000..9b9eb13
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInformation;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.test.TestApexModelCreator;
+
+public class TestApexTestModelCreator2 implements TestApexModelCreator<AxModel> {
+
+    @Override
+    public AxModel getModel() {
+        AxModel basicModel = new AxModel();
+
+        basicModel.setKey(new AxArtifactKey("BasicModel", "0.0.1"));
+        basicModel.setKeyInformation(new AxKeyInformation(new AxArtifactKey("KeyInfoMapKey", "0.0.1")));
+
+        basicModel.getKeyInformation().getKeyInfoMap().put(basicModel.getKey(), new AxKeyInfo(basicModel.getKey()));
+        basicModel.getKeyInformation().getKeyInfoMap().put(basicModel.getKeyInformation().getKey(), new AxKeyInfo(basicModel.getKeyInformation().getKey()));
+        basicModel.getKeyInformation().get("BasicModel").setDescription("");
+        return basicModel;
+    }
+
+    @Override
+    public final AxModel getMalstructuredModel() {
+        return getModel();
+    }
+
+    @Override
+    public final AxModel getObservationModel() {
+        return getModel();
+    }
+
+    @Override
+    public final AxModel getWarningModel() {
+        return getModel();
+    }
+
+    @Override
+    public final AxModel getInvalidModel() {
+        return getModel();
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestBasicModelTest.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestBasicModelTest.java
new file mode 100644 (file)
index 0000000..ea5433f
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.test.TestApexModel;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestBasicModelTest {
+
+    @Test
+    public void testNormalModelCreator() throws ApexException {
+        TestApexModel<AxModel> testApexModel = new TestApexModel<AxModel>(AxModel.class, new TestApexBasicModelCreator());
+
+        testApexModel.testApexModelValid();
+        try {
+            testApexModel.testApexModelVaidateObservation();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertEquals("model should have observations", e.getMessage());
+        }
+        testApexModel.testApexModelVaidateWarning();
+        testApexModel.testApexModelVaidateInvalidModel();
+        testApexModel.testApexModelVaidateMalstructured();
+
+        testApexModel.testApexModelWriteReadJSON();
+        testApexModel.testApexModelWriteReadXML();
+    }
+
+    @Test
+    public void testModelCreator0() throws ApexException {
+        TestApexModel<AxModel> testApexModel = new TestApexModel<AxModel>(AxModel.class, new TestApexTestModelCreator0());
+
+        testApexModel.testApexModelValid();
+        try {
+            testApexModel.testApexModelVaidateObservation();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertEquals("model should have observations", e.getMessage());
+        }
+        try {
+            testApexModel.testApexModelVaidateWarning();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertEquals("model should have warnings", e.getMessage());
+        }
+        try {
+            testApexModel.testApexModelVaidateInvalidModel();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertEquals("should not be valid ***validation of model successful***", e.getMessage());
+        }
+        try {
+            testApexModel.testApexModelVaidateMalstructured();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertEquals("should not be valid ***validation of model successful***", e.getMessage());
+        }
+    }
+
+    @Test
+    public void testModelCreator1() throws ApexException {
+        TestApexModel<AxModel> testApexModel = new TestApexModel<AxModel>(AxModel.class, new TestApexTestModelCreator1());
+
+        try {
+            testApexModel.testApexModelValid();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().startsWith("model is invalid"));
+        }
+        try {
+            testApexModel.testApexModelVaidateObservation();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().startsWith("model is invalid"));
+        }
+        try {
+            testApexModel.testApexModelVaidateWarning();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().startsWith("model is invalid"));
+        }
+        testApexModel.testApexModelVaidateInvalidModel();
+        testApexModel.testApexModelVaidateMalstructured();
+    }
+    
+    @Test
+    public void testModelCreator2() throws ApexException {
+        TestApexModel<AxModel> testApexModel = new TestApexModel<AxModel>(AxModel.class, new TestApexTestModelCreator2());
+
+        testApexModel.testApexModelValid();
+        testApexModel.testApexModelVaidateObservation();
+        try {
+            testApexModel.testApexModelVaidateWarning();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertEquals("model should have warnings", e.getMessage());
+        }
+    }
+    
+    @Test
+    public void testModelCreator1XMLJSON() throws ApexException {
+        TestApexModel<AxModel> testApexModel = new TestApexModel<AxModel>(AxModel.class, new TestApexTestModelCreator1());
+
+        try {
+            testApexModel.testApexModelWriteReadJSON();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().startsWith("error processing file"));
+        }
+
+        try {
+            testApexModel.testApexModelWriteReadXML();
+            fail("Test should throw an exception");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().startsWith("error processing file"));
+        }
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestConceptGetter.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestConceptGetter.java
new file mode 100644 (file)
index 0000000..a6ff9dc
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.UUID;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.handling.ApexModelFileWriter;
+import org.onap.apex.model.basicmodel.handling.ApexModelReader;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestConceptGetter {
+
+    @Test
+    public void testConceptGetter() throws IOException, ApexException {
+        AxModel basicModel = new TestApexBasicModelCreator().getModel();
+        assertNotNull(basicModel);
+       
+        AxKeyInfo intKI01 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey01", "0.0.1"), UUID.randomUUID(), "IntegerKIKey01 description");
+        AxKeyInfo intKI11 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey11", "0.0.1"), UUID.randomUUID(), "IntegerKIKey11 description");
+        AxKeyInfo intKI21 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey21", "0.0.1"), UUID.randomUUID(), "IntegerKIKey21 description");
+        AxKeyInfo intKI22 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey22", "0.0.2"), UUID.randomUUID(), "IntegerKIKey22 description");
+        AxKeyInfo intKI23 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey23", "0.0.3"), UUID.randomUUID(), "IntegerKIKey23 description");
+        AxKeyInfo intKI24 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey24", "0.0.4"), UUID.randomUUID(), "IntegerKIKey24 description");
+        AxKeyInfo intKI25 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey25", "0.0.5"), UUID.randomUUID(), "IntegerKIKey25 description");
+        AxKeyInfo intKI26 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey26", "0.0.6"), UUID.randomUUID(), "IntegerKIKey26 description");
+        AxKeyInfo intKI31 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey31", "0.0.1"), UUID.randomUUID(), "IntegerKIKey31 description");
+        AxKeyInfo intKI41 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey41", "0.0.1"), UUID.randomUUID(), "IntegerKIKey41 description");
+        AxKeyInfo intKI51 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey51", "0.0.1"), UUID.randomUUID(), "IntegerKIKey51 description");
+        AxKeyInfo intKI52 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey52", "0.0.2"), UUID.randomUUID(), "IntegerKIKey52 description");
+        AxKeyInfo intKI53 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey53", "0.0.3"), UUID.randomUUID(), "IntegerKIKey53 description");
+        AxKeyInfo intKI54 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey54", "0.0.4"), UUID.randomUUID(), "IntegerKIKey54 description");
+        AxKeyInfo intKI61 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey61", "0.0.1"), UUID.randomUUID(), "IntegerKIKey61 description");
+        AxKeyInfo intKI62 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey62", "0.0.2"), UUID.randomUUID(), "IntegerKIKey62 description");
+        AxKeyInfo intKI63 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey63", "0.0.3"), UUID.randomUUID(), "IntegerKIKey63 description");
+        AxKeyInfo intKI64 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey64", "0.0.4"), UUID.randomUUID(), "IntegerKIKey64 description");
+        AxKeyInfo intKI71 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey71", "0.0.1"), UUID.randomUUID(), "IntegerKIKey71 description");
+        AxKeyInfo intKI81 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey81", "0.0.1"), UUID.randomUUID(), "IntegerKIKey81 description");
+        AxKeyInfo intKI91 = new AxKeyInfo(new AxArtifactKey("IntegerKIKey91", "0.0.1"), UUID.randomUUID(), "IntegerKIKey91 description");
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI31.getKey(), intKI31);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI24.getKey(), intKI24);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI11.getKey(), intKI11);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI64.getKey(), intKI64);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI41.getKey(), intKI41);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI51.getKey(), intKI51);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI23.getKey(), intKI23);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI81.getKey(), intKI81);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI71.getKey(), intKI71);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI01.getKey(), intKI01);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI91.getKey(), intKI91);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI52.getKey(), intKI52);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI53.getKey(), intKI53);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI62.getKey(), intKI62);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI54.getKey(), intKI54);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI26.getKey(), intKI26);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI22.getKey(), intKI22);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI25.getKey(), intKI25);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI21.getKey(), intKI21);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI61.getKey(), intKI61);
+        basicModel.getKeyInformation().getKeyInfoMap().put(intKI63.getKey(), intKI63);
+
+        AxKeyInfo floatKI01 = new AxKeyInfo(new AxArtifactKey("FloatKIKey01", "0.0.1"), UUID.randomUUID(), "IntegerKIKey01 description");
+        AxKeyInfo floatKI11 = new AxKeyInfo(new AxArtifactKey("FloatKIKey11", "0.0.1"), UUID.randomUUID(), "IntegerKIKey11 description");
+        AxKeyInfo floatKI21 = new AxKeyInfo(new AxArtifactKey("FloatKIKey21", "0.0.1"), UUID.randomUUID(), "IntegerKIKey21 description");
+        AxKeyInfo floatKI31 = new AxKeyInfo(new AxArtifactKey("FloatKIKey31", "0.0.1"), UUID.randomUUID(), "IntegerKIKey31 description");
+        AxKeyInfo floatKI41 = new AxKeyInfo(new AxArtifactKey("FloatKIKey41", "0.0.1"), UUID.randomUUID(), "IntegerKIKey41 description");
+        AxKeyInfo floatKI51 = new AxKeyInfo(new AxArtifactKey("FloatKIKey51", "0.0.1"), UUID.randomUUID(), "IntegerKIKey51 description");
+        AxKeyInfo floatKI61 = new AxKeyInfo(new AxArtifactKey("FloatKIKey61", "0.0.1"), UUID.randomUUID(), "IntegerKIKey61 description");
+        AxKeyInfo floatKI71 = new AxKeyInfo(new AxArtifactKey("FloatKIKey71", "0.0.1"), UUID.randomUUID(), "IntegerKIKey71 description");
+        AxKeyInfo floatKI81 = new AxKeyInfo(new AxArtifactKey("FloatKIKey81", "0.0.1"), UUID.randomUUID(), "IntegerKIKey81 description");
+        AxKeyInfo floatKI82 = new AxKeyInfo(new AxArtifactKey("FloatKIKey82", "0.0.2"), UUID.randomUUID(), "IntegerKIKey82 description");
+        AxKeyInfo floatKI83 = new AxKeyInfo(new AxArtifactKey("FloatKIKey83", "0.0.3"), UUID.randomUUID(), "IntegerKIKey83 description");
+        AxKeyInfo floatKI91 = new AxKeyInfo(new AxArtifactKey("FloatKIKey91", "0.0.1"), UUID.randomUUID(), "IntegerKIKey91 description");
+        AxKeyInfo floatKI92 = new AxKeyInfo(new AxArtifactKey("FloatKIKey92", "0.0.2"), UUID.randomUUID(), "IntegerKIKey92 description");
+        AxKeyInfo floatKI93 = new AxKeyInfo(new AxArtifactKey("FloatKIKey93", "0.0.3"), UUID.randomUUID(), "IntegerKIKey93 description");
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI11.getKey(), floatKI11);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI83.getKey(), floatKI83);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI51.getKey(), floatKI51);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI71.getKey(), floatKI71);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI21.getKey(), floatKI21);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI81.getKey(), floatKI81);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI92.getKey(), floatKI92);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI91.getKey(), floatKI91);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI01.getKey(), floatKI01);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI82.getKey(), floatKI82);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI61.getKey(), floatKI61);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI41.getKey(), floatKI41);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI31.getKey(), floatKI31);
+        basicModel.getKeyInformation().getKeyInfoMap().put(floatKI93.getKey(), floatKI93);
+
+        assertNull(basicModel.getKeyInformation().get("NonExistantKey", "0.0.6"));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey26", "0.0.6").equals(intKI26));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey62", "0.0.2").equals(intKI62));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey21", "0.0.1").equals(intKI21));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey61", "0.0.1").equals(intKI61));
+       
+        assertNull(basicModel.getKeyInformation().get("NonExistantKey"));
+       
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey01").equals(intKI01));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey11").equals(intKI11));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey26").equals(intKI26));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey31").equals(intKI31));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey41").equals(intKI41));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey54").equals(intKI54));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey64").equals(intKI64));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey71").equals(intKI71));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey81").equals(intKI81));
+        assertTrue(basicModel.getKeyInformation().get("IntegerKIKey91").equals(intKI91));
+       
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey01").equals(floatKI01));
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey11").equals(floatKI11));
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey21").equals(floatKI21));
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey31").equals(floatKI31));
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey41").equals(floatKI41));
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey51").equals(floatKI51));
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey61").equals(floatKI61));
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey71").equals(floatKI71));
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey83").equals(floatKI83));
+        assertTrue(basicModel.getKeyInformation().get("FloatKIKey93").equals(floatKI93));
+
+   
+        // Ensure marshalling and unmarshalling is OK
+        ApexModelReader<AxModel> modelReader = new ApexModelReader<AxModel>(AxModel.class);
+        ApexModelFileWriter<AxModel> modelWriter = new ApexModelFileWriter<AxModel>(true);
+       
+        modelReader.setValidateFlag(false);
+        modelWriter.setValidateFlag(false);
+       
+        File tempXMLFile = File.createTempFile("ApexModel", "xml");
+        modelWriter.apexModelWriteJSONFile(basicModel, AxModel.class, tempXMLFile.getCanonicalPath());
+       
+        FileInputStream xmlFileInputStream = new FileInputStream(tempXMLFile);
+        AxModel readXMLModel = modelReader.read(xmlFileInputStream);
+        xmlFileInputStream.close();
+        assertTrue(basicModel.equals(readXMLModel));
+        assertTrue(readXMLModel.getKeyInformation().get("IntegerKIKey91").equals(intKI91));
+        assertNotNull(readXMLModel.getKeyInformation().get("FloatKIKey"));
+        tempXMLFile.delete();
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestExceptions.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestExceptions.java
new file mode 100644 (file)
index 0000000..0dd271f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.handling.ApexModelException;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestExceptions {
+
+    @Test
+    public void test() {
+        assertNotNull(new ApexModelException("Message"));
+        assertNotNull(new ApexModelException("Message", new IOException()));
+
+        ApexModelException ame = new ApexModelException("Message", new IOException("IO exception message"));
+        assertEquals("Message\ncaused by: Message\ncaused by: IO exception message", ame.getCascadedMessage());
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelFileWriter.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelFileWriter.java
new file mode 100644 (file)
index 0000000..c2116a1
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.handling.ApexModelFileWriter;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestModelFileWriter {
+
+    @Test
+    public void testModelFileWriter() throws IOException, ApexException {
+        AxModel model = new TestApexBasicModelCreator().getModel();
+
+        ApexModelFileWriter<AxModel> modelFileWriter = new ApexModelFileWriter<>(true);
+
+        modelFileWriter.setValidateFlag(true);
+        assertTrue(modelFileWriter.isValidateFlag());
+
+        File tempFile = File.createTempFile("ApexFileWriterTest", "test");
+        File tempDir = tempFile.getParentFile();
+        tempFile.delete();
+        
+        File jsonTempFile = new File(tempDir.getAbsolutePath() + "/aaa/ApexFileWriterTest.json");
+        File xmlTempFile = new File(tempDir.getAbsolutePath() + "/ccc/ApexFileWriterTest.xml");
+        
+        modelFileWriter.apexModelWriteJSONFile(model, AxModel.class, jsonTempFile.getAbsolutePath());
+
+        modelFileWriter.apexModelWriteXMLFile(model, AxModel.class, xmlTempFile.getAbsolutePath());
+        
+        jsonTempFile.delete();
+        xmlTempFile.delete();
+        new File(tempDir.getAbsolutePath() + "/aaa").delete();
+        new File(tempDir.getAbsolutePath() + "/ccc").delete();
+       
+        jsonTempFile = new File(tempDir.getAbsolutePath() + "/aaa/bbb/ApexFileWriterTest.json");
+        xmlTempFile = new File(tempDir.getAbsolutePath() + "/ccc/ddd/ApexFileWriterTest.xml");
+        
+        modelFileWriter.apexModelWriteJSONFile(model, AxModel.class, jsonTempFile.getAbsolutePath());
+        modelFileWriter.apexModelWriteXMLFile(model, AxModel.class, xmlTempFile.getAbsolutePath());
+                
+        jsonTempFile.delete();
+        xmlTempFile.delete();
+
+        new File(tempDir.getAbsolutePath() + "/aaa/bbb").delete();
+        new File(tempDir.getAbsolutePath() + "/aaa").delete();
+        new File(tempDir.getAbsolutePath() + "/ccc/ddd").delete();
+        new File(tempDir.getAbsolutePath() + "/ccc").delete();
+        
+        File dirA = new File(tempDir.getAbsolutePath() + "/aaa");
+        //File dirB = new File(tempDir.getAbsolutePath() + "/aaa/bbb");
+        dirA.createNewFile();
+        //dirB.createNewFile();
+        
+        jsonTempFile = new File(tempDir.getAbsolutePath() + "/aaa/bbb/ApexFileWriterTest.json");
+        jsonTempFile = new File(tempDir.getAbsolutePath() + "/aaa/bbb/ApexFileWriterTest.xml");
+
+        try {
+            modelFileWriter.apexModelWriteJSONFile(model, AxModel.class, jsonTempFile.getAbsolutePath());
+            fail("this test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().contains("could not create directory "));
+        }
+
+        try {
+            modelFileWriter.apexModelWriteXMLFile(model, AxModel.class, jsonTempFile.getAbsolutePath());
+            fail("this test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().contains("could not create directory "));
+        }
+
+        dirA.delete();
+
+        dirA = new File(tempDir.getAbsolutePath() + "/aaa");
+        File fileB = new File(tempDir.getAbsolutePath() + "/aaa/bbb");
+        dirA.mkdir();
+        fileB.createNewFile();
+        
+        jsonTempFile = new File(tempDir.getAbsolutePath() + "/aaa/bbb/ApexFileWriterTest.json");
+        jsonTempFile = new File(tempDir.getAbsolutePath() + "/aaa/bbb/ApexFileWriterTest.xml");
+
+        try {
+            modelFileWriter.apexModelWriteJSONFile(model, AxModel.class, jsonTempFile.getAbsolutePath());
+            fail("this test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().contains("error processing file "));
+        }
+
+        try {
+            modelFileWriter.apexModelWriteXMLFile(model, AxModel.class, jsonTempFile.getAbsolutePath());
+            fail("this test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().contains("error processing file "));
+        }
+
+        fileB.delete();
+        dirA.delete();
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelReader.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelReader.java
new file mode 100644 (file)
index 0000000..134f6ff
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.handling.ApexModelReader;
+import org.onap.apex.model.basicmodel.handling.ApexModelWriter;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestModelReader {
+
+    @Test
+    public void testModelReader() throws IOException, ApexException {
+        AxModel model = new TestApexBasicModelCreator().getModel();
+        AxModel invalidModel = new TestApexBasicModelCreator().getInvalidModel();
+        
+        ApexModelWriter<AxModel> modelWriter = new ApexModelWriter<AxModel>(AxModel.class);
+        modelWriter.setValidateFlag(true);
+        modelWriter.setJsonOutput(true);
+        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        modelWriter.write(model, baos);
+        
+        ByteArrayOutputStream baosInvalid = new ByteArrayOutputStream();
+        modelWriter.setValidateFlag(false);
+        modelWriter.write(invalidModel, baosInvalid);
+        
+        ApexModelReader<AxModel> modelReader = new ApexModelReader<AxModel>(AxModel.class, true);
+        
+        modelReader.setValidateFlag(true);
+        assertTrue(modelReader.getValidateFlag());
+        
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        AxModel readModel = modelReader.read(bais);
+        assertEquals(model, readModel);
+        
+        ByteArrayInputStream baisInvalid = new ByteArrayInputStream(baosInvalid.toByteArray());
+        try {
+            modelReader.read(baisInvalid);
+            fail("test should throw an exceptino here");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().startsWith("Apex concept validation failed"));
+        }
+        
+        modelReader.setValidateFlag(false);
+        assertFalse(modelReader.getValidateFlag());
+        
+        ByteArrayInputStream bais2 = new ByteArrayInputStream(baos.toByteArray());
+        AxModel readModel2 = modelReader.read(bais2);
+        assertEquals(model, readModel2);
+        
+        modelWriter.setJsonOutput(false);
+        
+        ByteArrayOutputStream baosXML = new ByteArrayOutputStream();
+        modelWriter.write(model, baosXML);
+        
+        ByteArrayInputStream baisXML = new ByteArrayInputStream(baosXML.toByteArray());
+        AxModel readModelXML = modelReader.read(baisXML);
+        assertEquals(model, readModelXML);
+        
+        String dummyString = "SomeDummyText";
+        ByteArrayInputStream baisDummy = new ByteArrayInputStream(dummyString.getBytes());
+        try {
+            modelReader.read(baisDummy);
+            fail("test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("format of input for Apex concept is neither JSON nor XML", e.getMessage());
+        }
+        
+        try {
+            ByteArrayInputStream nullBais = null;
+            modelReader.read(nullBais);
+            fail("test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("concept stream may not be null", e.getMessage());
+        }
+        
+        try {
+            FileInputStream fis = new FileInputStream(new File("somewhere/over/the/rainbow"));
+            modelReader.read(fis);
+            fail("test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().contains("rainbow"));
+        }
+        
+        File tempFile = File.createTempFile("Apex", "Dummy");
+        try {
+            BufferedReader br = new BufferedReader(new FileReader(tempFile));
+            br.close();
+            modelReader.read(br);
+            fail("test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("Unable to read Apex concept ", e.getMessage());
+        }
+        finally {
+            tempFile.delete();
+        }
+        
+        modelReader.setSchema(null);
+        
+        tempFile = File.createTempFile("Apex", "Dummy");
+        try {
+            modelReader.setSchema(tempFile.getCanonicalPath());
+            fail("test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("Unable to load schema", e.getMessage());
+        }
+        finally {
+            tempFile.delete();
+        }
+        
+        modelReader.setSchema("xml/example.xsd");
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelSaver.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelSaver.java
new file mode 100644 (file)
index 0000000..182d341
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.handling.ApexModelSaver;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestModelSaver {
+
+    @Test
+    public void testModelSaver() throws IOException, ApexException {
+        AxModel model = new TestApexBasicModelCreator().getModel();
+        
+        Path tempPath = Files.createTempDirectory("ApexTest");
+        
+        ApexModelSaver<AxModel> modelSaver = new ApexModelSaver<AxModel>(AxModel.class, model, tempPath.toAbsolutePath().toString());
+        
+        modelSaver.apexModelWriteXML();
+        modelSaver.apexModelWriteJSON();
+        
+        Files.deleteIfExists(new File(tempPath.toAbsolutePath() + "/BasicModel.json").toPath());
+        Files.deleteIfExists(new File(tempPath.toAbsolutePath() + "/BasicModel.xml").toPath());
+        Files.deleteIfExists(tempPath);
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelStringWriter.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelStringWriter.java
new file mode 100644 (file)
index 0000000..2f4fcd2
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.handling.ApexModelStringWriter;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestModelStringWriter {
+
+    @Test
+    public void testModelStringWriter() throws IOException, ApexException {
+        AxModel basicModel = new TestApexBasicModelCreator().getModel();
+        assertNotNull(basicModel);
+       
+        AxKeyInfo intKI   = basicModel.getKeyInformation().get("IntegerKIKey");
+        AxKeyInfo floatKI = basicModel.getKeyInformation().get("FloatKIKey");
+
+        // Ensure marshalling is OK
+        ApexModelStringWriter<AxKeyInfo> stringWriter = new ApexModelStringWriter<AxKeyInfo>(true);
+        
+        assertNotNull(stringWriter.writeJSONString(intKI,   AxKeyInfo.class));
+        assertNotNull(stringWriter.writeJSONString(floatKI, AxKeyInfo.class));
+       
+        assertNotNull(stringWriter.writeString(intKI,   AxKeyInfo.class, true));
+        assertNotNull(stringWriter.writeString(floatKI, AxKeyInfo.class, true));
+       
+        assertNotNull(stringWriter.writeString(intKI,   AxKeyInfo.class, false));
+        assertNotNull(stringWriter.writeString(floatKI, AxKeyInfo.class, false));
+        
+        assertNotNull(stringWriter.writeXMLString(intKI,   AxKeyInfo.class));
+        assertNotNull(stringWriter.writeXMLString(floatKI, AxKeyInfo.class));
+        
+        try {
+            stringWriter.writeString(null, AxKeyInfo.class, true);
+            fail("test should thrown an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("concept may not be null", e.getMessage());
+        }
+        
+        try {
+            stringWriter.writeString(null, AxKeyInfo.class, false);
+            fail("test should thrown an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("concept may not be null", e.getMessage());
+        }
+        
+        try {
+            stringWriter.writeJSONString(null, AxKeyInfo.class);
+            fail("test should thrown an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("error writing JSON string", e.getMessage());
+        }
+        
+        try {
+            stringWriter.writeXMLString(null, AxKeyInfo.class);
+            fail("test should thrown an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("error writing XML string", e.getMessage());
+        }
+        
+        stringWriter.setValidateFlag(true);
+        assertTrue(stringWriter.isValidateFlag());
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelWriter.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestModelWriter.java
new file mode 100644 (file)
index 0000000..a21c148
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.ApexException;
+import org.onap.apex.model.basicmodel.concepts.AxModel;
+import org.onap.apex.model.basicmodel.handling.ApexModelWriter;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestModelWriter {
+
+    @Test
+    public void testModelWriter() throws IOException, ApexException {
+        AxModel model = new TestApexBasicModelCreator().getModel();
+        
+        ApexModelWriter<AxModel> modelWriter = new ApexModelWriter<AxModel>(AxModel.class);
+        
+        modelWriter.setValidateFlag(true);
+        assertTrue(modelWriter.getValidateFlag());
+        assertEquals(0, modelWriter.getCDataFieldSet().size());
+        
+        assertFalse(modelWriter.isJsonOutput());
+        modelWriter.setJsonOutput(true);
+        assertTrue(modelWriter.isJsonOutput());
+        modelWriter.setJsonOutput(false);
+        assertFalse(modelWriter.isJsonOutput());
+        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+        modelWriter.write(model, baos);
+        modelWriter.setJsonOutput(true);
+        modelWriter.write(model, baos);
+        modelWriter.setJsonOutput(false);
+        
+        modelWriter.setValidateFlag(false);
+        modelWriter.write(model, baos);
+        modelWriter.setJsonOutput(true);
+        modelWriter.write(model, baos);
+        modelWriter.setJsonOutput(false);
+        
+        modelWriter.setValidateFlag(true);
+        model.getKeyInformation().getKeyInfoMap().clear();
+        try {
+            modelWriter.write(model, baos);
+            fail("Test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("Apex concept xml (BasicModel:0.0.1) validation failed", e.getMessage());
+        }
+        model.getKeyInformation().generateKeyInfo(model);
+
+        try {
+            modelWriter.write(null, baos);
+            fail("Test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("concept may not be null", e.getMessage());
+        }
+        
+        try {
+            ByteArrayOutputStream nullBaos = null;
+            modelWriter.write(model, nullBaos);
+            fail("Test should throw an exception here");
+        }
+        catch (Exception e) {
+            assertEquals("concept stream may not be null", e.getMessage());
+        }
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestSchemaGenerator.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/handling/TestSchemaGenerator.java
new file mode 100644 (file)
index 0000000..2e10b51
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.handling;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.handling.ApexSchemaGenerator;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestSchemaGenerator {
+
+    @Test
+    public void test() throws IOException {
+        final ByteArrayOutputStream baos0 = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos0));
+        
+        final String[] args0 = {};
+        ApexSchemaGenerator.main(args0);
+        assertTrue(baos0.toString().contains("usage: ApexSchemaGenerator apex-root-class [schema-file-name]"));
+        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
+        
+        final ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos1));
+        
+        final String[] args1 = {"hello", "goodbye", "here"};
+        ApexSchemaGenerator.main(args1);
+        assertTrue(baos1.toString().contains("usage: ApexSchemaGenerator apex-root-class [schema-file-name]"));
+        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
+        
+        final ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos2));
+        
+        final String[] args2 = {"hello", "goodbye"};
+        ApexSchemaGenerator.main(args2);
+        assertTrue(baos2.toString().contains("error on Apex schema output"));
+        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
+        
+        final ByteArrayOutputStream baos3 = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos3));
+        
+        final String[] args3 = {"hello"};
+        ApexSchemaGenerator.main(args3);
+        assertTrue(baos3.toString().contains("could not create JAXB context, root class hello not found"));
+        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
+        
+        final ByteArrayOutputStream baos4 = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos4));
+        
+        final String[] args4 = {"org.onap.apex.model.basicmodel.concepts.AxModel"};
+        ApexSchemaGenerator.main(args4);
+        assertTrue(baos4.toString().contains("targetNamespace=\"http://www.ericsson.com/apex\""));
+        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
+        
+        final ByteArrayOutputStream baos5 = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos5));
+        
+        final File tempFile = File.createTempFile("ApexSchemaGeneratorTest", "xsd");
+        final String[] args5 = {"org.onap.apex.model.basicmodel.concepts.AxModel", tempFile.getCanonicalPath()};
+        
+        ApexSchemaGenerator.main(args5);
+        assertTrue(tempFile.length() > 100);
+        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
+        tempFile.delete();
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/IllegalParameters.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/IllegalParameters.java
new file mode 100644 (file)
index 0000000..3cb4808
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.service;
+
+import org.onap.apex.model.basicmodel.service.AbstractParameters;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class IllegalParameters extends AbstractParameters {
+    public IllegalParameters() {
+        super("somewhere.over.the.rainbow");
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/LegalParameters.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/LegalParameters.java
new file mode 100644 (file)
index 0000000..2bab6fd
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.service;
+
+import org.onap.apex.model.basicmodel.service.AbstractParameters;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class LegalParameters extends AbstractParameters {
+    public LegalParameters() {
+        super(LegalParameters.class.getCanonicalName());
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/TestAbstractParameters.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/TestAbstractParameters.java
new file mode 100644 (file)
index 0000000..e9a0e2f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestAbstractParameters {
+
+    @Test
+    public void testAbstractParameters() {
+        final LegalParameters parameters = new LegalParameters();
+        assertNotNull(parameters);
+        assertEquals("AbstractParameters [parameterClassName=org.onap.apex.model.basicmodel.service.LegalParameters]", parameters.toString());
+
+        assertEquals(LegalParameters.class, parameters.getParameterClass());
+        assertEquals("org.onap.apex.model.basicmodel.service.LegalParameters", parameters.getParameterClassName());
+        
+        try {
+            new IllegalParameters();
+            fail("test should throw an exception here");
+        }
+        catch (final Exception e) {
+            assertEquals("class \"somewhere.over.the.rainbow\" not found or not an instance of \"org.onap.apex.model.basicmodel.service.IllegalParameters\"", e.getMessage());
+        }
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/TestModelService.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/TestModelService.java
new file mode 100644 (file)
index 0000000..51af9ba
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.AxKeyInformation;
+import org.onap.apex.model.basicmodel.handling.TestApexBasicModelCreator;
+import org.onap.apex.model.basicmodel.service.ModelService;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestModelService {
+
+    @Test
+    public void testModelService() {
+        ModelService.clear();
+
+        assertFalse(ModelService.existsModel(AxKeyInformation.class));
+        try {
+            ModelService.getModel(AxKeyInformation.class);
+        }
+        catch (Exception e) {
+            assertEquals("Model for org.onap.apex.model.basicmodel.concepts.AxKeyInformation not found in model service", e.getMessage());
+        }
+        
+        ModelService.registerModel(AxKeyInformation.class, new TestApexBasicModelCreator().getModel().getKeyInformation());
+        assertTrue(ModelService.existsModel(AxKeyInformation.class));
+        assertNotNull(ModelService.getModel(AxKeyInformation.class));
+        
+        ModelService.deregisterModel(AxKeyInformation.class);
+       
+        assertFalse(ModelService.existsModel(AxKeyInformation.class));
+        try {
+            ModelService.getModel(AxKeyInformation.class);
+        }
+        catch (Exception e) {
+            assertEquals("Model for org.onap.apex.model.basicmodel.concepts.AxKeyInformation not found in model service", e.getMessage());
+        }
+
+        ModelService.registerModel(AxKeyInformation.class, new TestApexBasicModelCreator().getModel().getKeyInformation());
+        assertTrue(ModelService.existsModel(AxKeyInformation.class));
+        assertNotNull(ModelService.getModel(AxKeyInformation.class));
+        
+        ModelService.clear();
+        assertFalse(ModelService.existsModel(AxKeyInformation.class));
+        try {
+            ModelService.getModel(AxKeyInformation.class);
+        }
+        catch (Exception e) {
+            assertEquals("Model for org.onap.apex.model.basicmodel.concepts.AxKeyInformation not found in model service", e.getMessage());
+        }
+
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/TestParameterService.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/service/TestParameterService.java
new file mode 100644 (file)
index 0000000..ff2a9c8
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.service.ParameterService;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestParameterService {
+
+    @Test
+    public void testParameterService() {
+        ParameterService.clear();
+
+        assertFalse(ParameterService.existsParameters(LegalParameters.class));
+        try {
+            ParameterService.getParameters(LegalParameters.class);
+        }
+        catch (final Exception e) {
+            assertEquals("Parameters for org.onap.apex.model.basicmodel.service.LegalParameters not found in parameter service", e.getMessage());
+        }
+        
+        ParameterService.registerParameters(LegalParameters.class, new LegalParameters());
+        assertTrue(ParameterService.existsParameters(LegalParameters.class));
+        assertNotNull(ParameterService.getParameters(LegalParameters.class));
+        
+        ParameterService.deregisterParameters(LegalParameters.class);
+       
+        assertFalse(ParameterService.existsParameters(LegalParameters.class));
+        try {
+            ParameterService.getParameters(LegalParameters.class);
+        }
+        catch (final Exception e) {
+            assertEquals("Parameters for org.onap.apex.model.basicmodel.service.LegalParameters not found in parameter service", e.getMessage());
+        }
+
+        ParameterService.registerParameters(LegalParameters.class, new LegalParameters());
+        assertTrue(ParameterService.existsParameters(LegalParameters.class));
+        assertNotNull(ParameterService.getParameters(LegalParameters.class));
+        
+        assertNotNull(ParameterService.getAll());
+        ParameterService.clear();
+        assertFalse(ParameterService.existsParameters(LegalParameters.class));
+        try {
+            ParameterService.getParameters(LegalParameters.class);
+        }
+        catch (final Exception e) {
+            assertEquals("Parameters for org.onap.apex.model.basicmodel.service.LegalParameters not found in parameter service", e.getMessage());
+        }
+        
+    }
+}
diff --git a/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/xml/TestAxReferenceKeyAdapter.java b/model/basic-model/src/test/java/org/onap/apex/model/basicmodel/xml/TestAxReferenceKeyAdapter.java
new file mode 100644 (file)
index 0000000..b723439
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.apex.model.basicmodel.xml;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.onap.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.apex.model.basicmodel.xml.AxReferenceKeyAdapter;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestAxReferenceKeyAdapter {
+
+    @Test
+    public void test() throws Exception {
+        AxReferenceKeyAdapter arka = new AxReferenceKeyAdapter();
+        assertNotNull(arka);
+        
+        AxReferenceKey rKey = new AxReferenceKey("Name", "0.0.1", "PLN", "LN");
+        
+        String rKeyString = arka.marshal(rKey);
+        assertEquals("LN", rKeyString);
+        assertEquals(rKey.getLocalName(),arka.unmarshal(rKeyString).getLocalName());
+    }
+}
diff --git a/model/basic-model/src/test/resources/META-INF/persistence.xml b/model/basic-model/src/test/resources/META-INF/persistence.xml
new file mode 100644 (file)
index 0000000..5d02906
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2016-2018 Ericsson. 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.
+  
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
+    <persistence-unit name="DAOTest" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+
+        <class>org.onap.apex.model.basicmodel.dao.converters.CDATAConditioner</class>
+        <class>org.onap.apex.model.basicmodel.dao.converters.UUID2String</class>
+        <class>org.onap.apex.model.basicmodel.concepts.AxArtifactKey</class>
+        <class>org.onap.apex.model.basicmodel.concepts.AxReferenceKey</class>
+        <class>org.onap.apex.model.basicmodel.concepts.AxKeyInfo</class>
+        <class>org.onap.apex.model.basicmodel.concepts.AxKeyInformation</class>
+        <class>org.onap.apex.model.basicmodel.concepts.AxModel</class>
+        <class>org.onap.apex.model.basicmodel.concepts.TestEntity</class>
+
+        <properties>
+            <property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:apex_test" />
+            <property name="javax.persistence.target-database" value="Derby" />
+            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
+
+            <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
+            <property name="eclipselink.ddl-generation.output-mode" value="database"/>
+            <property name="eclipselink.logging.level"  value="INFO" />
+        </properties>
+    </persistence-unit>
+</persistence>
diff --git a/model/basic-model/src/test/resources/logback-test.xml b/model/basic-model/src/test/resources/logback-test.xml
new file mode 100644 (file)
index 0000000..d9d77f7
--- /dev/null
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2016-2018 Ericsson. 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.
+  
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<configuration>
+
+    <contextName>Apex</contextName>
+    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
+    <property name="LOG_DIR" value="${java.io.tmpdir}/apex_logging/" />
+
+    <!-- USE FOR STD OUT ONLY -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <Pattern>%d %contextName [%t] %level %logger{36} - %msg%n</Pattern>
+        </encoder>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="STDOUT" />
+    </root>
+
+    <logger name="org.infinispan" level="INFO" additivity="false">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <logger name="org.apache.zookeeper.ClientCnxn" level="OFF" additivity="false">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <appender name="FILE"
+        class="ch.qos.logback.core.FileAppender">
+        <file>${LOG_DIR}/apex.log</file>
+        <encoder>
+            <pattern>%d %-5relative [procId=${processId}] [%thread] %-5level
+                %logger{26} - %msg %n %ex{full}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="CTXT_FILE"
+        class="ch.qos.logback.core.FileAppender">
+        <file>${LOG_DIR}/apex_ctxt.log</file>
+        <encoder>
+            <pattern>%d %-5relative [procId=${processId}] [%thread] %-5level
+                %logger{26} - %msg %n %ex{full}</pattern>
+        </encoder>
+    </appender>
+
+    <logger name="com.ericsson.apex.core.context.impl.monitoring" level="TRACE" additivity="false">
+        <appender-ref ref="CTXT_FILE" />
+    </logger>
+
+    <logger name="com.ericsson.apex.core.context" level="INFO" additivity="false">
+        <appender-ref ref="STDOUT" />
+    </logger>
+</configuration>
diff --git a/model/pom.xml b/model/pom.xml
new file mode 100644 (file)
index 0000000..1345ca3
--- /dev/null
@@ -0,0 +1,40 @@
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2018 Ericsson. 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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.onap.policy.apex.apex-pdp</groupId>
+        <artifactId>apex-pdp</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+    </parent>
+    
+    <groupId>org.onap.policy.apex.apex-pdp.model</groupId>
+    <artifactId>model</artifactId>
+    <packaging>pom</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>The model for Apex, it comtains definitions of all Apex concepts and also has handling for Apex models.</description>
+
+    <modules>
+        <module>utiliites</module>
+        <module>basic-model</module>
+    </modules>
+</project>
\ No newline at end of file
diff --git a/model/utiliites/pom.xml b/model/utiliites/pom.xml
new file mode 100644 (file)
index 0000000..b956ebf
--- /dev/null
@@ -0,0 +1,57 @@
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2018 Ericsson. 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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.onap.policy.apex.apex-pdp.model</groupId>
+        <artifactId>model</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>utiliites</artifactId>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr4-runtime</artifactId>
+            <version>4.6</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr4-maven-plugin</artifactId>
+                <version>4.6</version>
+                <executions>
+                    <execution>
+                        <id>antlr-sources</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>antlr4</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/model/utiliites/src/main/antlr4/org/onap/policy/apex/model/utilities/typeutils/ParametrizedType.g4 b/model/utiliites/src/main/antlr4/org/onap/policy/apex/model/utilities/typeutils/ParametrizedType.g4
new file mode 100644 (file)
index 0000000..3a37d40
--- /dev/null
@@ -0,0 +1,58 @@
+//-------------------------------------------------------------------------------
+// ============LICENSE_START=======================================================
+//  Copyright (C) 2016-2018 Ericsson. 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.
+// 
+// SPDX-License-Identifier: Apache-2.0
+// ============LICENSE_END=========================================================
+//-------------------------------------------------------------------------------
+
+grammar ParametrizedType;
+
+//For more information see:
+// http://stackoverflow.com/questions/39401083/class-forname-equivalent-for-creating-parameterizedtypes-from-string
+// https://github.com/KetothXupack/stackoverflow-answers/tree/master/q39401083
+
+@parser::header {
+ //For more information see:
+ // http://stackoverflow.com/questions/39401083/class-forname-equivalent-for-creating-parameterizedtypes-from-string
+ // https://github.com/KetothXupack/stackoverflow-answers/tree/master/q39401083
+
+
+ //Note: Unused Imports  
+ //Since this is generated code compile warnings are to be expected and cannot always be suppressed
+ //See https://github.com/antlr/antlr4/issues/1192 
+ import org.onap.policy.apex.model.utilities.typeutils.ClassBuilder;
+}
+
+type returns[ClassBuilder value]
+    : cls=CLASS          { $value = ClassBuilder.parse($cls.text); }
+    | cls=CLASS          { $value = ClassBuilder.parse($cls.text); }
+      LT head=type       { $value.add($head.value); }
+        (COMMA tail=type { $value.add($tail.value); })* GT
+    ;
+
+GT  : '>'
+    ;
+
+LT  : '<'
+    ;
+
+COMMA
+    : ','
+    ;
+
+CLASS
+    : ('a'..'z'|'A'..'Z') ('a'..'z'|'A'..'Z'|'0'..'9'|'$'|'.'|'_')*
+    ;
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/Assertions.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/Assertions.java
new file mode 100644 (file)
index 0000000..c215f3f
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+/**
+ * The Class Assertions is a template class that is used as a shorthand for assertions in the source code.
+ *
+ * @author Sajeevan Achuthan (sajeevan.achuthan@ericsson.com)
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public final class Assertions {
+    /**
+     * Private constructor used to prevent sub class instantiation.
+     */
+    private Assertions() {
+    }
+
+    /**
+     * Checks if a string parameter matches a regular expression.
+     *
+     * @param parameterName the string parameter name
+     * @param parameterValue the string parameter value
+     * @param pattern The regular expression
+     * @return the trimmed string
+     */
+    public static String validateStringParameter(final String parameterName, final String parameterValue, final String pattern) {
+        argumentNotNull(parameterName, "parameter name is null");
+        argumentNotNull(parameterValue, "parameter \"" + parameterName + "\" is null");
+        argumentNotNull(pattern, "parameter pattern is null");
+
+        final String trimmedValue = parameterValue.trim();
+        if (trimmedValue.matches(pattern)) {
+            return trimmedValue;
+        }
+        else {
+            throw new IllegalArgumentException(
+                    "parameter \"" + parameterName + "\": value \"" + parameterValue + "\", does not match regular expression \"" + pattern + "\"");
+        }
+    }
+
+    /**
+     * Used as a shorthand to check that method arguments are not null, throws IllegalArgumentException on error.
+     *
+     * @param <T> the generic type of the argument to check
+     * @param value the value of the type
+     * @param message the error message to issue
+     */
+    public static <T> void argumentNotNull(final T value, final String message) {
+        if (value == null) {
+            throw new IllegalArgumentException(message);
+        }
+    }
+
+    /**
+     * Used as a shorthand to check that method arguments are not false, throws IllegalArgumentException on error.
+     *
+     * @param value the value to check if false
+     * @param message the error message to issue
+     */
+    public static void argumentNotFalse(final boolean value, final String message) {
+        if (!value) {
+            throw new IllegalArgumentException(message);
+        }
+    }
+
+    /**
+     * Used as a shorthand to check that method arguments are not null, throws an exception of the specified type on error.
+     *
+     * @param <T> the generic type of the argument to check
+     * @param <E> the exception to throw if incoming value is null
+     * @param value the value of the type
+     * @param exceptionClass the class of exception to return an instance of
+     * @param message the error message to issue
+     * @throws E an instance of the passed Exception Class
+     */
+    public static <T, E extends Exception> void argumentNotNull(final T value, final Class<E> exceptionClass, final String message) throws E {
+        if (value == null) {
+            // Instantiate the exception and throw it
+            try {
+                throw exceptionClass.getConstructor(String.class).newInstance(message);
+            }
+            catch (final Exception errorException) {
+                throw new IllegalArgumentException(message, errorException);
+            }
+        }
+    }
+
+    /**
+     * Used as a shorthand to check that method argument is not false, throws an exception of the specified type on error.
+     *
+     * @param <E> the exception to throw if incoming value is false
+     * @param value the value to check if false
+     * @param exceptionClass the class of exception to return an instance of
+     * @param message the error message to issue
+     * @throws E an instance of the passed Exception Class
+     */
+    public static <E extends Exception> void argumentNotFalse(final boolean value, final Class<E> exceptionClass, final String message) throws E {
+        if (!value) {
+            // Instantiate the exception and throw it
+            try {
+                throw exceptionClass.getConstructor(String.class).newInstance(message);
+            }
+            catch (final Exception errorException) {
+                throw new IllegalArgumentException(message, errorException);
+            }
+        }
+    }
+
+    /**
+     * Used as a shorthand to check that an object is an instance of a given class, throws IllegalArgumentException on error.
+     *
+     * @param <T> the generic type of the argument to check
+     * @param objectInstance the object instance for which to check the class
+     * @param requiredClass the class that the object should be an instance of
+     * @throws IllegalArgumentException if the incoming object is not an instance of requiredClass
+     */
+    public static <T> void instanceOf(final Object objectInstance, final Class<T> requiredClass) {
+        if (!requiredClass.isAssignableFrom(objectInstance.getClass())) {
+            throw new IllegalArgumentException(objectInstance.getClass().getCanonicalName() + " is not an instance of " + requiredClass.getCanonicalName());
+        }
+    }
+
+    /**
+     * Used as a shorthand to check that an instance of a class can be an instance of a given class, throws IllegalArgumentException on error.
+     *
+     * @param <T> the generic type of the argument to check
+     * @param checkClass the class to check
+     * @param requiredClass the class that the object should be an instance of
+     * @throws IllegalArgumentException if the incoming object is not an instance of requiredClass
+     */
+    public static <T> void assignableFrom(final Class<?> checkClass, final Class<T> requiredClass) {
+        if (!requiredClass.isAssignableFrom(checkClass)) {
+            throw new IllegalArgumentException(checkClass.getCanonicalName() + " is not an instance of " + requiredClass.getCanonicalName());
+        }
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/CollectionUtils.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/CollectionUtils.java
new file mode 100644 (file)
index 0000000..fb7207e
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * This is common utility class with static methods for handling collections.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class CollectionUtils {
+    /**
+     * Private constructor used to prevent sub class instantiation.
+     */
+    private CollectionUtils() {
+    }
+
+    /**
+     * Compare two lists, checks for equality, then for equality on members.
+     *
+     * @param <T> The type of the lists being compared
+     * @param leftList The leftmost List
+     * @param rightList The rightmost list
+     * @return an integer indicating how different the lists are
+     */
+    public static <T> int compareLists(final List<? extends Comparable<T>> leftList, final List<? extends Comparable<T>> rightList) {
+        // Check for nulls
+        if (leftList == null && rightList == null) {
+            return 0;
+        }
+        if (leftList != null && rightList == null) {
+            return -1;
+        }
+        if (leftList == null) {
+            return 1;
+        }
+
+        // Check for equality
+        if (leftList.equals(rightList)) {
+            return 0;
+        }
+        
+        return compareListEntries(leftList, rightList);
+    }
+
+    /**
+     * Compare two lists for equality on members.
+     *
+     * @param <T> The type of the lists being compared
+     * @param leftList The leftmost List
+     * @param rightList The rightmost list
+     * @return an integer indicating how different the lists are
+     */
+    private static <T> int compareListEntries(final List<? extends Comparable<T>> leftList, final List<? extends Comparable<T>> rightList) {
+        
+        // Iterate down the lists till we find a difference
+        final ListIterator<?> leftIterator = leftList.listIterator();
+        final ListIterator<?> rightIterator = rightList.listIterator();
+
+        while (true) {
+            // Check the iterators
+            if (!leftIterator.hasNext() && !rightIterator.hasNext()) {
+                return 0;
+            }
+            if (leftIterator.hasNext() && !rightIterator.hasNext()) {
+                return -1;
+            }
+            if (!leftIterator.hasNext() && rightIterator.hasNext()) {
+                return 1;
+            }
+
+            // Get the next objects
+            @SuppressWarnings("unchecked")
+            final T leftObject = (T) leftIterator.next();
+            @SuppressWarnings("unchecked")
+            final T rightObject = (T) rightIterator.next();
+
+            // Compare the objects
+            @SuppressWarnings("unchecked")
+            final int comparisonResult = ((Comparable<T>) leftObject).compareTo(rightObject);
+
+            // Check the comparison result
+            if (comparisonResult != 0) {
+                return comparisonResult;
+            }
+        }
+       }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/DirectoryUtils.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/DirectoryUtils.java
new file mode 100644 (file)
index 0000000..00e5cb4
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import java.io.File;
+
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This is common utility class with static methods for handling directories. It is an abstract class to prevent any direct instantiation and private
+ * constructor to prevent extending this class.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class DirectoryUtils {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(DirectoryUtils.class);
+
+    /**
+     * Private constructor used to prevent sub class instantiation.
+     */
+    private DirectoryUtils() {
+    }
+
+    /**
+     * Method to get an empty temporary directory in the system temporary directory on the local machine that will be deleted on (normal) shutdown.
+     *
+     * @param nameprefix The prefix of the filename. System.nanoTime() will be appended to the pattern to create a unique file pattern
+     * @return The temporary directory
+     */
+    public static File getLocalTempDirectory(final String nameprefix) {
+        try {
+            // Get the name of the temporary directory
+            final String tempDirName = System.getProperty("java.io.tmpdir") + "/" + nameprefix + System.nanoTime();
+            final File tempDir = new File(tempDirName);
+
+            // Delete the directory if it already exists
+            if (tempDir.exists()) {
+                return null;
+            }
+
+            // Make the directory
+            tempDir.mkdirs();
+
+            // Add a shutdown hook that deletes the directory contents when the JVM closes
+            Runtime.getRuntime().addShutdownHook(new DirectoryDeleteShutdownHook(tempDir));
+
+            LOGGER.trace("creating temp directory\"{}\" : ", tempDir.getAbsolutePath());
+            return tempDir;
+        }
+        catch (final Exception e) {
+            LOGGER.debug("error creating temp directory\"{}\" : " + e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * Method to recursively delete all the files in a directory.
+     *
+     * @param tempDir the directory to empty
+     * @return true if the operation succeeds, false otherwise
+     */
+    public static boolean emptyDirectory(final File tempDir) {
+        // Sanity check
+        if (!tempDir.exists() || !tempDir.isDirectory()) {
+            return false;
+        }
+
+        // Walk the directory structure deleting files as we go
+        final File[] files = tempDir.listFiles();
+        if (files != null) {
+            for (final File directoryFile : files) {
+                // Check if this is a directory itself
+                if (directoryFile.isDirectory()) {
+                    // Recurse into the sub directory and empty it
+                    emptyDirectory(directoryFile);
+                }
+
+                // Delete the directory entry
+                directoryFile.delete();
+            }
+        }
+
+        return true;
+    }
+}
+
+/**
+ * The Class DirectoryShutdownHook removes the contents of a directory and the directory itself at shutdown.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+final class DirectoryDeleteShutdownHook extends Thread {
+    // The directory we are acting on
+    private final File tempDir;
+
+    /**
+     * Constructor that defines the directory to act on at shutdown.
+     *
+     * @param tempDir The temporary directory to delete
+     */
+    DirectoryDeleteShutdownHook(final File tempDir) {
+        this.tempDir = tempDir;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Runnable#run()
+     */
+    @Override
+    public void run() {
+        if (tempDir.exists()) {
+            // Empty and delete the directory
+            DirectoryUtils.emptyDirectory(tempDir);
+            tempDir.delete();
+        }
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/PropertyUtils.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/PropertyUtils.java
new file mode 100644 (file)
index 0000000..72f8563
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import java.util.Map.Entry;
+
+/**
+ * Convenience methods for handling Java properties class instances.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class PropertyUtils {
+    /**
+     * Private constructor used to prevent sub class instantiation.
+     */
+    private PropertyUtils() {
+    }
+
+    /**
+     * Return all properties as a string.
+     *
+     * @return a string containing all the property values
+     */
+    public static String getAllProperties() {
+        final StringBuilder builder = new StringBuilder();
+
+        for (final Entry<Object, Object> property : System.getProperties().entrySet()) {
+            builder.append(property.getKey().toString());
+            builder.append('=');
+            builder.append(property.getValue().toString());
+            builder.append('\n');
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * Checks if a property is set. If the property is set with no value or with a value of "true", this method returns true. It returns "false" if the property
+     * is not set or is set to false
+     *
+     * @param propertyName The property to check
+     * @return true if the property is set to true, false otherwise
+     */
+    public static boolean propertySetOrTrue(final String propertyName) {
+        if (propertyName == null) {
+            return false;
+        }
+
+        final String propertyValue = System.getProperty(propertyName);
+        if (propertyValue == null) {
+            return false;
+        }
+
+        if (propertyValue.trim().length() == 0) {
+            return true;
+        }
+
+        return new Boolean(propertyValue);
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/ResourceUtils.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/ResourceUtils.java
new file mode 100644 (file)
index 0000000..588748d
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This is common utility class with static methods for handling Java resources on the class path. It is an abstract class to prevent any direct instantiation
+ * and private constructor to prevent extending this class.
+ *
+ * @author Sajeevan Achuthan (sajeevan.achuthan@ericsson.com)
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class ResourceUtils {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ResourceUtils.class);
+
+    // The length of byte buffers used to read resources into strings
+    private static final int BYTE_BUFFER_LENGH = 1024;
+
+    /**
+     * Private constructor used to prevent sub class instantiation.
+     */
+    private ResourceUtils() {
+    }
+
+    /**
+     * Method to resolve a resource; the local file system is checked first and then the class path is checked.
+     *
+     * @param resourceName The resource name
+     * @return A URL to a resource
+     */
+    public static URL getURL4Resource(final String resourceName) {
+        // Check the local fine system first
+        final URL urlToResource = getLocalFile(resourceName);
+
+        // Check if this is a local file
+        if (urlToResource != null) {
+            return urlToResource;
+        }
+        else {
+            // Resort to the class path
+            return getURLResource(resourceName);
+        }
+    }
+
+    /**
+     * Method to return a resource as a string. The resource can be on the local file system or in the class path. The resource is resolved and loaded into a
+     * string.
+     *
+     * @param resourceName The resource name
+     * @return A string containing the resource
+     */
+    public static String getResourceAsString(final String resourceName) {
+        // Get the resource as a stream, we'll convert it to a string then
+        final InputStream resourceStream = getResourceAsStream(resourceName);
+        if (resourceStream == null) {
+            return null;
+        }
+
+        // Read the stream contents in to an output stream
+        final ByteArrayOutputStream resourceOutputStreamBuffer = new ByteArrayOutputStream();
+        final byte[] resourceBuffer = new byte[BYTE_BUFFER_LENGH];
+        int length;
+        try {
+            while ((length = resourceStream.read(resourceBuffer)) != -1) {
+                resourceOutputStreamBuffer.write(resourceBuffer, 0, length);
+            }
+        }
+        catch (final IOException e) {
+            LOGGER.debug("error reading resource stream \"{}\" : " + e.getMessage(), resourceName, e);
+            return null;
+        }
+
+        return resourceOutputStreamBuffer.toString();
+    }
+
+    /**
+     * Method to return a resource as a stream. The resource can be on the local file system or in the class path. The resource is resolved and returned as a
+     * stream.
+     *
+     * @param resourceName The resource name
+     * @return A stream attached to the resource
+     */
+    public static InputStream getResourceAsStream(final String resourceName) {
+        // Find a URL to the resource first
+        final URL urlToResource = getURL4Resource(resourceName);
+
+        // Check if the resource exists
+        if (urlToResource == null) {
+            // No resource found
+            LOGGER.debug("cound not find resource \"{}\" : ", resourceName);
+            return null;
+        }
+
+        // Read the resource into a string
+        try {
+            return urlToResource.openStream();
+        }
+        catch (final IOException e) {
+            // Any of many IO exceptions such as the resource is a directory
+            LOGGER.debug("error attaching resource \"{}\" to stream : " + e.getMessage(), resourceName, e);
+            return null;
+        }
+    }
+
+    /**
+     * Method to get a URL resource from the class path.
+     *
+     * @param resourceName The resource name
+     * @return The URL to the resource
+     */
+    public static URL getURLResource(final String resourceName) {
+        try {
+            final ClassLoader classLoader = ResourceUtils.class.getClassLoader();
+
+            final String[] fileParts = resourceName.split("/");
+            // Read the resource
+            URL url = classLoader.getResource(resourceName);
+
+            // Check if the resource is defined
+            if (url != null) {
+                // Return the resource as a file name
+                LOGGER.debug("found URL resource \"{}\" : ", url);
+                return url;
+            }
+            else {
+                url = classLoader.getResource(fileParts[fileParts.length - 1]);
+                if (url == null) {
+                    LOGGER.debug("cound not find URL resource \"{}\" : ", resourceName);
+                    return null;
+                }
+                LOGGER.debug("found URL resource \"{}\" : ", url);
+                return url;
+            }
+        }
+        catch (final Exception e) {
+            LOGGER.debug("error getting URL resource \"{}\" : " + e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * Method to get a URL resource from the local machine.
+     *
+     * @param resourceName The resource name
+     * @return The URL to the resource
+     */
+    public static URL getLocalFile(final String resourceName) {
+        try {
+            // Input might already be in URL format
+            final URL ret = new URL(resourceName);
+            final File f = new File(ret.toURI());
+            if (f.exists()) {
+                return ret;
+            }
+        }
+        catch (final Exception ignore) {
+                       // We ignore exceptions here and catch them below
+        }
+
+        try {
+            final File f = new File(resourceName);
+            // Check if the file exists
+            if (f.exists()) {
+                final URL urlret = f.toURI().toURL();
+                LOGGER.debug("resource \"{}\" was found on the local file system", f.toURI().toURL());
+                return urlret;
+            }
+            else {
+                LOGGER.debug("resource \"{}\" does not exist on the local file system", resourceName);
+                return null;
+            }
+        }
+        catch (final Exception e) {
+            LOGGER.debug("error finding resource \"{}\" : " + e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * Gets the file path for a resource on the local file system or on the class path.
+     *
+     * @param resource the resource to the get the file path for
+     * @return the resource file path
+     */
+    public static String getFilePath4Resource(final String resource) {
+        if (resource == null) {
+            return null;
+        }
+
+        URL modelFileURL = getURL4Resource(resource);
+        if (modelFileURL != null) {
+            return modelFileURL.getPath();
+        }
+        else {
+            return resource;
+        }
+    }
+
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/TextFileUtils.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/TextFileUtils.java
new file mode 100644 (file)
index 0000000..d05245f
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ * The Class TextFileUtils is class that provides useful functions for handling text files. Functions to read and wrtie text files to strings and strings are
+ * provided.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class TextFileUtils {
+    private static final int READER_CHAR_BUFFER_SIZE_4096 = 4096;
+
+    private TextFileUtils() {
+               // This class cannot be initialized
+    }
+    
+    /**
+     * Method to return the contents of a text file as a string.
+     *
+     * @param textFilePath The path to the file as a string
+     * @return A string containing the contents of the file
+     * @throws IOException on errors reading text from the file
+     */
+    public static String getTextFileAsString(final String textFilePath) throws IOException {
+        final File textFile = new File(textFilePath);
+        final FileInputStream textFileInputStream = new FileInputStream(textFile);
+        final byte[] textData = new byte[(int) textFile.length()];
+        textFileInputStream.read(textData);
+        textFileInputStream.close();
+        return new String(textData);
+    }
+
+    /**
+     * Method to write contents of a string to a text file.
+     *
+     * @param outString The string to write
+     * @param textFilePath The path to the file as a string
+     * @throws IOException on errors reading text from the file
+     */
+    public static void putStringAsTextFile(final String outString, final String textFilePath) throws IOException {
+        final File textFile = new File(textFilePath);
+        putStringAsFile(outString, textFile);
+    }
+
+    /**
+     * Method to write contents of a string to a text file.
+     *
+     * @param outString The string to write
+     * @param textFile The file to write the string to
+     * @throws IOException on errors reading text from the file
+     */
+    public static void putStringAsFile(final String outString, final File textFile) throws IOException {
+        final FileOutputStream textFileOutputStream = new FileOutputStream(textFile);
+        textFileOutputStream.write(outString.getBytes());
+        textFileOutputStream.close();
+    }
+
+    /**
+     * Method to return the contents of a text steam as a string.
+     *
+     * @param textStream The stream
+     * @return A string containing the output of the stream as text
+     * @throws IOException on errors reading text from the file
+     */
+    public static String getStreamAsString(final InputStream textStream) throws IOException {
+        return getReaderAsString(new BufferedReader(new InputStreamReader(textStream)));
+    }
+
+    /**
+     * Method to return the contents of a reader steam as a string. This closes the reader after use
+     *
+     * @param textReader The reader
+     * @return A string containing the output of the reader as text
+     * @throws IOException on errors reading text from the file
+     */
+    public static String getReaderAsString(final BufferedReader textReader) throws IOException {
+
+        final StringBuilder builder = new StringBuilder();
+        int charsRead = -1;
+        final char[] chars = new char[READER_CHAR_BUFFER_SIZE_4096];
+        do {
+            charsRead = textReader.read(chars, 0, chars.length);
+            if (charsRead > 0) {
+                builder.append(chars, 0, charsRead);
+            }
+        }
+        while (charsRead > 0);
+        return builder.toString();
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/TreeMapUtils.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/TreeMapUtils.java
new file mode 100644 (file)
index 0000000..02ab0dd
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/**
+ * This class provides utility functions for tree maps. A function to find the nearest match in the tree map to an input string is provided.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class TreeMapUtils {
+
+    /**
+     * This class is a utility class that can't be instantiated.
+     */
+    private TreeMapUtils() {
+    }
+
+    /**
+     * Find the list of entries that matches a given word, for example "p" will match "put", "policy", and "push".
+     *
+     * @param <T> the generic type for the value of the tree map
+     * @param searchMap the map that the method operates on
+     * @param word the word to search for
+     * @return the list of entries in the {@code searchMap} that match the {@code word}
+     */
+    public static <T> List<Entry<String, T>> findMatchingEntries(final TreeMap<String, T> searchMap, final String word) {
+        final List<Entry<String, T>> foundNodes = new ArrayList<>();
+
+        // A straight match check
+        if (searchMap.containsKey(word)) {
+            foundNodes.add(new SimpleEntry<>(word, searchMap.get(word)));
+            return foundNodes;
+        }
+
+        // Set up the beginning point for our search for a list of near matches
+        String foundKeyword = searchMap.floorKey(word);
+        if (foundKeyword == null) {
+            foundKeyword = searchMap.firstKey();
+        }
+        else {
+            foundKeyword = searchMap.higherKey(foundKeyword);
+        }
+
+        // Find all the nodes that start with the word we are searching for
+        while (foundKeyword != null) {
+            if (foundKeyword.startsWith(word)) {
+                foundNodes.add(new SimpleEntry<>(foundKeyword, searchMap.get(foundKeyword)));
+                foundKeyword = searchMap.higherKey(foundKeyword);
+            }
+            else {
+                break;
+            }
+        }
+        return foundNodes;
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyComparer.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyComparer.java
new file mode 100644 (file)
index 0000000..8903ea8
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities.comparison;
+
+/**
+ * This class compares two keys and returns their differences. It is used in bulk comparisons in models where maps of keys are being compared. The
+ * {@link KeyComparer} that is returned does the actual comparison
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <K> the type of key being compared
+ */
+public class KeyComparer<K> {
+
+    /**
+     * Compare two keys and return their differences.
+     *
+     * @param leftKey The left key of the comparison
+     * @param rightKey The right key of the comparison
+     * @return The difference between the keys
+     */
+    public KeyDifference<K> compareKeys(final K leftKey, final K rightKey) {
+        return new KeyDifference<>(leftKey, rightKey);
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyDifference.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyDifference.java
new file mode 100644 (file)
index 0000000..43c44ae
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities.comparison;
+
+/**
+ * This class is used to template key differences for bulk key comparisons in models. It performs a difference check between two keys.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <K> the generic type
+ */
+public class KeyDifference<K> {
+    // The keys being compared
+    private K leftKey;
+    private K rightKey;
+
+    /**
+     * Constructor used to set the keys being compared.
+     *
+     * @param leftKey the left key that is being compared
+     * @param rightKey the right key that is being compared
+     */
+    public KeyDifference(final K leftKey, final K rightKey) {
+        this.leftKey = leftKey;
+        this.rightKey = rightKey;
+    }
+
+    /**
+     * Gets the left key.
+     *
+     * @return the left key
+     */
+    public K getLeftKey() {
+        return leftKey;
+    }
+
+    /**
+     * Gets the right key.
+     *
+     * @return the right key
+     */
+    public K getRightKey() {
+        return rightKey;
+    }
+
+    /**
+     * Checks if the left and right keys are equal.
+     *
+     * @return true, if checks if is equal
+     */
+    public boolean isEqual() {
+        return leftKey.equals(rightKey);
+    }
+
+    /**
+     * Gets a string representation of the difference between the keys.
+     *
+     * @param diffsOnly if set, then a blank string is returned if the keys are equal
+     * @return the difference between the keys as a string
+     */
+    public String asString(final boolean diffsOnly) {
+        StringBuilder builder = new StringBuilder();
+
+        if (leftKey.equals(rightKey)) {
+            if (!diffsOnly) {
+                builder.append("left key ");
+                builder.append(leftKey);
+                builder.append(" equals right key ");
+                builder.append(rightKey);
+                builder.append('\n');
+            }
+        }
+        else {
+            builder.append("left key ");
+            builder.append(leftKey);
+            builder.append(" and right key ");
+            builder.append(rightKey);
+            builder.append(" differ\n");
+        }
+
+        return builder.toString();
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyedMapComparer.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyedMapComparer.java
new file mode 100644 (file)
index 0000000..b11f77a
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities.comparison;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Compare two maps and returns their differences. The types of the keys and the values in the two maps being comapred must be the same. The class returns
+ * entries that are only in the left map, only in the right map, entries that have identical keys and different values and entries that have different keys and
+ * different values in a {@link KeyedMapDifference} instance.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <K> the type of the keys in the maps being compared
+ * @param <V> the type of the values in the maps being compared
+ */
+public class KeyedMapComparer<K, V> {
+    /**
+     * Compare two maps and return their differences in a {@link KeyedMapDifference} instance.
+     *
+     * @param leftMap The left map to be compared
+     * @param rightMap The right map to be compared
+     * @return The common, left only, and right only maps in a {@link KeyedMapDifference} instance
+     */
+    public KeyedMapDifference<K, V> compareMaps(final Map<K, V> leftMap, final Map<K, V> rightMap) {
+        KeyedMapDifference<K, V> result = new KeyedMapDifference<>();
+
+        // Get the keys that are only in the left map
+        Set<K> leftOnlyKeys = new TreeSet<>(leftMap.keySet());
+        leftOnlyKeys.removeAll(rightMap.keySet());
+
+        // Get the keys that are only in the right map
+        Set<K> rightOnlyKeys = new TreeSet<>(rightMap.keySet());
+        rightOnlyKeys.removeAll(leftMap.keySet());
+
+        // Find the keys common across both maps
+        Set<K> commonKeys = new TreeSet<>(rightMap.keySet());
+        commonKeys.addAll(leftMap.keySet());
+        commonKeys.removeAll(leftOnlyKeys);
+        commonKeys.removeAll(rightOnlyKeys);
+
+        // Now save the left values
+        for (K key : leftOnlyKeys) {
+            result.getLeftOnly().put(key, leftMap.get(key));
+        }
+
+        // Now save the right values
+        for (K key : rightOnlyKeys) {
+            result.getRightOnly().put(key, rightMap.get(key));
+        }
+
+        // Save the common values to two maps, an identical and different map
+        for (K key : commonKeys) {
+            // Check if the values are identical in each map
+            V leftValue = leftMap.get(key);
+            V rightValue = rightMap.get(key);
+
+            // Store as appropriate
+            if (leftValue.equals(rightValue)) {
+                result.getIdenticalValues().put(key, leftValue);
+            }
+            else {
+                // Store the two values
+                List<V> valueList = new ArrayList<>();
+                valueList.add(leftValue);
+                valueList.add(rightValue);
+
+                result.getDifferentValues().put(key, valueList);
+            }
+        }
+
+        return result;
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyedMapDifference.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/KeyedMapDifference.java
new file mode 100644 (file)
index 0000000..0f9d6ca
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities.comparison;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/**
+ * This class holds the result of a difference check between two keyed maps. Four results are returned in the class. The {@code leftOnly} result is the entries
+ * that appear only in the left map. the {@code rightOnly} result is the entries that appear only in the right map. The {@code differentValues} result are the
+ * entries that have the same key but different values in the maps being compared. The {@code identicalValues} result are the entries with identical keys and
+ * values in both maps being compared.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @param <K> the generic type
+ * @param <V> the generic type
+ */
+public class KeyedMapDifference<K, V> {
+       private static final String KEY = "key=";
+       private static final String VALUE = ",value=";
+
+       // Three maps to hold the comparison result
+       private Map<K, V> leftOnly = new TreeMap<>();
+       private Map<K, V> rightOnly = new TreeMap<>();
+       private Map<K, V> identicalValues = new TreeMap<>();
+       private Map<K, List<V>> differentValues = new TreeMap<>();
+
+       /**
+        * Gets the entries that were found only in the left map.
+        *
+        * @return the entries only in the left map
+        */
+       public Map<K, V> getLeftOnly() {
+               return leftOnly;
+       }
+
+       /**
+        * Gets the entries that were found only in the right map.
+        *
+        * @return the entries only in the right map
+        */
+       public Map<K, V> getRightOnly() {
+               return rightOnly;
+       }
+
+       /**
+        * Gets the entries that were identical (keys and values the same) in both maps.
+        *
+        * @return the identical entries
+        */
+       public Map<K, V> getIdenticalValues() {
+               return identicalValues;
+       }
+
+       /**
+        * Gets the entries that had the same key but different values in both maps.
+        *
+        * @return the entries that were different. There are two values in the list of values for each entry. The first value is the value that was in the left map
+        *         and the second value is the value that was in the right map.
+        */
+       public Map<K, List<V>> getDifferentValues() {
+               return differentValues;
+       }
+
+       /**
+        * Return a string representation of the differences.
+        *
+        * @param diffsOnly if set, then a blank string is returned if the maps are equal
+        * @param keysOnly if set, then a terse string that prints only the keys is returned, otherwise both keys and values are printed
+        * @return the string
+        */
+       public String asString(final boolean diffsOnly, final boolean keysOnly) {
+               StringBuilder builder = new StringBuilder();
+
+               if (leftOnly.isEmpty()) {
+                       if (!diffsOnly) {
+                               builder.append("*** all left keys in right\n");
+                       }
+               }
+               else {
+                       builder.append(getInOneSideOnlyAsString(leftOnly, "left",  keysOnly));
+               }
+
+               if (leftOnly.isEmpty()) {
+                       if (!diffsOnly) {
+                               builder.append("*** all right keys in left\n");
+                       }
+               }
+               else {
+                       builder.append(getInOneSideOnlyAsString(rightOnly, "right",  keysOnly));
+               }
+
+               if (differentValues.isEmpty()) {
+                       if (!diffsOnly) {
+                               builder.append("*** all values in left and right are identical\n");
+                       }
+               }
+               else {
+                       builder.append(getDifferencesAsString(keysOnly));
+               }
+
+               if (!diffsOnly) {
+                       builder.append(getIdenticalsAsString(keysOnly));
+               }
+
+               return builder.toString();
+       }
+
+       /**
+        * Output the entries in a map with entries that are in one side only as a string
+        * @param sideMap the map for the side being checked
+        * @param sideMapString the string that represents the map in output strings
+        * @param keysOnly if true, just add key information and not entries
+        * @return the entries as a string
+        */
+       private Object getInOneSideOnlyAsString(final Map<K, V> sideMap, final String sideMapString, final boolean keysOnly) {
+               StringBuilder builder = new StringBuilder();
+
+               builder.append("*** list of keys on " + sideMapString + " only\n");
+               for (Entry<K, V> leftEntry : sideMap.entrySet()) {
+                       builder.append(KEY);
+                       builder.append(leftEntry.getKey());
+                       if (!keysOnly) {
+                               builder.append(VALUE);
+                               builder.append(leftEntry.getValue());
+                       }
+                       builder.append('\n');
+               }
+
+               return builder.toString();
+       }
+
+       /**
+        * Output the differences between two the maps as a string
+        * @param keysOnly if true, just add key information and not entries
+        * @return the differences as a string
+        */
+       private String getDifferencesAsString(final boolean keysOnly) {
+               StringBuilder builder = new StringBuilder();
+
+               builder.append("*** list of differing entries between left and right\n");
+               for (Entry<K, List<V>> differentEntry : differentValues.entrySet()) {
+                       builder.append(KEY);
+                       builder.append(differentEntry.getKey());
+                       if (!keysOnly) {
+                               builder.append(",values={");
+                               boolean first = true;
+                               for (V differentEntryValue : differentEntry.getValue()) {
+                                       builder.append(differentEntryValue);
+                                       if (first) {
+                                               first = false;
+                                       }
+                                       else {
+                                               builder.append(',');
+                                       }
+                               }
+                               builder.append("}");
+                       }
+                       builder.append('\n');
+               }
+
+               return builder.toString();
+       }
+
+       /**
+        * Output the identical entries in the maps as a string
+        * @param keysOnly if true, just add key information and not entries
+        * @return the identical entries as a string
+        */
+       private String getIdenticalsAsString(final boolean keysOnly) {
+               StringBuilder builder = new StringBuilder();
+
+               builder.append("*** list of identical entries in left and right\n");
+               for (Entry<K, V> identicalEntry : identicalValues.entrySet()) {
+                       builder.append(KEY);
+                       builder.append(identicalEntry.getKey());
+                       if (!keysOnly) {
+                               builder.append(VALUE);
+                               builder.append(identicalEntry.getValue());
+                       }
+                       builder.append('\n');
+               }
+
+               return builder.toString();
+       }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/package-info.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/comparison/package-info.java
new file mode 100644 (file)
index 0000000..f0488ea
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides utility template classes that compare keys and maps of any type.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.model.utilities.comparison;
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/package-info.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/package-info.java
new file mode 100644 (file)
index 0000000..446d009
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides utility classes that are used in APEX models and indeed in other packages that use APEX models.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.model.utilities;
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/typeutils/ClassBuilder.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/typeutils/ClassBuilder.java
new file mode 100644 (file)
index 0000000..e806bd7
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities.typeutils;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+//CHECKSTYLE:OFF: checkstyle:IllegalImport
+import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
+//CHECKSTYLE:ON: checkstyle:IllegalImport
+
+/**
+ * This class is a utility class that builds a class with a set of user defined fields. It is used to get the Type of fields in Java schemas<br>
+ * For more information see:<br>
+ * <a href="http://stackoverflow.com/questions/39401083/class-forname-equivalent-for-creating-parameterizedtypes-from-string">
+ * http://stackoverflow.com/questions/39401083/class-forname-equivalent-for-creating-parameterizedtypes-from-string</a><br>
+ * <a href="https://github.com/KetothXupack/stackoverflow-answers/tree/master/q39401083">
+ * https://github.com/KetothXupack/stackoverflow-answers/tree/master/q39401083</a><br>
+ */
+@SuppressWarnings("restriction")
+public class ClassBuilder {
+    private final Class<?> clazz;
+    private final List<ClassBuilder> parameters = new ArrayList<>();
+
+    /**
+     * Constructor that sets the class for the class builder.
+     *
+     * @param clazz the class of the class builder
+     */
+    public ClassBuilder(final Class<?> clazz) {
+        this.clazz = clazz;
+    }
+
+    /**
+     * Creates a {@link ClassBuilder} instance for a class with the given class name.
+     *
+     * @param className the class name of the class builder to create
+     * @return the class builder that is created
+     */
+    public static ClassBuilder parse(final String className) {
+        try {
+            return new ClassBuilder(Class.forName(className));
+        }
+        catch (ClassNotFoundException e) {
+            try {
+                return new ClassBuilder(Class.forName("java.lang." + className));
+            }
+            catch (Exception ignore) {
+                throw new IllegalArgumentException("Class '" + className + "' not found. Also looked for a class called 'java.lang." + className + "'", e);
+            }
+        }
+    }
+
+    /**
+     * Adds a field to the class builder. Each field is itself a class builder.
+     *
+     * @param fieldBuilder the class builder for the field
+     */
+    public void add(final ClassBuilder fieldBuilder) {
+        parameters.add(fieldBuilder);
+    }
+
+    /**
+     * Builds the {@link Type} of the class.
+     *
+     * @return the {@link Type} of the class
+     */
+    public Type build() {
+        // class is not parameterized
+        if (parameters.isEmpty()) {
+            return clazz;
+        }
+        Type[] paramtypes = new Type[parameters.size()];
+        int i = 0;
+        for (ClassBuilder classBuilder : parameters) {
+            paramtypes[i++] = classBuilder.build();
+        }
+        return ParameterizedTypeImpl.make(clazz, paramtypes, null);
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/typeutils/TypeBuilder.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/typeutils/TypeBuilder.java
new file mode 100644 (file)
index 0000000..a3f22a4
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities.typeutils;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.BailErrorStrategy;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.TokenStream;
+
+/**
+ * This class .
+ */
+public final class TypeBuilder {
+    /**
+     * Private constructor used to prevent sub class instantiation.
+     */
+    private TypeBuilder() {
+    }
+
+    /**
+     * Builds the Type of the Type string that was input.
+     *
+     * @param type the java Type as a string
+     * @return the Type of the string that was input
+     */
+    public static Type build(final String type) {
+        if (type == null || type.length() == 0) {
+            throw new IllegalArgumentException("Blank type string passed to " + TypeBuilder.class.getCanonicalName() + ".build(String type)");
+        }
+
+        try {
+            final CharStream stream = new ANTLRInputStream(type);
+            final TokenStream tokenStream = new CommonTokenStream(new ParametrizedTypeLexer(stream));
+
+            final ParametrizedTypeParser parser = new ParametrizedTypeParser(tokenStream);
+            parser.removeErrorListeners();
+            parser.setErrorHandler(new BailErrorStrategy());
+            parser.setBuildParseTree(true);
+            return parser.type().value.build();
+        }
+        catch (final Exception e) {
+            throw new IllegalArgumentException("Failed to build type '" + type + "': " + e, e);
+        }
+    }
+
+    /**
+     * Gets the class of Java Type.
+     *
+     * @param type the java Type as a string
+     * @return the java Type
+     */
+    public static Class<?> getJavaTypeClass(final String type) {
+        return getJavaTypeClass(build(type));
+    }
+
+    /**
+     * Gets the class of Java Type.
+     *
+     * @param type the java Type as a Type
+     * @return the java Type
+     */
+    public static Class<?> getJavaTypeClass(final Type type) {
+        if (type instanceof Class<?>) {
+            return (Class<?>) type;
+        }
+        else if (type instanceof ParameterizedType) {
+            final Type raw = ((ParameterizedType) type).getRawType();
+            if (!(raw instanceof Class<?>)) {
+                throw new IllegalArgumentException(
+                        "The Parameterised javatype " + type + " with base type " + raw + "  is not a Java 'Class' that can be instantiated");
+            }
+            return (Class<?>) raw;
+        }
+        throw new IllegalArgumentException("The Parameterised javatype " + type + " is not a Java 'Type' that has a 'Class'");
+    }
+
+    /**
+     * Gets the parameters of a Java Type.
+     *
+     * @param type the Java Type
+     * @return the parameters of the java Type
+     */
+    public static Type[] getJavaTypeParameters(final Type type) {
+        if (type instanceof Class<?>) {
+            return new Type[0];
+        }
+        else if (type instanceof ParameterizedType) {
+            return ((ParameterizedType) type).getActualTypeArguments();
+        }
+        throw new IllegalArgumentException("\"The Parameterised javatype \" + type + \" is not a Java 'Type' that has parameter types");
+    }
+}
diff --git a/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/typeutils/package-info.java b/model/utiliites/src/main/java/org/onap/policy/apex/model/utilities/typeutils/package-info.java
new file mode 100644 (file)
index 0000000..ed4b079
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides utility classes that operate on and work with Java Types.
+ * 
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.model.utilities.typeutils;
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/AssertionsTest.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/AssertionsTest.java
new file mode 100644 (file)
index 0000000..db25147
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.onap.policy.apex.model.utilities.Assertions;
+
+/**
+ * The Class ResourceUtilsTest.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class AssertionsTest {
+    @Test
+    public void testAssertions() {
+        Assertions.argumentNotFalse(true, "it is true");
+        
+        try {
+            Assertions.argumentNotFalse(false, "it is false");
+        }
+        catch (IllegalArgumentException e) {
+            assertEquals("it is false", e.getMessage());
+        }
+        
+        Assertions.argumentNotFalse(true, ArithmeticException.class, "it is true");
+        
+        try {
+            Assertions.argumentNotFalse(false, ArithmeticException.class, "it is false");
+        }
+        catch (Exception e) {
+            assertEquals("it is false", e.getMessage());
+        }
+        
+        Assertions.argumentNotNull("Hello", "it is OK");
+        
+        try {
+            Assertions.argumentNotNull(null, "it is null");
+        }
+        catch (IllegalArgumentException e) {
+            assertEquals("it is null", e.getMessage());
+        }
+
+        Assertions.argumentNotNull(true, ArithmeticException.class, "it is OK");
+        
+        try {
+            Assertions.argumentNotNull(null, ArithmeticException.class, "it is null");
+        }
+        catch (Exception e) {
+            assertEquals("it is null", e.getMessage());
+        }
+        
+        Assertions.assignableFrom(java.util.TreeMap.class, java.util.Map.class);
+        
+        try {
+            Assertions.assignableFrom(java.util.Map.class, java.util.TreeMap.class);
+        }
+        catch (IllegalArgumentException e) {
+            assertEquals("java.util.Map is not an instance of java.util.TreeMap", e.getMessage());
+        }
+        
+        Assertions.instanceOf("Hello", String.class);
+        
+        try {
+            Assertions.instanceOf(100, String.class);
+        }
+        catch (IllegalArgumentException e) {
+            assertEquals("java.lang.Integer is not an instance of java.lang.String", e.getMessage());
+        }
+        
+        Assertions.validateStringParameter("name", "MyName", "^M.*e$");
+
+        try {
+            Assertions.validateStringParameter("name", "MyName", "^M.*f$");
+        }
+        catch (IllegalArgumentException e) {
+            assertEquals("parameter \"name\": value \"MyName\", does not match regular expression \"^M.*f$\"", e.getMessage());
+        }
+    }
+}
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/CollectionUtilitiesTest.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/CollectionUtilitiesTest.java
new file mode 100644 (file)
index 0000000..4682d98
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.onap.policy.apex.model.utilities.CollectionUtils;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class CollectionUtilitiesTest {
+
+    @Test
+    public void testNullLists() {
+        List<String> leftList  = new ArrayList<String>();
+        List<String> rightList = new ArrayList<String>();
+        
+        int result = 0;
+        
+        result = CollectionUtils.compareLists(null, null);
+        assertEquals(0, result);
+
+        result = CollectionUtils.compareLists(leftList, null);
+        assertEquals(-1, result);
+
+        result = CollectionUtils.compareLists(null, rightList);
+        assertEquals(1, result);
+
+        result = CollectionUtils.compareLists(leftList, rightList);
+        assertEquals(0, result);
+
+        leftList.add("AAA");
+        result = CollectionUtils.compareLists(leftList, rightList);
+        assertEquals(-1, result);
+
+        rightList.add("AAA");
+        result = CollectionUtils.compareLists(leftList, rightList);
+        assertEquals(0, result);
+
+        rightList.add("BBB");
+        result = CollectionUtils.compareLists(leftList, rightList);
+        assertEquals(1, result);
+
+        leftList.add("BBB");
+        result = CollectionUtils.compareLists(leftList, rightList);
+        assertEquals(0, result);
+
+        leftList.add("CCA");
+        rightList.add("CCB");
+        result = CollectionUtils.compareLists(leftList, rightList);
+        assertEquals(-1, result);
+        
+        leftList.remove(leftList.size() -1);
+        rightList.remove(rightList.size() -1);
+        result = CollectionUtils.compareLists(leftList, rightList);
+        assertEquals(0, result);
+
+        leftList.add("CCB");
+        rightList.add("CCA");
+        result = CollectionUtils.compareLists(leftList, rightList);
+        assertEquals(1, result);
+        
+        leftList.remove(leftList.size() -1);
+        rightList.remove(rightList.size() -1);
+        result = CollectionUtils.compareLists(leftList, rightList);
+        assertEquals(0, result);
+    }
+}
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/DirectoryUtilsTest.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/DirectoryUtilsTest.java
new file mode 100644 (file)
index 0000000..84e9733
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.onap.policy.apex.model.utilities.DirectoryUtils;
+import org.onap.policy.apex.model.utilities.TextFileUtils;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class DirectoryUtilsTest {
+
+    @Test
+    public void test() throws IOException {
+        DirectoryUtils.emptyDirectory(new File("/i/dont/exist"));
+        
+        File tempDir = Files.createTempDirectory("test").toFile();
+
+        Files.createTempDirectory(tempDir.toPath(), "testsubprefix");
+
+        TextFileUtils.putStringAsTextFile("Temp File 0 contents", tempDir.getAbsolutePath() + "/tempFile0.tmp");
+        TextFileUtils.putStringAsTextFile("Temp File 1 contents", tempDir.getAbsolutePath() + "/tempFile1.tmp");
+        
+        DirectoryUtils.emptyDirectory(tempDir);
+        
+        DirectoryUtils.getLocalTempDirectory(null);
+        
+        byte[] byteArray = new byte[] {0, 0, 0};
+        DirectoryUtils.getLocalTempDirectory(Arrays.toString(byteArray));
+    }
+
+}
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/PropertyUtilsTest.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/PropertyUtilsTest.java
new file mode 100644 (file)
index 0000000..e25e3ff
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.onap.policy.apex.model.utilities.PropertyUtils;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class PropertyUtilsTest {
+
+    @Test
+    public void test() {
+        System.setProperty("boolean.true", "true");
+        System.setProperty("boolean.false", "false");
+        System.setProperty("boolean.blank", " ");
+        
+        assertNotNull(PropertyUtils.getAllProperties());
+        
+        assertEquals(false, PropertyUtils.propertySetOrTrue(null));
+        assertEquals(false, PropertyUtils.propertySetOrTrue("ZOOBY"));
+        assertEquals(true,  PropertyUtils.propertySetOrTrue("boolean.true"));
+        assertEquals(true,  PropertyUtils.propertySetOrTrue("boolean.blank"));
+        assertEquals(false, PropertyUtils.propertySetOrTrue("boolean.false"));
+    }
+}
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/ResourceUtilsTest.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/ResourceUtilsTest.java
new file mode 100644 (file)
index 0000000..9f78906
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.apex.model.utilities.ResourceUtils;
+
+/**
+ * The Class ResourceUtilsTest.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ResourceUtilsTest {
+    private File tmpDir = null;
+    private File tmpEmptyFile = null;
+    private File tmpUsedFile = null;
+
+    private String jarDirResource = null;
+    private String jarFileResource = null;
+
+    private final String pathDirResource = "testdir";
+    private final String pathFileResource = "testdir/testfile.xml";
+
+    private final String nonExistantResource = "somewhere/over/the/rainbow";
+    private final String invalidResource = "@%%%\\\\_:::DESD";
+
+    /**
+     * Setup resource utils test.
+     *
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    @Before
+    public void setupResourceUtilsTest() throws IOException {
+        tmpDir = new File(System.getProperty("java.io.tmpdir"));
+        tmpEmptyFile = File.createTempFile(this.getClass().getName(), ".tmp");
+        tmpUsedFile = File.createTempFile(this.getClass().getName(), ".tmp");
+
+        jarDirResource = "META-INF";
+        jarFileResource = "META-INF/MANIFEST.MF";
+
+        final FileWriter fileWriter = new FileWriter(tmpUsedFile);
+        fileWriter.write("Bluebirds fly over the rainbow");
+        fileWriter.close();
+    }
+
+    /**
+     * Test get url resource.
+     */
+    @Test
+    public void testGetURLResource() {
+        URL theURL = ResourceUtils.getURLResource(tmpDir.getAbsolutePath());
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getURLResource(tmpEmptyFile.getAbsolutePath());
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getURLResource(tmpUsedFile.getAbsolutePath());
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getURLResource(jarDirResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURLResource(jarFileResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURLResource(pathDirResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURLResource(pathFileResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURLResource("file:///" + pathDirResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile("src/test/resources/" + pathDirResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile("src/test/resources/" + pathFileResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURLResource(nonExistantResource);
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getURLResource(invalidResource);
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getURLResource(null);
+        assertNull(theURL);
+    }
+
+    /**
+     * Test get local file.
+     */
+    @Test
+    public void testGetLocalFile() {
+        URL theURL = ResourceUtils.getLocalFile(tmpDir.getAbsolutePath());
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile(tmpEmptyFile.getAbsolutePath());
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile(tmpUsedFile.getAbsolutePath());
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile(jarDirResource);
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile(jarFileResource);
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile(pathDirResource);
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile(pathFileResource);
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile("src/test/resources/" + pathDirResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile("src/test/resources/" + pathFileResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile(nonExistantResource);
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile(invalidResource);
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getLocalFile("file:///");
+        assertNotNull(theURL);
+        
+        theURL = ResourceUtils.getLocalFile("file:///testdir/testfile.xml");
+        assertNull(theURL);
+        
+        theURL = ResourceUtils.getLocalFile(null);
+        assertNull(theURL);
+    }
+
+    /**
+     * Test get resource as stream.
+     */
+    @Test
+    public void testGetResourceAsStream() {
+        InputStream theStream = ResourceUtils.getResourceAsStream(tmpDir.getAbsolutePath());
+        assertNotNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream(tmpEmptyFile.getAbsolutePath());
+        assertNotNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream(tmpUsedFile.getAbsolutePath());
+        assertNotNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream(jarDirResource);
+        assertNotNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream(jarFileResource);
+        assertNotNull(theStream);
+        
+        theStream = ResourceUtils.getResourceAsStream(pathDirResource);
+        assertNotNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream(pathFileResource);
+        assertNotNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream("src/test/resources/" + pathDirResource);
+        assertNotNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream("src/test/resources/" + pathFileResource);
+        assertNotNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream(nonExistantResource);
+        assertNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream(invalidResource);
+        assertNull(theStream);
+
+        theStream = ResourceUtils.getResourceAsStream(null);
+        assertNull(null);
+
+        theStream = ResourceUtils.getResourceAsStream("");
+        assertNull(null);
+    }
+
+    /**
+     * Test get resource as string.
+     */
+    @Test
+    public void testGetResourceAsString() {
+        String theString = ResourceUtils.getResourceAsString(tmpDir.getAbsolutePath());
+        assertNotNull(theString);
+
+        theString = ResourceUtils.getResourceAsString(tmpEmptyFile.getAbsolutePath());
+        assertTrue(theString.equals(""));
+
+        theString = ResourceUtils.getResourceAsString(tmpUsedFile.getAbsolutePath());
+        assertTrue(theString.equals("Bluebirds fly over the rainbow"));
+
+        theString = ResourceUtils.getResourceAsString(jarFileResource);
+        assertNotNull(theString);
+
+        theString = ResourceUtils.getResourceAsString(pathDirResource);
+        assertNotNull(theString);
+
+        theString = ResourceUtils.getResourceAsString(pathFileResource);
+        assertNotNull(theString);
+
+        theString = ResourceUtils.getResourceAsString("src/test/resources/" + pathDirResource);
+        assertNotNull(theString);
+
+        theString = ResourceUtils.getResourceAsString("src/test/resources/" + pathFileResource);
+        assertNotNull(theString);
+
+        theString = ResourceUtils.getResourceAsString(nonExistantResource);
+        assertNull(theString);
+
+        theString = ResourceUtils.getResourceAsString(invalidResource);
+        assertNull(theString);
+
+        theString = ResourceUtils.getResourceAsString(null);
+        assertNull(theString);
+
+        theString = ResourceUtils.getResourceAsString("");
+        assertEquals("org\ntestdir\n", theString);
+    }
+
+    @Test
+    public void testGetURL4Resource() {
+        URL theURL = ResourceUtils.getURL4Resource(tmpDir.getAbsolutePath());
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource(tmpEmptyFile.getAbsolutePath());
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource(tmpUsedFile.getAbsolutePath());
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource(jarDirResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource(jarFileResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource(pathDirResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource(pathFileResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource("src/test/resources/" + pathDirResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource("src/test/resources/" + pathFileResource);
+        assertNotNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource(nonExistantResource);
+        assertNull(theURL);
+
+        theURL = ResourceUtils.getURL4Resource(invalidResource);
+        assertNull(theURL);
+    }
+
+    @Test
+    public void testGetFilePath4Resource() {
+        assertNull(ResourceUtils.getFilePath4Resource(null));
+        assertEquals("/something/else", ResourceUtils.getFilePath4Resource("/something/else"));
+        assertTrue(ResourceUtils.getFilePath4Resource("xml/example.xml").endsWith("xml/example.xml"));
+    }
+    
+    /**
+     * Cleandown resource utils test.
+     */
+    @After
+    public void cleandownResourceUtilsTest() {
+        tmpEmptyFile.delete();
+        tmpUsedFile.delete();
+    }
+}
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/TextFileUtilsTest.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/TextFileUtilsTest.java
new file mode 100644 (file)
index 0000000..4e5cba3
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.junit.Test;
+import org.onap.policy.apex.model.utilities.TextFileUtils;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TextFileUtilsTest {
+
+    @Test
+    public void test() throws IOException {
+        File tempTextFile = File.createTempFile("Test", "txt");
+        
+        TextFileUtils.putStringAsTextFile("This is the contents of a text file", tempTextFile.getAbsolutePath());
+        
+        String textFileString0 = TextFileUtils.getTextFileAsString(tempTextFile.getAbsolutePath());
+        assertEquals("This is the contents of a text file", textFileString0);
+        
+        FileInputStream fis = new FileInputStream(tempTextFile);
+        String textFileString1 = TextFileUtils.getStreamAsString(fis);
+        assertEquals(textFileString0, textFileString1);
+        
+    }
+
+}
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/TreeMapUtilsTest.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/TreeMapUtilsTest.java
new file mode 100644 (file)
index 0000000..10a31e3
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.junit.Test;
+import org.onap.policy.apex.model.utilities.TreeMapUtils;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TreeMapUtilsTest {
+
+    @Test
+    public void test() {
+        TreeMap<String, String> testTreeMap = new TreeMap<String, String>();
+        testTreeMap.put("G", "G");
+        testTreeMap.put("H", "H");
+        testTreeMap.put("JA", "JA");
+        testTreeMap.put("JAM", "JAM");
+        testTreeMap.put("JOE", "JOE");
+        testTreeMap.put("JOSH", "JOSH");
+        testTreeMap.put("K", "K");
+        
+        List<Entry<String, String>> foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "F");
+        assertEquals(0, foundKeyList.size());
+
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "G");
+        assertEquals("G", foundKeyList.get(0).getKey());
+
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "H");
+        assertEquals("H", foundKeyList.get(0).getKey());
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "I");
+        assertEquals(0, foundKeyList.size());
+        
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "J");
+        assertEquals("JA", foundKeyList.get(0).getKey());
+        
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "JA");
+        assertEquals("JA", foundKeyList.get(0).getKey());
+        
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "JB");
+        assertEquals(0, foundKeyList.size());
+
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "JO");
+        assertEquals("JOE", foundKeyList.get(0).getKey());
+        
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "JOE");
+        assertEquals("JOE", foundKeyList.get(0).getKey());
+        
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "JOS");
+        assertEquals("JOSH", foundKeyList.get(0).getKey());
+        
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "JOSH");
+        assertEquals("JOSH", foundKeyList.get(0).getKey());
+        
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "K");
+        assertEquals("K", foundKeyList.get(0).getKey());
+        
+        foundKeyList = TreeMapUtils.findMatchingEntries(testTreeMap, "L");
+        assertEquals(0, foundKeyList.size());
+    }
+}
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/typeutils/ParserTest.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/typeutils/ParserTest.java
new file mode 100644 (file)
index 0000000..bf42261
--- /dev/null
@@ -0,0 +1,92 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities.typeutils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.Type;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.BailErrorStrategy;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.TokenStream;
+import org.junit.Test;
+
+
+/**
+ */
+public class ParserTest {
+    @Test
+    public void testParser() {
+        final CharStream stream = new ANTLRInputStream(
+                "java.util.Map<java.util.List<java.lang.Integer>,java.util.Set<java.lang.String>>");
+        final TokenStream tokenStream = new CommonTokenStream(new ParametrizedTypeLexer(stream));
+
+        final ParametrizedTypeParser parser = new ParametrizedTypeParser(tokenStream);
+        parser.removeErrorListeners();
+        parser.setErrorHandler(new BailErrorStrategy());
+        parser.setBuildParseTree(true);
+        assertEquals("java.util.Map<java.util.List<java.lang.Integer>, java.util.Set<java.lang.String>>",
+                parser.type().value.build().getTypeName());
+
+    }
+
+    @Test
+    public void testBuilder() throws IllegalArgumentException {
+        String t = "java.util.Map<java.util.List<java.lang.Integer>,java.util.Set<java.lang.String>>";
+        Type ret = TypeBuilder.build(t);
+        assertEquals("java.util.Map<java.util.List<java.lang.Integer>, java.util.Set<java.lang.String>>",
+                ret.getTypeName());
+        assertEquals(java.util.Map.class, TypeBuilder.getJavaTypeClass(ret));
+
+        final Type[] args = TypeBuilder.getJavaTypeParameters(ret);
+        assertEquals("java.util.List<java.lang.Integer>", args[0].getTypeName());
+        assertEquals("java.util.Set<java.lang.String>", args[1].getTypeName());
+        t = "java.lang.Integer";
+        ret = TypeBuilder.build(t);
+        assertEquals(java.lang.Integer.class, TypeBuilder.getJavaTypeClass(ret));
+
+    }
+
+    @Test
+    public void testBoundaryConditions() {
+        try {
+            TypeBuilder.build(null);
+            fail("Test should throw exception");
+        } catch (final IllegalArgumentException e) {
+            assertEquals(
+                    "Blank type string passed to org.onap.policy.apex.model.utilities.typeutils.TypeBuilder.build(String type)",
+                    e.getMessage());
+        }
+
+        try {
+            TypeBuilder.build("org.zooby.Wooby");
+            fail("Test should throw exception");
+        } catch (final IllegalArgumentException e) {
+            assertEquals(e.getMessage(), "Failed to build type 'org.zooby.Wooby': java.lang.IllegalArgumentException: "
+                    + "Class 'org.zooby.Wooby' not found. Also looked for a class called 'java.lang.org.zooby.Wooby'");
+        }
+
+        assertEquals(TypeBuilder.getJavaTypeClass("java.lang.String"), String.class);
+    }
+}
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/typeutils/TestKeyComparer.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/typeutils/TestKeyComparer.java
new file mode 100644 (file)
index 0000000..c2e84c6
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities.typeutils;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.policy.apex.model.utilities.comparison.KeyComparer;
+import org.onap.policy.apex.model.utilities.comparison.KeyDifference;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestKeyComparer {
+
+    @Test
+    public void test() {
+        KeyDifference<String> keyDifference = new KeyComparer<String>().compareKeys("Hello", "Goodbye");
+        
+        assertFalse(keyDifference.isEqual());
+        assertTrue("Hello".equals(keyDifference.getLeftKey().toString()));
+        assertTrue("Goodbye".equals(keyDifference.getRightKey().toString()));
+
+        assertTrue("left key Hello and right key Goodbye differ\n".equals(keyDifference.asString(true)));
+        assertTrue("left key Hello and right key Goodbye differ\n".equals(keyDifference.asString(false)));
+        
+        KeyDifference<String> keyDifference2 = new KeyComparer<String>().compareKeys("Here", "Here");
+        assertTrue("".equals(keyDifference2.asString(true)));
+        assertTrue("left key Here equals right key Here\n".equals(keyDifference2.asString(false)));
+    }
+}
diff --git a/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/typeutils/TestKeyedMapComparer.java b/model/utiliites/src/test/java/org/onap/policy/apex/model/utilities/typeutils/TestKeyedMapComparer.java
new file mode 100644 (file)
index 0000000..33b8101
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2016-2018 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.model.utilities.typeutils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.TreeMap;
+
+import org.junit.Test;
+import org.onap.policy.apex.model.utilities.comparison.KeyedMapComparer;
+import org.onap.policy.apex.model.utilities.comparison.KeyedMapDifference;
+
+/**
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TestKeyedMapComparer {
+
+    @Test
+    public void test() {
+        TreeMap<String, String> leftMap = new TreeMap<String, String>();
+        leftMap.put("B", "BBBBB");
+        leftMap.put("C", "CCCCC");
+        leftMap.put("E", "EEEEE");
+        leftMap.put("G", "GGGGG");
+
+        TreeMap<String, String> rightMap = new TreeMap<String, String>();
+        rightMap.put("A", "AAAAA");
+        rightMap.put("B", "B");
+        rightMap.put("D", "DDDDD");
+        rightMap.put("E", "EEEEE");
+        rightMap.put("F", "FFFFF");
+        rightMap.put("G", "G");
+        
+        KeyedMapDifference<String, String> kmComparedSame = new KeyedMapComparer<String, String>().compareMaps(leftMap, leftMap);
+        KeyedMapDifference<String, String> kmComparedDiff = new KeyedMapComparer<String, String>().compareMaps(leftMap, rightMap);
+        
+        assertTrue(kmComparedSame.getIdenticalValues().equals(leftMap));
+        assertEquals(1, kmComparedDiff.getLeftOnly().size());
+        assertEquals(3, kmComparedDiff.getRightOnly().size());
+        assertEquals(2, kmComparedDiff.getDifferentValues().size());
+        assertEquals(1, kmComparedDiff.getIdenticalValues().size());
+        
+        assertNotNull(kmComparedSame.asString(true, true));
+        assertNotNull(kmComparedSame.asString(true, false));
+        assertNotNull(kmComparedSame.asString(false, false));
+        assertNotNull(kmComparedSame.asString(false, true));
+        
+        assertNotNull(kmComparedDiff.asString(true, true));
+        assertNotNull(kmComparedDiff.asString(true, false));
+        assertNotNull(kmComparedDiff.asString(false, false));
+        assertNotNull(kmComparedDiff.asString(false, true));
+    }
+}
diff --git a/model/utiliites/src/test/resources/testdir/testfile.xml b/model/utiliites/src/test/resources/testdir/testfile.xml
new file mode 100644 (file)
index 0000000..ddffc58
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2016-2018 Ericsson. 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.
+  
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
diff --git a/pom.xml b/pom.xml
new file mode 100644 (file)
index 0000000..7f911d9
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,124 @@
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2018 Ericsson. 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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.onap.policy.parent</groupId>
+        <artifactId>integration</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+        <relativePath />
+    </parent>
+
+    <groupId>org.onap.policy.apex.apex-pdp</groupId>
+    <artifactId>apex-pdp</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>Apex PDP engine</name>
+    <description>Packaging for all the Apex components, the engine, the WAR service, and the editor.</description>
+
+    <properties>
+        <encoding>UTF-8</encoding>
+        <file.encoding>UTF-8</file.encoding>
+    </properties>
+
+    <distributionManagement>
+        <site>
+            <id>ecomp-site</id>
+            <url>dav:${onap.nexus.url}${sitePath}</url>
+        </site>
+    </distributionManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-ext</artifactId>
+            <version>1.7.25</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+        </dependency>
+    </dependencies>
+
+
+    <profiles>
+        <profile>
+            <!--This profile is used to store Eclipse m2e settings only. It has no 
+                influence on the Maven build itself. -->
+            <id>only-eclipse</id>
+            <activation>
+                <property>
+                    <name>m2e.version</name>
+                </property>
+            </activation>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.eclipse.m2e</groupId>
+                            <artifactId>lifecycle-mapping</artifactId>
+                            <version>1.0.0</version>
+                            <configuration>
+                                <lifecycleMappingMetadata>
+                                    <pluginExecutions>
+                                        <pluginExecution>
+                                            <pluginExecutionFilter>
+                                                <groupId>org.commonjava.maven.plugins</groupId>
+                                                <artifactId>directory-maven-plugin</artifactId>
+                                                <versionRange>0.2</versionRange>
+                                                <goals>
+                                                    <goal>directory-of</goal>
+                                                </goals>
+                                            </pluginExecutionFilter>
+                                            <action>
+                                                <execute />
+                                            </action>
+                                        </pluginExecution>
+                                    </pluginExecutions>
+                                </lifecycleMappingMetadata>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+    </profiles>
+
+
+    <modules>
+        <module>model</module>
+    </modules>
+</project>
\ No newline at end of file
diff --git a/version.properties b/version.properties
new file mode 100644 (file)
index 0000000..a3ac0d9
--- /dev/null
@@ -0,0 +1,13 @@
+# Versioning variables
+# Note that these variables cannot be structured (e.g. : version.release or version.snapshot etc... )
+# because they are used in Jenkins, whose plug-in doesn't support
+
+major=2
+minor=0
+patch=0
+
+base_version=${major}.${minor}.${patch}
+
+# Release must be completed with git revision # in Jenkins
+release_version=${base_version}
+snapshot_version=${base_version}-SNAPSHOT